feat: monorepo consolidation — forge pipeline, MACP protocol, framework plugin, profiles/guides/skills
Work packages completed: - WP1: packages/forge — pipeline runner, stage adapter, board tasks, brief classifier, persona loader with project-level overrides. 89 tests, 95.62% coverage. - WP2: packages/macp — credential resolver, gate runner, event emitter, protocol types. 65 tests, 96.24% coverage. Full Python-to-TS port preserving all behavior. - WP3: plugins/mosaic-framework — OC rails injection plugin (before_agent_start + subagent_spawning hooks for Mosaic contract enforcement). - WP4: profiles/ (domains, tech-stacks, workflows), guides/ (17 docs), skills/ (5 universal skills), forge pipeline assets (48 markdown files). Board deliberation: docs/reviews/consolidation-board-memo.md Brief: briefs/monorepo-consolidation.md Consolidates mosaic/stack (forge, MACP, bootstrap framework) into mosaic/mosaic-stack. 154 new tests total. Zero Python — all TypeScript/ESM.
This commit is contained in:
150
docs/tasks/WP2-macp-package.md
Normal file
150
docs/tasks/WP2-macp-package.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# WP2: packages/macp — MACP Protocol Package
|
||||
|
||||
## Context
|
||||
|
||||
Port the MACP protocol layer from Python (in ~/src/mosaic-stack/tools/macp/) to TypeScript as `packages/macp` in this monorepo. This package provides the foundational protocol types, quality gate execution, credential resolution, and event system that `packages/coord` and `plugins/macp` depend on.
|
||||
|
||||
**Board decisions that constrain this work:**
|
||||
|
||||
- No Python in the new repo — everything rewrites to TypeScript
|
||||
- OpenBrain learning capture/recall is OUT OF SCOPE (deferred to future brief)
|
||||
- 85% test coverage on TS implementation files
|
||||
- Credential resolver behavior must be captured as test fixtures BEFORE rewrite
|
||||
- Clean index.ts exports, no internal path leakage
|
||||
|
||||
## Source Files (Python → TypeScript)
|
||||
|
||||
### 1. credential-resolver.ts
|
||||
|
||||
**Source:** `~/src/mosaic-stack/tools/macp/dispatcher/credential_resolver.py`
|
||||
|
||||
Resolution order (MUST preserve exactly):
|
||||
|
||||
1. Mosaic credential files (`~/.config/mosaic/credentials/{provider}.env`)
|
||||
2. OpenClaw config (`~/.openclaw/openclaw.json`) — env block + models.providers.{provider}.apiKey
|
||||
3. Ambient environment variables
|
||||
4. CredentialError (failure)
|
||||
|
||||
Key behaviors to preserve:
|
||||
|
||||
- Provider registry: anthropic, openai, zai → env var names + credential file paths + OC config paths
|
||||
- Dotenv parser: handles single/double quotes, comments, blank lines
|
||||
- JSON5 stripping: placeholder-extraction approach (NOT naive regex) — protects URLs and timestamps inside string values
|
||||
- OC config permission check: warn on world-readable, skip if wrong owner
|
||||
- Redacted marker detection: `__OPENCLAW_REDACTED__` values skipped
|
||||
- Task-level override via `credentials.provider_key_env`
|
||||
|
||||
### 2. gate-runner.ts
|
||||
|
||||
**Source:** `~/src/mosaic-stack/tools/macp/controller/gate_runner.py`
|
||||
|
||||
Three gate types:
|
||||
|
||||
- `mechanical`: shell command, pass = exit code 0
|
||||
- `ai-review`: shell command producing JSON, parse findings, fail on blockers
|
||||
- `ci-pipeline`: placeholder (always passes for now)
|
||||
|
||||
Key behaviors:
|
||||
|
||||
- `normalize_gate()`: accepts string or dict, normalizes to gate entry
|
||||
- `run_gate()`: executes single gate, returns result with pass/fail
|
||||
- `run_gates()`: executes all gates, emits events, returns (all_passed, results)
|
||||
- AI review parsing: `_count_ai_findings()` reads stats.blockers or findings[].severity
|
||||
- `fail_on` modes: "blocker" (default) or "any"
|
||||
|
||||
### 3. event-emitter.ts
|
||||
|
||||
**Source:** `~/src/mosaic-stack/tools/macp/controller/gate_runner.py` (emit_event, append_event functions) + `~/src/mosaic-stack/tools/macp/events/`
|
||||
|
||||
- Append structured events to ndjson file
|
||||
- Event types: task.assigned, task.started, task.completed, task.failed, task.escalated, task.gated, task.retry.scheduled, rail.check.started, rail.check.passed, rail.check.failed
|
||||
- Each event: event_id (uuid), event_type, task_id, status, timestamp, source, message, metadata
|
||||
|
||||
### 4. types.ts
|
||||
|
||||
**Source:** `~/src/mosaic-stack/tools/macp/protocol/task.schema.json`
|
||||
|
||||
TypeScript types for:
|
||||
|
||||
- Task (id, title, status, dispatch, runtime, depends_on, depends_on_policy, quality_gates, timeout_seconds, metadata, etc.)
|
||||
- Event (event_id, event_type, task_id, status, timestamp, source, message, metadata)
|
||||
- GateResult (command, exit_code, type, passed, output, findings, blockers)
|
||||
- TaskResult (task_id, status, completed_at, exit_code, gate_results, files_changed, etc.)
|
||||
- CredentialError, ProviderRegistry
|
||||
|
||||
### 5. schemas/ (copy)
|
||||
|
||||
Copy `~/src/mosaic-stack/tools/macp/protocol/task.schema.json` as-is.
|
||||
|
||||
## Package Structure
|
||||
|
||||
```
|
||||
packages/macp/
|
||||
├── src/
|
||||
│ ├── index.ts
|
||||
│ ├── types.ts
|
||||
│ ├── credential-resolver.ts
|
||||
│ ├── gate-runner.ts
|
||||
│ ├── event-emitter.ts
|
||||
│ └── schemas/
|
||||
│ └── task.schema.json
|
||||
├── __tests__/
|
||||
│ ├── credential-resolver.test.ts
|
||||
│ ├── gate-runner.test.ts
|
||||
│ └── event-emitter.test.ts
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
└── vitest.config.ts
|
||||
```
|
||||
|
||||
## Package.json
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@mosaic/macp",
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"vitest": "workspace:*",
|
||||
"typescript": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Zero external dependencies. Uses node:fs, node:path, node:child_process, node:crypto only.
|
||||
|
||||
## Test Requirements
|
||||
|
||||
Port ALL existing Python tests as TypeScript equivalents:
|
||||
|
||||
- `test_resolve_from_file` → credential file resolution
|
||||
- `test_resolve_from_ambient` → ambient env resolution
|
||||
- `test_resolve_from_oc_config_env_block` → OC config env block
|
||||
- `test_resolve_from_oc_config_provider_apikey` → OC config provider
|
||||
- `test_oc_config_precedence` → mosaic file wins over OC config
|
||||
- `test_oc_config_missing_file` → graceful fallback
|
||||
- `test_json5_strip` → structural transforms
|
||||
- `test_json5_strip_urls_and_timestamps` → URLs/timestamps survive
|
||||
- `test_redacted_values_skipped` → redacted marker detection
|
||||
- `test_oc_config_permission_warning` → file permission check
|
||||
- `test_resolve_missing_raises` → CredentialError thrown
|
||||
- Gate runner: mechanical pass/fail, AI review parsing, ci-pipeline placeholder
|
||||
- Event emitter: append to ndjson, event structure validation
|
||||
|
||||
## ESM Requirements
|
||||
|
||||
- `"type": "module"` in package.json
|
||||
- NodeNext module resolution in tsconfig
|
||||
- `.js` extensions in all imports
|
||||
- No CommonJS (`require`, `module.exports`)
|
||||
|
||||
## Integration Points
|
||||
|
||||
After this package is built:
|
||||
|
||||
- `packages/coord` should import `@mosaic/macp` for event emission and gate types
|
||||
- `plugins/macp` should import `@mosaic/macp` for credential resolution and protocol types
|
||||
Reference in New Issue
Block a user