@alevental/cccp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/.claude/skills/cccp-pipeline/SKILL.md +562 -0
  2. package/.claude/skills/cccp-run/SKILL.md +111 -0
  3. package/README.md +280 -0
  4. package/dist/activity-bus.d.ts +9 -0
  5. package/dist/activity-bus.js +10 -0
  6. package/dist/activity-bus.js.map +1 -0
  7. package/dist/agent-resolver.d.ts +29 -0
  8. package/dist/agent-resolver.js +122 -0
  9. package/dist/agent-resolver.js.map +1 -0
  10. package/dist/agent.d.ts +39 -0
  11. package/dist/agent.js +117 -0
  12. package/dist/agent.js.map +1 -0
  13. package/dist/autoresearch.d.ts +11 -0
  14. package/dist/autoresearch.js +295 -0
  15. package/dist/autoresearch.js.map +1 -0
  16. package/dist/cli.d.ts +2 -0
  17. package/dist/cli.js +157 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/config.d.ts +126 -0
  20. package/dist/config.js +76 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/context.d.ts +24 -0
  23. package/dist/context.js +82 -0
  24. package/dist/context.js.map +1 -0
  25. package/dist/contract.d.ts +26 -0
  26. package/dist/contract.js +65 -0
  27. package/dist/contract.js.map +1 -0
  28. package/dist/db.d.ts +70 -0
  29. package/dist/db.js +358 -0
  30. package/dist/db.js.map +1 -0
  31. package/dist/dispatcher.d.ts +9 -0
  32. package/dist/dispatcher.js +7 -0
  33. package/dist/dispatcher.js.map +1 -0
  34. package/dist/errors.d.ts +16 -0
  35. package/dist/errors.js +30 -0
  36. package/dist/errors.js.map +1 -0
  37. package/dist/evaluator.d.ts +23 -0
  38. package/dist/evaluator.js +49 -0
  39. package/dist/evaluator.js.map +1 -0
  40. package/dist/gate/auto-approve.d.ts +9 -0
  41. package/dist/gate/auto-approve.js +11 -0
  42. package/dist/gate/auto-approve.js.map +1 -0
  43. package/dist/gate/gate-strategy.d.ts +22 -0
  44. package/dist/gate/gate-strategy.js +2 -0
  45. package/dist/gate/gate-strategy.js.map +1 -0
  46. package/dist/gate/gate-watcher.d.ts +15 -0
  47. package/dist/gate/gate-watcher.js +64 -0
  48. package/dist/gate/gate-watcher.js.map +1 -0
  49. package/dist/logger.d.ts +24 -0
  50. package/dist/logger.js +22 -0
  51. package/dist/logger.js.map +1 -0
  52. package/dist/mcp/gate-notifier.d.ts +26 -0
  53. package/dist/mcp/gate-notifier.js +161 -0
  54. package/dist/mcp/gate-notifier.js.map +1 -0
  55. package/dist/mcp/mcp-config.d.ts +25 -0
  56. package/dist/mcp/mcp-config.js +80 -0
  57. package/dist/mcp/mcp-config.js.map +1 -0
  58. package/dist/mcp/mcp-server.d.ts +1 -0
  59. package/dist/mcp/mcp-server.js +262 -0
  60. package/dist/mcp/mcp-server.js.map +1 -0
  61. package/dist/pge.d.ts +12 -0
  62. package/dist/pge.js +361 -0
  63. package/dist/pge.js.map +1 -0
  64. package/dist/pipeline.d.ts +6 -0
  65. package/dist/pipeline.js +120 -0
  66. package/dist/pipeline.js.map +1 -0
  67. package/dist/prompt.d.ts +67 -0
  68. package/dist/prompt.js +121 -0
  69. package/dist/prompt.js.map +1 -0
  70. package/dist/runner.d.ts +11 -0
  71. package/dist/runner.js +494 -0
  72. package/dist/runner.js.map +1 -0
  73. package/dist/scaffold/index.d.ts +14 -0
  74. package/dist/scaffold/index.js +260 -0
  75. package/dist/scaffold/index.js.map +1 -0
  76. package/dist/scaffold/templates.d.ts +47 -0
  77. package/dist/scaffold/templates.js +2177 -0
  78. package/dist/scaffold/templates.js.map +1 -0
  79. package/dist/stage-helpers.d.ts +7 -0
  80. package/dist/stage-helpers.js +27 -0
  81. package/dist/stage-helpers.js.map +1 -0
  82. package/dist/state.d.ts +43 -0
  83. package/dist/state.js +177 -0
  84. package/dist/state.js.map +1 -0
  85. package/dist/stream/stream-tail.d.ts +17 -0
  86. package/dist/stream/stream-tail.js +95 -0
  87. package/dist/stream/stream-tail.js.map +1 -0
  88. package/dist/stream/stream.d.ts +142 -0
  89. package/dist/stream/stream.js +251 -0
  90. package/dist/stream/stream.js.map +1 -0
  91. package/dist/temp-tracker.d.ts +6 -0
  92. package/dist/temp-tracker.js +24 -0
  93. package/dist/temp-tracker.js.map +1 -0
  94. package/dist/tui/cmux.d.ts +22 -0
  95. package/dist/tui/cmux.js +82 -0
  96. package/dist/tui/cmux.js.map +1 -0
  97. package/dist/tui/components.d.ts +21 -0
  98. package/dist/tui/components.js +108 -0
  99. package/dist/tui/components.js.map +1 -0
  100. package/dist/tui/dashboard.d.ts +6 -0
  101. package/dist/tui/dashboard.js +125 -0
  102. package/dist/tui/dashboard.js.map +1 -0
  103. package/dist/tui/detail-log.d.ts +10 -0
  104. package/dist/tui/detail-log.js +171 -0
  105. package/dist/tui/detail-log.js.map +1 -0
  106. package/dist/types.d.ts +273 -0
  107. package/dist/types.js +2 -0
  108. package/dist/types.js.map +1 -0
  109. package/examples/agents/diff-evaluator.md +57 -0
  110. package/examples/agents/prompt-tuner.md +30 -0
  111. package/examples/agents/summarizer.md +14 -0
  112. package/examples/autoresearch-artifacts/expected-output.md +17 -0
  113. package/examples/autoresearch-artifacts/prompt.md +35 -0
  114. package/examples/autoresearch-artifacts/source-material.md +28 -0
  115. package/examples/business-case.yaml +41 -0
  116. package/examples/cccp.yaml +48 -0
  117. package/examples/content-calendar.yaml +59 -0
  118. package/examples/customer-feedback-loop.yaml +44 -0
  119. package/examples/design-sprint.yaml +54 -0
  120. package/examples/feature-development.yaml +96 -0
  121. package/examples/growth-experiment.yaml +49 -0
  122. package/examples/incident-runbook.yaml +43 -0
  123. package/examples/product-launch.yaml +85 -0
  124. package/examples/prompt-tuning.yaml +25 -0
  125. package/examples/quarterly-planning.yaml +51 -0
  126. package/examples/sprint-cycle.yaml +67 -0
  127. package/package.json +47 -0
package/README.md ADDED
@@ -0,0 +1,280 @@
1
+ # CCCP
2
+
3
+ **Claude Code and Cmux Pipeline Reagent** — deterministic YAML-based pipeline orchestration for workflows built around [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and [cmux](https://github.com/manaflow-ai/cmux).
4
+
5
+ ## The problem
6
+
7
+ Complex multi-stage workflows (SDLC pipelines, research pipelines, content pipelines) rely on Claude as a "file-routing state machine" — dispatching agents, reading evaluations, routing on PASS/FAIL. Over long runs, context degrades: Claude forgets iteration counts, skips sub-stages, misreads evaluations, or loses routing logic.
8
+
9
+ ## The solution
10
+
11
+ CCCP moves the state machine into deterministic TypeScript code. It reads YAML pipeline definitions, dispatches agents via `claude -p` (each with fresh context), parses evaluations with regex, and routes without interpretation. A cmux split-pane dashboard shows live progress. Human approval gates are handled via an MCP server.
12
+
13
+ - Uses Max subscription — no API keys needed
14
+ - Each agent gets a fresh context window
15
+ - Evaluation routing is regex, not interpretation
16
+ - State persists to disk — resume after crashes
17
+ - Works with any project, any agents, any workflow
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ git clone <repo-url> && cd cccp
23
+ npm install
24
+ npm link # makes `cccp` available globally
25
+ ```
26
+
27
+ ## Quick start
28
+
29
+ Scaffold a project:
30
+
31
+ ```bash
32
+ cd my-project
33
+ cccp init
34
+ ```
35
+
36
+ This creates:
37
+
38
+ ```
39
+ cccp.yaml # project config (agent paths, MCP profiles)
40
+ pipelines/example.yaml # example pipeline
41
+ agents/ # example agent definitions
42
+ ```
43
+
44
+ Preview what the pipeline will do:
45
+
46
+ ```bash
47
+ cccp run -f pipelines/example.yaml -p my-project --dry-run
48
+ ```
49
+
50
+ Run it for real:
51
+
52
+ ```bash
53
+ cccp run -f pipelines/example.yaml -p my-project
54
+ ```
55
+
56
+ ## Pipeline YAML
57
+
58
+ Pipelines are sequences of typed stages:
59
+
60
+ ```yaml
61
+ name: my-pipeline
62
+ description: What this pipeline does.
63
+
64
+ stages:
65
+ # Simple agent dispatch
66
+ - name: research
67
+ type: agent
68
+ agent: researcher
69
+ output: "{artifact_dir}/research.md"
70
+
71
+ # Plan-Generate-Evaluate with retry loop
72
+ - name: design
73
+ type: pge
74
+ task: "Design the system architecture."
75
+ inputs:
76
+ - "{artifact_dir}/research.md"
77
+ planner:
78
+ agent: architect
79
+ operation: task-planning
80
+ generator:
81
+ agent: architect
82
+ operation: design # optional sub-operation
83
+ mcp_profile: base # optional MCP server profile
84
+ evaluator:
85
+ agent: reviewer
86
+ contract:
87
+ deliverable: "{artifact_dir}/design.md"
88
+ guidance: "System must be modular with documented data flow."
89
+ max_iterations: 3
90
+ on_fail: stop # stop | skip | human_gate
91
+
92
+ # Human approval gate
93
+ - name: approval
94
+ type: human_gate
95
+ prompt: "Review the design. Approve to proceed."
96
+ artifacts:
97
+ - "{artifact_dir}/design.md"
98
+ ```
99
+
100
+ ### Stage types
101
+
102
+ | Type | What it does |
103
+ |------|-------------|
104
+ | `agent` | Dispatch one agent, collect output |
105
+ | `pge` | Dispatch planner -> evaluator writes contract -> dispatch generator -> dispatch evaluator -> parse `### Overall: PASS/FAIL` -> retry generator/evaluator on FAIL up to `max_iterations` |
106
+ | `human_gate` | Block until approved via MCP tool call or state file edit |
107
+
108
+ ### Variables
109
+
110
+ Built-in variables available in all string fields:
111
+
112
+ | Variable | Value |
113
+ |----------|-------|
114
+ | `{project}` | Project name from `--project` |
115
+ | `{project_dir}` | Project directory |
116
+ | `{artifact_dir}` | Resolved artifact output directory |
117
+ | `{pipeline_name}` | Pipeline name |
118
+ | `{iteration}` | Current PGE iteration (1-based) |
119
+
120
+ ## Agents
121
+
122
+ CCCP ships no agents — you bring your own. Agents are markdown files that become the `--system-prompt-file` for `claude -p`.
123
+
124
+ **Flat file agent** (`agents/implementer.md`):
125
+ ```markdown
126
+ ---
127
+ name: implementer
128
+ description: Implements code changes.
129
+ ---
130
+
131
+ # Implementer Agent
132
+
133
+ Your instructions here...
134
+ ```
135
+
136
+ **Directory agent with operations** (`agents/architect/`):
137
+ ```
138
+ agents/architect/
139
+ agent.md # base instructions (always included)
140
+ health-assessment.md # operation: health-assessment
141
+ plan-authoring.md # operation: plan-authoring
142
+ ```
143
+
144
+ Reference an operation in the pipeline:
145
+ ```yaml
146
+ generator:
147
+ agent: architect
148
+ operation: plan-authoring
149
+ ```
150
+
151
+ ### Agent search paths
152
+
153
+ CCCP searches for agents in order (first match wins):
154
+
155
+ 1. `agents/` relative to the pipeline YAML file
156
+ 2. `<project>/.claude/agents/`
157
+ 3. `<project>/agents/`
158
+ 4. Paths listed in `cccp.yaml` → `agent_paths`
159
+
160
+ ## Project config (`cccp.yaml`)
161
+
162
+ Place at your project root:
163
+
164
+ ```yaml
165
+ agent_paths:
166
+ - ./agents
167
+ - ./vendor/shared-agents
168
+
169
+ mcp_profiles:
170
+ base:
171
+ servers:
172
+ qmd:
173
+ command: qmd
174
+ args: [serve, --stdio]
175
+ design:
176
+ extends: base
177
+ servers:
178
+ figma:
179
+ command: npx
180
+ args: [-y, figma-console-mcp]
181
+
182
+ artifact_dir: docs/projects/{project}/{pipeline_name}
183
+ default_mcp_profile: base
184
+ ```
185
+
186
+ MCP profiles use `extends` for inheritance. Each agent gets only the servers its profile specifies via `--strict-mcp-config`.
187
+
188
+ ## Evaluation format
189
+
190
+ Evaluator agents must produce files containing this line:
191
+
192
+ ```markdown
193
+ ### Overall: PASS
194
+ ```
195
+
196
+ or
197
+
198
+ ```markdown
199
+ ### Overall: FAIL
200
+ ```
201
+
202
+ CCCP reads only this line. Everything else in the evaluation (criterion tables, iteration guidance) is for the generator agent on retry.
203
+
204
+ ## CLI reference
205
+
206
+ ```
207
+ cccp run -f <pipeline.yaml> -p <project> [options]
208
+ --dry-run Show what would execute without running agents
209
+ --headless Auto-approve all human gates
210
+ -d, --project-dir Project directory (default: cwd)
211
+ -a, --artifact-dir Override artifact output directory
212
+ -v, --var key=value Set pipeline variables (repeatable)
213
+
214
+ cccp resume -p <project> -r <run-id-prefix> [--headless]
215
+ Resume an interrupted pipeline from the last incomplete stage
216
+
217
+ cccp dashboard -r <run-id-prefix>
218
+ Launch the TUI dashboard to monitor a running pipeline
219
+
220
+ cccp gate-server
221
+ Start the MCP server for pipeline gate interaction
222
+
223
+ cccp init [--dir <path>]
224
+ Scaffold cccp.yaml, example pipeline, and example agents
225
+ ```
226
+
227
+ ## Gate interaction
228
+
229
+ When a pipeline hits a `human_gate` stage, it writes a pending gate to the SQLite state database (`.cccp/cccp.db`) and waits.
230
+
231
+ **Option 1: MCP server** — Register the gate server in your project's `.mcp.json`:
232
+
233
+ ```json
234
+ {
235
+ "mcpServers": {
236
+ "cccp-gate": {
237
+ "command": "npx",
238
+ "args": ["tsx", "/path/to/cccp/src/cli.ts", "gate-server"]
239
+ }
240
+ }
241
+ }
242
+ ```
243
+
244
+ Then from Claude Code: call `pipeline_status` to see what's pending, `pipeline_gate_respond` to approve/reject.
245
+
246
+ **Option 2: Headless** — `cccp run --headless` auto-approves all gates.
247
+
248
+ ## State & resume
249
+
250
+ Pipeline state is persisted to a SQLite database at `{projectDir}/.cccp/cccp.db` after every transition (stage start, planner dispatch, contract dispatch, generator dispatch, evaluator dispatch, routing decision). If a run is interrupted:
251
+
252
+ ```bash
253
+ cccp resume -p my-project -r <run-id-prefix>
254
+ ```
255
+
256
+ Completed stages are skipped. PGE stages resume at the correct iteration and sub-step.
257
+
258
+ ## cmux integration
259
+
260
+ When running inside a [cmux](https://github.com/manaflow-ai/cmux) workspace (`CMUX_WORKSPACE_ID` is set), CCCP automatically:
261
+
262
+ - Updates the sidebar status pill with current stage
263
+ - Sets the progress bar
264
+ - Sends desktop notifications for gates and pipeline completion
265
+ - Can open the dashboard in a cmux split pane
266
+
267
+ Without cmux, CCCP falls back to plain terminal output.
268
+
269
+ ## Development
270
+
271
+ ```bash
272
+ npm test # run all tests (143 tests)
273
+ npm run typecheck # tsc --noEmit
274
+ npm run test:watch # watch mode
275
+ npm run build # compile TypeScript to dist/
276
+ ```
277
+
278
+ ## License
279
+
280
+ MIT
@@ -0,0 +1,9 @@
1
+ import { EventEmitter } from "node:events";
2
+ /**
3
+ * Module-level singleton event bus for passing agent activity updates
4
+ * from the runner to the TUI dashboard within the same process.
5
+ *
6
+ * The runner publishes: activityBus.emit("activity", agentActivity)
7
+ * The dashboard subscribes: activityBus.on("activity", handler)
8
+ */
9
+ export declare const activityBus: EventEmitter<[never]>;
@@ -0,0 +1,10 @@
1
+ import { EventEmitter } from "node:events";
2
+ /**
3
+ * Module-level singleton event bus for passing agent activity updates
4
+ * from the runner to the TUI dashboard within the same process.
5
+ *
6
+ * The runner publishes: activityBus.emit("activity", agentActivity)
7
+ * The dashboard subscribes: activityBus.on("activity", handler)
8
+ */
9
+ export const activityBus = new EventEmitter();
10
+ //# sourceMappingURL=activity-bus.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-bus.js","sourceRoot":"","sources":["../src/activity-bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,YAAY,EAAE,CAAC"}
@@ -0,0 +1,29 @@
1
+ export interface ResolvedAgent {
2
+ /** Absolute path to the agent's main markdown file. */
3
+ agentPath: string;
4
+ /** Absolute path to the operation file (if applicable). */
5
+ operationPath?: string;
6
+ /** Whether this is a directory-style agent. */
7
+ isDirectory: boolean;
8
+ }
9
+ /**
10
+ * Resolve an agent name to file path(s) by searching configured directories.
11
+ *
12
+ * Search order (first match wins):
13
+ * 1. Each directory in `searchPaths`, in order
14
+ *
15
+ * For each search directory, tries:
16
+ * - `<dir>/<agent>.md` — flat-file agent
17
+ * - `<dir>/<agent>/agent.md` — directory-style agent
18
+ *
19
+ * If an `operation` is specified and the agent is directory-style:
20
+ * - Also resolves `<dir>/<agent>/<operation>.md`
21
+ *
22
+ * If the agent name already ends in `.md` or contains a path separator,
23
+ * it's treated as a direct path (absolute or relative to projectDir).
24
+ */
25
+ export declare function resolveAgent(agentName: string, searchPaths: string[], operation?: string, projectDir?: string): Promise<ResolvedAgent>;
26
+ /**
27
+ * List all available operations for a directory-style agent.
28
+ */
29
+ export declare function listOperations(agentName: string, searchPaths: string[]): Promise<string[]>;
@@ -0,0 +1,122 @@
1
+ import { access, readdir } from "node:fs/promises";
2
+ import { resolve, join, basename, dirname } from "node:path";
3
+ // ---------------------------------------------------------------------------
4
+ // Resolution logic
5
+ // ---------------------------------------------------------------------------
6
+ /**
7
+ * Resolve an agent name to file path(s) by searching configured directories.
8
+ *
9
+ * Search order (first match wins):
10
+ * 1. Each directory in `searchPaths`, in order
11
+ *
12
+ * For each search directory, tries:
13
+ * - `<dir>/<agent>.md` — flat-file agent
14
+ * - `<dir>/<agent>/agent.md` — directory-style agent
15
+ *
16
+ * If an `operation` is specified and the agent is directory-style:
17
+ * - Also resolves `<dir>/<agent>/<operation>.md`
18
+ *
19
+ * If the agent name already ends in `.md` or contains a path separator,
20
+ * it's treated as a direct path (absolute or relative to projectDir).
21
+ */
22
+ export async function resolveAgent(agentName, searchPaths, operation, projectDir) {
23
+ // Direct path — skip search if agent looks like a path.
24
+ if (agentName.includes("/") || agentName.endsWith(".md")) {
25
+ return resolveDirectPath(agentName, operation, projectDir);
26
+ }
27
+ // Search configured paths.
28
+ for (const searchDir of searchPaths) {
29
+ // Try flat file: <dir>/<agent>.md
30
+ const flatPath = join(searchDir, `${agentName}.md`);
31
+ if (await fileExists(flatPath)) {
32
+ if (operation) {
33
+ // Flat file agents don't have operations — check if there's a
34
+ // sibling directory with the operation file.
35
+ const opPath = join(searchDir, agentName, `${operation}.md`);
36
+ if (await fileExists(opPath)) {
37
+ // There's actually a directory-style agent alongside the flat file.
38
+ const dirAgentPath = join(searchDir, agentName, "agent.md");
39
+ if (await fileExists(dirAgentPath)) {
40
+ return {
41
+ agentPath: dirAgentPath,
42
+ operationPath: opPath,
43
+ isDirectory: true,
44
+ };
45
+ }
46
+ }
47
+ throw new Error(`Agent "${agentName}" is a flat file and does not support operation "${operation}"`);
48
+ }
49
+ return { agentPath: flatPath, isDirectory: false };
50
+ }
51
+ // Try directory: <dir>/<agent>/agent.md
52
+ const dirAgentPath = join(searchDir, agentName, "agent.md");
53
+ if (await fileExists(dirAgentPath)) {
54
+ let operationPath;
55
+ if (operation) {
56
+ operationPath = join(searchDir, agentName, `${operation}.md`);
57
+ if (!(await fileExists(operationPath))) {
58
+ throw new Error(`Operation "${operation}" not found for agent "${agentName}" at: ${operationPath}`);
59
+ }
60
+ }
61
+ return {
62
+ agentPath: dirAgentPath,
63
+ operationPath,
64
+ isDirectory: true,
65
+ };
66
+ }
67
+ }
68
+ const searched = searchPaths.map((p) => ` - ${p}`).join("\n");
69
+ throw new Error(`Agent "${agentName}" not found. Searched:\n${searched}`);
70
+ }
71
+ /**
72
+ * List all available operations for a directory-style agent.
73
+ */
74
+ export async function listOperations(agentName, searchPaths) {
75
+ for (const searchDir of searchPaths) {
76
+ const agentDir = join(searchDir, agentName);
77
+ try {
78
+ const entries = await readdir(agentDir);
79
+ return entries
80
+ .filter((e) => e.endsWith(".md") && e !== "agent.md")
81
+ .map((e) => e.replace(/\.md$/, ""));
82
+ }
83
+ catch {
84
+ continue;
85
+ }
86
+ }
87
+ return [];
88
+ }
89
+ // ---------------------------------------------------------------------------
90
+ // Helpers
91
+ // ---------------------------------------------------------------------------
92
+ async function resolveDirectPath(agentPath, operation, projectDir) {
93
+ const absPath = projectDir
94
+ ? resolve(projectDir, agentPath)
95
+ : resolve(agentPath);
96
+ if (!(await fileExists(absPath))) {
97
+ throw new Error(`Agent file not found: ${absPath}`);
98
+ }
99
+ // Check if it's a directory-style agent (path ends with agent.md).
100
+ const isDir = basename(absPath) === "agent.md";
101
+ let operationPath;
102
+ if (operation) {
103
+ if (!isDir) {
104
+ throw new Error(`Agent at "${absPath}" is a flat file and does not support operation "${operation}"`);
105
+ }
106
+ operationPath = resolve(dirname(absPath), `${operation}.md`);
107
+ if (!(await fileExists(operationPath))) {
108
+ throw new Error(`Operation "${operation}" not found at: ${operationPath}`);
109
+ }
110
+ }
111
+ return { agentPath: absPath, operationPath, isDirectory: isDir };
112
+ }
113
+ async function fileExists(path) {
114
+ try {
115
+ await access(path);
116
+ return true;
117
+ }
118
+ catch {
119
+ return false;
120
+ }
121
+ }
122
+ //# sourceMappingURL=agent-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-resolver.js","sourceRoot":"","sources":["../src/agent-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { AgentResult } from "./types.js";
2
+ export interface DispatchOptions {
3
+ /** The user prompt (task context) passed via -p. */
4
+ userPrompt: string;
5
+ /** Path to the system prompt file (agent markdown). */
6
+ systemPromptFile: string;
7
+ /** Path to MCP config JSON file, if any. */
8
+ mcpConfigFile?: string;
9
+ /** Explicit list of allowed tools. */
10
+ allowedTools?: string[];
11
+ /** Expected output file path (to check existence after). */
12
+ expectedOutput?: string;
13
+ /** Working directory for the subprocess. */
14
+ cwd: string;
15
+ /** If true, print the command instead of running it. */
16
+ dryRun?: boolean;
17
+ /** Agent name (for stream logging). */
18
+ agentName?: string;
19
+ /** Directory for stream log files (.stream.jsonl). */
20
+ streamLogDir?: string;
21
+ /** Callback for stream activity updates. */
22
+ onActivity?: (activity: import("./stream/stream.js").AgentActivity) => void;
23
+ /** Claude config directory (CLAUDE_CONFIG_DIR). */
24
+ claudeConfigDir?: string;
25
+ /** Permission mode for the agent subprocess (default: bypassPermissions). */
26
+ permissionMode?: string;
27
+ /** Suppress agent stderr (when TUI dashboard is rendering). */
28
+ quiet?: boolean;
29
+ }
30
+ /**
31
+ * Dispatch an agent by spawning `claude` as a child process.
32
+ *
33
+ * Agents inherit the project's CLAUDE.md, hooks, and auth context.
34
+ * The agent's markdown definition is appended via --append-system-prompt-file.
35
+ *
36
+ * Returns an AgentResult with exit code, output existence check, and duration.
37
+ * In dry-run mode, prints the command and returns a synthetic success result.
38
+ */
39
+ export declare function dispatchAgent(opts: DispatchOptions): Promise<AgentResult>;
package/dist/agent.js ADDED
@@ -0,0 +1,117 @@
1
+ import { spawn } from "node:child_process";
2
+ import { access } from "node:fs/promises";
3
+ import { StreamParser } from "./stream/stream.js";
4
+ // ---------------------------------------------------------------------------
5
+ // Build the claude CLI argument list
6
+ // ---------------------------------------------------------------------------
7
+ function buildArgs(opts) {
8
+ const args = [
9
+ "-p",
10
+ opts.userPrompt,
11
+ "--append-system-prompt-file",
12
+ opts.systemPromptFile,
13
+ "--output-format",
14
+ "stream-json",
15
+ "--verbose",
16
+ ];
17
+ if (opts.mcpConfigFile) {
18
+ args.push("--mcp-config", opts.mcpConfigFile);
19
+ args.push("--strict-mcp-config");
20
+ }
21
+ if (opts.allowedTools?.length) {
22
+ args.push("--allowedTools", opts.allowedTools.join(","));
23
+ }
24
+ // Permission mode — default to bypassPermissions for pipeline agents.
25
+ const mode = opts.permissionMode ?? "bypassPermissions";
26
+ args.push("--permission-mode", mode);
27
+ return args;
28
+ }
29
+ // ---------------------------------------------------------------------------
30
+ // Dispatch
31
+ // ---------------------------------------------------------------------------
32
+ /**
33
+ * Dispatch an agent by spawning `claude` as a child process.
34
+ *
35
+ * Agents inherit the project's CLAUDE.md, hooks, and auth context.
36
+ * The agent's markdown definition is appended via --append-system-prompt-file.
37
+ *
38
+ * Returns an AgentResult with exit code, output existence check, and duration.
39
+ * In dry-run mode, prints the command and returns a synthetic success result.
40
+ */
41
+ export async function dispatchAgent(opts) {
42
+ const args = buildArgs(opts);
43
+ if (opts.dryRun) {
44
+ console.log("\n[dry-run] Would execute:");
45
+ console.log(` claude ${args.map((a) => (a.includes(" ") ? `"${a}"` : a)).join(" ")}`);
46
+ console.log(` cwd: ${opts.cwd}`);
47
+ if (opts.claudeConfigDir) {
48
+ console.log(` CLAUDE_CONFIG_DIR: ${opts.claudeConfigDir}`);
49
+ }
50
+ if (opts.expectedOutput) {
51
+ console.log(` expected output: ${opts.expectedOutput}`);
52
+ }
53
+ return {
54
+ exitCode: 0,
55
+ outputPath: opts.expectedOutput,
56
+ outputExists: false,
57
+ durationMs: 0,
58
+ };
59
+ }
60
+ const start = Date.now();
61
+ const agentName = opts.agentName ?? "agent";
62
+ // Set up stream parser for event processing and logging.
63
+ const parser = new StreamParser(agentName);
64
+ if (opts.streamLogDir) {
65
+ const logPath = `${opts.streamLogDir}/${agentName}.stream.jsonl`;
66
+ await parser.startLog(logPath);
67
+ }
68
+ if (opts.onActivity) {
69
+ parser.on("activity", opts.onActivity);
70
+ }
71
+ // Build environment — inherit parent env, set CLAUDE_CONFIG_DIR if configured.
72
+ const env = { ...process.env };
73
+ if (opts.claudeConfigDir) {
74
+ env.CLAUDE_CONFIG_DIR = opts.claudeConfigDir;
75
+ }
76
+ const exitCode = await new Promise((resolve, reject) => {
77
+ const child = spawn("claude", args, {
78
+ cwd: opts.cwd,
79
+ env,
80
+ stdio: ["ignore", "pipe", "pipe"],
81
+ });
82
+ // Feed stdout through stream parser.
83
+ child.stdout.on("data", (chunk) => {
84
+ parser.feed(chunk.toString());
85
+ });
86
+ // Stderr goes to parent stderr (unless TUI is active).
87
+ if (!opts.quiet) {
88
+ child.stderr.pipe(process.stderr);
89
+ }
90
+ child.on("error", (err) => {
91
+ parser.flush();
92
+ reject(new Error(`Failed to spawn claude: ${err.message}`));
93
+ });
94
+ child.on("close", (code) => {
95
+ parser.flush();
96
+ resolve(code ?? 1);
97
+ });
98
+ });
99
+ const durationMs = Date.now() - start;
100
+ let outputExists = false;
101
+ if (opts.expectedOutput) {
102
+ try {
103
+ await access(opts.expectedOutput);
104
+ outputExists = true;
105
+ }
106
+ catch {
107
+ outputExists = false;
108
+ }
109
+ }
110
+ return {
111
+ exitCode,
112
+ outputPath: opts.expectedOutput,
113
+ outputExists,
114
+ durationMs,
115
+ };
116
+ }
117
+ //# sourceMappingURL=agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.js","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { AutoresearchStage, AutoresearchResult, RunContext, PipelineState } from "./types.js";
2
+ /**
3
+ * Execute a full Adjust-Execute-Evaluate cycle for an autoresearch stage.
4
+ *
5
+ * 1. [iter > 1] Dispatch adjuster → modifies the artifact
6
+ * 2. Dispatch executor → produces output using current artifact
7
+ * 3. Dispatch evaluator → compares output against ground truth
8
+ * 4. Parse evaluation (regex on ### Overall: PASS/FAIL)
9
+ * 5. Route: PASS → done, FAIL + max reached → escalate, FAIL → continue
10
+ */
11
+ export declare function runAutoresearchCycle(stage: AutoresearchStage, ctx: RunContext, state: PipelineState, onProgress?: (eventType?: string, eventData?: Record<string, unknown>) => Promise<void>): Promise<AutoresearchResult>;