@llm-dev-ops/agentics-cli 1.4.7 → 1.4.8

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 (43) hide show
  1. package/dist/cli/index.js +109 -0
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/contracts/adr-006-claude-code-synthesis-runner.d.ts +196 -0
  4. package/dist/contracts/adr-006-claude-code-synthesis-runner.d.ts.map +1 -0
  5. package/dist/contracts/adr-006-claude-code-synthesis-runner.js +177 -0
  6. package/dist/contracts/adr-006-claude-code-synthesis-runner.js.map +1 -0
  7. package/dist/contracts/adr-007-subcommand-synthesis-router.d.ts +273 -0
  8. package/dist/contracts/adr-007-subcommand-synthesis-router.d.ts.map +1 -0
  9. package/dist/contracts/adr-007-subcommand-synthesis-router.js +226 -0
  10. package/dist/contracts/adr-007-subcommand-synthesis-router.js.map +1 -0
  11. package/dist/contracts/adr-008-synthesis-artifact-persistence.d.ts +323 -0
  12. package/dist/contracts/adr-008-synthesis-artifact-persistence.d.ts.map +1 -0
  13. package/dist/contracts/adr-008-synthesis-artifact-persistence.js +184 -0
  14. package/dist/contracts/adr-008-synthesis-artifact-persistence.js.map +1 -0
  15. package/dist/mcp/mcp-server.d.ts +35 -0
  16. package/dist/mcp/mcp-server.d.ts.map +1 -0
  17. package/dist/mcp/mcp-server.js +692 -0
  18. package/dist/mcp/mcp-server.js.map +1 -0
  19. package/dist/runtime/claude-code-runner.d.ts +93 -0
  20. package/dist/runtime/claude-code-runner.d.ts.map +1 -0
  21. package/dist/runtime/claude-code-runner.js +588 -0
  22. package/dist/runtime/claude-code-runner.js.map +1 -0
  23. package/dist/runtime/index.d.ts +5 -0
  24. package/dist/runtime/index.d.ts.map +1 -0
  25. package/dist/runtime/index.js +5 -0
  26. package/dist/runtime/index.js.map +1 -0
  27. package/dist/synthesis/artifact-writer.d.ts +62 -0
  28. package/dist/synthesis/artifact-writer.d.ts.map +1 -0
  29. package/dist/synthesis/artifact-writer.js +603 -0
  30. package/dist/synthesis/artifact-writer.js.map +1 -0
  31. package/dist/synthesis/index.d.ts +7 -0
  32. package/dist/synthesis/index.d.ts.map +1 -0
  33. package/dist/synthesis/index.js +7 -0
  34. package/dist/synthesis/index.js.map +1 -0
  35. package/dist/synthesis/prompts/index.d.ts +50 -0
  36. package/dist/synthesis/prompts/index.d.ts.map +1 -0
  37. package/dist/synthesis/prompts/index.js +502 -0
  38. package/dist/synthesis/prompts/index.js.map +1 -0
  39. package/dist/synthesis/router.d.ts +70 -0
  40. package/dist/synthesis/router.d.ts.map +1 -0
  41. package/dist/synthesis/router.js +346 -0
  42. package/dist/synthesis/router.js.map +1 -0
  43. package/package.json +1 -1
@@ -0,0 +1,177 @@
1
+ /**
2
+ * ADR-006: Claude Code Synthesis Runner — Subprocess Invocation & Contract Binding
3
+ *
4
+ * STATUS: Proposed
5
+ * DATE: 2026-02-07
6
+ * AUTHORS: Platform Engineering
7
+ * DEPENDS-ON: ADR-001 (Command Semantics), ADR-002 (Operational Enforcement)
8
+ *
9
+ * ============================================================================
10
+ * CONTEXT
11
+ * ============================================================================
12
+ *
13
+ * The Agentics CLI needs to invoke Claude Code (the locally-installed Claude
14
+ * CLI binary) for decision-grade subcommands. This is modeled after how
15
+ * Claude Flow performs a single synthesis+plan step per command invocation.
16
+ *
17
+ * Currently, the CLI has an "executive synthesis" tool that runs as a detached
18
+ * fire-and-forget process (src/cli/index.ts:42-67). This is insufficient:
19
+ *
20
+ * - It does not capture Claude Code's output synchronously
21
+ * - It does not validate output against contract schemas
22
+ * - It is not subcommand-aware (fires on all commands that produce output)
23
+ * - It cannot feed structured JSON into the platform pipeline
24
+ *
25
+ * We need a focused module that:
26
+ * 1. Detects the Claude Code binary (claude, claude-code, or env-configured)
27
+ * 2. Invokes it synchronously via child_process.execFileSync or spawn+await
28
+ * 3. Sends a structured prompt via --print flag (non-interactive, JSON output)
29
+ * 4. Captures stdout, strips code fences, parses JSON
30
+ * 5. Validates against the agentics-contracts schema for that subcommand
31
+ * 6. Returns the typed object for downstream pipeline consumption
32
+ *
33
+ * ============================================================================
34
+ * DECISION
35
+ * ============================================================================
36
+ *
37
+ * 1. A new module `src/runtime/claude-code-runner.ts` will be created.
38
+ *
39
+ * 2. It will use Node.js `child_process.execFileSync` for synchronous
40
+ * single-invocation semantics (one call per decision command).
41
+ *
42
+ * 3. The binary is resolved in order:
43
+ * a. AGENTICS_CLAUDE_BIN environment variable (explicit path)
44
+ * b. `claude` on PATH (standard Claude Code CLI)
45
+ * c. `claude-code` on PATH (alternate binary name)
46
+ * If none found, throw a CLIError with code ECLI-SYNTH-001.
47
+ *
48
+ * 4. Invocation uses the `--print` flag for non-interactive JSON output:
49
+ * ```
50
+ * claude --print --output-format json --model <model> "<prompt>"
51
+ * ```
52
+ * The prompt is a single string constructed by the synthesis router.
53
+ *
54
+ * 5. Environment variables supported:
55
+ * - AGENTICS_CLAUDE_BIN: Override binary path
56
+ * - AGENTICS_CLAUDE_MODEL: Override model (default: claude-sonnet-4-20250514)
57
+ * - AGENTICS_CLAUDE_TIMEOUT_MS: Timeout (default: 120000)
58
+ * - AGENTICS_DEV: When set, enables verbose debug output to stderr
59
+ *
60
+ * 6. Output processing:
61
+ * a. Capture stdout as string
62
+ * b. Strip markdown code fences if present (```json ... ```)
63
+ * c. JSON.parse the result
64
+ * d. Validate against the contract schema for the given subcommand
65
+ * e. Return typed object or throw ContractValidationError
66
+ *
67
+ * 7. Each invocation includes a run-id and seed in the prompt for
68
+ * determinism and traceability.
69
+ *
70
+ * ============================================================================
71
+ * INTERFACE CONTRACT
72
+ * ============================================================================
73
+ *
74
+ * ```typescript
75
+ * interface ClaudeCodeRunnerOptions {
76
+ * model?: string;
77
+ * timeoutMs?: number;
78
+ * runId: string;
79
+ * seed?: number;
80
+ * verbose?: boolean;
81
+ * }
82
+ *
83
+ * interface ClaudeCodeRunnerResult<T> {
84
+ * data: T;
85
+ * runId: string;
86
+ * model: string;
87
+ * durationMs: number;
88
+ * rawOutput: string;
89
+ * }
90
+ *
91
+ * interface IClaudeCodeRunner {
92
+ * resolve(): string; // Returns binary path or throws
93
+ * invoke<T>(prompt: string, options: ClaudeCodeRunnerOptions): ClaudeCodeRunnerResult<T>;
94
+ * }
95
+ * ```
96
+ *
97
+ * ============================================================================
98
+ * ERROR CODES
99
+ * ============================================================================
100
+ *
101
+ * | Code | Meaning | Exit |
102
+ * |-------------------|---------------------------------------------|------|
103
+ * | ECLI-SYNTH-001 | Claude Code binary not found | 127 |
104
+ * | ECLI-SYNTH-002 | Claude Code invocation failed (non-zero) | 1 |
105
+ * | ECLI-SYNTH-003 | Output is not valid JSON | 140 |
106
+ * | ECLI-SYNTH-004 | Output failed contract validation | 140 |
107
+ * | ECLI-SYNTH-005 | Invocation timed out | 124 |
108
+ *
109
+ * ============================================================================
110
+ * ALTERNATIVES CONSIDERED
111
+ * ============================================================================
112
+ *
113
+ * A. Use the Anthropic API directly (HTTP client):
114
+ * Rejected — the requirement is to use the locally-installed Claude Code
115
+ * binary, matching Claude Flow's execution model. This also avoids
116
+ * managing API keys in the CLI when Claude Code already handles auth.
117
+ *
118
+ * B. Use the existing executive-synthesis detached process:
119
+ * Rejected — fire-and-forget cannot feed results into the platform
120
+ * pipeline. Synchronous capture is required.
121
+ *
122
+ * C. Use stdin piping instead of --print flag:
123
+ * Rejected — --print is the Claude Code standard for non-interactive
124
+ * programmatic use. Stdin piping is for interactive sessions.
125
+ *
126
+ * ============================================================================
127
+ * CONSEQUENCES
128
+ * ============================================================================
129
+ *
130
+ * - Claude Code must be installed locally for decision-grade commands
131
+ * - Commands that are SYNTHESIS_FORBIDDEN never invoke this module
132
+ * - Each decision-grade invocation has exactly one Claude Code call
133
+ * - All outputs are contract-validated before reaching the platform
134
+ * - Binary resolution is deterministic and debuggable via AGENTICS_DEV
135
+ *
136
+ * ============================================================================
137
+ * SECURITY CONSIDERATIONS
138
+ * ============================================================================
139
+ *
140
+ * - The prompt is constructed entirely from CLI arguments and templates;
141
+ * no user input is interpolated without sanitization.
142
+ * - The Claude Code binary inherits the user's environment but no
143
+ * additional secrets are passed beyond what's already in the shell.
144
+ * - Output is validated against a strict schema; malformed output is
145
+ * rejected with ECLI-SYNTH-003/004.
146
+ * - Timeout prevents runaway processes.
147
+ */
148
+ /**
149
+ * Schema mapping: maps (command, subcommand) to the response schema name
150
+ * used for validating Claude Code output.
151
+ *
152
+ * This is the bridge between ADR-001 command semantics and the contract
153
+ * validator. Each decision-grade subcommand maps to exactly one schema.
154
+ */
155
+ export const SYNTHESIS_SCHEMA_MAP = {
156
+ 'simulate.create': 'simulation',
157
+ 'simulate.run': 'simulation',
158
+ 'plan.create': 'plan',
159
+ 'plan.approve': 'plan',
160
+ 'deploy.preview': 'intent',
161
+ 'deploy.run': 'intent',
162
+ 'deploy.rollback': 'intent',
163
+ 'export.terraform': 'export',
164
+ 'export.kubernetes': 'export',
165
+ 'export.erp': 'export',
166
+ 'policy.create': 'base',
167
+ 'policy.edit': 'base',
168
+ 'policy.enable': 'base',
169
+ 'policy.disable': 'base',
170
+ 'policy.dry-run': 'base',
171
+ 'quantify.create': 'roiReport',
172
+ 'quantify.compare': 'roiReport',
173
+ 'erp.surface': 'base',
174
+ 'erp.map': 'base',
175
+ 'erp.export': 'export',
176
+ };
177
+ //# sourceMappingURL=adr-006-claude-code-synthesis-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adr-006-claude-code-synthesis-runner.js","sourceRoot":"","sources":["../../src/contracts/adr-006-claude-code-synthesis-runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkJG;AAkDH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAqC;IACpE,iBAAiB,EAAE,YAAY;IAC/B,cAAc,EAAE,YAAY;IAC5B,aAAa,EAAE,MAAM;IACrB,cAAc,EAAE,MAAM;IACtB,gBAAgB,EAAE,QAAQ;IAC1B,YAAY,EAAE,QAAQ;IACtB,iBAAiB,EAAE,QAAQ;IAC3B,kBAAkB,EAAE,QAAQ;IAC5B,mBAAmB,EAAE,QAAQ;IAC7B,YAAY,EAAE,QAAQ;IACtB,eAAe,EAAE,MAAM;IACvB,aAAa,EAAE,MAAM;IACrB,eAAe,EAAE,MAAM;IACvB,gBAAgB,EAAE,MAAM;IACxB,gBAAgB,EAAE,MAAM;IACxB,iBAAiB,EAAE,WAAW;IAC9B,kBAAkB,EAAE,WAAW;IAC/B,aAAa,EAAE,MAAM;IACrB,SAAS,EAAE,MAAM;IACjB,YAAY,EAAE,QAAQ;CACd,CAAC"}
@@ -0,0 +1,273 @@
1
+ /**
2
+ * ADR-007: Subcommand-Aware Synthesis Router
3
+ *
4
+ * STATUS: Proposed
5
+ * DATE: 2026-02-07
6
+ * AUTHORS: Platform Engineering
7
+ * DEPENDS-ON: ADR-001 (Command Semantics), ADR-006 (Claude Code Runner)
8
+ *
9
+ * ============================================================================
10
+ * CONTEXT
11
+ * ============================================================================
12
+ *
13
+ * ADR-001 defines a COMMAND_REGISTRY with synthesis governance classifications:
14
+ * - SYNTHESIS_REQUIRED: LLM invocation expected
15
+ * - SYNTHESIS_FORBIDDEN: Must NEVER trigger synthesis
16
+ * - COMMITMENT_GRADE: Requires ID + confirmation + synthesis
17
+ *
18
+ * The current CLI dispatches commands via a monolithic switch statement in
19
+ * src/cli/index.ts. Decision-grade subcommands call their respective
20
+ * command executors (executePlanCreateCommand, executeSimulateRunCommand, etc.)
21
+ * which talk to the platform API. The executive synthesis tool fires as an
22
+ * afterthought (fire-and-forget detached process).
23
+ *
24
+ * What's missing is a routing layer that sits BETWEEN argument parsing and
25
+ * command execution, intercepting decision-grade subcommands to:
26
+ * 1. Construct a subcommand-specific prompt
27
+ * 2. Call Claude Code Runner (ADR-006)
28
+ * 3. Validate the output
29
+ * 4. Feed it into the platform pipeline
30
+ *
31
+ * ============================================================================
32
+ * DECISION
33
+ * ============================================================================
34
+ *
35
+ * 1. A new module `src/synthesis/router.ts` will implement the synthesis
36
+ * routing layer.
37
+ *
38
+ * 2. The router takes a SynthesisRequest:
39
+ * ```typescript
40
+ * interface SynthesisRequest {
41
+ * command: string; // e.g. "simulate"
42
+ * subcommand: string; // e.g. "create"
43
+ * positionalArgs: string[]; // from parsed CLI args
44
+ * options: Record<string, string>;
45
+ * flags: Record<string, boolean>;
46
+ * userContext: {
47
+ * userId: string;
48
+ * orgId: string;
49
+ * traceId: string;
50
+ * };
51
+ * }
52
+ * ```
53
+ *
54
+ * 3. Routing logic:
55
+ * a. Look up (command, subcommand) in ADR-001 COMMAND_REGISTRY
56
+ * b. If synthesis === 'SYNTHESIS_FORBIDDEN', return null immediately
57
+ * c. If synthesis === 'SYNTHESIS_REQUIRED' or 'COMMITMENT_GRADE':
58
+ * i. Generate a run-id (UUID v4)
59
+ * ii. Load the prompt template for this (command, subcommand)
60
+ * iii. Inject arguments, context, run-id, and contract requirements
61
+ * iv. Call ClaudeCodeRunner.invoke()
62
+ * v. Return the validated SynthesisResult
63
+ *
64
+ * 4. SynthesisResult structure:
65
+ * ```typescript
66
+ * interface SynthesisResult<T> {
67
+ * data: T; // Contract-validated output
68
+ * runId: string; // UUID for this synthesis run
69
+ * command: string;
70
+ * subcommand: string;
71
+ * model: string; // Model used
72
+ * durationMs: number;
73
+ * contractSchema: string; // Schema name used for validation
74
+ * }
75
+ * ```
76
+ *
77
+ * 5. The router is a pure function with no side effects beyond calling
78
+ * ClaudeCodeRunner. It does NOT:
79
+ * - Write artifacts (that's ADR-008)
80
+ * - Call the platform API (that's the command executor)
81
+ * - Modify CLI state
82
+ *
83
+ * ============================================================================
84
+ * PROMPT TEMPLATE SYSTEM
85
+ * ============================================================================
86
+ *
87
+ * 1. Templates live in `src/synthesis/prompts/` as exported string constants
88
+ * (not .txt files — TypeScript provides compile-time safety and tree-shaking).
89
+ *
90
+ * 2. Each template is a function: (args: PromptArgs) => string
91
+ *
92
+ * 3. PromptArgs includes:
93
+ * - runId: string
94
+ * - seed: number
95
+ * - command: string
96
+ * - subcommand: string
97
+ * - positionalArgs: string[]
98
+ * - contractSchemaName: string
99
+ * - contractSchemaFields: string (human-readable field list)
100
+ *
101
+ * 4. Every template MUST include:
102
+ * - "Respond ONLY with a JSON object. No prose, no markdown, no explanation."
103
+ * - The exact contract schema name
104
+ * - The run-id and seed
105
+ * - The required fields for the output schema
106
+ *
107
+ * 5. Template naming: `{command}_{subcommand}` (e.g., simulate_create)
108
+ *
109
+ * ============================================================================
110
+ * DECISION-GRADE SUBCOMMAND MATRIX
111
+ * ============================================================================
112
+ *
113
+ * | Command | Subcommand | Synthesis Class | Contract Schema |
114
+ * |-----------|------------|----------------------|------------------|
115
+ * | simulate | create | SYNTHESIS_REQUIRED | simulation |
116
+ * | simulate | run | COMMITMENT_GRADE | simulation |
117
+ * | plan | create | SYNTHESIS_REQUIRED | plan |
118
+ * | plan | approve | COMMITMENT_GRADE | plan |
119
+ * | deploy | preview | SYNTHESIS_REQUIRED | intent |
120
+ * | deploy | run | COMMITMENT_GRADE | intent |
121
+ * | deploy | rollback | COMMITMENT_GRADE | intent |
122
+ * | export | terraform | SYNTHESIS_REQUIRED | export |
123
+ * | export | kubernetes | SYNTHESIS_REQUIRED | export |
124
+ * | export | erp | SYNTHESIS_REQUIRED | export |
125
+ * | policy | create | SYNTHESIS_REQUIRED | base |
126
+ * | policy | edit | SYNTHESIS_REQUIRED | base |
127
+ * | policy | enable | COMMITMENT_GRADE | base |
128
+ * | policy | disable | SYNTHESIS_REQUIRED | base |
129
+ * | policy | dry-run | SYNTHESIS_REQUIRED | base |
130
+ * | quantify | create | SYNTHESIS_REQUIRED | roiReport |
131
+ * | quantify | compare | COMMITMENT_GRADE | roiReport |
132
+ * | erp | surface | SYNTHESIS_REQUIRED | base |
133
+ * | erp | map | SYNTHESIS_REQUIRED | base |
134
+ * | erp | export | SYNTHESIS_REQUIRED | export |
135
+ *
136
+ * All other (command, subcommand) combinations return null from the router.
137
+ *
138
+ * ============================================================================
139
+ * INTEGRATION POINT
140
+ * ============================================================================
141
+ *
142
+ * The router is called from the CLI dispatch in src/cli/index.ts.
143
+ * The integration follows this pattern:
144
+ *
145
+ * ```typescript
146
+ * // In the command handler (e.g., simulate create)
147
+ * const synthesisResult = synthesisRouter.route({
148
+ * command: parsed.command,
149
+ * subcommand: parsed.subcommand,
150
+ * positionalArgs: parsed.positionalArgs,
151
+ * options: parsed.options,
152
+ * flags: parsed.flags,
153
+ * userContext: { userId, orgId, traceId },
154
+ * });
155
+ *
156
+ * if (synthesisResult) {
157
+ * // Decision-grade: use Claude Code output
158
+ * const platformResult = await executeWithSynthesis(synthesisResult);
159
+ * await persistArtifacts(synthesisResult, platformResult);
160
+ * } else {
161
+ * // Non-synthesis: proceed with existing command handler
162
+ * await executeExistingHandler(...);
163
+ * }
164
+ * ```
165
+ *
166
+ * ============================================================================
167
+ * ALTERNATIVES CONSIDERED
168
+ * ============================================================================
169
+ *
170
+ * A. Middleware-based routing (intercept all commands):
171
+ * Rejected — synthesis is the exception, not the rule. A middleware
172
+ * pattern would add overhead to every command, including the majority
173
+ * that are SYNTHESIS_FORBIDDEN.
174
+ *
175
+ * B. Prompt templates as external .txt files:
176
+ * Rejected — TypeScript functions provide compile-time safety,
177
+ * argument validation, and can reference contract types. External
178
+ * files would need a runtime loader and lose type safety.
179
+ *
180
+ * C. One giant prompt for all subcommands:
181
+ * Rejected — each subcommand has unique argument shapes, contract
182
+ * schemas, and domain-specific instructions. Specialized prompts
183
+ * produce better-structured output.
184
+ *
185
+ * ============================================================================
186
+ * CONSEQUENCES
187
+ * ============================================================================
188
+ *
189
+ * - Every decision-grade subcommand gets exactly one Claude Code call
190
+ * - Non-decision commands have zero synthesis overhead
191
+ * - Prompt templates are version-controlled and type-safe
192
+ * - New decision-grade subcommands require:
193
+ * a. ADR-001 COMMAND_REGISTRY entry with SYNTHESIS_REQUIRED/COMMITMENT_GRADE
194
+ * b. ADR-006 SYNTHESIS_SCHEMA_MAP entry
195
+ * c. A prompt template function in src/synthesis/prompts/
196
+ * d. CLI handler integration per the pattern above
197
+ * - The router is stateless and testable in isolation
198
+ */
199
+ /**
200
+ * Narrowed synthesis governance class for decision-grade subcommands.
201
+ * SYNTHESIS_FORBIDDEN commands never reach the router — only these two are valid.
202
+ */
203
+ export type SynthesisGovernanceClass = 'SYNTHESIS_REQUIRED' | 'COMMITMENT_GRADE';
204
+ export interface SynthesisRequest {
205
+ readonly command: string;
206
+ readonly subcommand: string;
207
+ readonly positionalArgs: readonly string[];
208
+ readonly options: Readonly<Record<string, string>>;
209
+ readonly flags: Readonly<Record<string, boolean>>;
210
+ readonly userContext: {
211
+ readonly userId: string;
212
+ readonly orgId: string;
213
+ readonly traceId: string;
214
+ };
215
+ }
216
+ export interface SynthesisResult<T = unknown> {
217
+ /** Contract-validated output from Claude Code */
218
+ readonly data: T;
219
+ /** UUID for this synthesis run */
220
+ readonly runId: string;
221
+ /** Primary command */
222
+ readonly command: string;
223
+ /** Subcommand */
224
+ readonly subcommand: string;
225
+ /** Model used for synthesis */
226
+ readonly model: string;
227
+ /** Duration of Claude Code invocation */
228
+ readonly durationMs: number;
229
+ /** Contract schema used for validation */
230
+ readonly contractSchema: string;
231
+ /** Raw Claude Code output (for artifact persistence) */
232
+ readonly rawOutput: string;
233
+ /** ADR-001 synthesis governance classification */
234
+ readonly synthesisClass: SynthesisGovernanceClass;
235
+ /** The prompt that was sent to Claude Code (for artifact persistence and debugging) */
236
+ readonly prompt: string;
237
+ }
238
+ export interface PromptArgs {
239
+ readonly runId: string;
240
+ readonly seed: number;
241
+ readonly command: string;
242
+ readonly subcommand: string;
243
+ readonly positionalArgs: readonly string[];
244
+ readonly options: Readonly<Record<string, string>>;
245
+ readonly contractSchemaName: string;
246
+ }
247
+ /** Type for prompt template functions */
248
+ export type PromptTemplate = (args: PromptArgs) => string;
249
+ /**
250
+ * Result of building a synthesis prompt without invoking Claude Code.
251
+ * Used for dry-run mode and testing.
252
+ */
253
+ export interface SynthesisPromptResult {
254
+ /** The fully-constructed prompt string */
255
+ readonly prompt: string;
256
+ /** Generated run identifier */
257
+ readonly runId: string;
258
+ /** Generated seed for determinism */
259
+ readonly seed: number;
260
+ /** The (command.subcommand) routing key */
261
+ readonly key: string;
262
+ /** Contract schema name for validation */
263
+ readonly contractSchema: string;
264
+ /** ADR-001 synthesis governance classification */
265
+ readonly synthesisClass: SynthesisGovernanceClass;
266
+ }
267
+ /**
268
+ * The decision-grade subcommand set.
269
+ * This is the canonical list; any subcommand NOT in this set
270
+ * must NEVER trigger Claude Code invocation.
271
+ */
272
+ export declare const DECISION_GRADE_SUBCOMMANDS: ReadonlySet<string>;
273
+ //# sourceMappingURL=adr-007-subcommand-synthesis-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adr-007-subcommand-synthesis-router.d.ts","sourceRoot":"","sources":["../../src/contracts/adr-007-subcommand-synthesis-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * ADR-007: Subcommand-Aware Synthesis Router
3
+ *
4
+ * STATUS: Proposed
5
+ * DATE: 2026-02-07
6
+ * AUTHORS: Platform Engineering
7
+ * DEPENDS-ON: ADR-001 (Command Semantics), ADR-006 (Claude Code Runner)
8
+ *
9
+ * ============================================================================
10
+ * CONTEXT
11
+ * ============================================================================
12
+ *
13
+ * ADR-001 defines a COMMAND_REGISTRY with synthesis governance classifications:
14
+ * - SYNTHESIS_REQUIRED: LLM invocation expected
15
+ * - SYNTHESIS_FORBIDDEN: Must NEVER trigger synthesis
16
+ * - COMMITMENT_GRADE: Requires ID + confirmation + synthesis
17
+ *
18
+ * The current CLI dispatches commands via a monolithic switch statement in
19
+ * src/cli/index.ts. Decision-grade subcommands call their respective
20
+ * command executors (executePlanCreateCommand, executeSimulateRunCommand, etc.)
21
+ * which talk to the platform API. The executive synthesis tool fires as an
22
+ * afterthought (fire-and-forget detached process).
23
+ *
24
+ * What's missing is a routing layer that sits BETWEEN argument parsing and
25
+ * command execution, intercepting decision-grade subcommands to:
26
+ * 1. Construct a subcommand-specific prompt
27
+ * 2. Call Claude Code Runner (ADR-006)
28
+ * 3. Validate the output
29
+ * 4. Feed it into the platform pipeline
30
+ *
31
+ * ============================================================================
32
+ * DECISION
33
+ * ============================================================================
34
+ *
35
+ * 1. A new module `src/synthesis/router.ts` will implement the synthesis
36
+ * routing layer.
37
+ *
38
+ * 2. The router takes a SynthesisRequest:
39
+ * ```typescript
40
+ * interface SynthesisRequest {
41
+ * command: string; // e.g. "simulate"
42
+ * subcommand: string; // e.g. "create"
43
+ * positionalArgs: string[]; // from parsed CLI args
44
+ * options: Record<string, string>;
45
+ * flags: Record<string, boolean>;
46
+ * userContext: {
47
+ * userId: string;
48
+ * orgId: string;
49
+ * traceId: string;
50
+ * };
51
+ * }
52
+ * ```
53
+ *
54
+ * 3. Routing logic:
55
+ * a. Look up (command, subcommand) in ADR-001 COMMAND_REGISTRY
56
+ * b. If synthesis === 'SYNTHESIS_FORBIDDEN', return null immediately
57
+ * c. If synthesis === 'SYNTHESIS_REQUIRED' or 'COMMITMENT_GRADE':
58
+ * i. Generate a run-id (UUID v4)
59
+ * ii. Load the prompt template for this (command, subcommand)
60
+ * iii. Inject arguments, context, run-id, and contract requirements
61
+ * iv. Call ClaudeCodeRunner.invoke()
62
+ * v. Return the validated SynthesisResult
63
+ *
64
+ * 4. SynthesisResult structure:
65
+ * ```typescript
66
+ * interface SynthesisResult<T> {
67
+ * data: T; // Contract-validated output
68
+ * runId: string; // UUID for this synthesis run
69
+ * command: string;
70
+ * subcommand: string;
71
+ * model: string; // Model used
72
+ * durationMs: number;
73
+ * contractSchema: string; // Schema name used for validation
74
+ * }
75
+ * ```
76
+ *
77
+ * 5. The router is a pure function with no side effects beyond calling
78
+ * ClaudeCodeRunner. It does NOT:
79
+ * - Write artifacts (that's ADR-008)
80
+ * - Call the platform API (that's the command executor)
81
+ * - Modify CLI state
82
+ *
83
+ * ============================================================================
84
+ * PROMPT TEMPLATE SYSTEM
85
+ * ============================================================================
86
+ *
87
+ * 1. Templates live in `src/synthesis/prompts/` as exported string constants
88
+ * (not .txt files — TypeScript provides compile-time safety and tree-shaking).
89
+ *
90
+ * 2. Each template is a function: (args: PromptArgs) => string
91
+ *
92
+ * 3. PromptArgs includes:
93
+ * - runId: string
94
+ * - seed: number
95
+ * - command: string
96
+ * - subcommand: string
97
+ * - positionalArgs: string[]
98
+ * - contractSchemaName: string
99
+ * - contractSchemaFields: string (human-readable field list)
100
+ *
101
+ * 4. Every template MUST include:
102
+ * - "Respond ONLY with a JSON object. No prose, no markdown, no explanation."
103
+ * - The exact contract schema name
104
+ * - The run-id and seed
105
+ * - The required fields for the output schema
106
+ *
107
+ * 5. Template naming: `{command}_{subcommand}` (e.g., simulate_create)
108
+ *
109
+ * ============================================================================
110
+ * DECISION-GRADE SUBCOMMAND MATRIX
111
+ * ============================================================================
112
+ *
113
+ * | Command | Subcommand | Synthesis Class | Contract Schema |
114
+ * |-----------|------------|----------------------|------------------|
115
+ * | simulate | create | SYNTHESIS_REQUIRED | simulation |
116
+ * | simulate | run | COMMITMENT_GRADE | simulation |
117
+ * | plan | create | SYNTHESIS_REQUIRED | plan |
118
+ * | plan | approve | COMMITMENT_GRADE | plan |
119
+ * | deploy | preview | SYNTHESIS_REQUIRED | intent |
120
+ * | deploy | run | COMMITMENT_GRADE | intent |
121
+ * | deploy | rollback | COMMITMENT_GRADE | intent |
122
+ * | export | terraform | SYNTHESIS_REQUIRED | export |
123
+ * | export | kubernetes | SYNTHESIS_REQUIRED | export |
124
+ * | export | erp | SYNTHESIS_REQUIRED | export |
125
+ * | policy | create | SYNTHESIS_REQUIRED | base |
126
+ * | policy | edit | SYNTHESIS_REQUIRED | base |
127
+ * | policy | enable | COMMITMENT_GRADE | base |
128
+ * | policy | disable | SYNTHESIS_REQUIRED | base |
129
+ * | policy | dry-run | SYNTHESIS_REQUIRED | base |
130
+ * | quantify | create | SYNTHESIS_REQUIRED | roiReport |
131
+ * | quantify | compare | COMMITMENT_GRADE | roiReport |
132
+ * | erp | surface | SYNTHESIS_REQUIRED | base |
133
+ * | erp | map | SYNTHESIS_REQUIRED | base |
134
+ * | erp | export | SYNTHESIS_REQUIRED | export |
135
+ *
136
+ * All other (command, subcommand) combinations return null from the router.
137
+ *
138
+ * ============================================================================
139
+ * INTEGRATION POINT
140
+ * ============================================================================
141
+ *
142
+ * The router is called from the CLI dispatch in src/cli/index.ts.
143
+ * The integration follows this pattern:
144
+ *
145
+ * ```typescript
146
+ * // In the command handler (e.g., simulate create)
147
+ * const synthesisResult = synthesisRouter.route({
148
+ * command: parsed.command,
149
+ * subcommand: parsed.subcommand,
150
+ * positionalArgs: parsed.positionalArgs,
151
+ * options: parsed.options,
152
+ * flags: parsed.flags,
153
+ * userContext: { userId, orgId, traceId },
154
+ * });
155
+ *
156
+ * if (synthesisResult) {
157
+ * // Decision-grade: use Claude Code output
158
+ * const platformResult = await executeWithSynthesis(synthesisResult);
159
+ * await persistArtifacts(synthesisResult, platformResult);
160
+ * } else {
161
+ * // Non-synthesis: proceed with existing command handler
162
+ * await executeExistingHandler(...);
163
+ * }
164
+ * ```
165
+ *
166
+ * ============================================================================
167
+ * ALTERNATIVES CONSIDERED
168
+ * ============================================================================
169
+ *
170
+ * A. Middleware-based routing (intercept all commands):
171
+ * Rejected — synthesis is the exception, not the rule. A middleware
172
+ * pattern would add overhead to every command, including the majority
173
+ * that are SYNTHESIS_FORBIDDEN.
174
+ *
175
+ * B. Prompt templates as external .txt files:
176
+ * Rejected — TypeScript functions provide compile-time safety,
177
+ * argument validation, and can reference contract types. External
178
+ * files would need a runtime loader and lose type safety.
179
+ *
180
+ * C. One giant prompt for all subcommands:
181
+ * Rejected — each subcommand has unique argument shapes, contract
182
+ * schemas, and domain-specific instructions. Specialized prompts
183
+ * produce better-structured output.
184
+ *
185
+ * ============================================================================
186
+ * CONSEQUENCES
187
+ * ============================================================================
188
+ *
189
+ * - Every decision-grade subcommand gets exactly one Claude Code call
190
+ * - Non-decision commands have zero synthesis overhead
191
+ * - Prompt templates are version-controlled and type-safe
192
+ * - New decision-grade subcommands require:
193
+ * a. ADR-001 COMMAND_REGISTRY entry with SYNTHESIS_REQUIRED/COMMITMENT_GRADE
194
+ * b. ADR-006 SYNTHESIS_SCHEMA_MAP entry
195
+ * c. A prompt template function in src/synthesis/prompts/
196
+ * d. CLI handler integration per the pattern above
197
+ * - The router is stateless and testable in isolation
198
+ */
199
+ /**
200
+ * The decision-grade subcommand set.
201
+ * This is the canonical list; any subcommand NOT in this set
202
+ * must NEVER trigger Claude Code invocation.
203
+ */
204
+ export const DECISION_GRADE_SUBCOMMANDS = new Set([
205
+ 'simulate.create',
206
+ 'simulate.run',
207
+ 'plan.create',
208
+ 'plan.approve',
209
+ 'deploy.preview',
210
+ 'deploy.run',
211
+ 'deploy.rollback',
212
+ 'export.terraform',
213
+ 'export.kubernetes',
214
+ 'export.erp',
215
+ 'policy.create',
216
+ 'policy.edit',
217
+ 'policy.enable',
218
+ 'policy.disable',
219
+ 'policy.dry-run',
220
+ 'quantify.create',
221
+ 'quantify.compare',
222
+ 'erp.surface',
223
+ 'erp.map',
224
+ 'erp.export',
225
+ ]);
226
+ //# sourceMappingURL=adr-007-subcommand-synthesis-router.js.map