Compare commits
2 Commits
9af3192d1d
...
48b6ca6bd7
| Author | SHA1 | Date | |
|---|---|---|---|
| 48b6ca6bd7 | |||
| 4b0000c116 |
@@ -1,430 +0,0 @@
|
||||
# Attune Project Rules
|
||||
|
||||
## Project Overview
|
||||
Attune is an **event-driven automation and orchestration platform** built in Rust, similar to StackStorm. It enables building complex workflows triggered by events with multi-tenancy, RBAC, and human-in-the-loop capabilities.
|
||||
|
||||
## Development Status: Pre-Production
|
||||
|
||||
**This project is under active development with no users, deployments, or stable releases.**
|
||||
|
||||
### Breaking Changes Policy
|
||||
- **Breaking changes are explicitly allowed and encouraged** when they improve the architecture, API design, or developer experience
|
||||
- **No backward compatibility required** - there are no existing versions to support
|
||||
- **Database migrations can be modified or consolidated** - no production data exists
|
||||
- **API contracts can change freely** - no external integrations depend on them, only internal interfaces with other services and the web UI must be maintained.
|
||||
- **Configuration formats can be redesigned** - no existing config files need migration
|
||||
- **Service interfaces can be refactored** - no live deployments to worry about
|
||||
|
||||
When this project reaches v1.0 or gets its first production deployment, this section should be removed and replaced with appropriate stability guarantees and versioning policies.
|
||||
|
||||
## Languages & Core Technologies
|
||||
- **Primary Language**: Rust 2021 edition
|
||||
- **Database**: PostgreSQL 14+ (primary data store + LISTEN/NOTIFY pub/sub)
|
||||
- **Message Queue**: RabbitMQ 3.12+ (via lapin)
|
||||
- **Cache**: Redis 7.0+ (optional)
|
||||
- **Web UI**: TypeScript + React 19 + Vite
|
||||
- **Async Runtime**: Tokio
|
||||
- **Web Framework**: Axum 0.8
|
||||
- **ORM**: SQLx (compile-time query checking)
|
||||
|
||||
## Project Structure (Cargo Workspace)
|
||||
|
||||
```
|
||||
attune/
|
||||
├── Cargo.toml # Workspace root
|
||||
├── config.{development,test}.yaml # Environment configs
|
||||
├── Makefile # Common dev tasks
|
||||
├── crates/ # Rust services
|
||||
│ ├── common/ # Shared library (models, db, repos, mq, config, error)
|
||||
│ ├── api/ # REST API service (8080)
|
||||
│ ├── executor/ # Execution orchestration service
|
||||
│ ├── worker/ # Action execution service (multi-runtime)
|
||||
│ ├── sensor/ # Event monitoring service
|
||||
│ ├── notifier/ # Real-time notification service
|
||||
│ └── cli/ # Command-line interface
|
||||
├── migrations/ # SQLx database migrations (18 tables)
|
||||
├── web/ # React web UI (Vite + TypeScript)
|
||||
├── packs/ # Pack bundles
|
||||
│ └── core/ # Core pack (timers, HTTP, etc.)
|
||||
├── docs/ # Technical documentation
|
||||
├── scripts/ # Helper scripts (DB setup, testing)
|
||||
└── tests/ # Integration tests
|
||||
```
|
||||
|
||||
## Service Architecture (Distributed Microservices)
|
||||
|
||||
1. **attune-api**: REST API gateway, JWT auth, all client interactions
|
||||
2. **attune-executor**: Manages execution lifecycle, scheduling, policy enforcement
|
||||
3. **attune-worker**: Executes actions in multiple runtimes (Python/Node.js/containers)
|
||||
4. **attune-sensor**: Monitors triggers, generates events
|
||||
5. **attune-notifier**: Real-time notifications via PostgreSQL LISTEN/NOTIFY + WebSocket
|
||||
|
||||
**Communication**: Services communicate via RabbitMQ for async operations
|
||||
|
||||
## Docker Compose Orchestration
|
||||
|
||||
**All Attune services run via Docker Compose.**
|
||||
|
||||
- **Compose file**: `docker-compose.yaml` (root directory)
|
||||
- **Configuration**: `config.docker.yaml` (Docker-specific settings)
|
||||
- **Default user**: `test@attune.local` / `TestPass123!` (auto-created)
|
||||
|
||||
**Services**:
|
||||
- **Infrastructure**: postgres, rabbitmq, redis
|
||||
- **Init** (run-once): migrations, init-user, init-packs
|
||||
- **Application**: api (8080), executor, worker-{shell,python,node,full}, sensor, notifier (8081), web (3000)
|
||||
|
||||
**Commands**:
|
||||
```bash
|
||||
docker compose up -d # Start all services
|
||||
docker compose down # Stop all services
|
||||
docker compose logs -f <svc> # View logs
|
||||
```
|
||||
|
||||
**Key environment overrides**: `JWT_SECRET`, `ENCRYPTION_KEY` (required for production)
|
||||
|
||||
## Domain Model & Event Flow
|
||||
|
||||
**Critical Event Flow**:
|
||||
```
|
||||
Sensor → Trigger fires → Event created → Rule evaluates →
|
||||
Enforcement created → Execution scheduled → Worker executes Action
|
||||
```
|
||||
|
||||
**Key Entities** (all in `public` schema, IDs are `i64`):
|
||||
- **Pack**: Bundle of automation components (actions, sensors, rules, triggers)
|
||||
- **Trigger**: Event type definition (e.g., "webhook_received")
|
||||
- **Sensor**: Monitors for trigger conditions, creates events
|
||||
- **Event**: Instance of a trigger firing with payload
|
||||
- **Action**: Executable task with parameters
|
||||
- **Rule**: Links triggers to actions with conditional logic
|
||||
- **Enforcement**: Represents a rule activation
|
||||
- **Execution**: Single action run; supports parent-child relationships for workflows
|
||||
- **Workflow Tasks**: Workflow-specific metadata stored in `execution.workflow_task` JSONB field
|
||||
- **Inquiry**: Human-in-the-loop async interaction (approvals, inputs)
|
||||
- **Identity**: User/service account with RBAC permissions
|
||||
- **Key**: Encrypted secrets storage
|
||||
|
||||
## Key Tools & Libraries
|
||||
|
||||
### Shared Dependencies (workspace-level)
|
||||
- **Async**: tokio, async-trait, futures
|
||||
- **Web**: axum, tower, tower-http
|
||||
- **Database**: sqlx (with postgres, json, chrono, uuid features)
|
||||
- **Serialization**: serde, serde_json, serde_yaml_ng
|
||||
- **Logging**: tracing, tracing-subscriber
|
||||
- **Error Handling**: anyhow, thiserror
|
||||
- **Config**: config crate (YAML + env vars)
|
||||
- **Validation**: validator
|
||||
- **Auth**: jsonwebtoken, argon2
|
||||
- **CLI**: clap
|
||||
- **OpenAPI**: utoipa, utoipa-swagger-ui
|
||||
- **Message Queue**: lapin (RabbitMQ)
|
||||
- **HTTP Client**: reqwest
|
||||
- **Testing**: mockall, tempfile, serial_test
|
||||
|
||||
### Web UI Dependencies
|
||||
- **Framework**: React 19 + react-router-dom
|
||||
- **State**: Zustand, @tanstack/react-query
|
||||
- **HTTP**: axios (with generated OpenAPI client)
|
||||
- **Styling**: Tailwind CSS
|
||||
- **Icons**: lucide-react
|
||||
- **Build**: Vite, TypeScript
|
||||
|
||||
## Configuration System
|
||||
- **Primary**: YAML config files (`config.yaml`, `config.{env}.yaml`)
|
||||
- **Overrides**: Environment variables with prefix `ATTUNE__` and separator `__`
|
||||
- Example: `ATTUNE__DATABASE__URL`, `ATTUNE__SERVER__PORT`
|
||||
- **Loading Priority**: Base config → env-specific config → env vars
|
||||
- **Required for Production**: `JWT_SECRET`, `ENCRYPTION_KEY` (32+ chars)
|
||||
- **Location**: Root directory or `ATTUNE_CONFIG` env var path
|
||||
|
||||
## Authentication & Security
|
||||
- **Auth Type**: JWT (access tokens: 1h, refresh tokens: 7d)
|
||||
- **Password Hashing**: Argon2id
|
||||
- **Protected Routes**: Use `RequireAuth(user)` extractor in Axum
|
||||
- **Secrets Storage**: AES-GCM encrypted in `key` table with scoped ownership
|
||||
- **User Info**: Stored in `identity` table
|
||||
|
||||
## Code Conventions & Patterns
|
||||
|
||||
### General
|
||||
- **Error Handling**: Use `attune_common::error::Error` and `Result<T>` type alias
|
||||
- **Async Everywhere**: All I/O operations use async/await with Tokio
|
||||
- **Module Structure**: Public API exposed via `mod.rs` with `pub use` re-exports
|
||||
|
||||
### Database Layer
|
||||
- **Schema**: All tables use unqualified names; schema determined by PostgreSQL `search_path`
|
||||
- **Production**: Always uses `public` schema (configured explicitly in `config.production.yaml`)
|
||||
- **Tests**: Each test uses isolated schema (e.g., `test_a1b2c3d4`) for true parallel execution
|
||||
- **Schema Resolution**: PostgreSQL `search_path` mechanism, NO hardcoded schema prefixes in queries
|
||||
- **Models**: Defined in `common/src/models.rs` with `#[derive(FromRow)]` for SQLx
|
||||
- **Repositories**: One per entity in `common/src/repositories/`, provides CRUD + specialized queries
|
||||
- **Pattern**: Services MUST interact with DB only through repository layer (no direct queries)
|
||||
- **Transactions**: Use SQLx transactions for multi-table operations
|
||||
- **IDs**: All IDs are `i64` (BIGSERIAL in PostgreSQL)
|
||||
- **Timestamps**: `created`/`updated` columns auto-managed by DB triggers
|
||||
- **JSON Fields**: Use `serde_json::Value` for flexible attributes/parameters, including `execution.workflow_task` JSONB
|
||||
- **Enums**: PostgreSQL enum types mapped with `#[sqlx(type_name = "...")]`
|
||||
- **Workflow Tasks**: Stored as JSONB in `execution.workflow_task` (consolidated from separate table 2026-01-27)
|
||||
**Table Count**: 17 tables total in the schema
|
||||
|
||||
### Pack File Loading
|
||||
- **Pack Base Directory**: Configured via `packs_base_dir` in config (defaults to `/opt/attune/packs`, development uses `./packs`)
|
||||
- **Action Script Resolution**: Worker constructs file paths as `{packs_base_dir}/{pack_ref}/actions/{entrypoint}`
|
||||
- **Runtime Selection**: Determined by action's runtime field (e.g., "Shell", "Python") - compared case-insensitively
|
||||
- **Parameter Passing**: Shell actions receive parameters as environment variables with `ATTUNE_ACTION_` prefix
|
||||
|
||||
### API Service (`crates/api`)
|
||||
- **Structure**: `routes/` (endpoints) + `dto/` (request/response) + `auth/` + `middleware/`
|
||||
- **Responses**: Standardized `ApiResponse<T>` wrapper with `data` field
|
||||
- **Protected Routes**: Apply `RequireAuth` middleware
|
||||
- **OpenAPI**: Documented with `utoipa` attributes (`#[utoipa::path]`)
|
||||
- **Error Handling**: Custom `ApiError` type with proper HTTP status codes
|
||||
- **Available at**: `http://localhost:8080` (dev), `/api-spec/openapi.json` for spec
|
||||
|
||||
### Common Library (`crates/common`)
|
||||
- **Modules**: `models`, `repositories`, `db`, `config`, `error`, `mq`, `crypto`, `utils`, `workflow`, `pack_registry`
|
||||
- **Exports**: Commonly used types re-exported from `lib.rs`
|
||||
- **Repository Layer**: All DB access goes through repositories in `repositories/`
|
||||
- **Message Queue**: Abstractions in `mq/` for RabbitMQ communication
|
||||
|
||||
### Web UI (`web/`)
|
||||
- **Generated Client**: OpenAPI client auto-generated from API spec
|
||||
- Run: `npm run generate:api` (requires API running on :8080)
|
||||
- Location: `src/api/`
|
||||
- **State Management**: Zustand for global state, TanStack Query for server state
|
||||
- **Styling**: Tailwind utility classes
|
||||
- **Dev Server**: `npm run dev` (typically :3000 or :5173)
|
||||
- **Build**: `npm run build`
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Common Commands (Makefile)
|
||||
```bash
|
||||
make build # Build all services
|
||||
make build-release # Release build
|
||||
make test # Run all tests
|
||||
make test-integration # Run integration tests
|
||||
make fmt # Format code
|
||||
make clippy # Run linter
|
||||
make lint # fmt + clippy
|
||||
|
||||
make run-api # Run API service
|
||||
make run-executor # Run executor service
|
||||
make run-worker # Run worker service
|
||||
make run-sensor # Run sensor service
|
||||
make run-notifier # Run notifier service
|
||||
|
||||
make db-create # Create database
|
||||
make db-migrate # Run migrations
|
||||
make db-reset # Drop & recreate DB
|
||||
```
|
||||
|
||||
### Database Operations
|
||||
- **Migrations**: Located in `migrations/`, applied via `sqlx migrate run`
|
||||
- **Test DB**: Separate `attune_test` database, setup with `make db-test-setup`
|
||||
- **Schema**: All tables in `public` schema with auto-updating timestamps
|
||||
- **Core Pack**: Load with `./scripts/load-core-pack.sh` after DB setup
|
||||
|
||||
### Testing
|
||||
- **Architecture**: Schema-per-test isolation (each test gets unique `test_<uuid>` schema)
|
||||
- **Parallel Execution**: Tests run concurrently without `#[serial]` constraints (4-8x faster)
|
||||
- **Unit Tests**: In module files alongside code
|
||||
- **Integration Tests**: In `tests/` directory
|
||||
- **Test DB Required**: Use `make db-test-setup` before integration tests
|
||||
- **Run**: `cargo test` or `make test` (parallel by default)
|
||||
- **Verbose**: `cargo test -- --nocapture --test-threads=1`
|
||||
- **Cleanup**: Schemas auto-dropped on test completion; orphaned schemas cleaned via `./scripts/cleanup-test-schemas.sh`
|
||||
- **SQLx Offline Mode**: Enabled for compile-time query checking without live DB; regenerate with `cargo sqlx prepare`
|
||||
|
||||
### CLI Tool
|
||||
```bash
|
||||
cargo install --path crates/cli # Install CLI
|
||||
attune auth login # Login
|
||||
attune pack list # List packs
|
||||
attune action execute <ref> --param key=value
|
||||
attune execution list # Monitor executions
|
||||
```
|
||||
|
||||
## Test Failure Protocol
|
||||
|
||||
**Proactively investigate and fix test failures when discovered, even if unrelated to the current task.**
|
||||
|
||||
### Guidelines:
|
||||
- **ALWAYS report test failures** to the user with relevant error output
|
||||
- **ALWAYS run tests** after making changes: `make test` or `cargo test`
|
||||
- **DO fix immediately** if the cause is obvious and fixable in 1-2 attempts
|
||||
- **DO ask the user** if the failure is complex, requires architectural changes, or you're unsure of the cause
|
||||
- **NEVER silently ignore** test failures or skip tests without approval
|
||||
- **Gather context**: Run with `cargo test -- --nocapture --test-threads=1` for details
|
||||
|
||||
### Priority:
|
||||
- **Critical** (build/compile failures): Fix immediately
|
||||
- **Related** (affects current work): Fix before proceeding
|
||||
- **Unrelated**: Report and ask if you should fix now or defer
|
||||
|
||||
When reporting, ask: "Should I fix this first or continue with [original task]?"
|
||||
|
||||
## Code Quality: Zero Warnings Policy
|
||||
|
||||
**Maintain zero compiler warnings across the workspace.** Clean builds ensure new issues are immediately visible.
|
||||
|
||||
### Workflow
|
||||
- **Check after changes:** `cargo check --all-targets --workspace`
|
||||
- **Before completing work:** Fix or document any warnings introduced
|
||||
- **End of session:** Verify zero warnings before finishing
|
||||
|
||||
### Handling Warnings
|
||||
- **Fix first:** Remove dead code, unused imports, unnecessary variables
|
||||
- **Prefix `_`:** For intentionally unused variables that document intent
|
||||
- **Use `#[allow(dead_code)]`:** For API methods intended for future use (add doc comment explaining why)
|
||||
- **Never ignore blindly:** Every suppression needs a clear rationale
|
||||
|
||||
### Conservative Approach
|
||||
- Preserve methods that complete a logical API surface
|
||||
- Keep test helpers that are part of shared infrastructure
|
||||
- When uncertain about removal, ask the user
|
||||
|
||||
### Red Flags
|
||||
- ❌ Introducing new warnings
|
||||
- ❌ Blanket `#[allow(warnings)]` without specific justification
|
||||
- ❌ Accumulating warnings over time
|
||||
|
||||
## File Naming & Location Conventions
|
||||
|
||||
### When Adding Features:
|
||||
- **New API Endpoint**:
|
||||
- Route handler in `crates/api/src/routes/<domain>.rs`
|
||||
- DTO in `crates/api/src/dto/<domain>.rs`
|
||||
- Update `routes/mod.rs` and main router
|
||||
- **New Domain Model**:
|
||||
- Add to `crates/common/src/models.rs`
|
||||
- Create migration in `migrations/YYYYMMDDHHMMSS_description.sql`
|
||||
- Add repository in `crates/common/src/repositories/<entity>.rs`
|
||||
- **New Service**: Add to `crates/` and update workspace `Cargo.toml` members
|
||||
- **Configuration**: Update `crates/common/src/config.rs` with serde defaults
|
||||
- **Documentation**: Add to `docs/` directory
|
||||
|
||||
### Important Files
|
||||
- `crates/common/src/models.rs` - All domain models
|
||||
- `crates/common/src/error.rs` - Error types
|
||||
- `crates/common/src/config.rs` - Configuration structure
|
||||
- `crates/api/src/routes/mod.rs` - API routing
|
||||
- `config.development.yaml` - Dev configuration
|
||||
- `Cargo.toml` - Workspace dependencies
|
||||
- `Makefile` - Development commands
|
||||
|
||||
## Common Pitfalls to Avoid
|
||||
1. **NEVER** bypass repositories - always use the repository layer for DB access
|
||||
2. **NEVER** forget `RequireAuth` middleware on protected endpoints
|
||||
3. **NEVER** hardcode service URLs - use configuration
|
||||
4. **NEVER** commit secrets in config files (use env vars in production)
|
||||
5. **NEVER** hardcode schema prefixes in SQL queries - rely on PostgreSQL `search_path` mechanism
|
||||
6. **ALWAYS** use PostgreSQL enum type mappings for custom enums
|
||||
7. **ALWAYS** use transactions for multi-table operations
|
||||
8. **ALWAYS** start with `attune/` or correct crate name when specifying file paths
|
||||
9. **ALWAYS** convert runtime names to lowercase for comparison (database may store capitalized)
|
||||
10. **REMEMBER** IDs are `i64`, not `i32` or `uuid`
|
||||
11. **REMEMBER** schema is determined by `search_path`, not hardcoded in queries (production uses `attune`, development uses `public`)
|
||||
12. **REMEMBER** to regenerate SQLx metadata after schema-related changes: `cargo sqlx prepare`
|
||||
|
||||
## Deployment
|
||||
- **Target**: Distributed deployment with separate service instances
|
||||
- **Docker**: Dockerfiles for each service (planned in `docker/` dir)
|
||||
- **Config**: Use environment variables for secrets in production
|
||||
- **Database**: PostgreSQL 14+ with connection pooling
|
||||
- **Message Queue**: RabbitMQ required for service communication
|
||||
- **Web UI**: Static files served separately or via API service
|
||||
|
||||
## Current Development Status
|
||||
- ✅ **Complete**: Database migrations (17 tables), API service (most endpoints), common library, message queue infrastructure, repository layer, JWT auth, CLI tool, Web UI (basic), Executor service (core functionality), Worker service (shell/Python execution)
|
||||
- 🔄 **In Progress**: Sensor service, advanced workflow features, Python runtime dependency management
|
||||
- 📋 **Planned**: Notifier service, execution policies, monitoring, pack registry system
|
||||
|
||||
## Quick Reference
|
||||
|
||||
### Start Development Environment
|
||||
```bash
|
||||
# Start PostgreSQL and RabbitMQ
|
||||
# Load core pack: ./scripts/load-core-pack.sh
|
||||
# Start API: make run-api
|
||||
# Start Web UI: cd web && npm run dev
|
||||
```
|
||||
|
||||
### File Path Examples
|
||||
- Models: `attune/crates/common/src/models.rs`
|
||||
- API routes: `attune/crates/api/src/routes/actions.rs`
|
||||
- Repositories: `attune/crates/common/src/repositories/execution.rs`
|
||||
- Migrations: `attune/migrations/*.sql`
|
||||
- Web UI: `attune/web/src/`
|
||||
- Config: `attune/config.development.yaml`
|
||||
|
||||
### Documentation Locations
|
||||
- API docs: `attune/docs/api-*.md`
|
||||
- Configuration: `attune/docs/configuration.md`
|
||||
- Architecture: `attune/docs/*-architecture.md`, `attune/docs/*-service.md`
|
||||
- Testing: `attune/docs/testing-*.md`, `attune/docs/running-tests.md`, `attune/docs/schema-per-test.md`
|
||||
- AI Agent Work Summaries: `attune/work-summary/*.md`
|
||||
- Deployment: `attune/docs/production-deployment.md`
|
||||
- DO NOT create additional documentation files in the root of the project. all new documentation describing how to use the system should be placed in the `attune/docs` directory, and documentation describing the work performed should be placed in the `attune/work-summary` directory.
|
||||
|
||||
## Work Summary & Reporting
|
||||
|
||||
**Avoid redundant summarization - summarize changes once at completion, not continuously.**
|
||||
|
||||
### Guidelines:
|
||||
- **Report progress** during work: brief status updates, blockers, questions
|
||||
- **Summarize once** at completion: consolidated overview of all changes made
|
||||
- **Work summaries**: Write to `attune/work-summary/*.md` only at task completion, not incrementally
|
||||
- **Avoid duplication**: Don't re-explain the same changes multiple times in different formats
|
||||
- **What changed, not how**: Focus on outcomes and impacts, not play-by-play narration
|
||||
|
||||
### Good Pattern:
|
||||
```
|
||||
[Making changes with tool calls and brief progress notes]
|
||||
...
|
||||
[At completion]
|
||||
"I've completed the task. Here's a summary of changes: [single consolidated overview]"
|
||||
```
|
||||
|
||||
### Bad Pattern:
|
||||
```
|
||||
[Makes changes]
|
||||
"So I changed X, Y, and Z..."
|
||||
[More changes]
|
||||
"To summarize, I modified X, Y, and Z..."
|
||||
[Writes work summary]
|
||||
"In this session I updated X, Y, and Z..."
|
||||
```
|
||||
|
||||
## Maintaining the AGENTS.md file
|
||||
|
||||
**IMPORTANT: Keep this file up-to-date as the project evolves.**
|
||||
|
||||
After making changes to the project, you MUST update this `AGENTS.md` file if any of the following occur:
|
||||
|
||||
- **New dependencies added or major dependencies removed** (check package.json, Cargo.toml, requirements.txt, etc.)
|
||||
- **Project structure changes**: new directories/modules created, existing ones renamed or removed
|
||||
- **Architecture changes**: new layers, patterns, or major refactoring that affects how components interact
|
||||
- **New frameworks or tools adopted** (e.g., switching from REST to GraphQL, adding a new testing framework)
|
||||
- **Deployment or infrastructure changes** (new CI/CD pipelines, different hosting, containerization added)
|
||||
- **New major features** that introduce new subsystems or significantly change existing ones
|
||||
- **Style guide or coding convention updates**
|
||||
|
||||
### `AGENTS.md` Content inclusion policy
|
||||
- DO NOT simply summarize changes in the `AGENTS.md` file. If there are existing sections that need updating due to changes in the application architecture or project structure, update them accordingly.
|
||||
- When relevant, work summaries should instead be written to `attune/work-summary/*.md`
|
||||
|
||||
### Update procedure:
|
||||
1. After completing your changes, review if they affect any section of `AGENTS.md`
|
||||
2. If yes, immediately update the relevant sections
|
||||
3. Add a brief comment at the top of `AGENTS.md` with the date and what was updated (optional but helpful)
|
||||
|
||||
### Update format:
|
||||
When updating, be surgical - modify only the affected sections rather than rewriting the entire file. Maintain the existing structure and tone.
|
||||
|
||||
**Treat `AGENTS.md` as living documentation.** An outdated `AGENTS.md` file is worse than no `AGENTS.md` file, as it will mislead future AI agents and waste time.
|
||||
|
||||
## Project Documentation Index
|
||||
{{DOCUMENTATION_INDEX}}
|
||||
527
Cargo.lock
generated
527
Cargo.lock
generated
@@ -66,6 +66,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alloca"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5a7d05ea6aea7e9e64d25b9156ba2fee3fdd659e34e41063cd2fc7cd020d7f4"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
@@ -74,9 +83,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "amq-protocol"
|
||||
version = "8.3.1"
|
||||
version = "10.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "355603365d2217f7fbc03f0be085ea1440498957890f04276402012cdde445f5"
|
||||
checksum = "8032525e9bb1bb8aa556476de729106e972b9fb811e5db21ce462a4f0f057d03"
|
||||
dependencies = [
|
||||
"amq-protocol-tcp",
|
||||
"amq-protocol-types",
|
||||
@@ -88,24 +97,22 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "amq-protocol-tcp"
|
||||
version = "8.3.1"
|
||||
version = "10.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d7b97a85e08671697e724a6b7f1459ff81603613695e3151764a9529c6fec15"
|
||||
checksum = "22f50ebc589843a42a1428b3e1b149164645bfe8c22a7ed0f128ad0af4aaad84"
|
||||
dependencies = [
|
||||
"amq-protocol-uri",
|
||||
"async-trait",
|
||||
"async-rs",
|
||||
"cfg-if",
|
||||
"executor-trait 2.1.2",
|
||||
"reactor-trait 2.8.0",
|
||||
"tcp-stream",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "amq-protocol-types"
|
||||
version = "8.3.1"
|
||||
version = "10.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2984a816dba991b5922503921d8f94650792bdeac47c27c83830710d2567f63"
|
||||
checksum = "12ffea0c942eb17ea55262e4cc57b223d8d6f896269b1313153f9215784dc2b8"
|
||||
dependencies = [
|
||||
"cookie-factory",
|
||||
"nom 8.0.0",
|
||||
@@ -115,9 +122,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "amq-protocol-uri"
|
||||
version = "8.3.1"
|
||||
version = "10.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31db8e69d1456ec8ecf6ee598707179cf1d95f34f7d30037b16ad43f0cddcff"
|
||||
checksum = "baa9f65c896cb658503e5547e262132ac356c26bc477afedfd8d3f324f4c5006"
|
||||
dependencies = [
|
||||
"amq-protocol-types",
|
||||
"percent-encoding",
|
||||
@@ -313,6 +320,19 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-compat"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1ba85bc55464dcbf728b56d97e119d673f4cf9062be330a9a26f3acf504a590"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"once_cell",
|
||||
"pin-project-lite",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-executor"
|
||||
version = "1.14.0"
|
||||
@@ -335,52 +355,10 @@ checksum = "13f937e26114b93193065fd44f507aa2e9169ad0cdabbb996920b1fe1ddea7ba"
|
||||
dependencies = [
|
||||
"async-channel",
|
||||
"async-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"blocking",
|
||||
"futures-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-global-executor-trait"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9af57045d58eeb1f7060e7025a1631cbc6399e0a1d10ad6735b3d0ea7f8346ce"
|
||||
dependencies = [
|
||||
"async-global-executor",
|
||||
"async-trait",
|
||||
"executor-trait 2.1.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-global-executor-trait"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3727b7da74b92d2d03403cf1142706b53423e5c050791af438f8f50edea057a"
|
||||
dependencies = [
|
||||
"async-global-executor",
|
||||
"async-global-executor-trait 2.2.0",
|
||||
"async-trait",
|
||||
"executor-trait 2.1.2",
|
||||
"executor-trait 3.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-io"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"futures-io",
|
||||
"futures-lite",
|
||||
"parking",
|
||||
"polling",
|
||||
"rustix",
|
||||
"slab",
|
||||
"windows-sys 0.61.2",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -394,18 +372,6 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-reactor-trait"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ab52004af1f14a170088bd9e10a2d3b2f2307ce04320e58a6ce36ee531be625"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-trait",
|
||||
"futures-core",
|
||||
"reactor-trait 3.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-recursion"
|
||||
version = "1.1.1"
|
||||
@@ -417,6 +383,23 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-rs"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cc222a468bdc5ebbe7ce4c595e16d433d531b3b8eda094b2ace18d9fd02fcaa3"
|
||||
dependencies = [
|
||||
"async-compat",
|
||||
"async-global-executor",
|
||||
"async-trait",
|
||||
"cfg-if",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"hickory-resolver",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-task"
|
||||
version = "4.7.1"
|
||||
@@ -467,7 +450,7 @@ dependencies = [
|
||||
"hmac",
|
||||
"jsonschema",
|
||||
"mockall",
|
||||
"rand 0.9.2",
|
||||
"rand 0.10.0",
|
||||
"reqwest 0.13.2",
|
||||
"reqwest-eventsource",
|
||||
"schemars",
|
||||
@@ -502,7 +485,7 @@ dependencies = [
|
||||
"attune-common",
|
||||
"chrono",
|
||||
"clap",
|
||||
"colored 2.2.0",
|
||||
"colored",
|
||||
"comfy-table",
|
||||
"config",
|
||||
"dialoguer",
|
||||
@@ -521,7 +504,7 @@ dependencies = [
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tokio-test",
|
||||
"tokio-tungstenite 0.26.2",
|
||||
"tokio-tungstenite",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"url",
|
||||
@@ -580,7 +563,7 @@ dependencies = [
|
||||
"dashmap",
|
||||
"futures",
|
||||
"lapin",
|
||||
"rand 0.8.5",
|
||||
"rand 0.10.0",
|
||||
"redis",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -736,7 +719,7 @@ dependencies = [
|
||||
"sha1",
|
||||
"sync_wrapper",
|
||||
"tokio",
|
||||
"tokio-tungstenite 0.28.0",
|
||||
"tokio-tungstenite",
|
||||
"tower",
|
||||
"tower-layer",
|
||||
"tower-service",
|
||||
@@ -1072,23 +1055,13 @@ version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1147,15 +1120,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.11"
|
||||
version = "0.16.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
|
||||
checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1294,25 +1267,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "criterion"
|
||||
version = "0.5.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f"
|
||||
checksum = "950046b2aa2492f9a536f5f4f9a3de7b9e2476e575e05bd6c333371add4d98f3"
|
||||
dependencies = [
|
||||
"alloca",
|
||||
"anes",
|
||||
"cast",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"criterion-plot",
|
||||
"is-terminal",
|
||||
"itertools",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"oorandom",
|
||||
"page_size",
|
||||
"plotters",
|
||||
"rayon",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"tinytemplate",
|
||||
"walkdir",
|
||||
@@ -1320,14 +1292,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "criterion-plot"
|
||||
version = "0.5.0"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
|
||||
checksum = "d8d80a2f4f5b554395e47b5d8305bc3d27813bacb73493eb1001e8f76dae29ea"
|
||||
dependencies = [
|
||||
"cast",
|
||||
"itertools",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "critical-section"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "cron"
|
||||
version = "0.15.0"
|
||||
@@ -1350,6 +1328,15 @@ dependencies = [
|
||||
"strum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
@@ -1606,14 +1593,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dialoguer"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de"
|
||||
checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96"
|
||||
dependencies = [
|
||||
"console",
|
||||
"shell-words",
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
@@ -1637,23 +1623,23 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.4.1"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1742,6 +1728,18 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum-as-inner"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
@@ -1812,24 +1810,6 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "executor-trait"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c39dff9342e4e0e16ce96be751eb21a94e94a87bb2f6e63ad1961c2ce109bf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "executor-trait"
|
||||
version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57d6a1fc6700fa12782770cb344a29172ae940ea41d5fd5049fdf236dd6eaa92"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fancy-regex"
|
||||
version = "0.17.0"
|
||||
@@ -1912,6 +1892,17 @@ dependencies = [
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e139bc46ca777eb5efaf62df0ab8cc5fd400866427e56c68b22e414e53bd3be"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"spin",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@@ -2251,6 +2242,52 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hickory-proto"
|
||||
version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8a6fe56c0038198998a6f217ca4e7ef3a5e51f46163bd6dd60b5c71ca6c6502"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"cfg-if",
|
||||
"data-encoding",
|
||||
"enum-as-inner",
|
||||
"futures-channel",
|
||||
"futures-io",
|
||||
"futures-util",
|
||||
"idna",
|
||||
"ipnet",
|
||||
"once_cell",
|
||||
"rand 0.9.2",
|
||||
"ring",
|
||||
"thiserror 2.0.18",
|
||||
"tinyvec",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hickory-resolver"
|
||||
version = "0.25.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc62a9a99b0bfb44d2ab95a7208ac952d31060efc16241c87eaf36406fecf87a"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"futures-util",
|
||||
"hickory-proto",
|
||||
"ipconfig",
|
||||
"moka",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"rand 0.9.2",
|
||||
"resolv-conf",
|
||||
"smallvec",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.4"
|
||||
@@ -2390,7 +2427,7 @@ dependencies = [
|
||||
"libc",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"socket2 0.5.10",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
@@ -2558,6 +2595,18 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipconfig"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
|
||||
dependencies = [
|
||||
"socket2 0.5.10",
|
||||
"widestring",
|
||||
"windows-sys 0.48.0",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.12.0"
|
||||
@@ -2574,17 +2623,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
@@ -2593,9 +2631,9 @@ checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
@@ -2661,9 +2699,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "jsonschema"
|
||||
version = "0.38.1"
|
||||
version = "0.44.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89f50532ce4a0ba3ae930212908d8ec50e7806065c059fe9c75da2ece6132294"
|
||||
checksum = "f98b64a413c93a1b413dfbaf973b78d271648b9cae50b10302ad88af78991672"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"bytecount",
|
||||
@@ -2680,7 +2718,8 @@ dependencies = [
|
||||
"referencing",
|
||||
"regex",
|
||||
"regex-syntax",
|
||||
"reqwest 0.12.28",
|
||||
"reqwest 0.13.2",
|
||||
"rustls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"unicode-general-category",
|
||||
@@ -2707,20 +2746,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lapin"
|
||||
version = "3.7.2"
|
||||
version = "4.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "913a84142a99160ecef997a5c17c53639bcbac4424a0315a5ffe6c8be8e8db86"
|
||||
checksum = "16eff4aa0d9ab12052d1f967ddec97cd03be4065eea8ed390e8f1dce1f03bf0a"
|
||||
dependencies = [
|
||||
"amq-protocol",
|
||||
"async-global-executor-trait 3.1.0",
|
||||
"async-reactor-trait",
|
||||
"async-rs",
|
||||
"async-trait",
|
||||
"backon",
|
||||
"executor-trait 2.1.2",
|
||||
"flume",
|
||||
"cfg-if",
|
||||
"flume 0.12.0",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"reactor-trait 2.8.0",
|
||||
"tokio",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@@ -2920,7 +2958,7 @@ checksum = "90820618712cab19cfc46b274c6c22546a82affcb3c3bdf0f29e3db8e1bb92c0"
|
||||
dependencies = [
|
||||
"assert-json-diff",
|
||||
"bytes",
|
||||
"colored 3.1.1",
|
||||
"colored",
|
||||
"futures-core",
|
||||
"http",
|
||||
"http-body",
|
||||
@@ -2937,6 +2975,23 @@ dependencies = [
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "moka"
|
||||
version = "0.12.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "85f8024e1c8e71c778968af91d43700ce1d11b219d127d79fb2934153b82b42b"
|
||||
dependencies = [
|
||||
"crossbeam-channel",
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
"equivalent",
|
||||
"parking_lot",
|
||||
"portable-atomic",
|
||||
"smallvec",
|
||||
"tagptr",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "multer"
|
||||
version = "3.1.0"
|
||||
@@ -3142,6 +3197,10 @@ name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
dependencies = [
|
||||
"critical-section",
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
@@ -3250,6 +3309,16 @@ dependencies = [
|
||||
"x509-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "page_size"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d5b2194ed13191c1999ae0704b7839fb18384fa22e49b57eeaa97d79ce40da"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.2.1"
|
||||
@@ -3506,20 +3575,6 @@ dependencies = [
|
||||
"plotters-backend",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
"hermit-abi",
|
||||
"pin-project-lite",
|
||||
"rustix",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.6.2"
|
||||
@@ -3532,6 +3587,12 @@ dependencies = [
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
|
||||
|
||||
[[package]]
|
||||
name = "potential_utf"
|
||||
version = "0.1.4"
|
||||
@@ -3640,7 +3701,7 @@ dependencies = [
|
||||
"quinn-udp",
|
||||
"rustc-hash",
|
||||
"rustls",
|
||||
"socket2",
|
||||
"socket2 0.5.10",
|
||||
"thiserror 2.0.18",
|
||||
"tokio",
|
||||
"tracing",
|
||||
@@ -3678,7 +3739,7 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"socket2",
|
||||
"socket2 0.5.10",
|
||||
"tracing",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
@@ -3809,30 +3870,6 @@ dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reactor-trait"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ffbbf16bc3e4db5fdcf4b77cebf1313610b54b339712aa90088d2d9b1acb1f1"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"reactor-trait 3.1.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reactor-trait"
|
||||
version = "3.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b1c85237926dd82e8bc3634240ecf2236ea81e904b3d83cdb1df974af9af293"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"async-trait",
|
||||
"executor-trait 2.1.2",
|
||||
"flume",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redis"
|
||||
version = "1.0.4"
|
||||
@@ -3853,7 +3890,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"ryu",
|
||||
"sha1_smol",
|
||||
"socket2",
|
||||
"socket2 0.6.2",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"url",
|
||||
@@ -3880,13 +3917,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.6"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43"
|
||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom 0.2.17",
|
||||
"libredox",
|
||||
"thiserror 1.0.69",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3911,9 +3948,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "referencing"
|
||||
version = "0.38.1"
|
||||
version = "0.44.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15a8af0c6bb8eaf8b07cb06fc31ff30ca6fe19fb99afa476c276d8b24f365b0b"
|
||||
checksum = "22952642836711d7a730d23a4dfb0d732e75a85e4c4f5704266d9c8fac278ff1"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"fluent-uri",
|
||||
@@ -3961,7 +3998,6 @@ checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"http",
|
||||
@@ -3998,6 +4034,7 @@ dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
@@ -4049,6 +4086,12 @@ dependencies = [
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "resolv-conf"
|
||||
version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.14"
|
||||
@@ -4186,9 +4229,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-connector"
|
||||
version = "0.21.11"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10eb7ce243317e6b6a342ef6bff8c2e0d46d78120a9aeb2ee39693a569615c96"
|
||||
checksum = "f510f2d983baf4a45354ae8ca5abf5a6cdb3c47244ea22f705499d6d9c09a912"
|
||||
dependencies = [
|
||||
"futures-io",
|
||||
"futures-rustls",
|
||||
@@ -4211,15 +4254,6 @@ dependencies = [
|
||||
"security-framework",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50"
|
||||
dependencies = [
|
||||
"rustls-pki-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pki-types"
|
||||
version = "1.14.0"
|
||||
@@ -4609,6 +4643,16 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.6.2"
|
||||
@@ -4818,7 +4862,7 @@ checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"chrono",
|
||||
"flume",
|
||||
"flume 0.11.1",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
@@ -4938,6 +4982,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tagptr"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417"
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.44"
|
||||
@@ -4951,16 +5001,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tcp-stream"
|
||||
version = "0.30.9"
|
||||
version = "0.34.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282ebecea8280bce8b7a0695b5dc93a19839dd445cbba70d3e07c9f6e12c4653"
|
||||
checksum = "228ee8f41fd20e97f2af4afdd54901b1711aef9d49136d8d6c53f10f4416a4cb"
|
||||
dependencies = [
|
||||
"async-rs",
|
||||
"cfg-if",
|
||||
"futures-io",
|
||||
"p12-keystore",
|
||||
"reactor-trait 2.8.0",
|
||||
"rustls-connector",
|
||||
"rustls-pemfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5118,7 +5167,7 @@ dependencies = [
|
||||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2",
|
||||
"socket2 0.6.2",
|
||||
"tokio-macros",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
@@ -5193,20 +5242,6 @@ dependencies = [
|
||||
"tokio-stream",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tungstenite 0.26.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.28.0"
|
||||
@@ -5215,8 +5250,10 @@ checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tungstenite 0.28.0",
|
||||
"tokio-native-tls",
|
||||
"tungstenite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5391,24 +5428,6 @@ version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.26.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"data-encoding",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"native-tls",
|
||||
"rand 0.9.2",
|
||||
"sha1",
|
||||
"thiserror 2.0.18",
|
||||
"utf-8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.28.0"
|
||||
@@ -5420,6 +5439,7 @@ dependencies = [
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
"native-tls",
|
||||
"rand 0.9.2",
|
||||
"sha1",
|
||||
"thiserror 2.0.18",
|
||||
@@ -5912,6 +5932,12 @@ dependencies = [
|
||||
"wasite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -5934,7 +5960,7 @@ version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||
dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6040,15 +6066,6 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.60.2"
|
||||
@@ -6328,6 +6345,16 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wiremock"
|
||||
version = "0.6.5"
|
||||
|
||||
24
Cargo.toml
24
Cargo.toml
@@ -20,7 +20,7 @@ repository = "https://git.rdrx.app/attune-system/attune"
|
||||
|
||||
[workspace.dependencies]
|
||||
# Async runtime
|
||||
tokio = { version = "1.42", features = ["full"] }
|
||||
tokio = { version = "1.50", features = ["full"] }
|
||||
tokio-util = "0.7"
|
||||
tokio-stream = { version = "0.1", features = ["sync"] }
|
||||
|
||||
@@ -52,7 +52,7 @@ config = "0.15"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
|
||||
# UUID
|
||||
uuid = { version = "1.11", features = ["v4", "serde"] }
|
||||
uuid = { version = "1.21", features = ["v4", "serde"] }
|
||||
|
||||
# Validation
|
||||
validator = { version = "0.20", features = ["derive"] }
|
||||
@@ -62,19 +62,19 @@ clap = { version = "4.5", features = ["derive"] }
|
||||
|
||||
# Message queue / PubSub
|
||||
# RabbitMQ
|
||||
lapin = "3.7"
|
||||
lapin = "4.1"
|
||||
# Redis
|
||||
redis = { version = "1.0", features = ["tokio-comp", "connection-manager"] }
|
||||
|
||||
# JSON Schema
|
||||
schemars = { version = "1.2", features = ["chrono04"] }
|
||||
jsonschema = "0.38"
|
||||
jsonschema = "0.44"
|
||||
|
||||
# OpenAPI/Swagger
|
||||
utoipa = { version = "5.4", features = ["chrono", "uuid"] }
|
||||
|
||||
# JWT
|
||||
jsonwebtoken = { version = "10.2", features = ["hmac", "sha2"] }
|
||||
jsonwebtoken = { version = "10.3", features = ["hmac", "sha2"] }
|
||||
|
||||
# Encryption
|
||||
argon2 = "0.5"
|
||||
@@ -84,22 +84,22 @@ aes-gcm = "0.10"
|
||||
sha2 = "0.10"
|
||||
|
||||
# Regular expressions
|
||||
regex = "1.11"
|
||||
regex = "1.12"
|
||||
|
||||
# HTTP client
|
||||
reqwest = { version = "0.13", features = ["json"] }
|
||||
reqwest-eventsource = "0.6"
|
||||
hyper = { version = "1.0", features = ["full"] }
|
||||
hyper = { version = "1.8", features = ["full"] }
|
||||
|
||||
# File system utilities
|
||||
walkdir = "2.4"
|
||||
walkdir = "2.5"
|
||||
|
||||
# Archive/compression
|
||||
tar = "0.4"
|
||||
flate2 = "1.0"
|
||||
flate2 = "1.1"
|
||||
|
||||
# WebSocket client
|
||||
tokio-tungstenite = { version = "0.26", features = ["native-tls"] }
|
||||
tokio-tungstenite = { version = "0.28", features = ["native-tls"] }
|
||||
|
||||
# URL parsing
|
||||
url = "2.5"
|
||||
@@ -112,11 +112,11 @@ futures = "0.3"
|
||||
semver = { version = "1.0", features = ["serde"] }
|
||||
|
||||
# Temp files
|
||||
tempfile = "3.8"
|
||||
tempfile = "3.26"
|
||||
|
||||
# Testing
|
||||
mockall = "0.14"
|
||||
serial_test = "3.2"
|
||||
serial_test = "3.4"
|
||||
|
||||
# Concurrent data structures
|
||||
dashmap = "6.1"
|
||||
|
||||
12
Makefile
12
Makefile
@@ -19,7 +19,8 @@ help:
|
||||
@echo " make test - Run all tests"
|
||||
@echo " make test-common - Run tests for common library"
|
||||
@echo " make test-api - Run tests for API service"
|
||||
@echo " make test-integration - Run integration tests"
|
||||
@echo " make test-integration - Run integration tests (common + API)"
|
||||
@echo " make test-integration-api - Run API integration tests (requires DB)"
|
||||
@echo " make check - Check code without building"
|
||||
@echo ""
|
||||
@echo "Code Quality:"
|
||||
@@ -88,13 +89,18 @@ test-api:
|
||||
test-verbose:
|
||||
cargo test -- --nocapture --test-threads=1
|
||||
|
||||
test-integration:
|
||||
test-integration: test-integration-api
|
||||
@echo "Setting up test database..."
|
||||
@make db-test-setup
|
||||
@echo "Running integration tests..."
|
||||
@echo "Running common integration tests..."
|
||||
cargo test --test '*' -p attune-common -- --test-threads=1
|
||||
@echo "Integration tests complete"
|
||||
|
||||
test-integration-api:
|
||||
@echo "Running API integration tests..."
|
||||
cargo test -p attune-api --features integration-tests -- --test-threads=1
|
||||
@echo "API integration tests complete"
|
||||
|
||||
test-with-db: db-test-setup test-integration
|
||||
@echo "All tests with database complete"
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ authors.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
|
||||
[features]
|
||||
integration-tests = []
|
||||
|
||||
[lib]
|
||||
name = "attune_api"
|
||||
path = "src/lib.rs"
|
||||
@@ -77,7 +80,7 @@ tempfile = { workspace = true }
|
||||
|
||||
# Authentication
|
||||
argon2 = { workspace = true }
|
||||
rand = "0.9"
|
||||
rand = "0.10"
|
||||
|
||||
# HMAC and cryptography
|
||||
hmac = "0.12"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg(feature = "integration-tests")]
|
||||
//! Integration tests for health check and authentication endpoints
|
||||
|
||||
use axum::http::StatusCode;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg(feature = "integration-tests")]
|
||||
//! Integration tests for pack registry system
|
||||
//!
|
||||
//! This module tests:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg(feature = "integration-tests")]
|
||||
//! Integration tests for pack workflow sync and validation
|
||||
|
||||
mod helpers;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg(feature = "integration-tests")]
|
||||
//! Integration tests for SSE execution stream endpoint
|
||||
//!
|
||||
//! These tests verify that:
|
||||
@@ -86,7 +87,6 @@ async fn create_test_execution(pool: &PgPool, action_id: i64) -> Result<Executio
|
||||
/// Run with: cargo test test_sse_stream_receives_execution_updates -- --ignored --nocapture
|
||||
/// After starting: cargo run -p attune-api -- -c config.test.yaml
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_sse_stream_receives_execution_updates() -> Result<()> {
|
||||
// Set up test context with auth
|
||||
let ctx = TestContext::new().await?.with_auth().await?;
|
||||
@@ -225,7 +225,6 @@ async fn test_sse_stream_receives_execution_updates() -> Result<()> {
|
||||
|
||||
/// Test that SSE stream correctly filters by execution_id
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_sse_stream_filters_by_execution_id() -> Result<()> {
|
||||
// Set up test context with auth
|
||||
let ctx = TestContext::new().await?.with_auth().await?;
|
||||
@@ -327,7 +326,6 @@ async fn test_sse_stream_filters_by_execution_id() -> Result<()> {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_sse_stream_requires_authentication() -> Result<()> {
|
||||
// Try to connect without token
|
||||
let sse_url = "http://localhost:8080/api/v1/executions/stream";
|
||||
@@ -373,7 +371,6 @@ async fn test_sse_stream_requires_authentication() -> Result<()> {
|
||||
|
||||
/// Test streaming all executions (no filter)
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_sse_stream_all_executions() -> Result<()> {
|
||||
// Set up test context with auth
|
||||
let ctx = TestContext::new().await?.with_auth().await?;
|
||||
@@ -466,7 +463,6 @@ async fn test_sse_stream_all_executions() -> Result<()> {
|
||||
|
||||
/// Test that PostgreSQL NOTIFY triggers actually fire
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_postgresql_notify_trigger_fires() -> Result<()> {
|
||||
let ctx = TestContext::new().await?;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg(feature = "integration-tests")]
|
||||
//! Integration tests for webhook API endpoints
|
||||
|
||||
use attune_api::{AppState, Server};
|
||||
@@ -108,7 +109,6 @@ async fn get_auth_token(app: &axum::Router, username: &str, password: &str) -> S
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore] // Run with --ignored flag when database is available
|
||||
async fn test_enable_webhook() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -151,7 +151,6 @@ async fn test_enable_webhook() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_disable_webhook() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -202,7 +201,6 @@ async fn test_disable_webhook() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_regenerate_webhook_key() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -254,7 +252,6 @@ async fn test_regenerate_webhook_key() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_regenerate_webhook_key_not_enabled() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -291,7 +288,6 @@ async fn test_regenerate_webhook_key_not_enabled() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_receive_webhook() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -362,7 +358,6 @@ async fn test_receive_webhook() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_receive_webhook_invalid_key() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state));
|
||||
@@ -392,7 +387,6 @@ async fn test_receive_webhook_invalid_key() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_receive_webhook_disabled() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -442,7 +436,6 @@ async fn test_receive_webhook_disabled() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_requires_auth_for_management() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -475,7 +468,6 @@ async fn test_webhook_requires_auth_for_management() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_receive_webhook_minimal_payload() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg(feature = "integration-tests")]
|
||||
//! Comprehensive integration tests for webhook security features (Phase 3)
|
||||
//!
|
||||
//! Tests cover:
|
||||
@@ -122,7 +123,6 @@ fn generate_hmac_signature(payload: &[u8], secret: &str, algorithm: &str) -> Str
|
||||
// ============================================================================
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_hmac_sha256_valid() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -189,7 +189,6 @@ async fn test_webhook_hmac_sha256_valid() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_hmac_sha512_valid() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -246,7 +245,6 @@ async fn test_webhook_hmac_sha512_valid() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_hmac_invalid_signature() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -302,7 +300,6 @@ async fn test_webhook_hmac_invalid_signature() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_hmac_missing_signature() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -355,7 +352,6 @@ async fn test_webhook_hmac_missing_signature() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_hmac_wrong_secret() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -418,7 +414,6 @@ async fn test_webhook_hmac_wrong_secret() {
|
||||
// ============================================================================
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_rate_limit_enforced() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -494,7 +489,6 @@ async fn test_webhook_rate_limit_enforced() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_rate_limit_disabled() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -541,7 +535,6 @@ async fn test_webhook_rate_limit_disabled() {
|
||||
// ============================================================================
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_ip_whitelist_allowed() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -612,7 +605,6 @@ async fn test_webhook_ip_whitelist_allowed() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_ip_whitelist_blocked() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -669,7 +661,6 @@ async fn test_webhook_ip_whitelist_blocked() {
|
||||
// ============================================================================
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_payload_size_limit_enforced() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
@@ -720,7 +711,6 @@ async fn test_webhook_payload_size_limit_enforced() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn test_webhook_payload_size_within_limit() {
|
||||
let state = setup_test_state().await;
|
||||
let server = Server::new(std::sync::Arc::new(state.clone()));
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![cfg(feature = "integration-tests")]
|
||||
//! Integration tests for workflow API endpoints
|
||||
|
||||
use attune_common::repositories::{
|
||||
|
||||
@@ -38,7 +38,7 @@ chrono = { workspace = true }
|
||||
|
||||
# Configuration
|
||||
config = { workspace = true }
|
||||
dirs = "5.0"
|
||||
dirs = "6.0"
|
||||
|
||||
# URL encoding
|
||||
urlencoding = "2.1"
|
||||
@@ -52,9 +52,9 @@ flate2 = { workspace = true }
|
||||
tokio-tungstenite = { workspace = true }
|
||||
|
||||
# Terminal UI
|
||||
colored = "2.1"
|
||||
comfy-table = "7.1"
|
||||
dialoguer = "0.11"
|
||||
colored = "3.1"
|
||||
comfy-table = "7.2"
|
||||
dialoguer = "0.12"
|
||||
|
||||
# Authentication
|
||||
jsonwebtoken = { workspace = true }
|
||||
@@ -66,7 +66,7 @@ tracing-subscriber = { workspace = true }
|
||||
[dev-dependencies]
|
||||
tempfile = { workspace = true }
|
||||
wiremock = "0.6"
|
||||
assert_cmd = "2.0"
|
||||
predicates = "3.0"
|
||||
mockito = "1.2"
|
||||
assert_cmd = "2.1"
|
||||
predicates = "3.1"
|
||||
mockito = "1.7"
|
||||
tokio-test = "0.4"
|
||||
|
||||
@@ -161,7 +161,7 @@ impl Connection {
|
||||
pub async fn close(&self) -> MqResult<()> {
|
||||
let mut conn_guard = self.connection.write().await;
|
||||
if let Some(conn) = conn_guard.take() {
|
||||
conn.close(200, "Normal shutdown")
|
||||
conn.close(200, "Normal shutdown".into())
|
||||
.await
|
||||
.map_err(|e| MqError::Connection(format!("Failed to close connection: {}", e)))?;
|
||||
info!("Connection closed");
|
||||
@@ -187,7 +187,7 @@ impl Connection {
|
||||
|
||||
channel
|
||||
.exchange_declare(
|
||||
&config.name,
|
||||
config.name.as_str().into(),
|
||||
kind,
|
||||
ExchangeDeclareOptions {
|
||||
durable: config.durable,
|
||||
@@ -216,7 +216,7 @@ impl Connection {
|
||||
|
||||
channel
|
||||
.queue_declare(
|
||||
&config.name,
|
||||
config.name.as_str().into(),
|
||||
QueueDeclareOptions {
|
||||
durable: config.durable,
|
||||
exclusive: config.exclusive,
|
||||
@@ -248,9 +248,9 @@ impl Connection {
|
||||
|
||||
channel
|
||||
.queue_bind(
|
||||
queue,
|
||||
exchange,
|
||||
routing_key,
|
||||
queue.into(),
|
||||
exchange.into(),
|
||||
routing_key.into(),
|
||||
QueueBindOptions::default(),
|
||||
FieldTable::default(),
|
||||
)
|
||||
@@ -315,7 +315,7 @@ impl Connection {
|
||||
|
||||
channel
|
||||
.queue_declare(
|
||||
&config.name,
|
||||
config.name.as_str().into(),
|
||||
QueueDeclareOptions {
|
||||
durable: config.durable,
|
||||
exclusive: config.exclusive,
|
||||
|
||||
@@ -59,8 +59,8 @@ impl Consumer {
|
||||
let consumer = self
|
||||
.channel
|
||||
.basic_consume(
|
||||
&self.config.queue,
|
||||
&self.config.tag,
|
||||
self.config.queue.as_str().into(),
|
||||
self.config.tag.as_str().into(),
|
||||
BasicConsumeOptions {
|
||||
no_ack: self.config.auto_ack,
|
||||
exclusive: self.config.exclusive,
|
||||
|
||||
@@ -88,8 +88,8 @@ impl Publisher {
|
||||
let confirmation = self
|
||||
.channel
|
||||
.basic_publish(
|
||||
exchange,
|
||||
routing_key,
|
||||
exchange.into(),
|
||||
routing_key.into(),
|
||||
BasicPublishOptions::default(),
|
||||
&payload,
|
||||
properties,
|
||||
@@ -129,8 +129,8 @@ impl Publisher {
|
||||
|
||||
self.channel
|
||||
.basic_publish(
|
||||
exchange,
|
||||
routing_key,
|
||||
exchange.into(),
|
||||
routing_key.into(),
|
||||
BasicPublishOptions::default(),
|
||||
payload,
|
||||
properties,
|
||||
|
||||
@@ -61,7 +61,7 @@ impl RuleLifecycleListener {
|
||||
// Declare exchange (idempotent)
|
||||
channel
|
||||
.exchange_declare(
|
||||
&self.mq_exchange,
|
||||
self.mq_exchange.as_str().into(),
|
||||
lapin::ExchangeKind::Topic,
|
||||
ExchangeDeclareOptions {
|
||||
durable: true,
|
||||
@@ -78,7 +78,7 @@ impl RuleLifecycleListener {
|
||||
let queue_name = format!("sensor.{}", self.sensor_ref);
|
||||
channel
|
||||
.queue_declare(
|
||||
&queue_name,
|
||||
queue_name.as_str().into(),
|
||||
QueueDeclareOptions {
|
||||
durable: true,
|
||||
..Default::default()
|
||||
@@ -101,9 +101,9 @@ impl RuleLifecycleListener {
|
||||
for routing_key in &routing_keys {
|
||||
channel
|
||||
.queue_bind(
|
||||
&queue_name,
|
||||
&self.mq_exchange,
|
||||
routing_key,
|
||||
queue_name.as_str().into(),
|
||||
self.mq_exchange.as_str().into(),
|
||||
(*routing_key).into(),
|
||||
QueueBindOptions::default(),
|
||||
FieldTable::default(),
|
||||
)
|
||||
@@ -147,8 +147,8 @@ impl RuleLifecycleListener {
|
||||
// Start consuming messages
|
||||
let consumer = channel
|
||||
.basic_consume(
|
||||
&queue_name,
|
||||
"sensor-timer-consumer",
|
||||
queue_name.as_str().into(),
|
||||
"sensor-timer-consumer".into(),
|
||||
BasicConsumeOptions {
|
||||
no_ack: false,
|
||||
..Default::default()
|
||||
|
||||
@@ -34,11 +34,11 @@ dashmap = { workspace = true }
|
||||
serde_yaml_ng = { workspace = true }
|
||||
validator = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
rand = "0.8"
|
||||
rand = "0.10"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = { workspace = true }
|
||||
criterion = "0.5"
|
||||
criterion = "0.8"
|
||||
|
||||
[[bench]]
|
||||
name = "context_clone"
|
||||
|
||||
@@ -62,7 +62,7 @@ impl RuleLifecycleListener {
|
||||
consumer
|
||||
.channel()
|
||||
.queue_declare(
|
||||
queue,
|
||||
queue.into(),
|
||||
lapin::options::QueueDeclareOptions {
|
||||
durable: true,
|
||||
exclusive: false,
|
||||
@@ -78,9 +78,9 @@ impl RuleLifecycleListener {
|
||||
consumer
|
||||
.channel()
|
||||
.queue_bind(
|
||||
queue,
|
||||
exchange,
|
||||
routing_key,
|
||||
queue.into(),
|
||||
exchange.into(),
|
||||
(*routing_key).into(),
|
||||
lapin::options::QueueBindOptions::default(),
|
||||
lapin::types::FieldTable::default(),
|
||||
)
|
||||
|
||||
12
deny.toml
12
deny.toml
@@ -4,17 +4,7 @@ all-features = true
|
||||
[advisories]
|
||||
version = 2
|
||||
yanked = "deny"
|
||||
# Note: RUSTSEC-2023-0071 (rsa via sqlx-mysql) is in Cargo.lock but unreachable —
|
||||
# sqlx-macros-core unconditionally resolves sqlx-mysql; we only use postgres.
|
||||
# cargo deny's graph analysis correctly identifies it as unreachable, so no
|
||||
# ignore entry is needed here. If cargo audit is ever re-added, it will need
|
||||
# --ignore RUSTSEC-2023-0071 since it scans the lockfile without graph analysis.
|
||||
ignore = [
|
||||
# rustls-pemfile v2.x - unmaintained
|
||||
# Transitive dependency via lapin → amq-protocol-tcp → tcp-stream.
|
||||
# No alternative available until lapin updates its TLS stack.
|
||||
{ id = "RUSTSEC-2025-0134", reason = "transitive via lapin TLS stack; no alternative" },
|
||||
]
|
||||
ignore = []
|
||||
|
||||
[licenses]
|
||||
version = 2
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate AGENTS.md index file in minified format.
|
||||
|
||||
This script scans the docs, scripts, and work-summary directories
|
||||
and generates a minified index file that helps AI agents quickly
|
||||
understand the project structure and available documentation.
|
||||
|
||||
The script uses AGENTS.md.template as a base and injects the generated
|
||||
index at the {{DOCUMENTATION_INDEX}} placeholder.
|
||||
|
||||
Usage:
|
||||
python scripts/generate_agents_md_index.py
|
||||
"""
|
||||
|
||||
import os
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Set
|
||||
|
||||
|
||||
def get_project_root() -> Path:
|
||||
"""Get the project root directory (parent of scripts/)."""
|
||||
script_dir = Path(__file__).parent
|
||||
return script_dir.parent
|
||||
|
||||
|
||||
def scan_directory(
|
||||
base_path: Path, extensions: Set[str] = None
|
||||
) -> Dict[str, List[str]]:
|
||||
"""
|
||||
Scan a directory and organize files by subdirectory.
|
||||
|
||||
Args:
|
||||
base_path: Directory to scan
|
||||
extensions: Set of file extensions to include (e.g., {'.md', '.py'}). None means all files.
|
||||
|
||||
Returns:
|
||||
Dictionary mapping relative directory paths to lists of filenames
|
||||
"""
|
||||
if not base_path.exists():
|
||||
return {}
|
||||
|
||||
structure = defaultdict(list)
|
||||
|
||||
for item in sorted(base_path.rglob("*")):
|
||||
if item.is_file():
|
||||
# Filter by extension if specified
|
||||
if extensions and item.suffix not in extensions:
|
||||
continue
|
||||
|
||||
# Get relative path from base_path
|
||||
rel_path = item.relative_to(base_path)
|
||||
parent_dir = str(rel_path.parent) if rel_path.parent != Path(".") else ""
|
||||
|
||||
structure[parent_dir].append(item.name)
|
||||
|
||||
return structure
|
||||
|
||||
|
||||
def format_directory_entry(
|
||||
dir_path: str, files: List[str], max_files: int = None
|
||||
) -> str:
|
||||
"""
|
||||
Format a directory entry in minified format.
|
||||
|
||||
Args:
|
||||
dir_path: Directory path (empty string for root)
|
||||
files: List of filenames in the directory
|
||||
max_files: Maximum number of files to list before truncating
|
||||
|
||||
Returns:
|
||||
Formatted string like "path:{file1,file2,...}"
|
||||
"""
|
||||
if not files:
|
||||
return ""
|
||||
|
||||
# Sort files for consistency
|
||||
sorted_files = sorted(files)
|
||||
|
||||
# Truncate if needed
|
||||
if max_files and len(sorted_files) > max_files:
|
||||
file_list = sorted_files[:max_files] + ["..."]
|
||||
else:
|
||||
file_list = sorted_files
|
||||
|
||||
files_str = ",".join(file_list)
|
||||
|
||||
if dir_path:
|
||||
return f"{dir_path}:{{{files_str}}}"
|
||||
else:
|
||||
return f"root:{{{files_str}}}"
|
||||
|
||||
|
||||
def generate_index_content(root_dirs: Dict[str, Dict[str, any]]) -> str:
|
||||
"""
|
||||
Generate the documentation index content.
|
||||
|
||||
Args:
|
||||
root_dirs: Dictionary mapping directory names to their scan configs
|
||||
|
||||
Returns:
|
||||
Formatted index content as a string
|
||||
"""
|
||||
lines = []
|
||||
|
||||
lines.append("[Attune Project Documentation Index]")
|
||||
lines.append("|root: ./")
|
||||
lines.append(
|
||||
"|IMPORTANT: Prefer retrieval-led reasoning over pre-training-led reasoning"
|
||||
)
|
||||
lines.append(
|
||||
"|IMPORTANT: This index provides a quick overview - use grep/read_file for details"
|
||||
)
|
||||
lines.append("|")
|
||||
lines.append("| Format: path/to/dir:{file1,file2,...}")
|
||||
lines.append(
|
||||
"| '...' indicates truncated file list - use grep/list_directory for full contents"
|
||||
)
|
||||
lines.append("|")
|
||||
lines.append("| To regenerate this index: make generate-agents-index")
|
||||
lines.append("|")
|
||||
|
||||
# Process each root directory
|
||||
for dir_name, config in root_dirs.items():
|
||||
base_path = config["path"]
|
||||
extensions = config.get("extensions")
|
||||
max_files = config.get("max_files", 10)
|
||||
|
||||
structure = scan_directory(base_path, extensions)
|
||||
|
||||
if not structure:
|
||||
lines.append(f"|{dir_name}: (empty)")
|
||||
continue
|
||||
|
||||
# Sort directories for consistent output
|
||||
sorted_dirs = sorted(structure.keys())
|
||||
|
||||
for dir_path in sorted_dirs:
|
||||
files = structure[dir_path]
|
||||
|
||||
# Build the full path relative to project root
|
||||
if dir_path:
|
||||
full_path = f"{dir_name}/{dir_path}"
|
||||
else:
|
||||
full_path = dir_name
|
||||
|
||||
entry = format_directory_entry(full_path, files, max_files)
|
||||
if entry:
|
||||
lines.append(f"|{entry}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def generate_agents_md(
|
||||
template_path: Path, output_path: Path, root_dirs: Dict[str, Dict[str, any]]
|
||||
) -> None:
|
||||
"""
|
||||
Generate the AGENTS.md file using template.
|
||||
|
||||
Args:
|
||||
template_path: Path to AGENTS.md.template file
|
||||
output_path: Path where AGENTS.md should be written
|
||||
root_dirs: Dictionary mapping directory names to their scan configs
|
||||
"""
|
||||
# Generate the index content
|
||||
index_content = generate_index_content(root_dirs)
|
||||
|
||||
# Read the template
|
||||
if not template_path.exists():
|
||||
print(f"⚠️ Template not found at {template_path}")
|
||||
print(f" Creating AGENTS.md without template...")
|
||||
content = index_content + "\n"
|
||||
else:
|
||||
template = template_path.read_text()
|
||||
# Inject the index into the template
|
||||
content = template.replace("{{DOCUMENTATION_INDEX}}", index_content)
|
||||
|
||||
# Write to file
|
||||
output_path.write_text(content)
|
||||
print(f"✓ Generated {output_path}")
|
||||
index_lines = index_content.count("\n") + 1
|
||||
total_lines = content.count("\n") + 1
|
||||
print(f" Index lines: {index_lines}")
|
||||
print(f" Total lines: {total_lines}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Main entry point."""
|
||||
project_root = get_project_root()
|
||||
|
||||
# Configuration for directories to scan
|
||||
root_dirs = {
|
||||
"docs": {
|
||||
"path": project_root / "docs",
|
||||
"extensions": {".md", ".txt", ".yaml", ".yml", ".json", ".sh"},
|
||||
"max_files": 15,
|
||||
},
|
||||
"scripts": {
|
||||
"path": project_root / "scripts",
|
||||
"extensions": {".sh", ".py", ".sql", ".js", ".html"},
|
||||
"max_files": 20,
|
||||
},
|
||||
"work-summary": {
|
||||
"path": project_root / "work-summary",
|
||||
"extensions": {".md", ".txt"},
|
||||
"max_files": 20,
|
||||
},
|
||||
}
|
||||
|
||||
template_path = project_root / "AGENTS.md.template"
|
||||
output_path = project_root / "AGENTS.md"
|
||||
|
||||
print("Generating AGENTS.md index...")
|
||||
print(f"Project root: {project_root}")
|
||||
print(f"Template: {template_path}")
|
||||
print()
|
||||
|
||||
# Generate the index
|
||||
generate_agents_md(template_path, output_path, root_dirs)
|
||||
|
||||
print()
|
||||
print("Index generation complete!")
|
||||
print(f"Review the generated file at: {output_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user