@momentiq/dark-factory-cli 2.1.0 → 2.2.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 (103) hide show
  1. package/dist/adapters/static-schema-lint.js +1 -1
  2. package/dist/cli.js +3 -3
  3. package/dist/cli.js.map +1 -1
  4. package/dist/commands/onboard.d.ts +64 -1
  5. package/dist/commands/onboard.d.ts.map +1 -1
  6. package/dist/commands/onboard.js +265 -53
  7. package/dist/commands/onboard.js.map +1 -1
  8. package/dist/doctor.d.ts.map +1 -1
  9. package/dist/doctor.js +20 -0
  10. package/dist/doctor.js.map +1 -1
  11. package/dist/mcp/server.d.ts.map +1 -1
  12. package/dist/mcp/server.js +2 -0
  13. package/dist/mcp/server.js.map +1 -1
  14. package/dist/mcp/tools/onboard.d.ts +6 -0
  15. package/dist/mcp/tools/onboard.d.ts.map +1 -0
  16. package/dist/mcp/tools/onboard.js +115 -0
  17. package/dist/mcp/tools/onboard.js.map +1 -0
  18. package/dist/onboard/apply-plan.d.ts +29 -0
  19. package/dist/onboard/apply-plan.d.ts.map +1 -0
  20. package/dist/onboard/apply-plan.js +80 -0
  21. package/dist/onboard/apply-plan.js.map +1 -0
  22. package/dist/onboard/auto-profile.d.ts +3 -0
  23. package/dist/onboard/auto-profile.d.ts.map +1 -0
  24. package/dist/onboard/auto-profile.js +20 -0
  25. package/dist/onboard/auto-profile.js.map +1 -0
  26. package/dist/onboard/generate-plan.d.ts +18 -0
  27. package/dist/onboard/generate-plan.d.ts.map +1 -0
  28. package/dist/onboard/generate-plan.js +68 -0
  29. package/dist/onboard/generate-plan.js.map +1 -0
  30. package/dist/onboard/llm-client.d.ts +45 -0
  31. package/dist/onboard/llm-client.d.ts.map +1 -0
  32. package/dist/onboard/llm-client.js +84 -0
  33. package/dist/onboard/llm-client.js.map +1 -0
  34. package/dist/onboard/prompts/scaffold.md +93 -0
  35. package/dist/onboard/prompts.d.ts +13 -0
  36. package/dist/onboard/prompts.d.ts.map +1 -0
  37. package/dist/onboard/prompts.js +54 -0
  38. package/dist/onboard/prompts.js.map +1 -0
  39. package/dist/onboard/scaffold-schema.d.ts +194 -0
  40. package/dist/onboard/scaffold-schema.d.ts.map +1 -0
  41. package/dist/onboard/scaffold-schema.js +73 -0
  42. package/dist/onboard/scaffold-schema.js.map +1 -0
  43. package/dist/onboard/schema.d.ts.map +1 -1
  44. package/dist/onboard/schema.js +7 -1
  45. package/dist/onboard/schema.js.map +1 -1
  46. package/dist/onboard/seeders/adr.d.ts +3 -0
  47. package/dist/onboard/seeders/adr.d.ts.map +1 -0
  48. package/dist/onboard/seeders/adr.js +212 -0
  49. package/dist/onboard/seeders/adr.js.map +1 -0
  50. package/dist/onboard/seeders/agent-review-config/cloud.canonical.json +22 -0
  51. package/dist/onboard/seeders/agent-review-config/local.canonical.json +21 -0
  52. package/dist/onboard/seeders/agent-review-config.d.ts +3 -0
  53. package/dist/onboard/seeders/agent-review-config.d.ts.map +1 -0
  54. package/dist/onboard/seeders/agent-review-config.js +38 -0
  55. package/dist/onboard/seeders/agent-review-config.js.map +1 -0
  56. package/dist/onboard/seeders/cycle1-bootstrap.d.ts +3 -0
  57. package/dist/onboard/seeders/cycle1-bootstrap.d.ts.map +1 -0
  58. package/dist/onboard/seeders/cycle1-bootstrap.js +76 -0
  59. package/dist/onboard/seeders/cycle1-bootstrap.js.map +1 -0
  60. package/dist/onboard/seeders/index.d.ts +47 -0
  61. package/dist/onboard/seeders/index.d.ts.map +1 -0
  62. package/dist/onboard/seeders/index.js +37 -0
  63. package/dist/onboard/seeders/index.js.map +1 -0
  64. package/dist/onboard/seeders/runbook.d.ts +13 -0
  65. package/dist/onboard/seeders/runbook.d.ts.map +1 -0
  66. package/dist/onboard/seeders/runbook.js +85 -0
  67. package/dist/onboard/seeders/runbook.js.map +1 -0
  68. package/dist/onboard/seeders/templates/adr.md.tmpl +26 -0
  69. package/dist/onboard/seeders/templates/cycle1-bootstrap.md.tmpl +64 -0
  70. package/dist/onboard/seeders/templates/runbook.md.tmpl +26 -0
  71. package/dist/onboard/template-loader.d.ts +20 -0
  72. package/dist/onboard/template-loader.d.ts.map +1 -0
  73. package/dist/onboard/template-loader.js +143 -0
  74. package/dist/onboard/template-loader.js.map +1 -0
  75. package/dist/onboard/template-ref.d.ts +15 -0
  76. package/dist/onboard/template-ref.d.ts.map +1 -0
  77. package/dist/onboard/template-ref.js +45 -0
  78. package/dist/onboard/template-ref.js.map +1 -0
  79. package/dist/onboard/validate.d.ts +19 -0
  80. package/dist/onboard/validate.d.ts.map +1 -0
  81. package/dist/onboard/validate.js +127 -0
  82. package/dist/onboard/validate.js.map +1 -0
  83. package/dist/onboard/writers/dry-run-renderer.d.ts +6 -0
  84. package/dist/onboard/writers/dry-run-renderer.d.ts.map +1 -0
  85. package/dist/onboard/writers/dry-run-renderer.js +88 -0
  86. package/dist/onboard/writers/dry-run-renderer.js.map +1 -0
  87. package/dist/onboard/writers/emit.d.ts +6 -0
  88. package/dist/onboard/writers/emit.d.ts.map +1 -0
  89. package/dist/onboard/writers/emit.js +29 -0
  90. package/dist/onboard/writers/emit.js.map +1 -0
  91. package/dist/onboard/writers/merge.d.ts +16 -0
  92. package/dist/onboard/writers/merge.d.ts.map +1 -0
  93. package/dist/onboard/writers/merge.js +142 -0
  94. package/dist/onboard/writers/merge.js.map +1 -0
  95. package/dist/onboard/writers/pr-writer.d.ts +44 -0
  96. package/dist/onboard/writers/pr-writer.d.ts.map +1 -0
  97. package/dist/onboard/writers/pr-writer.js +104 -0
  98. package/dist/onboard/writers/pr-writer.js.map +1 -0
  99. package/dist/onboard/writers/skip.d.ts +9 -0
  100. package/dist/onboard/writers/skip.d.ts.map +1 -0
  101. package/dist/onboard/writers/skip.js +9 -0
  102. package/dist/onboard/writers/skip.js.map +1 -0
  103. package/package.json +4 -1
@@ -0,0 +1,115 @@
1
+ // packages/cli/src/mcp/tools/onboard.ts
2
+ //
3
+ // Cycle 15 Phase C — `df_onboard {target, mode}` MCP tool.
4
+ //
5
+ // Delegates EVERYTHING beyond analysis-only to `cmdOnboard()` from
6
+ // `src/commands/onboard.ts` (Task 4.5) so the MCP path returns the SAME
7
+ // merged plan as the CLI path. The MCP tool MUST NOT re-assemble a plan
8
+ // from seeders alone — that would skip Phase B's LLM-emitted CLAUDE.md
9
+ // and break Task 5 metric 1 through the MCP path.
10
+ //
11
+ // Per-mode `destructiveHint` annotation is set on the response (NOT on
12
+ // the tool registration) because it varies per call:
13
+ // - analysis-only / dry-run → false (read-only / in-memory)
14
+ // - apply / pr → true (writes to working tree / opens PR)
15
+ //
16
+ // Tool-registration `openWorldHint: true` applies to ALL modes —
17
+ // analysis reads the filesystem; pr reaches GitHub via gh.
18
+ import { z } from "zod";
19
+ import { analyze } from "../../onboard/analyze.js";
20
+ import { cmdOnboard } from "../../commands/onboard.js";
21
+ function isDestructive(mode) {
22
+ return mode === "apply" || mode === "pr";
23
+ }
24
+ function renderMarkdownSummary(input) {
25
+ if ("analysis" in input.sc) {
26
+ const a = input.sc.analysis;
27
+ return [
28
+ `**df_onboard** (mode=analysis-only)`,
29
+ `- canonicalName: ${a.canonicalName || "(unknown)"}`,
30
+ `- stacks: ${a.stacks.map((s) => s.language).join(", ") || "(none)"}`,
31
+ `- services: ${a.services.length}`,
32
+ `- decisions: ${a.decisions.length}`,
33
+ `- analyzerErrors: ${a.analyzerErrors.length}`,
34
+ ].join("\n");
35
+ }
36
+ const p = input.sc;
37
+ return [
38
+ `**df_onboard** (mode=${input.mode}, dryRun=${p.dryRun}, applied=${p.applied})`,
39
+ `- files in plan: ${p.plan.files.length}`,
40
+ p.branchName ? `- branch: ${p.branchName}` : null,
41
+ ]
42
+ .filter((line) => Boolean(line))
43
+ .join("\n");
44
+ }
45
+ export function registerOnboardTool(server, _opts = {}) {
46
+ server.registerTool("df_onboard", {
47
+ title: "Dark Factory onboard",
48
+ description: "Run `df onboard` on a target repo. Modes: analysis-only (Phase A — emit RepoAnalysis only), " +
49
+ "dry-run (Phase B+C — emit merged ScaffoldPlan without writing), apply (Phase B+C — write files " +
50
+ "to working tree), pr (Phase B+C — branch + commit + open a PR via gh). 'apply' and 'pr' mutate " +
51
+ "the working tree; their per-call response carries `annotations.destructiveHint: true`.",
52
+ inputSchema: {
53
+ target: z
54
+ .string()
55
+ .describe("Absolute path to the target repo's working tree."),
56
+ mode: z
57
+ .enum(["analysis-only", "dry-run", "apply", "pr"])
58
+ .describe("Operation mode. 'analysis-only' is read-only; 'dry-run' computes a plan but writes nothing; " +
59
+ "'apply' writes files in place; 'pr' writes to a fresh branch and opens a PR."),
60
+ },
61
+ outputSchema: {
62
+ analysis: z
63
+ .unknown()
64
+ .optional()
65
+ .describe("Present when mode='analysis-only' — the RepoAnalysis JSON."),
66
+ plan: z
67
+ .unknown()
68
+ .optional()
69
+ .describe("Present when mode != 'analysis-only' — the merged ScaffoldPlan."),
70
+ dryRun: z.boolean().optional(),
71
+ applied: z.boolean().optional(),
72
+ branchName: z.string().nullable().optional(),
73
+ },
74
+ annotations: {
75
+ // openWorldHint applies to ALL modes — analysis reads the
76
+ // filesystem; pr reaches GitHub via gh. destructiveHint is NOT
77
+ // set at registration because it varies per-mode (set per-call
78
+ // on the response below).
79
+ openWorldHint: true,
80
+ },
81
+ }, async (args) => {
82
+ const target = args.target;
83
+ const mode = args.mode;
84
+ const destructiveHint = isDestructive(mode);
85
+ if (mode === "analysis-only") {
86
+ const analysis = await analyze(target);
87
+ const result = { analysis };
88
+ return {
89
+ structuredContent: result,
90
+ content: [{ type: "text", text: renderMarkdownSummary({ mode, sc: result }) }],
91
+ // Per-call destructive flag — analysis-only is read-only.
92
+ annotations: { destructiveHint },
93
+ };
94
+ }
95
+ // dry-run / apply / pr — delegate to cmdOnboard. `json: true` is
96
+ // structurally irrelevant in the orchestrator's contract today
97
+ // (the orchestrator always returns the structured plan; the CLI
98
+ // shim handles rendered diff output), but pass it explicitly so
99
+ // the intent ("MCP wants the structured plan, not a rendered
100
+ // ANSI diff") is documented at the call site.
101
+ const out = (await cmdOnboard({ target, mode }));
102
+ const result = {
103
+ plan: out.plan,
104
+ dryRun: mode === "dry-run",
105
+ applied: out.applied,
106
+ branchName: out.branchName,
107
+ };
108
+ return {
109
+ structuredContent: result,
110
+ content: [{ type: "text", text: renderMarkdownSummary({ mode, sc: result }) }],
111
+ annotations: { destructiveHint },
112
+ };
113
+ });
114
+ }
115
+ //# sourceMappingURL=onboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../../src/mcp/tools/onboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { type MergeResult } from "./writers/merge.js";
2
+ import { type SkipResult } from "./writers/skip.js";
3
+ import type { ScaffoldPlan } from "./scaffold-schema.js";
4
+ export type ApplyMode = "dry-run" | "apply";
5
+ export interface EmitResult {
6
+ path: string;
7
+ action: "emit";
8
+ wrote: boolean;
9
+ }
10
+ export type ApplyFileResult = EmitResult | MergeResult | SkipResult;
11
+ export interface ApplyResult {
12
+ mode: ApplyMode;
13
+ results: ApplyFileResult[];
14
+ rendered?: string;
15
+ }
16
+ export interface ApplyOptions {
17
+ mode: ApplyMode;
18
+ force?: boolean;
19
+ color?: boolean;
20
+ stderr?: (s: string) => void;
21
+ }
22
+ export declare class ScaffoldApplyError extends Error {
23
+ written: string[];
24
+ notWritten: string[];
25
+ cause: unknown;
26
+ constructor(message: string, written: string[], notWritten: string[], cause: unknown);
27
+ }
28
+ export declare function applyPlan(rootDir: string, plan: ScaffoldPlan, opts: ApplyOptions): Promise<ApplyResult>;
29
+ //# sourceMappingURL=apply-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-plan.d.ts","sourceRoot":"","sources":["../../src/onboard/apply-plan.ts"],"names":[],"mappings":"AAcA,OAAO,EAAc,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAClE,OAAO,EAAa,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE5C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,CAAC;AAEpE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B;AAED,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;gBACZ,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO;CAOrF;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,WAAW,CAAC,CAuDtB"}
@@ -0,0 +1,80 @@
1
+ // packages/cli/src/onboard/apply-plan.ts
2
+ //
3
+ // Dispatcher over the three writers + the dry-run renderer. The PR writer
4
+ // is a separate entry point (pr-writer.ts) because it spans subprocess
5
+ // orchestration (gh auth check + branch + commit + gh pr create) that
6
+ // doesn't belong in this hot path.
7
+ //
8
+ // Partial-failure contract (per B-D7): on any write error mid-loop, collect
9
+ // the written-so-far list + the not-written list and re-throw a
10
+ // ScaffoldApplyError. Idempotency: callers can re-run --apply after fixing
11
+ // the disk/permission issue; written files are overwritten with identical
12
+ // content; merge files re-detect the BEGIN/END block.
13
+ import { writeEmit } from "./writers/emit.js";
14
+ import { writeMerge } from "./writers/merge.js";
15
+ import { writeSkip } from "./writers/skip.js";
16
+ import { renderDryRun } from "./writers/dry-run-renderer.js";
17
+ export class ScaffoldApplyError extends Error {
18
+ written;
19
+ notWritten;
20
+ cause;
21
+ constructor(message, written, notWritten, cause) {
22
+ super(message);
23
+ this.name = "ScaffoldApplyError";
24
+ this.written = written;
25
+ this.notWritten = notWritten;
26
+ this.cause = cause;
27
+ }
28
+ }
29
+ export async function applyPlan(rootDir, plan, opts) {
30
+ if (opts.mode !== "dry-run" && opts.mode !== "apply") {
31
+ throw new Error(`df onboard: applyPlan does not handle mode "${opts.mode}". ` +
32
+ "For pr mode, use runPrMode(plan, ...) from pr-writer.ts.");
33
+ }
34
+ if (opts.mode === "dry-run") {
35
+ const renderOpts = opts.color !== undefined ? { color: opts.color } : {};
36
+ const rendered = await renderDryRun(rootDir, plan, renderOpts);
37
+ const results = plan.files.map((f) => {
38
+ if (f.action === "skip")
39
+ return { path: f.path, action: "skip", rationale: f.rationale, wrote: false };
40
+ if (f.action === "emit")
41
+ return { path: f.path, action: "emit", wrote: false };
42
+ return { path: f.path, action: "merge", wrote: false, skipped: false };
43
+ });
44
+ return { mode: "dry-run", results, rendered };
45
+ }
46
+ // apply mode
47
+ const results = [];
48
+ const written = [];
49
+ for (let i = 0; i < plan.files.length; i++) {
50
+ const file = plan.files[i];
51
+ try {
52
+ if (file.action === "skip") {
53
+ results.push(await writeSkip(rootDir, file));
54
+ continue;
55
+ }
56
+ if (file.action === "emit") {
57
+ await writeEmit(rootDir, file, { force: opts.force ?? false });
58
+ results.push({ path: file.path, action: "emit", wrote: true });
59
+ written.push(file.path);
60
+ continue;
61
+ }
62
+ // merge
63
+ const mergeOpts = opts.stderr !== undefined ? { stderr: opts.stderr } : {};
64
+ const r = await writeMerge(rootDir, file, mergeOpts);
65
+ results.push(r);
66
+ if (r.wrote)
67
+ written.push(file.path);
68
+ }
69
+ catch (err) {
70
+ const notWritten = plan.files.slice(i).map((f) => f.path);
71
+ throw new ScaffoldApplyError(`df onboard: write failed at ${file.path} (${err instanceof Error ? err.message : String(err)}). ` +
72
+ `Files written before the failure: ${written.length ? written.join(", ") : "(none)"}. ` +
73
+ `Files NOT written: ${notWritten.join(", ")}. ` +
74
+ `Re-run \`df onboard --apply\` after addressing the disk/perm issue; ` +
75
+ `written files will be overwritten with the same content (idempotent).`, written, notWritten, err);
76
+ }
77
+ }
78
+ return { mode: "apply", results };
79
+ }
80
+ //# sourceMappingURL=apply-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-plan.js","sourceRoot":"","sources":["../../src/onboard/apply-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RepoAnalysis } from "./schema.js";
2
+ export declare function autoProfile(analysis: RepoAnalysis): "local" | "cloud";
3
+ //# sourceMappingURL=auto-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-profile.d.ts","sourceRoot":"","sources":["../../src/onboard/auto-profile.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wBAAgB,WAAW,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,GAAG,OAAO,CAGrE"}
@@ -0,0 +1,20 @@
1
+ // packages/cli/src/onboard/auto-profile.ts
2
+ //
3
+ // Resolve the critic profile (local | cloud) from a RepoAnalysis when the
4
+ // operator did not pass --profile explicitly.
5
+ //
6
+ // This module is shipped as its own file (not inline in commands/onboard.ts)
7
+ // so Phase C's deterministic .agent-review/config.json seeder can import the
8
+ // same function via `import { autoProfile } from "../auto-profile.js"`. The
9
+ // single-source-of-truth keeps Phase B + Phase C aligned on the heuristic
10
+ // without either side re-implementing it.
11
+ //
12
+ // Heuristic (B-D8): a repo that already has a DF cli-pin AND a cloud PR
13
+ // workflow is one that already runs the cloud quartet — keep them on
14
+ // `cloud`. Everything else defaults to `local`. Explicit `--profile` always
15
+ // wins; this function is only the fallback.
16
+ export function autoProfile(analysis) {
17
+ const dfWired = analysis.dfPresence.cliPin !== null && analysis.dfPresence.prWorkflow;
18
+ return dfWired ? "cloud" : "local";
19
+ }
20
+ //# sourceMappingURL=auto-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-profile.js","sourceRoot":"","sources":["../../src/onboard/auto-profile.ts"],"names":[],"mappings":"AAAA,2CAA2C;AAC3C,EAAE;AACF,0EAA0E;AAC1E,8CAA8C;AAC9C,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,4EAA4E;AAC5E,0EAA0E;AAC1E,0CAA0C;AAC1C,EAAE;AACF,wEAAwE;AACxE,qEAAqE;AACrE,4EAA4E;AAC5E,4CAA4C;AAI5C,MAAM,UAAU,WAAW,CAAC,QAAsB;IAChD,MAAM,OAAO,GAAG,QAAQ,CAAC,UAAU,CAAC,MAAM,KAAK,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,UAAU,CAAC;IACtF,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AACrC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type ScaffoldPlan } from "./scaffold-schema.js";
2
+ import { type LlmInputs, type LlmResult } from "./llm-client.js";
3
+ import type { RepoAnalysis } from "./schema.js";
4
+ import type { Template } from "./template-loader.js";
5
+ export interface GeneratePlanOptions {
6
+ apiKey?: string;
7
+ modelId: string;
8
+ /** Resolved critic profile (B-D8). Flows into the scaffold prompt so the LLM
9
+ * emits a profile-correct `.agent-review/config.json`. The CLI resolves the
10
+ * profile (explicit `--profile` flag, else `autoProfile(analysis)`) before
11
+ * calling generatePlan. */
12
+ profile: "local" | "cloud";
13
+ callLlm?: (inputs: LlmInputs) => Promise<LlmResult>;
14
+ }
15
+ export interface GeneratePlanResult extends Omit<ScaffoldPlan, never> {
16
+ }
17
+ export declare function generatePlan(analysis: RepoAnalysis, template: Template, opts: GeneratePlanOptions): Promise<ScaffoldPlan>;
18
+ //# sourceMappingURL=generate-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-plan.d.ts","sourceRoot":"","sources":["../../src/onboard/generate-plan.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;;;gCAG4B;IAC5B,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;IAE3B,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;CACrD;AAED,MAAM,WAAW,kBAAmB,SAAQ,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC;CAEpE;AAID,wBAAsB,YAAY,CAChC,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,YAAY,CAAC,CAsDvB"}
@@ -0,0 +1,68 @@
1
+ // packages/cli/src/onboard/generate-plan.ts
2
+ //
3
+ // Stage B entry point. Composes the prompt renderer, the LLM client, and
4
+ // the ScaffoldPlanSchema validator into one async function. One retry on
5
+ // validation failure (the model gets a chance to fix its own JSON when
6
+ // shown the Zod error); zero retries on transient LLM errors (the LLM
7
+ // client wrapper already handles those).
8
+ import { zodToJsonSchema } from "zod-to-json-schema";
9
+ import { ScaffoldPlanSchema, SCAFFOLD_PLAN_BYTE_BUDGET, } from "./scaffold-schema.js";
10
+ import { renderScaffoldPrompt } from "./prompts.js";
11
+ import { callScaffoldLlm, } from "./llm-client.js";
12
+ const TOOL_NAME = "emit_scaffold_plan";
13
+ export async function generatePlan(analysis, template, opts) {
14
+ const { systemPrompt, userMessage } = await renderScaffoldPrompt(analysis, template.files, { profile: opts.profile });
15
+ const inputSchema = zodToJsonSchema(ScaffoldPlanSchema, "ScaffoldPlan");
16
+ const callLlm = opts.callLlm ?? ((i) => callScaffoldLlm(i));
17
+ // exactOptionalPropertyTypes forbids assigning `undefined` to an optional
18
+ // property; conditionally spread `apiKey` only when defined so the llm-client
19
+ // falls through to its ANTHROPIC_API_KEY env-var lookup.
20
+ const baseInputs = {
21
+ systemPrompt,
22
+ toolName: TOOL_NAME,
23
+ toolInputSchema: inputSchema,
24
+ modelId: opts.modelId,
25
+ ...(opts.apiKey !== undefined ? { apiKey: opts.apiKey } : {}),
26
+ };
27
+ // Attempt 1
28
+ let result = await callLlm({ ...baseInputs, userMessage });
29
+ let parsed = ScaffoldPlanSchema.safeParse(stampTemplateRef(result.planJson, template));
30
+ if (!parsed.success) {
31
+ // Capture the first-attempt issues BEFORE the retry overwrites `parsed`,
32
+ // so the final error can cite both attempts (per W3 finding round-1).
33
+ const firstAttemptIssues = parsed.error.issues;
34
+ // Retry once with the validation error appended — the model often self-corrects.
35
+ const retryMessage = `${userMessage}\n\n## Previous attempt rejected\n` +
36
+ "Your last tool call did not validate. Issues:\n" +
37
+ firstAttemptIssues.map((i) => `- ${i.path.join(".")}: ${i.message}`).join("\n") +
38
+ "\n\nEmit `emit_scaffold_plan` again, fixing each issue above.";
39
+ result = await callLlm({ ...baseInputs, userMessage: retryMessage });
40
+ parsed = ScaffoldPlanSchema.safeParse(stampTemplateRef(result.planJson, template));
41
+ if (!parsed.success) {
42
+ throw new Error(`df onboard: scaffold plan validation failed after retry. ` +
43
+ `First-attempt issues: ${formatZodIssues(firstAttemptIssues)}; ` +
44
+ `second-attempt issues: ${formatZodIssues(parsed.error.issues)}`);
45
+ }
46
+ }
47
+ // Byte-budget backstop (per B-D2). Per-array caps and per-field maxLength
48
+ // catch most overflows; this is the final guardrail before the writer.
49
+ const serialized = JSON.stringify(parsed.data);
50
+ if (serialized.length > SCAFFOLD_PLAN_BYTE_BUDGET) {
51
+ throw new Error(`df onboard: ScaffoldPlan exceeds ${SCAFFOLD_PLAN_BYTE_BUDGET}-byte (64 KB) budget: ` +
52
+ `produced ${serialized.length} bytes. Tighten per-file tailored_content or files[] count.`);
53
+ }
54
+ return parsed.data;
55
+ }
56
+ // stampTemplateRef forces the plan's templateRef to be the loader's canonicalRef,
57
+ // not the LLM's value — the LLM could echo a stale or fabricated ref, and the
58
+ // plan's provenance must be ground-truth.
59
+ function stampTemplateRef(planJson, template) {
60
+ if (planJson && typeof planJson === "object" && !Array.isArray(planJson)) {
61
+ return { ...planJson, templateRef: template.canonicalRef };
62
+ }
63
+ return planJson;
64
+ }
65
+ function formatZodIssues(issues) {
66
+ return issues.map((i) => `${i.path.join(".") || "<root>"}: ${i.message}`).join("; ");
67
+ }
68
+ //# sourceMappingURL=generate-plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-plan.js","sourceRoot":"","sources":["../../src/onboard/generate-plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ export interface LlmInputs {
2
+ systemPrompt: string;
3
+ userMessage: string;
4
+ toolName: string;
5
+ toolInputSchema: object;
6
+ apiKey?: string;
7
+ modelId: string;
8
+ maxTokens?: number;
9
+ }
10
+ export interface LlmResult {
11
+ planJson: unknown;
12
+ modelId: string;
13
+ inputTokens: number;
14
+ outputTokens: number;
15
+ attempts: number;
16
+ }
17
+ export interface LlmClientLike {
18
+ messages: {
19
+ create(params: unknown): Promise<{
20
+ id: string;
21
+ model: string;
22
+ content: Array<{
23
+ type: "tool_use";
24
+ name: string;
25
+ input: unknown;
26
+ } | {
27
+ type: "text";
28
+ text: string;
29
+ } | {
30
+ type: string;
31
+ }>;
32
+ usage: {
33
+ input_tokens: number;
34
+ output_tokens: number;
35
+ };
36
+ stop_reason: string;
37
+ }>;
38
+ };
39
+ }
40
+ export type LlmClientFactory = (apiKey: string) => LlmClientLike;
41
+ export interface CallOptions {
42
+ createClient?: LlmClientFactory;
43
+ }
44
+ export declare function callScaffoldLlm(inputs: LlmInputs, opts?: CallOptions): Promise<LlmResult>;
45
+ //# sourceMappingURL=llm-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../../src/onboard/llm-client.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE;QACR,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC;YAC/B,EAAE,EAAE,MAAM,CAAC;YACX,KAAK,EAAE,MAAM,CAAC;YACd,OAAO,EAAE,KAAK,CACV;gBAAE,IAAI,EAAE,UAAU,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,OAAO,CAAA;aAAE,GAClD;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,IAAI,EAAE,MAAM,CAAA;aAAE,GAC9B;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CACnB,CAAC;YACF,KAAK,EAAE;gBAAE,YAAY,EAAE,MAAM,CAAC;gBAAC,aAAa,EAAE,MAAM,CAAA;aAAE,CAAC;YACvD,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC,CAAC;KACJ,CAAC;CACH;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,aAAa,CAAC;AAkBjE,MAAM,WAAW,WAAW;IAC1B,YAAY,CAAC,EAAE,gBAAgB,CAAC;CACjC;AAED,wBAAsB,eAAe,CACnC,MAAM,EAAE,SAAS,EACjB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,SAAS,CAAC,CA2DpB"}
@@ -0,0 +1,84 @@
1
+ // packages/cli/src/onboard/llm-client.ts
2
+ //
3
+ // Anthropic Messages-API wrapper with tool-use structured output.
4
+ //
5
+ // Why a wrapper instead of calling the SDK directly: the call shape is
6
+ // shared by generatePlan() (Phase B) AND a future Phase B.1 prompt-test
7
+ // harness, and the retry classification (transient vs permanent) is
8
+ // security-critical (a 401 must never silently retry). Centralizing the
9
+ // shape here means a new caller can't accidentally drift from the policy.
10
+ //
11
+ // Tool-use binding: declare a single tool `emit_scaffold_plan` whose
12
+ // `input_schema` is the JSON-Schema rendering of ScaffoldPlanSchema; set
13
+ // tool_choice to force the model into a tool call; read the tool-use
14
+ // block's `input` as the candidate JSON. The SDK validates the JSON
15
+ // shape at the API boundary; downstream Zod validation re-checks the
16
+ // semantics (discriminated-union, byte budgets).
17
+ import Anthropic from "@anthropic-ai/sdk";
18
+ const DEFAULT_FACTORY = (apiKey) => new Anthropic({ apiKey });
19
+ const TRANSIENT_STATUSES = new Set([429, 500, 502, 503, 504]);
20
+ function isTransient(err) {
21
+ if (!(err instanceof Error))
22
+ return false;
23
+ const status = err.status;
24
+ if (typeof status === "number")
25
+ return TRANSIENT_STATUSES.has(status);
26
+ const code = err.code;
27
+ if (typeof code === "string" && /ECONNRESET|ETIMEDOUT|ENETUNREACH|EAI_AGAIN/.test(code)) {
28
+ return true;
29
+ }
30
+ return false;
31
+ }
32
+ export async function callScaffoldLlm(inputs, opts = {}) {
33
+ const apiKey = inputs.apiKey ?? process.env["ANTHROPIC_API_KEY"];
34
+ if (!apiKey || !apiKey.trim()) {
35
+ throw new Error("df onboard: ANTHROPIC_API_KEY is required for Phase B's scaffold-generation LLM call. " +
36
+ "Set the env var (or pass --api-key) and re-run.");
37
+ }
38
+ const factory = opts.createClient ?? DEFAULT_FACTORY;
39
+ const client = factory(apiKey);
40
+ const request = {
41
+ model: inputs.modelId,
42
+ max_tokens: inputs.maxTokens ?? 8192,
43
+ system: inputs.systemPrompt,
44
+ tools: [
45
+ {
46
+ name: inputs.toolName,
47
+ description: "Emit the tailored ScaffoldPlan JSON. The input schema is enforced strictly; " +
48
+ "fields not in the schema are rejected.",
49
+ input_schema: inputs.toolInputSchema,
50
+ },
51
+ ],
52
+ tool_choice: { type: "tool", name: inputs.toolName },
53
+ messages: [{ role: "user", content: inputs.userMessage }],
54
+ };
55
+ let attempts = 0;
56
+ let lastErr = null;
57
+ for (let attempt = 0; attempt < 2; attempt++) {
58
+ attempts++;
59
+ try {
60
+ const r = await client.messages.create(request);
61
+ const toolBlock = r.content.find((b) => b.type === "tool_use" &&
62
+ b.name === inputs.toolName);
63
+ if (!toolBlock) {
64
+ throw new Error(`df onboard: no tool_use block found in LLM response (got stop_reason=${r.stop_reason}). ` +
65
+ "The model did not honor tool_choice; check the prompt and model selection.");
66
+ }
67
+ return {
68
+ planJson: toolBlock.input,
69
+ modelId: r.model,
70
+ inputTokens: r.usage.input_tokens,
71
+ outputTokens: r.usage.output_tokens,
72
+ attempts,
73
+ };
74
+ }
75
+ catch (err) {
76
+ lastErr = err;
77
+ if (attempt === 0 && isTransient(err))
78
+ continue;
79
+ throw err;
80
+ }
81
+ }
82
+ throw lastErr instanceof Error ? lastErr : new Error(String(lastErr));
83
+ }
84
+ //# sourceMappingURL=llm-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llm-client.js","sourceRoot":"","sources":["../../src/onboard/llm-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ <!-- packages/cli/src/onboard/prompts/scaffold.md -->
2
+ # Dark Factory `df onboard` — Stage B scaffold prompt (cycle 15 Phase B)
3
+
4
+ You are the "Stage B" scaffold-tailoring agent inside `@momentiq/dark-factory-cli`'s
5
+ `df onboard` command. Your role is to consume a **structured `RepoAnalysis`** (the
6
+ deterministic Stage A output) and a **sage-blueprint template directory** (the raw
7
+ markdown/JSON/YAML files that define the agent-context-set scaffolding), then
8
+ emit a **`ScaffoldPlan`** describing how to tailor the template to the target repo.
9
+
10
+ ## Operating contract
11
+
12
+ You MUST emit your response via the `emit_scaffold_plan` tool call. Do NOT emit
13
+ prose text outside of the tool call. The tool's `input_schema` is strict; fields
14
+ outside the schema are rejected, and the action discriminator forces an unambiguous
15
+ choice per file.
16
+
17
+ For every file in the input template, choose exactly ONE action:
18
+
19
+ | Action | Use when | Required fields |
20
+ |---|---|---|
21
+ | `emit` | The target repo does NOT have this file yet, OR the existing file is empty/trivial and should be replaced. | `path`, `rationale`, `tailored_content` |
22
+ | `merge` | The target repo HAS a non-trivial version of this file and the LLM-tailored content should be APPENDED additively (NOT replace). Reserve for `CLAUDE.md` and `AGENTS.md`. | `path`, `rationale`, `tailored_content` |
23
+ | `skip` | The target repo already covers this file's intent, OR the file is irrelevant to the target's stack/services. | `path`, `rationale` (NO `tailored_content` — the schema rejects it) |
24
+
25
+ ### Tailoring rules
26
+
27
+ 1. **Cite the analysis, never invent.** Every claim in `tailored_content` must be
28
+ grounded in a field of `RepoAnalysis`. If you reference a service, it MUST
29
+ appear in `analysis.services[]`. If you cite a stack, it MUST appear in
30
+ `analysis.stacks[]`. If you describe a deploy story, cite `analysis.ci.deployStory`.
31
+ Hallucinating a non-existent service or stack is the worst possible failure
32
+ mode of this pipeline.
33
+
34
+ 2. **Substitute `{{ }}` placeholders.** The template files contain
35
+ `{{ project_name }}`, `{{ stack }}`, `{{ services }}` and similar Copier-style
36
+ placeholders. Replace each with the concrete value from `RepoAnalysis`:
37
+ - `{{ project_name }}` → `analysis.canonicalName.split("/")[1]`
38
+ - `{{ owner }}` → `analysis.canonicalName.split("/")[0]`
39
+ - `{{ stack }}` → `analysis.stacks[0]?.language` (or "polyglot" if multiple)
40
+ - `{{ services }}` → bulleted list from `analysis.services[]`
41
+ - `{{ default_branch }}` → `analysis.git.defaultBranch`
42
+ The bodies you emit must contain NO leftover `{{ }}` after substitution.
43
+
44
+ 3. **Use `merge` only for `CLAUDE.md` and `AGENTS.md`.** Other files don't have
45
+ the marker-comment infrastructure; use `emit` or `skip` for everything else.
46
+ When `analysis.docs.hasClaudeMd === true`, use `merge` for `CLAUDE.md`;
47
+ otherwise use `emit`. Same for `AGENTS.md`.
48
+
49
+ 4. **Skip when the target already covers it.** If `analysis.dfPresence.configJson === true`,
50
+ skip `.agent-review/config.json` — don't fight the existing gate. If
51
+ `analysis.dfPresence.prWorkflow === true`, skip `dark-factory-pr.yml`. Cite
52
+ the dfPresence field in the rationale.
53
+
54
+ 4a. **ALWAYS SKIP `.agent-review/config.json` (the Phase C seeder owns this path).** Emit a single `skip` entry for `.agent-review/config.json` with rationale "phase C seeder owns this path; phase B does not emit config.json"; do NOT include `tailored_content`. This applies regardless of `analysis.dfPresence.configJson`'s value and supersedes rule 4 for this specific path.
55
+
56
+ 5. **`merge` content rules.** When you emit `tailored_content` for a `merge`
57
+ action, that content is APPENDED after the existing file (with marker
58
+ comments managed by the CLI). Therefore:
59
+ - Do NOT include the user's existing headings.
60
+ - START with a top-level H2 section (e.g. `## Dark Factory onboarding`) so the
61
+ append reads naturally.
62
+ - Do NOT include `<!-- df onboard: inserted-by-cycle-15 -->` markers — the
63
+ CLI's merge writer adds them.
64
+
65
+ 6. **`rationale` is one sentence.** Plain English, ≤ 800 chars; reference the
66
+ specific analysis fields that drove the action choice.
67
+
68
+ 7. **`summary` is one paragraph.** ≤ 800 chars; what the LLM tailored, why, and
69
+ any caveats the operator should know.
70
+
71
+ ## Inputs
72
+
73
+ ### Resolved critic profile
74
+
75
+ `{{CRITIC_PROFILE}}`
76
+
77
+ (The phase-c seeder reads this resolved profile to emit the matching .agent-review/config.json; phase B's role is to thread it, not to emit the JSON.)
78
+
79
+ ### RepoAnalysis
80
+
81
+ ```json
82
+ {{ANALYSIS_JSON}}
83
+ ```
84
+
85
+ ### Template file list (path: sizeBytes)
86
+
87
+ {{TEMPLATE_FILE_LIST}}
88
+
89
+ ### Template file bodies
90
+
91
+ {{TEMPLATE_FILE_BODIES}}
92
+
93
+ ## Now emit the `emit_scaffold_plan` tool call.
@@ -0,0 +1,13 @@
1
+ import type { RepoAnalysis } from "./schema.js";
2
+ import type { TemplateFile } from "./template-loader.js";
3
+ export interface RenderedPrompt {
4
+ systemPrompt: string;
5
+ userMessage: string;
6
+ }
7
+ export interface RenderScaffoldPromptOptions {
8
+ /** Resolved critic profile (B-D8). Substituted into the system prompt's `{{CRITIC_PROFILE}}` placeholder so the LLM's `.agent-review/config.json` tailoring uses the right fleet. */
9
+ profile: "local" | "cloud";
10
+ }
11
+ export declare function renderScaffoldPromptSync(asset: string, analysis: RepoAnalysis, templateFiles: TemplateFile[], opts: RenderScaffoldPromptOptions): RenderedPrompt;
12
+ export declare function renderScaffoldPrompt(analysis: RepoAnalysis, templateFiles: TemplateFile[], opts: RenderScaffoldPromptOptions): Promise<RenderedPrompt>;
13
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/onboard/prompts.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAYzD,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,qLAAqL;IACrL,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;CAC5B;AAcD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,EACtB,aAAa,EAAE,YAAY,EAAE,EAC7B,IAAI,EAAE,2BAA2B,GAChC,cAAc,CAsBhB;AAED,wBAAsB,oBAAoB,CACxC,QAAQ,EAAE,YAAY,EACtB,aAAa,EAAE,YAAY,EAAE,EAC7B,IAAI,EAAE,2BAA2B,GAChC,OAAO,CAAC,cAAc,CAAC,CAGzB"}