@momentiq/dark-factory-cli 2.16.0 → 2.18.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 (67) hide show
  1. package/dist/adapters/codex-sdk.d.ts +30 -5
  2. package/dist/adapters/codex-sdk.d.ts.map +1 -1
  3. package/dist/adapters/codex-sdk.js +50 -15
  4. package/dist/adapters/codex-sdk.js.map +1 -1
  5. package/dist/branch-protection/audit_branch_protection.py +80 -2
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +14 -0
  8. package/dist/cli.js.map +1 -1
  9. package/dist/commands/mode.d.ts +2 -0
  10. package/dist/commands/mode.d.ts.map +1 -0
  11. package/dist/commands/mode.js +110 -0
  12. package/dist/commands/mode.js.map +1 -0
  13. package/dist/commands/objectives.d.ts.map +1 -1
  14. package/dist/commands/objectives.js +3 -3
  15. package/dist/commands/objectives.js.map +1 -1
  16. package/dist/commands/onboard.d.ts.map +1 -1
  17. package/dist/commands/onboard.js +3 -1
  18. package/dist/commands/onboard.js.map +1 -1
  19. package/dist/doctor.d.ts +1 -0
  20. package/dist/doctor.d.ts.map +1 -1
  21. package/dist/doctor.js +155 -7
  22. package/dist/doctor.js.map +1 -1
  23. package/dist/handoff/rehydrate-contract.d.ts +10 -0
  24. package/dist/handoff/rehydrate-contract.d.ts.map +1 -0
  25. package/dist/handoff/rehydrate-contract.js +73 -0
  26. package/dist/handoff/rehydrate-contract.js.map +1 -0
  27. package/dist/mcp/cycle-doc/parser.d.ts +25 -0
  28. package/dist/mcp/cycle-doc/parser.d.ts.map +1 -1
  29. package/dist/mcp/cycle-doc/parser.js +163 -11
  30. package/dist/mcp/cycle-doc/parser.js.map +1 -1
  31. package/dist/mcp/prompts.d.ts.map +1 -1
  32. package/dist/mcp/prompts.js +4 -39
  33. package/dist/mcp/prompts.js.map +1 -1
  34. package/dist/mcp/tools/handoff.d.ts.map +1 -1
  35. package/dist/mcp/tools/handoff.js +11 -2
  36. package/dist/mcp/tools/handoff.js.map +1 -1
  37. package/dist/mode/init.d.ts +17 -0
  38. package/dist/mode/init.d.ts.map +1 -0
  39. package/dist/mode/init.js +138 -0
  40. package/dist/mode/init.js.map +1 -0
  41. package/dist/mode/resolve.d.ts +24 -0
  42. package/dist/mode/resolve.d.ts.map +1 -0
  43. package/dist/mode/resolve.js +49 -0
  44. package/dist/mode/resolve.js.map +1 -0
  45. package/dist/mode/status.d.ts +14 -0
  46. package/dist/mode/status.d.ts.map +1 -0
  47. package/dist/mode/status.js +20 -0
  48. package/dist/mode/status.js.map +1 -0
  49. package/dist/onboard/prompts/scaffold.md +13 -0
  50. package/dist/onboard/seeders/design-md.d.ts +3 -0
  51. package/dist/onboard/seeders/design-md.d.ts.map +1 -0
  52. package/dist/onboard/seeders/design-md.js +138 -0
  53. package/dist/onboard/seeders/design-md.js.map +1 -0
  54. package/dist/onboard/seeders/index.d.ts +8 -0
  55. package/dist/onboard/seeders/index.d.ts.map +1 -1
  56. package/dist/onboard/seeders/index.js +3 -0
  57. package/dist/onboard/seeders/index.js.map +1 -1
  58. package/dist/onboard/validate.d.ts +17 -0
  59. package/dist/onboard/validate.d.ts.map +1 -1
  60. package/dist/onboard/validate.js +63 -42
  61. package/dist/onboard/validate.js.map +1 -1
  62. package/dist/skills/config.d.ts +15 -12
  63. package/dist/skills/config.d.ts.map +1 -1
  64. package/dist/skills/config.js +5 -0
  65. package/dist/skills/config.js.map +1 -1
  66. package/package.json +3 -3
  67. package/skills/objectives/SKILL.md.tmpl +19 -6
@@ -0,0 +1,24 @@
1
+ import type { DarkFactoryConfig, ModeConfig } from "@momentiq/dark-factory-schemas";
2
+ /**
3
+ * Pure precedence resolver. The CLI arg map can contain `mode` as a string
4
+ * (the value), `true` (bare `--mode` with no value), or be absent. The env
5
+ * map is `process.env` shape. Whitespace-trimmed; empty strings fall
6
+ * through. Returns `undefined` when no mode is selected.
7
+ */
8
+ export declare function resolveMode(args: {
9
+ mode?: string | boolean | undefined;
10
+ }, env: {
11
+ DF_MODE?: string | undefined;
12
+ }): string | undefined;
13
+ /**
14
+ * The result of applying a resolved mode name against the loaded
15
+ * darkfactory.yaml. Unlike the profile axis there is no back-compat
16
+ * pass-through: a mode name is meaningless without its guardrail catalog,
17
+ * so both "no catalog" and "name not in catalog" fail loudly.
18
+ */
19
+ export interface ResolvedMode {
20
+ modeName: string;
21
+ mode: ModeConfig;
22
+ }
23
+ export declare function resolveModeWithConfig(config: DarkFactoryConfig, modeName: string): ResolvedMode;
24
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/mode/resolve.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAEpF;;;;;GAKG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;CAAE,EAC7C,GAAG,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACpC,MAAM,GAAG,SAAS,CAYpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,iBAAiB,EACzB,QAAQ,EAAE,MAAM,GACf,YAAY,CAiBd"}
@@ -0,0 +1,49 @@
1
+ // Cycle 27 Phase A — `DF_MODE` / `--mode` operator-axis resolution.
2
+ //
3
+ // Selects an OPERATOR mode (Designer Mode first) from the `modes` catalog in
4
+ // darkfactory.yaml. This is deliberately a SEPARATE axis from the critic-fleet
5
+ // profile selector (`--profile` / `AGENT_REVIEW_PROFILE` / policy/profile.ts):
6
+ // a mode says who is driving the session and which guardrails apply; a profile
7
+ // says which critic fleet reviews the commit. Neither reads the other's inputs.
8
+ //
9
+ // Selection precedence (highest → lowest):
10
+ // 1. CLI `--mode <name>` flag.
11
+ // 2. `DF_MODE` env var.
12
+ // 3. No mode — unlike profiles there is NO default: an unmoded session is
13
+ // the normal engineer path, so absence must stay meaningful.
14
+ /**
15
+ * Pure precedence resolver. The CLI arg map can contain `mode` as a string
16
+ * (the value), `true` (bare `--mode` with no value), or be absent. The env
17
+ * map is `process.env` shape. Whitespace-trimmed; empty strings fall
18
+ * through. Returns `undefined` when no mode is selected.
19
+ */
20
+ export function resolveMode(args, env) {
21
+ const flagRaw = args.mode;
22
+ if (typeof flagRaw === "string") {
23
+ const trimmed = flagRaw.trim();
24
+ if (trimmed.length > 0)
25
+ return trimmed;
26
+ }
27
+ const envRaw = env.DF_MODE;
28
+ if (typeof envRaw === "string") {
29
+ const trimmed = envRaw.trim();
30
+ if (trimmed.length > 0)
31
+ return trimmed;
32
+ }
33
+ return undefined;
34
+ }
35
+ export function resolveModeWithConfig(config, modeName) {
36
+ if (!config.modes) {
37
+ throw new Error(`df mode: no \`modes\` catalog in darkfactory.yaml — mode "${modeName}" ` +
38
+ `cannot be resolved. Run \`df mode init ${modeName}\` to seed one.`);
39
+ }
40
+ const mode = config.modes[modeName];
41
+ if (!mode) {
42
+ const available = Object.keys(config.modes);
43
+ throw new Error(`df mode: unknown mode "${modeName}". ` +
44
+ `Available modes: ${available.length > 0 ? available.join(", ") : "(none)"}. ` +
45
+ `Set via --mode <name> or DF_MODE=<name>; no mode is the default.`);
46
+ }
47
+ return { modeName, mode };
48
+ }
49
+ //# sourceMappingURL=resolve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/mode/resolve.ts"],"names":[],"mappings":"AAAA,oEAAoE;AACpE,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,+EAA+E;AAC/E,+EAA+E;AAC/E,gFAAgF;AAChF,EAAE;AACF,2CAA2C;AAC3C,iCAAiC;AACjC,0BAA0B;AAC1B,4EAA4E;AAC5E,kEAAkE;AAIlE;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CACzB,IAA6C,EAC7C,GAAqC;IAErC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC;IAC1B,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,OAAO,CAAC;IACzC,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC;IAC3B,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9B,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,OAAO,CAAC;IACzC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAaD,MAAM,UAAU,qBAAqB,CACnC,MAAyB,EACzB,QAAgB;IAEhB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CACb,6DAA6D,QAAQ,IAAI;YACvE,0CAA0C,QAAQ,iBAAiB,CACtE,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,0BAA0B,QAAQ,KAAK;YACrC,oBAAoB,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI;YAC9E,kEAAkE,CACrE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,14 @@
1
+ import { type ModeConfig } from "@momentiq/dark-factory-schemas";
2
+ export type ModeStatusResult = {
3
+ active: false;
4
+ } | {
5
+ active: true;
6
+ modeName: string;
7
+ mode: ModeConfig;
8
+ };
9
+ export declare function modeStatus(repoRoot: string, args: {
10
+ mode?: string | boolean | undefined;
11
+ }, env: {
12
+ DF_MODE?: string | undefined;
13
+ }): ModeStatusResult;
14
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/mode/status.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,gCAAgC,CAAC;AAIxC,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,KAAK,CAAA;CAAE,GACjB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzD,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAA;CAAE,EAC7C,GAAG,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACpC,gBAAgB,CAWlB"}
@@ -0,0 +1,20 @@
1
+ // Cycle 27 Phase A — `df mode status`: report the session's active operator
2
+ // mode. "No mode" is the normal engineer path, not an error.
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { parse as parseYaml } from "yaml";
6
+ import { parseDarkFactoryConfig, } from "@momentiq/dark-factory-schemas";
7
+ import { resolveMode, resolveModeWithConfig } from "./resolve.js";
8
+ export function modeStatus(repoRoot, args, env) {
9
+ const modeName = resolveMode(args, env);
10
+ if (!modeName)
11
+ return { active: false };
12
+ const configPath = join(repoRoot, "darkfactory.yaml");
13
+ const raw = existsSync(configPath)
14
+ ? (parseYaml(readFileSync(configPath, "utf8")) ?? {})
15
+ : {};
16
+ const config = parseDarkFactoryConfig(raw);
17
+ const resolved = resolveModeWithConfig(config, modeName);
18
+ return { active: true, modeName: resolved.modeName, mode: resolved.mode };
19
+ }
20
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/mode/status.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,6DAA6D;AAE7D,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EACL,sBAAsB,GAEvB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAMlE,MAAM,UAAU,UAAU,CACxB,QAAgB,EAChB,IAA6C,EAC7C,GAAqC;IAErC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACxC,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC;IAExC,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;IACtD,MAAM,GAAG,GAAY,UAAU,CAAC,UAAU,CAAC;QACzC,CAAC,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACrD,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,MAAM,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC3C,MAAM,QAAQ,GAAG,qBAAqB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACzD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC5E,CAAC"}
@@ -55,6 +55,19 @@ For every file in the input template, choose exactly ONE action:
55
55
  When `analysis.docs.hasClaudeMd === true`, use `merge` for `CLAUDE.md`;
56
56
  otherwise use `emit`. Same for `AGENTS.md`.
57
57
 
58
+ 3b. **`AGENTS.md` is canonical; `CLAUDE.md` is a thin overlay.** Put ALL universal
59
+ agent doctrine (build/test commands, conventions, workflow, merge posture,
60
+ architecture) in `AGENTS.md` — it must stand alone. Most coding agents
61
+ (OpenCode, Codex, Cursor, Copilot, Gemini) read ONLY `AGENTS.md` and ignore
62
+ `CLAUDE.md` when both exist, so doctrine placed only in `CLAUDE.md` is invisible
63
+ to them. The `CLAUDE.md` content you emit must therefore be a thin overlay:
64
+ an `@AGENTS.md` import line (Claude Code expands it at load) followed by ONLY
65
+ genuinely Claude-Code-specific config (model defaults, Claude-only tool names).
66
+ Never restate universal doctrine in `CLAUDE.md` — that duplicates `AGENTS.md`
67
+ and drifts. For a `merge` into an existing `CLAUDE.md`, append a short overlay
68
+ section that points to `AGENTS.md` as canonical; for an `emit`, the body is
69
+ `@AGENTS.md` + the Claude-only section.
70
+
58
71
  4. **Skip when the target already covers it.** If `analysis.dfPresence.configJson === true`,
59
72
  skip `.agent-review/config.json` — don't fight the existing gate. If
60
73
  `analysis.dfPresence.prWorkflow === true`, skip `dark-factory-pr.yml`. Cite
@@ -0,0 +1,3 @@
1
+ import type { Seeder } from "./index.js";
2
+ export declare const designMdSeeder: Seeder;
3
+ //# sourceMappingURL=design-md.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-md.d.ts","sourceRoot":"","sources":["../../../src/onboard/seeders/design-md.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,YAAY,CAAC;AAoGtD,eAAO,MAAM,cAAc,EAAE,MA0B5B,CAAC"}
@@ -0,0 +1,138 @@
1
+ // packages/cli/src/onboard/seeders/design-md.ts
2
+ //
3
+ // DESIGN.md seeder — cycle 27 Phase A.
4
+ //
5
+ // Every DF-onboarded repo carries a DESIGN.md (Google Labs open DESIGN.md
6
+ // spec, Apr 2026): machine-readable design tokens as a YAML frontmatter
7
+ // block + human-readable design intent underneath — the design-side sibling
8
+ // of AGENTS.md. Deterministic emitter:
9
+ //
10
+ // - UI repo (react/next/vue/svelte/angular/... in `analysis.dependencies`)
11
+ // → full skeleton with token placeholders + a reuse-existing-components
12
+ // mandate (the guidance Designer Mode's persona and the chief-designer
13
+ // critic bind to).
14
+ // - No UI dependencies → minimal declaration that the repo currently has
15
+ // no UI surface, so agents don't invent one; the skeleton upgrades when
16
+ // a UI lands.
17
+ // - Repo already has a DESIGN.md → explicit `skip` plan (observability in
18
+ // the onboard dry-run rendering), never overwrite.
19
+ const UI_DEPENDENCY_NAMES = new Set([
20
+ "react",
21
+ "react-dom",
22
+ "next",
23
+ "vue",
24
+ "nuxt",
25
+ "svelte",
26
+ "@sveltejs/kit",
27
+ "solid-js",
28
+ "preact",
29
+ "astro",
30
+ "@angular/core",
31
+ ]);
32
+ function hasUiSurface(input) {
33
+ const deps = input.analysis
34
+ .dependencies;
35
+ if (!Array.isArray(deps))
36
+ return false;
37
+ return deps.some((d) => UI_DEPENDENCY_NAMES.has(d.name));
38
+ }
39
+ function repoName(input) {
40
+ const name = input.analysis.repo?.name;
41
+ return name && name.length > 0 ? name : "this repo";
42
+ }
43
+ const TOKEN_FRONTMATTER = `---
44
+ # DESIGN.md — machine-readable design tokens (Google Labs DESIGN.md spec).
45
+ # Replace the placeholder values below with your product's real tokens;
46
+ # agents treat this block as the single source of design truth.
47
+ colors:
48
+ primary: "#4f46e5"
49
+ surface: "#ffffff"
50
+ text: "#111827"
51
+ muted: "#6b7280"
52
+ typography:
53
+ body:
54
+ family: "system-ui"
55
+ size: "16px"
56
+ lineHeight: 1.5
57
+ heading:
58
+ family: "system-ui"
59
+ weight: 600
60
+ spacing:
61
+ unit: "4px"
62
+ scale: [4, 8, 12, 16, 24, 32, 48]
63
+ components:
64
+ policy: "reuse existing components before creating new ones"
65
+ ---
66
+ `;
67
+ function uiBody(name) {
68
+ return `${TOKEN_FRONTMATTER}
69
+ # ${name} — Design System
70
+
71
+ Seeded by \`df onboard\` (cycle 27). This file is the design-side sibling of
72
+ AGENTS.md: coding agents read it before generating or changing UI, and the
73
+ design-lens critics review against it. Keep it truthful — placeholder tokens
74
+ that don't match the product are worse than none.
75
+
76
+ ## Design Philosophy
77
+
78
+ Describe, in a few sentences, what the product should feel like and why.
79
+ Agents use this to make the thousand small calls tokens can't encode.
80
+
81
+ ## Visual Theme & Atmosphere
82
+
83
+ Describe density, tone, motion, and imagery expectations.
84
+
85
+ ## Do's and Don'ts
86
+
87
+ - DO reuse existing components before creating new ones — extend, don't fork.
88
+ - DO take every color, font, and spacing value from the tokens above.
89
+ - DON'T introduce new colors, fonts, or spacing values outside the tokens.
90
+ - DON'T remove accessibility affordances (focus rings, labels, contrast).
91
+ `;
92
+ }
93
+ function noUiBody(name) {
94
+ return `${TOKEN_FRONTMATTER}
95
+ # ${name} — Design System
96
+
97
+ Seeded by \`df onboard\` (cycle 27). ${name} currently exposes **no UI
98
+ surface** — no UI framework was detected among its dependencies. Agents must
99
+ not invent one. If a UI lands later, replace the placeholder tokens above
100
+ with real values and expand the sections below.
101
+
102
+ ## Design Philosophy
103
+
104
+ (No UI surface yet.)
105
+
106
+ ## Do's and Don'ts
107
+
108
+ - DON'T scaffold UI components in this repo without an approved plan.
109
+ - DO update this file in the same PR that introduces any UI surface.
110
+ `;
111
+ }
112
+ export const designMdSeeder = {
113
+ name: "design-md",
114
+ async seed(input) {
115
+ if (input.designMdExists) {
116
+ return [
117
+ {
118
+ path: "DESIGN.md",
119
+ action: "skip",
120
+ rationale: "DESIGN.md already present at repo root — df never overwrites a hand-maintained design doctrine file.",
121
+ },
122
+ ];
123
+ }
124
+ const name = repoName(input);
125
+ const ui = hasUiSurface(input);
126
+ return [
127
+ {
128
+ path: "DESIGN.md",
129
+ action: "emit",
130
+ rationale: ui
131
+ ? "UI dependencies detected — seed the Google Labs DESIGN.md skeleton (token frontmatter + design intent) so agents and design-lens critics share one design source of truth."
132
+ : "No UI dependencies detected — seed a minimal DESIGN.md declaring the absence of a UI surface so agents don't invent one.",
133
+ tailored_content: ui ? uiBody(name) : noUiBody(name),
134
+ },
135
+ ];
136
+ },
137
+ };
138
+ //# sourceMappingURL=design-md.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"design-md.js","sourceRoot":"","sources":["../../../src/onboard/seeders/design-md.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,uCAAuC;AACvC,EAAE;AACF,0EAA0E;AAC1E,wEAAwE;AACxE,4EAA4E;AAC5E,uCAAuC;AACvC,EAAE;AACF,4EAA4E;AAC5E,2EAA2E;AAC3E,0EAA0E;AAC1E,sBAAsB;AACtB,0EAA0E;AAC1E,2EAA2E;AAC3E,iBAAiB;AACjB,2EAA2E;AAC3E,sDAAsD;AAKtD,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,OAAO;IACP,WAAW;IACX,MAAM;IACN,KAAK;IACL,MAAM;IACN,QAAQ;IACR,eAAe;IACf,UAAU;IACV,QAAQ;IACR,OAAO;IACP,eAAe;CAChB,CAAC,CAAC;AAEH,SAAS,YAAY,CAAC,KAAkB;IACtC,MAAM,IAAI,GAAI,KAAK,CAAC,QAAuD;SACxE,YAAY,CAAC;IAChB,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACvC,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,QAAQ,CAAC,KAAkB;IAClC,MAAM,IAAI,GAAI,KAAK,CAAC,QAAyC,CAAC,IAAI,EAAE,IAAI,CAAC;IACzE,OAAO,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC;AACtD,CAAC;AAED,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuBzB,CAAC;AAEF,SAAS,MAAM,CAAC,IAAY;IAC1B,OAAO,GAAG,iBAAiB;IACzB,IAAI;;;;;;;;;;;;;;;;;;;;;;CAsBP,CAAC;AACF,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,GAAG,iBAAiB;IACzB,IAAI;;uCAE+B,IAAI;;;;;;;;;;;;;CAa1C,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAW;IACpC,IAAI,EAAE,WAAW;IACjB,KAAK,CAAC,IAAI,CAAC,KAAkB;QAC3B,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;YACzB,OAAO;gBACL;oBACE,IAAI,EAAE,WAAW;oBACjB,MAAM,EAAE,MAAM;oBACd,SAAS,EACP,sGAAsG;iBACzG;aACF,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC7B,MAAM,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC/B,OAAO;YACL;gBACE,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE,MAAM;gBACd,SAAS,EAAE,EAAE;oBACX,CAAC,CAAC,4KAA4K;oBAC9K,CAAC,CAAC,0HAA0H;gBAC9H,gBAAgB,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;aACrD;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import type { FilePlan } from "../scaffold-schema.js";
2
2
  import type { RepoAnalysis } from "../schema.js";
3
+ import { designMdSeeder } from "./design-md.js";
3
4
  export type { FilePlan } from "../scaffold-schema.js";
4
5
  /**
5
6
  * Input to a Phase C seeder.
@@ -23,6 +24,12 @@ export interface SeederInput {
23
24
  readonly existingRunbooks?: readonly string[];
24
25
  readonly now: Date;
25
26
  readonly profile?: "local" | "cloud";
27
+ /**
28
+ * True when the target repo already has a root DESIGN.md (cycle 27 —
29
+ * the design-md seeder must skip rather than overwrite). Populated by
30
+ * `cmdOnboard`; optional so prose-seeder unit tests need not set it.
31
+ */
32
+ readonly designMdExists?: boolean;
26
33
  }
27
34
  export interface Seeder {
28
35
  readonly name: string;
@@ -39,6 +46,7 @@ export { adrSeeder } from "./adr.js";
39
46
  export { cycle1BootstrapSeeder } from "./cycle1-bootstrap.js";
40
47
  export { runbookSeeder } from "./runbook.js";
41
48
  export { agentReviewConfigSeeder } from "./agent-review-config.js";
49
+ export { designMdSeeder };
42
50
  /**
43
51
  * The canonical seeder set wired into `cmdOnboard` (Task 4.5). Order is
44
52
  * presentation-only — `runSeeders` runs them concurrently.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/onboard/seeders/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAOjD,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;IACnB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC/C;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAcrB;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAKhD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/onboard/seeders/index.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAMjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtD;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;IAChC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;IACnB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;CAC/C;AAED;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,WAAW,EAClB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,EAAE,CAAC,CAcrB;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAMhD,CAAC"}
@@ -2,6 +2,7 @@ import { adrSeeder } from "./adr.js";
2
2
  import { cycle1BootstrapSeeder } from "./cycle1-bootstrap.js";
3
3
  import { runbookSeeder } from "./runbook.js";
4
4
  import { agentReviewConfigSeeder } from "./agent-review-config.js";
5
+ import { designMdSeeder } from "./design-md.js";
5
6
  /**
6
7
  * Run every seeder in parallel, isolating individual failures to stderr so a
7
8
  * single broken seeder does NOT block the rest of the merge. Phase C seeders
@@ -24,6 +25,7 @@ export { adrSeeder } from "./adr.js";
24
25
  export { cycle1BootstrapSeeder } from "./cycle1-bootstrap.js";
25
26
  export { runbookSeeder } from "./runbook.js";
26
27
  export { agentReviewConfigSeeder } from "./agent-review-config.js";
28
+ export { designMdSeeder };
27
29
  /**
28
30
  * The canonical seeder set wired into `cmdOnboard` (Task 4.5). Order is
29
31
  * presentation-only — `runSeeders` runs them concurrently.
@@ -33,5 +35,6 @@ export const ALL_SEEDERS_DEFAULT = [
33
35
  cycle1BootstrapSeeder,
34
36
  runbookSeeder,
35
37
  agentReviewConfigSeeder,
38
+ designMdSeeder,
36
39
  ];
37
40
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/onboard/seeders/index.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAiCnE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAkB,EAClB,OAA0B;IAE1B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,OAAO,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qBAAqB,CAAC,CAAC,IAAI,YAAY,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CACtF,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IACF,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,SAAS;IACT,qBAAqB;IACrB,aAAa;IACb,uBAAuB;CACxB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/onboard/seeders/index.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAuChD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAkB,EAClB,OAA0B;IAE1B,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QACtB,IAAI,CAAC;YACH,OAAO,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qBAAqB,CAAC,CAAC,IAAI,YAAY,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CACtF,CAAC;YACF,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IACF,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAsB;IACpD,SAAS;IACT,qBAAqB;IACrB,aAAa;IACb,uBAAuB;IACvB,cAAc;CACf,CAAC"}
@@ -16,4 +16,21 @@ export interface CheckAgentContextSetOptions {
16
16
  guidanceFiles: readonly string[] | undefined;
17
17
  }
18
18
  export declare function checkAgentContextSet(opts: CheckAgentContextSetOptions): Promise<DoctorCheck[]>;
19
+ export interface CheckDesignMdOptions {
20
+ repoRoot: string;
21
+ }
22
+ /**
23
+ * Cycle 27 Phase A — `agent_context.design_md`.
24
+ *
25
+ * DESIGN.md (Google Labs open spec) is the design-side sibling of AGENTS.md.
26
+ * Advisory for repos without a designer mode: a missing file PASSES with a
27
+ * recommendation. REQUIRED once `darkfactory.yaml` declares `modes.designer`:
28
+ * the Designer Mode persona and design-lens critics bind to this file, so its
29
+ * absence is a real gap and FAILS with remediation.
30
+ *
31
+ * Config read is deliberately tolerant (raw YAML key probe, not the strict
32
+ * canonical parser): a malformed darkfactory.yaml must surface through its
33
+ * own checks, not turn this one into a crash.
34
+ */
35
+ export declare function checkDesignMd(opts: CheckDesignMdOptions): Promise<DoctorCheck>;
19
36
  //# sourceMappingURL=validate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/onboard/validate.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAElE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;OAWG;IACH,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC9C;AA2DD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,2BAA2B,GAChC,OAAO,CAAC,WAAW,EAAE,CAAC,CA+DxB"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/onboard/validate.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAElE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;;OAWG;IACH,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC9C;AAmCD,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,2BAA2B,GAChC,OAAO,CAAC,WAAW,EAAE,CAAC,CA6DxB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,WAAW,CAAC,CAkCtB"}
@@ -1,51 +1,37 @@
1
1
  // Cycle 15 Phase C — `checkAgentContextSet()` for `df doctor`.
2
2
  //
3
- // Walks the cycle-15 D3 required-files set (CLAUDE.md, AGENTS.md,
4
- // .claude/settings.json, docs/PRINCIPLES.md, docs/roadmap/cycles/cycle1-*.md,
5
- // .agent-review/config.json) UNCONDITIONALLY, then optionally validates each
6
- // path in `context.guidanceFiles` (from the loaded AgentReviewConfig) resolves
7
- // to a real file under `repoRoot`.
3
+ // Walks the universal Dark-Factory required-files floor (CLAUDE.md, AGENTS.md,
4
+ // .claude/settings.json, .agent-review/config.json) UNCONDITIONALLY, then
5
+ // optionally validates each path in `context.guidanceFiles` (from the loaded
6
+ // AgentReviewConfig) resolves to a real file under `repoRoot`.
8
7
  //
9
8
  // Per Decision #7 (round-1 revision): the required-files walk runs regardless
10
- // of whether `context.guidanceFiles` is configured — the D3 set is the floor.
11
- // The guidance-file walk is opt-in: when `guidanceFiles` is undefined OR `[]`,
12
- // a single `agent_context.guidance_not_configured` informational marker is
13
- // emitted (passed: true, optional: true) so operators see the field was
14
- // skipped rather than silently absent.
9
+ // of whether `context.guidanceFiles` is configured — the universal floor is
10
+ // not opt-in. The guidance-file walk is opt-in: when `guidanceFiles` is
11
+ // undefined OR `[]`, a single `agent_context.guidance_not_configured`
12
+ // informational marker is emitted (passed: true, optional: true) so operators
13
+ // see the field was skipped rather than silently absent.
15
14
  //
16
15
  // Cycle 15 exit-criterion lines 297–303: "the post-apply check fails loudly
17
- // when any of [list] are missing or unwired (`context.guidanceFiles` does not
18
- // point at real files). All current repos must pass `df doctor` after this
19
- // lands."
20
- import { access, readdir } from "node:fs/promises";
16
+ // when any of [the universal floor] are missing or unwired (`context.guidanceFiles`
17
+ // does not point at real files). All current repos must pass `df doctor` after
18
+ // this lands."
19
+ import { access, readFile } from "node:fs/promises";
21
20
  import { constants } from "node:fs";
22
21
  import { resolve } from "node:path";
22
+ import { parse as parseYaml } from "yaml";
23
23
  const REQUIRED_FILES = [
24
- { key: "claude_md", name: "CLAUDE.md", path: "CLAUDE.md", isGlob: false },
25
- { key: "agents_md", name: "AGENTS.md", path: "AGENTS.md", isGlob: false },
24
+ { key: "claude_md", name: "CLAUDE.md", path: "CLAUDE.md" },
25
+ { key: "agents_md", name: "AGENTS.md", path: "AGENTS.md" },
26
26
  {
27
27
  key: "claude_settings",
28
28
  name: ".claude/settings.json",
29
29
  path: ".claude/settings.json",
30
- isGlob: false,
31
- },
32
- {
33
- key: "principles",
34
- name: "docs/PRINCIPLES.md",
35
- path: "docs/PRINCIPLES.md",
36
- isGlob: false,
37
- },
38
- {
39
- key: "cycle1_bootstrap",
40
- name: "docs/roadmap/cycles/cycle1-*.md",
41
- path: "docs/roadmap/cycles",
42
- isGlob: true,
43
30
  },
44
31
  {
45
32
  key: "config",
46
33
  name: ".agent-review/config.json",
47
34
  path: ".agent-review/config.json",
48
- isGlob: false,
49
35
  },
50
36
  ];
51
37
  async function fileExists(path) {
@@ -57,15 +43,6 @@ async function fileExists(path) {
57
43
  return false;
58
44
  }
59
45
  }
60
- async function cycle1GlobMatches(dir) {
61
- try {
62
- const entries = await readdir(dir);
63
- return entries.some((name) => /^cycle1-.*\.md$/.test(name));
64
- }
65
- catch {
66
- return false;
67
- }
68
- }
69
46
  const REMEDIATION = "run `df onboard --apply` to generate the missing agent-context files, or restore the file from version control";
70
47
  export async function checkAgentContextSet(opts) {
71
48
  const out = [];
@@ -76,9 +53,7 @@ export async function checkAgentContextSet(opts) {
76
53
  // fail when CLAUDE.md is missing.
77
54
  for (const req of REQUIRED_FILES) {
78
55
  const fullPath = resolve(opts.repoRoot, req.path);
79
- const exists = req.isGlob
80
- ? await cycle1GlobMatches(fullPath)
81
- : await fileExists(fullPath);
56
+ const exists = await fileExists(fullPath);
82
57
  out.push(exists
83
58
  ? {
84
59
  name: `agent_context.${req.key}`,
@@ -124,4 +99,50 @@ export async function checkAgentContextSet(opts) {
124
99
  }
125
100
  return out;
126
101
  }
102
+ /**
103
+ * Cycle 27 Phase A — `agent_context.design_md`.
104
+ *
105
+ * DESIGN.md (Google Labs open spec) is the design-side sibling of AGENTS.md.
106
+ * Advisory for repos without a designer mode: a missing file PASSES with a
107
+ * recommendation. REQUIRED once `darkfactory.yaml` declares `modes.designer`:
108
+ * the Designer Mode persona and design-lens critics bind to this file, so its
109
+ * absence is a real gap and FAILS with remediation.
110
+ *
111
+ * Config read is deliberately tolerant (raw YAML key probe, not the strict
112
+ * canonical parser): a malformed darkfactory.yaml must surface through its
113
+ * own checks, not turn this one into a crash.
114
+ */
115
+ export async function checkDesignMd(opts) {
116
+ const designPath = resolve(opts.repoRoot, "DESIGN.md");
117
+ const exists = await fileExists(designPath);
118
+ if (exists) {
119
+ return {
120
+ name: "agent_context.design_md",
121
+ passed: true,
122
+ detail: `DESIGN.md present at ${designPath}`,
123
+ };
124
+ }
125
+ let designerConfigured = false;
126
+ try {
127
+ const raw = await readFile(resolve(opts.repoRoot, "darkfactory.yaml"), "utf8");
128
+ const parsed = parseYaml(raw);
129
+ designerConfigured = parsed?.modes?.["designer"] !== undefined;
130
+ }
131
+ catch {
132
+ // Missing or unreadable darkfactory.yaml → no designer mode configured.
133
+ }
134
+ if (designerConfigured) {
135
+ return {
136
+ name: "agent_context.design_md",
137
+ passed: false,
138
+ detail: `DESIGN.md missing at ${designPath} — required: darkfactory.yaml declares modes.designer, whose persona and design-lens critics bind to it`,
139
+ remediation: "run `df onboard --apply` to seed a DESIGN.md skeleton (Google Labs spec), or author one at the repo root",
140
+ };
141
+ }
142
+ return {
143
+ name: "agent_context.design_md",
144
+ passed: true,
145
+ detail: `DESIGN.md not present at ${designPath} (advisory — recommended agent-context file; becomes required once a designer mode is configured)`,
146
+ };
147
+ }
127
148
  //# sourceMappingURL=validate.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/onboard/validate.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,kEAAkE;AAClE,8EAA8E;AAC9E,6EAA6E;AAC7E,+EAA+E;AAC/E,mCAAmC;AACnC,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,+EAA+E;AAC/E,2EAA2E;AAC3E,wEAAwE;AACxE,uCAAuC;AACvC,EAAE;AACF,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAC3E,UAAU;AAEV,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA4BpC,MAAM,cAAc,GAA4B;IAC9C,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE;IACzE,EAAE,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE;IACzE;QACE,GAAG,EAAE,iBAAiB;QACtB,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE,uBAAuB;QAC7B,MAAM,EAAE,KAAK;KACd;IACD;QACE,GAAG,EAAE,YAAY;QACjB,IAAI,EAAE,oBAAoB;QAC1B,IAAI,EAAE,oBAAoB;QAC1B,MAAM,EAAE,KAAK;KACd;IACD;QACE,GAAG,EAAE,kBAAkB;QACvB,IAAI,EAAE,iCAAiC;QACvC,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,IAAI;KACb;IACD;QACE,GAAG,EAAE,QAAQ;QACb,IAAI,EAAE,2BAA2B;QACjC,IAAI,EAAE,2BAA2B;QACjC,MAAM,EAAE,KAAK;KACd;CACF,CAAC;AAEF,KAAK,UAAU,UAAU,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,GAAW;IAC1C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,WAAW,GACf,gHAAgH,CAAC;AAEnH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAiC;IAEjC,MAAM,GAAG,GAAkB,EAAE,CAAC;IAE9B,qEAAqE;IACrE,yEAAyE;IACzE,+DAA+D;IAC/D,0EAA0E;IAC1E,kCAAkC;IAClC,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;QACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM;YACvB,CAAC,CAAC,MAAM,iBAAiB,CAAC,QAAQ,CAAC;YACnC,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;QAC/B,GAAG,CAAC,IAAI,CACN,MAAM;YACJ,CAAC,CAAC;gBACE,IAAI,EAAE,iBAAiB,GAAG,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,IAAI;gBACZ,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,eAAe,QAAQ,EAAE;aAC7C;YACH,CAAC,CAAC;gBACE,IAAI,EAAE,iBAAiB,GAAG,CAAC,GAAG,EAAE;gBAChC,MAAM,EAAE,KAAK;gBACb,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,eAAe,QAAQ,EAAE;gBAC5C,WAAW,EAAE,WAAW;aACzB,CACN,CAAC;IACJ,CAAC;IAED,0EAA0E;IAC1E,wEAAwE;IACxE,oBAAoB;IACpB,IAAI,IAAI,CAAC,aAAa,KAAK,SAAS,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxE,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,uCAAuC;YAC7C,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,IAAI;YACd,MAAM,EACJ,oJAAoJ;SACvJ,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACnD,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,CAAE,CAAC;YACnC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;YACzC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YACtC,GAAG,CAAC,IAAI,CACN,MAAM;gBACJ,CAAC,CAAC;oBACE,IAAI,EAAE,0BAA0B,CAAC,EAAE;oBACnC,MAAM,EAAE,IAAI;oBACZ,MAAM,EAAE,iBAAiB,CAAC,MAAM,GAAG,iBAAiB,IAAI,EAAE;iBAC3D;gBACH,CAAC,CAAC;oBACE,IAAI,EAAE,0BAA0B,CAAC,EAAE;oBACnC,MAAM,EAAE,KAAK;oBACb,MAAM,EAAE,iBAAiB,CAAC,MAAM,GAAG,2CAA2C,IAAI,CAAC,QAAQ,EAAE;oBAC7F,WAAW,EAAE,qEAAqE,CAAC,sBAAsB;iBAC1G,CACN,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/onboard/validate.ts"],"names":[],"mappings":"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"}
@@ -6,13 +6,13 @@ export declare const DarkFactoryConfigSchema: z.ZodObject<{
6
6
  slug: z.ZodOptional<z.ZodOptional<z.ZodString>>;
7
7
  ownerRepo: z.ZodOptional<z.ZodOptional<z.ZodString>>;
8
8
  }, "strip", z.ZodTypeAny, {
9
- ownerRepo?: string | undefined;
10
9
  displayName?: string | undefined;
11
10
  slug?: string | undefined;
12
- }, {
13
11
  ownerRepo?: string | undefined;
12
+ }, {
14
13
  displayName?: string | undefined;
15
14
  slug?: string | undefined;
15
+ ownerRepo?: string | undefined;
16
16
  }>>;
17
17
  docs: z.ZodOptional<z.ZodObject<{
18
18
  manifesto: z.ZodOptional<z.ZodOptional<z.ZodString>>;
@@ -57,7 +57,13 @@ export declare const DarkFactoryConfigSchema: z.ZodObject<{
57
57
  }, {
58
58
  enabled?: boolean | undefined;
59
59
  }>>>;
60
+ modes: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
60
61
  }, "strict", z.ZodTypeAny, {
62
+ repo?: {
63
+ displayName?: string | undefined;
64
+ slug?: string | undefined;
65
+ ownerRepo?: string | undefined;
66
+ } | undefined;
61
67
  docs?: {
62
68
  manifesto?: string | undefined;
63
69
  adrDir?: string | undefined;
@@ -65,11 +71,6 @@ export declare const DarkFactoryConfigSchema: z.ZodObject<{
65
71
  rfcDir?: string | undefined;
66
72
  prdDir?: string | undefined;
67
73
  } | undefined;
68
- repo?: {
69
- ownerRepo?: string | undefined;
70
- displayName?: string | undefined;
71
- slug?: string | undefined;
72
- } | undefined;
73
74
  agents?: {
74
75
  chiefEngineer?: string | undefined;
75
76
  } | undefined;
@@ -82,7 +83,13 @@ export declare const DarkFactoryConfigSchema: z.ZodObject<{
82
83
  skills?: Record<string, {
83
84
  enabled?: boolean | undefined;
84
85
  }> | undefined;
86
+ modes?: Record<string, unknown> | undefined;
85
87
  }, {
88
+ repo?: {
89
+ displayName?: string | undefined;
90
+ slug?: string | undefined;
91
+ ownerRepo?: string | undefined;
92
+ } | undefined;
86
93
  docs?: {
87
94
  manifesto?: string | undefined;
88
95
  adrDir?: string | undefined;
@@ -90,11 +97,6 @@ export declare const DarkFactoryConfigSchema: z.ZodObject<{
90
97
  rfcDir?: string | undefined;
91
98
  prdDir?: string | undefined;
92
99
  } | undefined;
93
- repo?: {
94
- ownerRepo?: string | undefined;
95
- displayName?: string | undefined;
96
- slug?: string | undefined;
97
- } | undefined;
98
100
  agents?: {
99
101
  chiefEngineer?: string | undefined;
100
102
  } | undefined;
@@ -107,6 +109,7 @@ export declare const DarkFactoryConfigSchema: z.ZodObject<{
107
109
  skills?: Record<string, {
108
110
  enabled?: boolean | undefined;
109
111
  }> | undefined;
112
+ modes?: Record<string, unknown> | undefined;
110
113
  }>;
111
114
  export type DarkFactoryConfig = z.infer<typeof DarkFactoryConfigSchema>;
112
115
  export interface LoadedDarkFactoryConfig {