From d39bb6326bfab569960c05c9b3f6047f9708ab8c Mon Sep 17 00:00:00 2001 From: Robert Dean Date: Fri, 6 Feb 2026 07:12:20 +0100 Subject: [PATCH 1/2] docs: add AI repo intelligence documentation set --- docs/ai/ARCHITECTURE.md | 52 ++++++++++++++++++++++++++++ docs/ai/CODEBASE_MAP.md | 65 +++++++++++++++++++++++++++++++++++ docs/ai/COMMANDS.md | 57 ++++++++++++++++++++++++++++++ docs/ai/CONVENTIONS.md | 27 +++++++++++++++ docs/ai/DEPLOYMENT.md | 40 +++++++++++++++++++++ docs/ai/HOTSPOTS.md | 38 ++++++++++++++++++++ docs/ai/SECURITY_AND_RISKS.md | 45 ++++++++++++++++++++++++ docs/ai/STACK.md | 30 ++++++++++++++++ docs/ai/TESTING.md | 36 +++++++++++++++++++ 9 files changed, 390 insertions(+) create mode 100644 docs/ai/ARCHITECTURE.md create mode 100644 docs/ai/CODEBASE_MAP.md create mode 100644 docs/ai/COMMANDS.md create mode 100644 docs/ai/CONVENTIONS.md create mode 100644 docs/ai/DEPLOYMENT.md create mode 100644 docs/ai/HOTSPOTS.md create mode 100644 docs/ai/SECURITY_AND_RISKS.md create mode 100644 docs/ai/STACK.md create mode 100644 docs/ai/TESTING.md diff --git a/docs/ai/ARCHITECTURE.md b/docs/ai/ARCHITECTURE.md new file mode 100644 index 0000000..fc5e0a8 --- /dev/null +++ b/docs/ai/ARCHITECTURE.md @@ -0,0 +1,52 @@ +# ARCHITECTURE + +- **High-level shape** + - A single-process MCP-style server composed of: + - transport layer (`http`, `stdio`) + - feature layer (project manifest + Drush/Composer adapters) + - infrastructure helpers (config loader, CLI runner, error mapping/cache/path helpers) + - Configuration-driven: server behavior depends on `drupalRoot` and optional binary paths/timeouts. + +## Request/operation flow + +- Startup: + - Entrypoint (`src/bin/http.ts` or `src/bin/stdio.ts`) calls `createMCPServer()`. + - `createMCPServer()` loads config and initializes `ServerState` with resources + tools. +- Invocation: + - Transport maps a route/action to a feature function. + - Each call is wrapped in `runOperation` for timing/status logging. + - Feature either returns `ok` data or structured failure/degraded/not_configured responses. + +## Component boundaries + +- **Transport layer** + - `src/transports/http.ts`: read-only GET API routing. + - `src/transports/stdio.ts`: read-only action switch over JSON lines. +- **Feature layer** + - `projectManifest.ts`: filesystem/composer inspection and module/theme discovery. + - `drushTools.ts`: Drush command execution, output parsing, module/theme type normalization. + - `composerTools.ts`: Composer file inspection and outdated package parsing/type tagging. +- **Infra/utilities** + - `config.ts`: defaults + input validation + error codes. + - `sandboxExecution.ts`: process execution (spawn), timeout kill, max parallel queue. + - `errorMapping.ts`: standardized CLI failure mapping. + - `cache.ts`: in-memory TTL cache used by `drush_pml`. + - `projectPaths.ts`: project root resolution and JSON file reads. + +## Data contracts + +- Shared response envelope and status model (`ok`, `degraded`, `error`, `timeout`, `not_configured`) live in `src/types.ts`. +- Tool/resource descriptors are static objects exposed via `/tools` and `/resources`. +- `project_manifest` schema version currently hardcoded to `0.1.0`. + +## Notable architectural constraints + +- Tool commands are fixed/allowlisted in code (no user-provided CLI flags through transport interfaces). +- Command execution defaults to serialized mode (`maxParallelCli` defaults to `1`). +- HTTP API is GET-only and does not implement auth, sessions, or protocol-level MCP envelopes. +- `features/sdkGeneration.ts` and sandbox code execution are placeholders (not production behavior yet). + +## Assumptions + +- Architecture description reflects current implementation, not full roadmap/RFC target state. +- No distributed components or persistent stores are present in the checked-in runtime package. diff --git a/docs/ai/CODEBASE_MAP.md b/docs/ai/CODEBASE_MAP.md new file mode 100644 index 0000000..18ecd53 --- /dev/null +++ b/docs/ai/CODEBASE_MAP.md @@ -0,0 +1,65 @@ +# CODEBASE_MAP + +- **What this repo is** + - DriftCore is currently an experimental MCP server focused on giving agents read-only, structured insight into a single Drupal project (project manifest + Drush/Composer inspection tools). + - The implementation that exists in this repository is centered in `packages/server`. +- **Top-level layout** + - `packages/server/`: TypeScript Node.js server package (runtime code, tests, Dockerfile, package scripts). + - `rfcs/`: product/architecture RFCs (not runtime code). + - `specs/`: product specs and acceptance criteria documents. + - `README.md`: project-level positioning and roadmap. + +## Main runtime entrypoints + +- **HTTP binary entrypoint**: `packages/server/src/bin/http.ts` + - Parses `--port` with `yargs`, creates server, starts HTTP transport. +- **STDIO binary entrypoint**: `packages/server/src/bin/stdio.ts` + - Creates server and starts STDIO transport. +- **Server composition root**: `packages/server/src/index.ts` + - Loads config, registers resources/tools, wraps operations with logging, exposes `handleHttp` and `handleStdio`. + +## Organization inside `packages/server/src` + +- `bin/`: executable CLIs (`http.ts`, `stdio.ts`). +- `transports/`: protocol adapters + - `http.ts`: GET routes (`/health`, `/resources`, `/tools`, `/project-manifest`, `/drush/*`, `/composer/*`). + - `stdio.ts`: JSON line actions (`resources`, `tools`, `project_manifest`, etc.). +- `features/`: business logic + - `projectManifest.ts`: builds `project_manifest` resource payload. + - `drushTools.ts`: `drift.drush_status`, `drift.drush_pml` execution + normalization. + - `composerTools.ts`: `drift.composer_info`, `drift.composer_outdated`. + - `config.ts`: config loading/defaulting/validation. + - `sandboxExecution.ts`: CLI process runner and concurrency controls. + - `errorMapping.ts`, `cache.ts`, `projectPaths.ts`, `schemaResources.ts`, `sdkGeneration.ts` (stub). +- `__tests__/`: node test suites for manifest parsing, tool parsing, schema/tool registration, non-write guarantees. +- `integration/smoke.ts`: HTTP smoke test. + +## Where to make changes + +- **Routing / external API surface** + - HTTP routes: `packages/server/src/transports/http.ts` + - STDIO actions: `packages/server/src/transports/stdio.ts` + - Tool/resource registration list: `packages/server/src/index.ts` +- **Data models / response shapes / contracts** + - Shared types and response envelopes: `packages/server/src/types.ts` + - Resource schema payload template: `packages/server/src/features/schemaResources.ts` +- **Domain logic** + - Drupal manifest discovery: `packages/server/src/features/projectManifest.ts` + - Drush adapters: `packages/server/src/features/drushTools.ts` + - Composer adapters: `packages/server/src/features/composerTools.ts` +- **Infra/runtime execution** + - Config handling/defaults/validation: `packages/server/src/config.ts` + - Child process execution + timeout + parallelism: `packages/server/src/features/sandboxExecution.ts` + - Container runtime packaging: `packages/server/Dockerfile` +- **Tests** + - Unit tests for tool parsing/behavior: `packages/server/src/__tests__/cliTools.test.ts` + - Non-write invariant: `packages/server/src/__tests__/cliTools.nonwrite.test.ts` + - Manifest behavior: `packages/server/src/__tests__/projectManifest.test.ts` + - Route-level smoke test: `packages/server/src/integration/smoke.ts` +- **UI** + - No UI frontend code exists in the current tree; this repo currently exposes MCP over HTTP/STDIO only. + +## Assumptions + +- This map assumes only currently tracked files are in scope (no hidden submodules/worktrees). +- There is no CI workflow config checked in right now; if CI exists externally, that is not visible from this repository contents. diff --git a/docs/ai/COMMANDS.md b/docs/ai/COMMANDS.md new file mode 100644 index 0000000..65edc7f --- /dev/null +++ b/docs/ai/COMMANDS.md @@ -0,0 +1,57 @@ +# COMMANDS + +- **Working directory assumption for commands below**: `packages/server`. + +## Build, lint, test + +- `npm install` +- `npm run build` +- `npm run lint` +- `npm test` +- `npm run integration` + +## Run server + +- **STDIO transport** + - `DRIFTCORE_CONFIG=/path/to/driftcore.config.json npm run start:stdio` +- **HTTP transport** + - `DRIFTCORE_CONFIG=/path/to/driftcore.config.json npm run start:http -- --port 8080` + +## HTTP endpoints (GET) + +- `/health` +- `/resources` +- `/tools` +- `/project-manifest` +- `/drush/status` +- `/drush/pml` +- `/composer/info` +- `/composer/outdated` + +## STDIO actions (JSON line input) + +- `resources` +- `tools` +- `project_manifest` +- `drush_status` +- `drush_pml` +- `composer_info` +- `composer_outdated` + +Example payload: + +```json +{"id":1,"action":"project_manifest"} +``` + +## Docker + +- Build image from package directory: + - `docker build -t driftcore-server .` +- Run container (config mount/env needed for useful behavior): + - `docker run --rm -p 8080:8080 -e DRIFTCORE_CONFIG=/config/driftcore.config.json -v /host/config:/config driftcore-server` + +## Assumptions + +- There is no root `package.json` command wrapper in the current repository. +- Docker run command is illustrative; actual Drupal/composer/drush paths must exist inside container/mounts. diff --git a/docs/ai/CONVENTIONS.md b/docs/ai/CONVENTIONS.md new file mode 100644 index 0000000..ffc2132 --- /dev/null +++ b/docs/ai/CONVENTIONS.md @@ -0,0 +1,27 @@ +# CONVENTIONS + +- **Language and module conventions** + - TypeScript ESM imports with explicit `.js` extensions in local imports. + - Strict TypeScript enabled (`"strict": true`). +- **Error/response conventions** + - Feature methods return structured envelopes with `status`, optional `data`, optional `error`. + - Config and CLI failures use explicit code strings (e.g., `E_CONFIG_INVALID_ROOT`, `E_JSON_PARSE`, `E_TIMEOUT`). + - CLI stderr is truncated before being returned. +- **Tooling conventions** + - Read-only by design in v0.1 tooling: fixed command args for Drush/Composer tools. + - No shell interpolation (`spawn(..., shell: false)`). +- **Configuration conventions** + - Config source precedence: explicit path -> `DRIFTCORE_CONFIG` env -> `./driftcore.config.json`. + - Defaults provided for module/theme dirs, timeouts, cache TTL, and CLI concurrency. +- **Testing conventions** + - Uses `node:test` and `assert/strict`. + - Tests create temporary fake Drupal projects in OS temp dirs. + - Includes a dedicated non-write behavior test. +- **Documentation/process conventions** + - RFC/spec docs exist and describe intended behavior, but implementation may lag roadmap content. + - Package README documents operational commands and expected config structure. + +## Assumptions + +- No external formatter/linter config (ESLint/Prettier) is currently checked in, so style conventions are inferred from source. +- Naming and error code patterns are inferred from current server package and may evolve. diff --git a/docs/ai/DEPLOYMENT.md b/docs/ai/DEPLOYMENT.md new file mode 100644 index 0000000..606501c --- /dev/null +++ b/docs/ai/DEPLOYMENT.md @@ -0,0 +1,40 @@ +# DEPLOYMENT + +- **Current deployment maturity** + - Repository contains a package-level Dockerfile for `@driftcore/server`. + - No checked-in CI/CD workflow or orchestrator manifests are present. + +## What exists now + +- `packages/server/Dockerfile` + - Base: `node:20-slim` + - Copies `package.json`, `tsconfig.json`, `src/` + - Runs `npm install && npm run build` + - Starts HTTP server: `node dist/bin/http.js` +- Runtime requires external config via `DRIFTCORE_CONFIG` (or default file path in working dir). + +## Minimal deployment pattern + +- Build the server image from `packages/server`. +- Provide `driftcore.config.json` at runtime (bind mount or baked image layer). +- Ensure target Drupal codebase and CLI binaries are reachable from runtime: + - `drupalRoot` path must be valid inside container. + - Drush and Composer paths must be valid (or discoverable defaults must exist). +- Expose HTTP port (default 8080) when using HTTP transport. + +## Operational considerations + +- Health probe can call `/health`. +- Since endpoints are GET and mostly inspection-oriented, deployment is stateless apart from in-memory cache. +- Logs are console-based; operation timing/status is emitted from server operation wrapper. + +## Unknowns / confirmation files if needed + +- CI/CD pipeline details: would need `.github/workflows/*` or external build system config. +- Kubernetes/Compose production topology: would need deployment manifests (not present). +- Secret management strategy: would need env/config management docs outside current repo. + +## Assumptions + +- Deployment guidance is based on what is checked into the repository only. +- No production hardening (auth/TLS/reverse proxy) is inferred unless configured externally. diff --git a/docs/ai/HOTSPOTS.md b/docs/ai/HOTSPOTS.md new file mode 100644 index 0000000..ed184e4 --- /dev/null +++ b/docs/ai/HOTSPOTS.md @@ -0,0 +1,38 @@ +# HOTSPOTS + +- **Method used** + - Hotspots estimated from git history file-touch counts (current tracked files only). + - Command used: `git log --name-only --pretty=format: | rg '.' | while read f; do [ -e "$f" ] && echo "$f"; done | sort | uniq -c | sort -nr | head -n 30` + +## Most changed areas (current files) + +- **Project docs / planning hotspots** + - `README.md` (high churn) + - `rfcs/RFC-0001-driftcore-mvp.md` (high churn) +- **Server API surface hotspots** + - `packages/server/src/index.ts` + - `packages/server/src/transports/http.ts` + - `packages/server/src/transports/stdio.ts` + - `packages/server/src/types.ts` +- **Tool behavior hotspots** + - `packages/server/src/features/drushTools.ts` + - `packages/server/src/features/schemaResources.ts` + - `packages/server/src/features/sandboxExecution.ts` +- **Packaging/test hotspots** + - `packages/server/package.json` + - `packages/server/src/integration/smoke.ts` + - `packages/server/src/__tests__/schemaResources.test.ts` + +## Practical implications + +- If changing tool contracts or route behavior, expect ripple effects in: + - `src/transports/*` + - `src/features/*Tools.ts` + - `src/types.ts` + - tests under `src/__tests__` and `src/integration`. +- Documentation and implementation can drift; cross-check README/RFC claims against `packages/server/src/*` before making architecture-level changes. + +## Assumptions + +- File-touch count is a coarse proxy for risk; it does not measure line-level churn or bug density. +- Some historic hotspots from deleted paths were intentionally excluded to keep this actionable for current code. diff --git a/docs/ai/SECURITY_AND_RISKS.md b/docs/ai/SECURITY_AND_RISKS.md new file mode 100644 index 0000000..a4a09ef --- /dev/null +++ b/docs/ai/SECURITY_AND_RISKS.md @@ -0,0 +1,45 @@ +# SECURITY_AND_RISKS + +## Existing safety mechanisms + +- **Command allowlisting by construction** + - Drush and Composer tools execute fixed command/arg sets; transport does not accept arbitrary flags. +- **No shell execution path** + - CLI runner uses `spawn(..., shell: false)`. +- **Timeout + process termination** + - Configurable timeouts for Drush/Composer calls, with SIGKILL on timeout. +- **Concurrency control** + - `maxParallelCli` defaults to `1` to reduce contention and limit parallel subprocess risk. +- **Structured error handling** + - Failures map to explicit status/error payloads to avoid crashes and opaque failures. +- **Non-write posture tested** + - Dedicated test verifies no tool invocation modifies a sentinel project file. + +## Current risks / gaps + +- **No auth on HTTP endpoints** + - API appears open by default (`/health`, `/tools`, tool endpoints). +- **Potential sensitive path leakage** + - Errors/diagnostics include command, cwd, and filesystem paths. +- **Resource exposure** + - `/composer/info` and `project_manifest` can expose dependency metadata and local project structure. +- **Process isolation is basic** + - Subprocesses run on host/container with cwd/env controls but without deeper sandboxing. +- **Placeholder sandbox execution API** + - `executeInSandbox` is currently a stub; future implementation is a high-risk area. +- **No built-in rate limiting or request size controls** + - Could enable abuse in exposed environments. + +## Recommended hardening backlog + +- Add authn/authz (token or mTLS) before exposing HTTP transport beyond localhost. +- Add optional response redaction mode for paths/stderr diagnostics. +- Add endpoint-level rate limiting and time-budget controls. +- Add explicit allowlist checks for resolved binary paths. +- Add contract tests for redaction, timeout behavior, and malformed CLI output resilience. +- Document threat model for local-dev vs shared-host deployment. + +## Assumptions + +- Security posture is assessed from application code only; external proxy/firewall controls are unknown. +- No secret scanning or SAST configuration is visible in repository contents. diff --git a/docs/ai/STACK.md b/docs/ai/STACK.md new file mode 100644 index 0000000..68105ef --- /dev/null +++ b/docs/ai/STACK.md @@ -0,0 +1,30 @@ +# STACK + +- **Language/runtime** + - TypeScript 5.x compiled to ESM JavaScript. + - Node.js 20+ runtime target. +- **Package/dependency management** + - `npm` for install/build/test in the implemented package. + - Single implemented package currently visible: `@driftcore/server`. +- **Core dependencies** + - `yargs` for CLI argument parsing (`--port` in HTTP entrypoint). + - Node standard library heavily used (`http`, `readline`, `child_process`, `fs`, `path`, `process`, `assert`, `node:test`). +- **Build and type-checking** + - TypeScript compiler (`tsc`) via `npm run build` and `npm run lint` (`--noEmit`). + - Output directory: `packages/server/dist`. +- **Testing stack** + - Built-in Node test runner (`node --test`) for unit tests. + - Integration smoke script hitting HTTP endpoints. +- **Runtime interfaces** + - STDIO line-based JSON protocol. + - HTTP GET endpoints. +- **Containerization** + - Dockerfile for server package based on `node:20-slim`; installs deps, builds TS, runs HTTP binary. +- **Drupal/tooling integration points** + - Executes Drush and Composer via child processes with fixed args and timeout/concurrency controls. + - Configurable binary paths and Drupal root via JSON config. + +## Assumptions + +- No root workspace manifest is present; stack details are inferred from `packages/server` and docs. +- No alternative package managers/scripts are configured in code beyond references in README text. diff --git a/docs/ai/TESTING.md b/docs/ai/TESTING.md new file mode 100644 index 0000000..8db989b --- /dev/null +++ b/docs/ai/TESTING.md @@ -0,0 +1,36 @@ +# TESTING + +- **Primary test entrypoints** + - `npm test` (from `packages/server`): build then run Node tests from compiled `dist/__tests__`. + - `npm run integration`: build then run HTTP transport smoke test (`dist/integration/smoke.js`). + - `npm run lint`: TypeScript type-check in no-emit mode. + +## Test suites in `packages/server/src` + +- `__tests__/projectManifest.test.ts` + - Valid manifest generation, not-configured behavior, degraded behavior on missing composer metadata. +- `__tests__/cliTools.test.ts` + - Drush status parsing, Drush pml normalization, composer info parsing, composer outdated parsing. +- `__tests__/cliTools.nonwrite.test.ts` + - Verifies tool invocations do not modify a sentinel project file. +- `__tests__/schemaResources.test.ts` + - Verifies required static schema resources and drush tool registration. +- `integration/smoke.ts` + - Starts ephemeral HTTP server and calls core endpoints (`/health`, `/resources`, `/project-manifest`, `/drush/status`, `/composer/info`). + +## Testing characteristics + +- Uses temporary directories to simulate Drupal project filesystem shape. +- Avoids requiring real Drush/Composer execution in unit tests by using runner stubs. +- Integration smoke test validates transport plumbing but does not assert real Drupal connectivity. + +## Gaps / what to add next + +- No property/fuzz tests for parsing untrusted CLI output. +- No contract tests for schema versioning backward compatibility. +- No CI config in repo to enforce test execution on PRs. + +## Assumptions + +- Test commands are package-local; there is no root-level test orchestrator currently checked in. +- “Integration” here means HTTP transport smoke coverage, not full Drupal sandbox integration. From 36835af0fb8ea12c704c5817995dd5b331ed0b87 Mon Sep 17 00:00:00 2001 From: Robert Dean Date: Fri, 6 Feb 2026 11:55:11 +0100 Subject: [PATCH 2/2] chore: add agent-runner placeholder package for CI installs --- packages/agent-runner/README.md | 5 +++++ packages/agent-runner/package-lock.json | 12 ++++++++++++ packages/agent-runner/package.json | 13 +++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 packages/agent-runner/README.md create mode 100644 packages/agent-runner/package-lock.json create mode 100644 packages/agent-runner/package.json diff --git a/packages/agent-runner/README.md b/packages/agent-runner/README.md new file mode 100644 index 0000000..c480876 --- /dev/null +++ b/packages/agent-runner/README.md @@ -0,0 +1,5 @@ +# @driftcore/agent-runner (placeholder) + +This directory intentionally provides a minimal placeholder package so CI jobs that still run `npm install --prefix packages/agent-runner` do not fail. + +The runtime implementation of an agent runner is not currently present in this repository. diff --git a/packages/agent-runner/package-lock.json b/packages/agent-runner/package-lock.json new file mode 100644 index 0000000..16bccbf --- /dev/null +++ b/packages/agent-runner/package-lock.json @@ -0,0 +1,12 @@ +{ + "name": "@driftcore/agent-runner", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@driftcore/agent-runner", + "version": "0.0.0" + } + } +} diff --git a/packages/agent-runner/package.json b/packages/agent-runner/package.json new file mode 100644 index 0000000..ff7d086 --- /dev/null +++ b/packages/agent-runner/package.json @@ -0,0 +1,13 @@ +{ + "name": "@driftcore/agent-runner", + "version": "0.0.0", + "private": true, + "description": "Placeholder package to satisfy CI install steps while agent-runner implementation is not present.", + "type": "module", + "scripts": { + "build": "node -e \"console.log('agent-runner placeholder: no build step')\"", + "lint": "node -e \"console.log('agent-runner placeholder: no lint step')\"", + "test": "node -e \"console.log('agent-runner placeholder: no tests')\"", + "integration": "node -e \"console.log('agent-runner placeholder: no integration tests')\"" + } +}