@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
@@ -0,0 +1,64 @@
1
+ import { loadState } from "../state.js";
2
+ import { notifyGateRequired } from "../tui/cmux.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Filesystem-polling gate strategy
5
+ // ---------------------------------------------------------------------------
6
+ const POLL_INTERVAL_MS = 2000;
7
+ /**
8
+ * Gate strategy that writes `gate_pending` to state.json and polls for
9
+ * a response. The response comes from either:
10
+ * - The MCP server (pipeline_gate_respond tool)
11
+ * - Direct edit of state.json
12
+ */
13
+ export class FilesystemGateStrategy {
14
+ runId;
15
+ projectDir;
16
+ quiet;
17
+ constructor(runId, projectDir, quiet) {
18
+ this.runId = runId;
19
+ this.projectDir = projectDir;
20
+ this.quiet = quiet;
21
+ }
22
+ async waitForGate(gate) {
23
+ await notifyGateRequired(gate.stageName);
24
+ if (!this.quiet) {
25
+ console.log(` ⏸ Waiting for gate approval: ${gate.stageName}`);
26
+ if (gate.prompt)
27
+ console.log(` ${gate.prompt}`);
28
+ }
29
+ return new Promise((resolve) => {
30
+ const interval = setInterval(async () => {
31
+ try {
32
+ const state = await loadState(this.runId, this.projectDir, true);
33
+ if (!state?.gate)
34
+ return;
35
+ if (state.gate.stageName !== gate.stageName)
36
+ return;
37
+ if (state.gate.status === "approved") {
38
+ clearInterval(interval);
39
+ if (!this.quiet)
40
+ console.log(` ✓ Gate approved`);
41
+ resolve({
42
+ approved: true,
43
+ feedback: state.gate.feedback,
44
+ });
45
+ }
46
+ else if (state.gate.status === "rejected") {
47
+ clearInterval(interval);
48
+ if (!this.quiet) {
49
+ console.log(` ✗ Gate rejected${state.gate.feedback ? `: ${state.gate.feedback}` : ""}`);
50
+ }
51
+ resolve({
52
+ approved: false,
53
+ feedback: state.gate.feedback,
54
+ });
55
+ }
56
+ }
57
+ catch {
58
+ // State file may be mid-write — ignore and retry.
59
+ }
60
+ }, POLL_INTERVAL_MS);
61
+ });
62
+ }
63
+ }
64
+ //# sourceMappingURL=gate-watcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-watcher.js","sourceRoot":"","sources":["../../src/gate/gate-watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD,8EAA8E;AAC9E,mCAAmC;AACnC,8EAA8E;AAE9E,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAE9B;;;;;GAKG;AACH,MAAM,OAAO,sBAAsB;IAEvB;IACA;IACA;IAHV,YACU,KAAa,EACb,UAAmB,EACnB,KAAe;QAFf,UAAK,GAAL,KAAK,CAAQ;QACb,eAAU,GAAV,UAAU,CAAS;QACnB,UAAK,GAAL,KAAK,CAAU;IACtB,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,IAAc;QAC9B,MAAM,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAEzC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,oCAAoC,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC;YAClE,IAAI,IAAI,CAAC,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACvD,CAAC;QAED,OAAO,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,EAAE;YAC3C,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;gBACtC,IAAI,CAAC;oBACH,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;oBACjE,IAAI,CAAC,KAAK,EAAE,IAAI;wBAAE,OAAO;oBAEzB,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,SAAS;wBAAE,OAAO;oBAEpD,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;wBACrC,aAAa,CAAC,QAAQ,CAAC,CAAC;wBACxB,IAAI,CAAC,IAAI,CAAC,KAAK;4BAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;wBACpD,OAAO,CAAC;4BACN,QAAQ,EAAE,IAAI;4BACd,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;yBAC9B,CAAC,CAAC;oBACL,CAAC;yBAAM,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;wBAC5C,aAAa,CAAC,QAAQ,CAAC,CAAC;wBACxB,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;4BAChB,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC7F,CAAC;wBACD,OAAO,CAAC;4BACN,QAAQ,EAAE,KAAK;4BACf,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ;yBAC9B,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC;oBACP,kDAAkD;gBACpD,CAAC;YACH,CAAC,EAAE,gBAAgB,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,24 @@
1
+ /** Minimal logger interface used throughout the pipeline runner. */
2
+ export interface Logger {
3
+ log(...args: unknown[]): void;
4
+ error(...args: unknown[]): void;
5
+ warn(...args: unknown[]): void;
6
+ }
7
+ /** Default logger that forwards everything to the console. */
8
+ export declare class ConsoleLogger implements Logger {
9
+ log(...args: unknown[]): void;
10
+ error(...args: unknown[]): void;
11
+ warn(...args: unknown[]): void;
12
+ }
13
+ /** Logger that suppresses log/warn but still emits errors (for TUI mode). */
14
+ export declare class QuietLogger implements Logger {
15
+ log(): void;
16
+ error(...args: unknown[]): void;
17
+ warn(): void;
18
+ }
19
+ /** Completely silent logger — useful for tests. */
20
+ export declare class SilentLogger implements Logger {
21
+ log(): void;
22
+ error(): void;
23
+ warn(): void;
24
+ }
package/dist/logger.js ADDED
@@ -0,0 +1,22 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Logger abstraction — decouples pipeline output from console
3
+ // ---------------------------------------------------------------------------
4
+ /** Default logger that forwards everything to the console. */
5
+ export class ConsoleLogger {
6
+ log(...args) { console.log(...args); }
7
+ error(...args) { console.error(...args); }
8
+ warn(...args) { console.warn(...args); }
9
+ }
10
+ /** Logger that suppresses log/warn but still emits errors (for TUI mode). */
11
+ export class QuietLogger {
12
+ log() { }
13
+ error(...args) { console.error(...args); }
14
+ warn() { }
15
+ }
16
+ /** Completely silent logger — useful for tests. */
17
+ export class SilentLogger {
18
+ log() { }
19
+ error() { }
20
+ warn() { }
21
+ }
22
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,8DAA8D;AAC9D,8EAA8E;AAS9E,8DAA8D;AAC9D,MAAM,OAAO,aAAa;IACxB,GAAG,CAAC,GAAG,IAAe,IAAU,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACvD,KAAK,CAAC,GAAG,IAAe,IAAU,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3D,IAAI,CAAC,GAAG,IAAe,IAAU,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;CAC1D;AAED,6EAA6E;AAC7E,MAAM,OAAO,WAAW;IACtB,GAAG,KAAU,CAAC;IACd,KAAK,CAAC,GAAG,IAAe,IAAU,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3D,IAAI,KAAU,CAAC;CAChB;AAED,mDAAmD;AACnD,MAAM,OAAO,YAAY;IACvB,GAAG,KAAU,CAAC;IACd,KAAK,KAAU,CAAC;IAChB,IAAI,KAAU,CAAC;CAChB"}
@@ -0,0 +1,26 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export interface GateNotifierOptions {
3
+ server: McpServer;
4
+ projectDir: string;
5
+ pollIntervalMs?: number;
6
+ }
7
+ /**
8
+ * Watches for pending human gates across all pipeline runs and sends
9
+ * MCP elicitation requests to the connected Claude Code session.
10
+ *
11
+ * Lifecycle: call `start()` after the MCP server connects, `stop()` on shutdown.
12
+ */
13
+ export declare class GateNotifier {
14
+ private opts;
15
+ private seenGates;
16
+ private elicitationSupported;
17
+ private intervalId;
18
+ private pendingElicitation;
19
+ constructor(opts: GateNotifierOptions);
20
+ start(): void;
21
+ stop(): void;
22
+ private poll;
23
+ private elicitGateApproval;
24
+ private writeGateResponse;
25
+ private gateKey;
26
+ }
@@ -0,0 +1,161 @@
1
+ import { openDatabase } from "../db.js";
2
+ import { discoverRuns, loadState, saveState } from "../state.js";
3
+ // ---------------------------------------------------------------------------
4
+ // Gate notifier — polls for pending gates and elicits approval via MCP
5
+ // ---------------------------------------------------------------------------
6
+ const DEFAULT_POLL_MS = 2000;
7
+ /**
8
+ * Watches for pending human gates across all pipeline runs and sends
9
+ * MCP elicitation requests to the connected Claude Code session.
10
+ *
11
+ * Lifecycle: call `start()` after the MCP server connects, `stop()` on shutdown.
12
+ */
13
+ export class GateNotifier {
14
+ opts;
15
+ seenGates = new Set();
16
+ elicitationSupported = true;
17
+ intervalId = null;
18
+ pendingElicitation = null;
19
+ constructor(opts) {
20
+ this.opts = opts;
21
+ }
22
+ start() {
23
+ if (this.intervalId)
24
+ return;
25
+ const ms = this.opts.pollIntervalMs ?? DEFAULT_POLL_MS;
26
+ this.intervalId = setInterval(() => void this.poll(), ms);
27
+ }
28
+ stop() {
29
+ if (this.intervalId) {
30
+ clearInterval(this.intervalId);
31
+ this.intervalId = null;
32
+ }
33
+ }
34
+ // -------------------------------------------------------------------------
35
+ // Poll loop
36
+ // -------------------------------------------------------------------------
37
+ async poll() {
38
+ if (!this.elicitationSupported)
39
+ return;
40
+ if (this.pendingElicitation)
41
+ return; // one at a time
42
+ try {
43
+ const db = await openDatabase(this.opts.projectDir);
44
+ db.reload();
45
+ const runs = await discoverRuns(this.opts.projectDir);
46
+ // Clean up seen gates for runs that no longer have a pending gate.
47
+ for (const key of this.seenGates) {
48
+ const [runId] = key.split(":");
49
+ const run = runs.find((r) => r.state.runId === runId);
50
+ if (!run || run.state.gate?.status !== "pending") {
51
+ this.seenGates.delete(key);
52
+ }
53
+ }
54
+ // Find new pending gates.
55
+ for (const run of runs) {
56
+ const gate = run.state.gate;
57
+ if (!gate || gate.status !== "pending")
58
+ continue;
59
+ const key = this.gateKey(run.state.runId, gate.stageName);
60
+ if (this.seenGates.has(key))
61
+ continue;
62
+ // Mark as seen immediately to avoid duplicate elicitations.
63
+ this.seenGates.add(key);
64
+ this.pendingElicitation = this.elicitGateApproval(run);
65
+ // Only process one gate per poll cycle.
66
+ return;
67
+ }
68
+ }
69
+ catch {
70
+ // DB may be mid-write or unavailable — ignore and retry next cycle.
71
+ }
72
+ }
73
+ // -------------------------------------------------------------------------
74
+ // Elicitation
75
+ // -------------------------------------------------------------------------
76
+ async elicitGateApproval(run) {
77
+ const gate = run.state.gate;
78
+ const runShort = run.state.runId.slice(0, 8);
79
+ try {
80
+ // Elicit approval from the user — this blocks until they respond.
81
+ let result;
82
+ try {
83
+ result = await this.opts.server.server.elicitInput({
84
+ message: [
85
+ `Pipeline gate requires approval (run ${runShort}).`,
86
+ "",
87
+ `Stage: ${gate.stageName}`,
88
+ gate.prompt ? `\n${gate.prompt}` : "",
89
+ ]
90
+ .filter(Boolean)
91
+ .join("\n"),
92
+ requestedSchema: {
93
+ type: "object",
94
+ properties: {
95
+ decision: {
96
+ type: "string",
97
+ title: "Decision",
98
+ description: "Approve or reject this gate",
99
+ enum: ["approve", "reject"],
100
+ default: "approve",
101
+ },
102
+ feedback: {
103
+ type: "string",
104
+ title: "Feedback",
105
+ description: "Optional feedback (passed to generator on rejection)",
106
+ },
107
+ },
108
+ required: ["decision"],
109
+ },
110
+ });
111
+ }
112
+ catch {
113
+ // Elicitation not supported by this client — disable for the session.
114
+ this.elicitationSupported = false;
115
+ return;
116
+ }
117
+ // Handle the elicitation result.
118
+ if (result.action === "cancel") {
119
+ // User dismissed — remove from seen so it can be re-prompted.
120
+ this.seenGates.delete(this.gateKey(run.state.runId, gate.stageName));
121
+ return;
122
+ }
123
+ if (result.action === "decline") {
124
+ // User explicitly declined — write rejection.
125
+ await this.writeGateResponse(run, false);
126
+ return;
127
+ }
128
+ // action === "accept" — check the form content.
129
+ const decision = result.content?.decision;
130
+ const feedback = result.content?.feedback;
131
+ const approved = decision !== "reject";
132
+ await this.writeGateResponse(run, approved, feedback);
133
+ }
134
+ catch {
135
+ // DB write error — transient, don't disable elicitation.
136
+ // Remove from seen so it can be retried on the next poll cycle.
137
+ this.seenGates.delete(this.gateKey(run.state.runId, gate.stageName));
138
+ }
139
+ finally {
140
+ this.pendingElicitation = null;
141
+ }
142
+ }
143
+ async writeGateResponse(run, approved, feedback) {
144
+ // Reload state to ensure we have the latest (gate may have been resolved externally).
145
+ const freshState = await loadState(run.state.runId, this.opts.projectDir, true);
146
+ if (!freshState?.gate || freshState.gate.status !== "pending") {
147
+ return; // Gate already resolved — discard.
148
+ }
149
+ freshState.gate.status = approved ? "approved" : "rejected";
150
+ freshState.gate.feedback = feedback;
151
+ freshState.gate.respondedAt = new Date().toISOString();
152
+ await saveState(freshState);
153
+ }
154
+ // -------------------------------------------------------------------------
155
+ // Helpers
156
+ // -------------------------------------------------------------------------
157
+ gateKey(runId, stageName) {
158
+ return `${runId}:${stageName}`;
159
+ }
160
+ }
161
+ //# sourceMappingURL=gate-notifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gate-notifier.js","sourceRoot":"","sources":["../../src/mcp/gate-notifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { McpProfile, McpServer, ProjectConfig } from "../config.js";
2
+ import type { TempFileTracker } from "../temp-tracker.js";
3
+ export interface McpConfigJson {
4
+ mcpServers: Record<string, {
5
+ command: string;
6
+ args?: string[];
7
+ env?: Record<string, string>;
8
+ }>;
9
+ }
10
+ /**
11
+ * Resolve a named MCP profile from the project config, following `extends` chains.
12
+ * Returns the merged set of MCP servers.
13
+ */
14
+ export declare function resolveProfile(profileName: string, profiles: Record<string, McpProfile>, visited?: Set<string>): Record<string, McpServer>;
15
+ /**
16
+ * Build the MCP config JSON object for a given profile.
17
+ */
18
+ export declare function buildMcpConfig(profileName: string, config: ProjectConfig): McpConfigJson;
19
+ /**
20
+ * Write an MCP config JSON file to a temp location and return the path.
21
+ * Returns `undefined` if no profile is specified and no default exists.
22
+ * If a {@link TempFileTracker} is provided the path is registered for
23
+ * automatic cleanup.
24
+ */
25
+ export declare function writeMcpConfigFile(profileName: string | undefined, config: ProjectConfig, tracker?: TempFileTracker): Promise<string | undefined>;
@@ -0,0 +1,80 @@
1
+ import { writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { randomUUID } from "node:crypto";
5
+ // ---------------------------------------------------------------------------
6
+ // Profile resolution with inheritance
7
+ // ---------------------------------------------------------------------------
8
+ /**
9
+ * Resolve a named MCP profile from the project config, following `extends` chains.
10
+ * Returns the merged set of MCP servers.
11
+ */
12
+ export function resolveProfile(profileName, profiles, visited = new Set()) {
13
+ if (visited.has(profileName)) {
14
+ throw new Error(`Circular MCP profile inheritance: ${[...visited, profileName].join(" → ")}`);
15
+ }
16
+ visited.add(profileName);
17
+ const profile = profiles[profileName];
18
+ if (!profile) {
19
+ throw new Error(`MCP profile "${profileName}" not found. Available: ${Object.keys(profiles).join(", ")}`);
20
+ }
21
+ // Start with parent servers if extending.
22
+ let servers = {};
23
+ if (profile.extends) {
24
+ servers = resolveProfile(profile.extends, profiles, visited);
25
+ }
26
+ // Merge this profile's servers (child overrides parent on name collision).
27
+ if (profile.servers) {
28
+ servers = { ...servers, ...profile.servers };
29
+ }
30
+ return servers;
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Config file generation
34
+ // ---------------------------------------------------------------------------
35
+ /**
36
+ * Build the MCP config JSON object for a given profile.
37
+ */
38
+ export function buildMcpConfig(profileName, config) {
39
+ const profiles = config.mcp_profiles ?? {};
40
+ const servers = resolveProfile(profileName, profiles);
41
+ const mcpServers = {};
42
+ for (const [name, server] of Object.entries(servers)) {
43
+ mcpServers[name] = {
44
+ command: server.command,
45
+ ...(server.args?.length ? { args: server.args } : {}),
46
+ ...(server.env && Object.keys(server.env).length > 0
47
+ ? { env: server.env }
48
+ : {}),
49
+ };
50
+ }
51
+ return { mcpServers };
52
+ }
53
+ /**
54
+ * Write an MCP config JSON file to a temp location and return the path.
55
+ * Returns `undefined` if no profile is specified and no default exists.
56
+ * If a {@link TempFileTracker} is provided the path is registered for
57
+ * automatic cleanup.
58
+ */
59
+ export async function writeMcpConfigFile(profileName, config, tracker) {
60
+ const name = profileName ?? config.default_mcp_profile;
61
+ if (!name)
62
+ return undefined;
63
+ if (!config.mcp_profiles || !config.mcp_profiles[name]) {
64
+ // Profile referenced but not defined — only warn if explicitly requested.
65
+ if (profileName) {
66
+ throw new Error(`MCP profile "${profileName}" not found in project config`);
67
+ }
68
+ return undefined;
69
+ }
70
+ const mcpConfig = buildMcpConfig(name, config);
71
+ // Don't write a file if there are no servers.
72
+ if (Object.keys(mcpConfig.mcpServers).length === 0) {
73
+ return undefined;
74
+ }
75
+ const filePath = join(tmpdir(), `cccp-mcp-${randomUUID()}.json`);
76
+ await writeFile(filePath, JSON.stringify(mcpConfig, null, 2), "utf-8");
77
+ tracker?.track(filePath);
78
+ return filePath;
79
+ }
80
+ //# sourceMappingURL=mcp-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-config.js","sourceRoot":"","sources":["../../src/mcp/mcp-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function startMcpServer(): Promise<void>;