cohorte 3.0.0-dev.5 → 3.0.0-dev.7

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 (95) hide show
  1. package/assets/manifest.json +16 -6
  2. package/assets/prompts/agents/brainstormer.md +3 -0
  3. package/assets/prompts/agents/spec-author.md +3 -0
  4. package/assets/schemas/commands.schema.json +7 -0
  5. package/assets/schemas/config.schema.json +22 -0
  6. package/dist/bundle-manifest.json +72 -48
  7. package/dist/chunks/align-ds-r_X_1aQ_.mjs +93 -0
  8. package/dist/chunks/align-ds-r_X_1aQ_.mjs.map +1 -0
  9. package/dist/chunks/audit-B4ZWQ_DI.mjs +179 -0
  10. package/dist/chunks/audit-B4ZWQ_DI.mjs.map +1 -0
  11. package/dist/chunks/brainstorm-DasVwI1D.mjs +123 -0
  12. package/dist/chunks/brainstorm-DasVwI1D.mjs.map +1 -0
  13. package/dist/chunks/build-crOld8gE.mjs +19 -0
  14. package/dist/chunks/build-crOld8gE.mjs.map +1 -0
  15. package/dist/chunks/{catalogue-B5uFqfzJ.mjs → catalogue-IaCJdfB8.mjs} +4 -4
  16. package/dist/chunks/{catalogue-B5uFqfzJ.mjs.map → catalogue-IaCJdfB8.mjs.map} +1 -1
  17. package/dist/chunks/{compose-CKo_q39e.mjs → compose-DRKjQcn0.mjs} +42 -23
  18. package/dist/chunks/compose-DRKjQcn0.mjs.map +1 -0
  19. package/dist/chunks/{config-DefHA2Lw.mjs → config-Cqu5XQoP.mjs} +2 -2
  20. package/dist/chunks/{config-DefHA2Lw.mjs.map → config-Cqu5XQoP.mjs.map} +1 -1
  21. package/dist/chunks/{contract-BkMjU1kR.mjs → contract-DjssDPpS.mjs} +66 -26
  22. package/dist/chunks/contract-DjssDPpS.mjs.map +1 -0
  23. package/dist/chunks/{diff-D_0hBwHl.mjs → diff-Qw0II0sj.mjs} +2 -2
  24. package/dist/chunks/{diff-D_0hBwHl.mjs.map → diff-Qw0II0sj.mjs.map} +1 -1
  25. package/dist/chunks/{discover-BJMwXyGL.mjs → discover-BZPolSZG.mjs} +2 -2
  26. package/dist/chunks/{discover-BJMwXyGL.mjs.map → discover-BZPolSZG.mjs.map} +1 -1
  27. package/dist/chunks/{doctor-CginW8y8.mjs → doctor-DcDFPvQM.mjs} +6 -6
  28. package/dist/chunks/{doctor-CginW8y8.mjs.map → doctor-DcDFPvQM.mjs.map} +1 -1
  29. package/dist/chunks/fix-B_oGzGVn.mjs +82 -0
  30. package/dist/chunks/fix-B_oGzGVn.mjs.map +1 -0
  31. package/dist/chunks/fleet-yWHQY2ya.mjs +297 -0
  32. package/dist/chunks/fleet-yWHQY2ya.mjs.map +1 -0
  33. package/dist/chunks/{init-CP6puNbE.mjs → init--FxxkrcT.mjs} +2 -2
  34. package/dist/chunks/{init-CP6puNbE.mjs.map → init--FxxkrcT.mjs.map} +1 -1
  35. package/dist/chunks/intake-Dd1KVXnO.mjs +12 -0
  36. package/dist/chunks/intake-Dd1KVXnO.mjs.map +1 -0
  37. package/dist/chunks/loop-BWsUpyus.mjs +212 -0
  38. package/dist/chunks/loop-BWsUpyus.mjs.map +1 -0
  39. package/dist/chunks/{migrate-DybihKzZ.mjs → migrate-DuYCAbE3.mjs} +2 -2
  40. package/dist/chunks/{migrate-DybihKzZ.mjs.map → migrate-DuYCAbE3.mjs.map} +1 -1
  41. package/dist/chunks/obsidian-BHLkXx_H.mjs +235 -0
  42. package/dist/chunks/obsidian-BHLkXx_H.mjs.map +1 -0
  43. package/dist/chunks/patch-sAgVqjpx.mjs +50 -0
  44. package/dist/chunks/patch-sAgVqjpx.mjs.map +1 -0
  45. package/dist/chunks/{policy-Clypo20s.mjs → policy-Du7WVBFX.mjs} +4 -4
  46. package/dist/chunks/{policy-Clypo20s.mjs.map → policy-Du7WVBFX.mjs.map} +1 -1
  47. package/dist/chunks/{reconcile-czNaLOP6.mjs → reconcile-BHn66X3C.mjs} +3 -3
  48. package/dist/chunks/{reconcile-czNaLOP6.mjs.map → reconcile-BHn66X3C.mjs.map} +1 -1
  49. package/dist/chunks/refactor-CoNoqLZr.mjs +153 -0
  50. package/dist/chunks/refactor-CoNoqLZr.mjs.map +1 -0
  51. package/dist/chunks/retro-Dr-2RTNN.mjs +78 -0
  52. package/dist/chunks/retro-Dr-2RTNN.mjs.map +1 -0
  53. package/dist/chunks/review-ZsBqp3vZ.mjs +35 -0
  54. package/dist/chunks/review-ZsBqp3vZ.mjs.map +1 -0
  55. package/dist/chunks/{run-CgTWYlcd.mjs → run-NGAxdsIX.mjs} +28 -5
  56. package/dist/chunks/run-NGAxdsIX.mjs.map +1 -0
  57. package/dist/chunks/{schema-C9QbUW4H.mjs → schema-Bq9qtgsd.mjs} +9 -4
  58. package/dist/chunks/schema-Bq9qtgsd.mjs.map +1 -0
  59. package/dist/chunks/ship-BizfUe62.mjs +140 -0
  60. package/dist/chunks/ship-BizfUe62.mjs.map +1 -0
  61. package/dist/chunks/spec-C2h3U64g.mjs +65 -0
  62. package/dist/chunks/spec-C2h3U64g.mjs.map +1 -0
  63. package/dist/chunks/spec-path-tptqR7W8.mjs +10 -0
  64. package/dist/chunks/spec-path-tptqR7W8.mjs.map +1 -0
  65. package/dist/chunks/{src-r0ECB1UJ.mjs → src-Bfr1yzsn.mjs} +3 -3
  66. package/dist/chunks/{src-r0ECB1UJ.mjs.map → src-Bfr1yzsn.mjs.map} +1 -1
  67. package/dist/chunks/{src-DZazJCp1.mjs → src-CPW2_Ons.mjs} +101 -17
  68. package/dist/chunks/src-CPW2_Ons.mjs.map +1 -0
  69. package/dist/chunks/{src-CmFjh4M0.mjs → src-DNsLSxgm.mjs} +2 -2
  70. package/dist/chunks/{src-CmFjh4M0.mjs.map → src-DNsLSxgm.mjs.map} +1 -1
  71. package/dist/chunks/{src-DcU4IXMe.mjs → src-DbS9gkJy.mjs} +2 -2
  72. package/dist/chunks/{src-DcU4IXMe.mjs.map → src-DbS9gkJy.mjs.map} +1 -1
  73. package/dist/chunks/{src-s7YRvk0t.mjs → src-yi5whv3n.mjs} +4 -2
  74. package/dist/chunks/src-yi5whv3n.mjs.map +1 -0
  75. package/dist/chunks/update-pipeline-Du-Gu1Pl.mjs +56 -0
  76. package/dist/chunks/update-pipeline-Du-Gu1Pl.mjs.map +1 -0
  77. package/dist/cli.mjs +29 -18
  78. package/dist/cli.mjs.map +1 -1
  79. package/package.json +1 -1
  80. package/dist/chunks/brainstorm-BwKA6yZP.mjs +0 -7
  81. package/dist/chunks/brainstorm-BwKA6yZP.mjs.map +0 -1
  82. package/dist/chunks/compose-CKo_q39e.mjs.map +0 -1
  83. package/dist/chunks/contract-BkMjU1kR.mjs.map +0 -1
  84. package/dist/chunks/fix-D4Tj8RVA.mjs +0 -18
  85. package/dist/chunks/fix-D4Tj8RVA.mjs.map +0 -1
  86. package/dist/chunks/review-BDdjb6kB.mjs +0 -17
  87. package/dist/chunks/review-BDdjb6kB.mjs.map +0 -1
  88. package/dist/chunks/run-CgTWYlcd.mjs.map +0 -1
  89. package/dist/chunks/schema-C9QbUW4H.mjs.map +0 -1
  90. package/dist/chunks/ship-DTuLGoaJ.mjs +0 -19
  91. package/dist/chunks/ship-DTuLGoaJ.mjs.map +0 -1
  92. package/dist/chunks/spec-Bq0P3jVh.mjs +0 -20
  93. package/dist/chunks/spec-Bq0P3jVh.mjs.map +0 -1
  94. package/dist/chunks/src-DZazJCp1.mjs.map +0 -1
  95. package/dist/chunks/src-s7YRvk0t.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-DybihKzZ.mjs","names":[],"sources":["../../../../apps/cli/src/commands/migrate/index.ts"],"sourcesContent":["// apps/cli/src/commands/migrate/index.ts — DESIGN §9 verb `migrate` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/migrate/**`.\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { rollbackV2Import, type V2ImportReport } from '@cohorte/project-model';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst migrate: CommandModule = {\n verb: 'migrate',\n async run(ctx, args) {\n const rollback = args.positionals.indexOf('--rollback');\n if (rollback !== -1) {\n const reportId = args.positionals[rollback + 1];\n if (!reportId) throw new Error('configuration/import-invalid: migrate --rollback requires a report id');\n const reportPath = join(resolve(ctx.cwd), '.cohorte', 'import-reports', `${reportId}.json`);\n const report = JSON.parse(await readFile(reportPath, 'utf8')) as V2ImportReport;\n const rolledBack = await rollbackV2Import(report);\n await writeFile(reportPath, `${JSON.stringify(rolledBack, null, 2)}\\n`, { mode: 0o600 });\n ctx.stdio.stdout.write(`${JSON.stringify(rolledBack)}\\n`);\n return 0;\n }\n const store = await (ctx.openMigrationStore ?? ctx.openStore)();\n try {\n const apply = args.positionals.includes('--apply');\n const report = await store.migrate(apply ? 'apply' : 'check');\n ctx.stdio.stdout.write(`${JSON.stringify(report)}\\n`);\n return !apply && report.pending.length > 0 ? 3 : 0;\n } finally {\n await store.close();\n }\n },\n};\n\nexport default migrate;\n"],"mappings":";;;;AASA,MAAM,UAAyB;CAC7B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,WAAW,KAAK,YAAY,QAAQ,YAAY;EACtD,IAAI,aAAa,IAAI;GACnB,MAAM,WAAW,KAAK,YAAY,WAAW;GAC7C,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,uEAAuE;GACtG,MAAM,aAAa,KAAK,QAAQ,IAAI,GAAG,GAAG,YAAY,kBAAkB,GAAG,SAAS,MAAM;GAC1F,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,YAAY,MAAM,CAAC;GAC5D,MAAM,aAAa,MAAM,iBAAiB,MAAM;GAChD,MAAM,UAAU,YAAY,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,IAAM,CAAC;GACvF,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,UAAU,EAAE,GAAG;GACxD,OAAO;EACT;EACA,MAAM,QAAQ,OAAO,IAAI,sBAAsB,IAAI,UAAA,CAAW;EAC9D,IAAI;GACF,MAAM,QAAQ,KAAK,YAAY,SAAS,SAAS;GACjD,MAAM,SAAS,MAAM,MAAM,QAAQ,QAAQ,UAAU,OAAO;GAC5D,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;GACpD,OAAO,CAAC,SAAS,OAAO,QAAQ,SAAS,IAAI,IAAI;EACnD,UAAU;GACR,MAAM,MAAM,MAAM;EACpB;CACF;AACF"}
1
+ {"version":3,"file":"migrate-DuYCAbE3.mjs","names":[],"sources":["../../../../apps/cli/src/commands/migrate/index.ts"],"sourcesContent":["// apps/cli/src/commands/migrate/index.ts — DESIGN §9 verb `migrate` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/migrate/**`.\nimport { readFile, writeFile } from 'node:fs/promises';\nimport { join, resolve } from 'node:path';\nimport { rollbackV2Import, type V2ImportReport } from '@cohorte/project-model';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst migrate: CommandModule = {\n verb: 'migrate',\n async run(ctx, args) {\n const rollback = args.positionals.indexOf('--rollback');\n if (rollback !== -1) {\n const reportId = args.positionals[rollback + 1];\n if (!reportId) throw new Error('configuration/import-invalid: migrate --rollback requires a report id');\n const reportPath = join(resolve(ctx.cwd), '.cohorte', 'import-reports', `${reportId}.json`);\n const report = JSON.parse(await readFile(reportPath, 'utf8')) as V2ImportReport;\n const rolledBack = await rollbackV2Import(report);\n await writeFile(reportPath, `${JSON.stringify(rolledBack, null, 2)}\\n`, { mode: 0o600 });\n ctx.stdio.stdout.write(`${JSON.stringify(rolledBack)}\\n`);\n return 0;\n }\n const store = await (ctx.openMigrationStore ?? ctx.openStore)();\n try {\n const apply = args.positionals.includes('--apply');\n const report = await store.migrate(apply ? 'apply' : 'check');\n ctx.stdio.stdout.write(`${JSON.stringify(report)}\\n`);\n return !apply && report.pending.length > 0 ? 3 : 0;\n } finally {\n await store.close();\n }\n },\n};\n\nexport default migrate;\n"],"mappings":";;;;AASA,MAAM,UAAyB;CAC7B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,WAAW,KAAK,YAAY,QAAQ,YAAY;EACtD,IAAI,aAAa,IAAI;GACnB,MAAM,WAAW,KAAK,YAAY,WAAW;GAC7C,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,uEAAuE;GACtG,MAAM,aAAa,KAAK,QAAQ,IAAI,GAAG,GAAG,YAAY,kBAAkB,GAAG,SAAS,MAAM;GAC1F,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,YAAY,MAAM,CAAC;GAC5D,MAAM,aAAa,MAAM,iBAAiB,MAAM;GAChD,MAAM,UAAU,YAAY,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,IAAM,CAAC;GACvF,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,UAAU,EAAE,GAAG;GACxD,OAAO;EACT;EACA,MAAM,QAAQ,OAAO,IAAI,sBAAsB,IAAI,UAAA,CAAW;EAC9D,IAAI;GACF,MAAM,QAAQ,KAAK,YAAY,SAAS,SAAS;GACjD,MAAM,SAAS,MAAM,MAAM,QAAQ,QAAQ,UAAU,OAAO;GAC5D,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;GACpD,OAAO,CAAC,SAAS,OAAO,QAAQ,SAAS,IAAI,IAAI;EACnD,UAAU;GACR,MAAM,MAAM,MAAM;EACpB;CACF;AACF"}
@@ -0,0 +1,235 @@
1
+ import { access, mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname, join, resolve } from "node:path";
3
+ import { parse, stringify } from "yaml";
4
+ //#region \0rolldown/runtime.js
5
+ var __defProp = Object.defineProperty;
6
+ var __exportAll = (all, no_symbols) => {
7
+ let target = {};
8
+ for (var name in all) __defProp(target, name, {
9
+ get: all[name],
10
+ enumerable: true
11
+ });
12
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
13
+ return target;
14
+ };
15
+ //#endregion
16
+ //#region src/commands/obsidian/index.ts
17
+ var obsidian_exports = /* @__PURE__ */ __exportAll({
18
+ configuredIdeas: () => configuredIdeas,
19
+ default: () => obsidian,
20
+ moveConfiguredCard: () => moveConfiguredCard
21
+ });
22
+ const COLUMNS = [
23
+ "Ideas",
24
+ "Brainstorm",
25
+ "Spec",
26
+ "Ready to build",
27
+ "Building",
28
+ "Review",
29
+ "Fix",
30
+ "Ship",
31
+ "Shipped"
32
+ ];
33
+ const STAGES = /* @__PURE__ */ new Map([
34
+ ["ideas", "Ideas"],
35
+ ["brainstorm", "Brainstorm"],
36
+ ["spec", "Spec"],
37
+ ["ready", "Ready to build"],
38
+ ["building", "Building"],
39
+ ["review", "Review"],
40
+ ["fix", "Fix"],
41
+ ["ship", "Ship"],
42
+ ["shipped", "Shipped"]
43
+ ]);
44
+ const BOARD_TEMPLATE = `---
45
+ kanban-plugin: board
46
+ ---
47
+
48
+ ${COLUMNS.map((column) => `## ${column}\n`).join("\n")}
49
+ %% kanban:settings
50
+ \`\`\`
51
+ {"kanban-plugin":"board","list-collapse":[false,false,false,false,false,false,false,false,false]}
52
+ \`\`\`
53
+ %%
54
+ `;
55
+ function parseCards(source) {
56
+ const lines = source.split(/\r?\n/);
57
+ let column = "";
58
+ const cards = [];
59
+ lines.forEach((line, lineIndex) => {
60
+ const heading = /^##\s+(.+?)\s*$/.exec(line);
61
+ if (heading) {
62
+ column = heading[1] ?? "";
63
+ return;
64
+ }
65
+ const card = /^-\s+\[([ xX])\]\s+(.+)$/.exec(line);
66
+ if (!card || !column) return;
67
+ const title = card[2] ?? "";
68
+ const tag = /#([a-z0-9][a-z0-9-]*)\b/i.exec(title);
69
+ if (!tag) return;
70
+ cards.push({
71
+ id: (tag[1] ?? "").toLowerCase(),
72
+ title,
73
+ checked: (card[1] ?? "").toLowerCase() === "x",
74
+ column,
75
+ line: lineIndex
76
+ });
77
+ });
78
+ return cards;
79
+ }
80
+ async function configuredIdeas(home) {
81
+ const resolved = await boardPath(home);
82
+ return parseCards(await readFile(resolved.path, "utf8")).filter((card) => card.column === "Ideas");
83
+ }
84
+ async function loadUserConfig(home) {
85
+ const path = join(home, ".cohorte", "config.yaml");
86
+ try {
87
+ const value = parse(await readFile(path, "utf8"));
88
+ return {
89
+ path,
90
+ value: value && typeof value === "object" ? value : {}
91
+ };
92
+ } catch (error) {
93
+ if (error.code !== "ENOENT") throw error;
94
+ return {
95
+ path,
96
+ value: {}
97
+ };
98
+ }
99
+ }
100
+ function configured(value) {
101
+ const integrations = value.integrations;
102
+ if (!integrations || typeof integrations !== "object") return void 0;
103
+ const obsidian = integrations.obsidian;
104
+ if (!obsidian || typeof obsidian !== "object") return void 0;
105
+ const { vaultPath, board } = obsidian;
106
+ return typeof vaultPath === "string" && typeof board === "string" ? {
107
+ vaultPath,
108
+ board
109
+ } : void 0;
110
+ }
111
+ async function boardPath(home) {
112
+ const config = configured((await loadUserConfig(home)).value);
113
+ if (!config) throw new Error("Obsidian is not configured; run `cohorte obsidian connect <vault> <board>`");
114
+ const path = resolve(config.vaultPath, config.board);
115
+ await access(path);
116
+ return {
117
+ config,
118
+ path
119
+ };
120
+ }
121
+ function replaceCard(source, id, target, title = id) {
122
+ const lines = source.split(/\r?\n/);
123
+ const cards = parseCards(source);
124
+ if (!COLUMNS.includes(target)) throw new Error(`Unknown Obsidian column: ${target}`);
125
+ const matches = cards.filter((item) => item.id === id);
126
+ const card = matches[0];
127
+ if (!card) {
128
+ const heading = lines.indexOf(`## ${target}`);
129
+ if (heading < 0) throw new Error(`Obsidian column ${target} was not found`);
130
+ let insert = heading + 1;
131
+ while (insert < lines.length && !(lines[insert] ?? "").startsWith("## ")) insert++;
132
+ lines.splice(insert, 0, `- [ ] ${title} #${id}`);
133
+ return lines.join("\n");
134
+ }
135
+ for (const duplicate of matches.slice(1).sort((a, b) => b.line - a.line)) lines.splice(duplicate.line, 1);
136
+ if (card.column === target) return lines.join("\n");
137
+ const line = lines[card.line] ?? "";
138
+ lines.splice(card.line, 1);
139
+ let heading = lines.indexOf(`## ${target}`);
140
+ if (heading < 0) {
141
+ if (!source.endsWith("\n")) lines.push("");
142
+ lines.push(`## ${target}`, "");
143
+ heading = lines.length - 2;
144
+ }
145
+ let insert = heading + 1;
146
+ while (insert < lines.length && !(lines[insert] ?? "").startsWith("## ")) insert++;
147
+ lines.splice(insert, 0, line);
148
+ return lines.join("\n");
149
+ }
150
+ /** Best-effort V2-compatible board mirror used by phase entry points. A missing or unconfigured board is a no-op. */
151
+ async function moveConfiguredCard(home, id, stage, title = id) {
152
+ try {
153
+ const resolved = await boardPath(home);
154
+ const source = await readFile(resolved.path, "utf8");
155
+ const next = replaceCard(source, id, STAGES.get(stage) ?? stage, title);
156
+ if (next !== source) await writeFile(resolved.path, next, "utf8");
157
+ return true;
158
+ } catch (error) {
159
+ if (error.code === "ENOENT" || String(error).includes("not configured")) return false;
160
+ throw error;
161
+ }
162
+ }
163
+ const obsidian = {
164
+ verb: "obsidian",
165
+ async run(ctx, args) {
166
+ const home = ctx.env.HOME ?? ctx.cwd;
167
+ if (args.subVerb === "create") {
168
+ const [vaultPath, board = "Weave/Tasks.md"] = args.positionals;
169
+ if (!vaultPath) return 2;
170
+ const path = resolve(vaultPath, board);
171
+ try {
172
+ await access(path);
173
+ throw new Error(`Obsidian board already exists: ${path}`);
174
+ } catch (error) {
175
+ if (error.code !== "ENOENT") throw error;
176
+ }
177
+ await mkdir(dirname(path), { recursive: true });
178
+ await writeFile(path, BOARD_TEMPLATE, "utf8");
179
+ const loaded = await loadUserConfig(home);
180
+ const integrations = loaded.value.integrations;
181
+ const nextIntegrations = integrations && typeof integrations === "object" ? { ...integrations } : {};
182
+ nextIntegrations.obsidian = {
183
+ vaultPath,
184
+ board
185
+ };
186
+ loaded.value.integrations = nextIntegrations;
187
+ await mkdir(dirname(loaded.path), { recursive: true });
188
+ await writeFile(loaded.path, stringify(loaded.value), "utf8");
189
+ ctx.stdio.stdout.write(`created and connected ${path}\n`);
190
+ return 0;
191
+ }
192
+ if (args.subVerb === "connect") {
193
+ const [vaultPath, board = "Weave/Tasks.md"] = args.positionals;
194
+ if (!vaultPath) return 2;
195
+ const loaded = await loadUserConfig(home);
196
+ const integrations = loaded.value.integrations;
197
+ const nextIntegrations = integrations && typeof integrations === "object" ? { ...integrations } : {};
198
+ nextIntegrations.obsidian = {
199
+ vaultPath,
200
+ board
201
+ };
202
+ loaded.value.integrations = nextIntegrations;
203
+ await mkdir(dirname(loaded.path), { recursive: true });
204
+ await writeFile(loaded.path, stringify(loaded.value), "utf8");
205
+ ctx.stdio.stdout.write(`connected ${resolve(vaultPath, board)}\n`);
206
+ return 0;
207
+ }
208
+ if (args.subVerb === "status") {
209
+ const resolved = await boardPath(home);
210
+ const cards = parseCards(await readFile(resolved.path, "utf8"));
211
+ if (args.json) ctx.stdio.stdout.write(`${JSON.stringify({
212
+ ...resolved.config,
213
+ path: resolved.path,
214
+ cards
215
+ })}\n`);
216
+ else ctx.stdio.stdout.write(`${resolved.path}\n${cards.map((card) => `${card.id}\t${card.column}\t${card.title}`).join("\n")}\n`);
217
+ return 0;
218
+ }
219
+ if (args.subVerb === "move") {
220
+ const [id, stage] = args.positionals;
221
+ const target = stage ? STAGES.get(stage) ?? stage : void 0;
222
+ if (!id || !target) return 2;
223
+ const resolved = await boardPath(home);
224
+ const source = await readFile(resolved.path, "utf8");
225
+ await writeFile(resolved.path, replaceCard(source, id, target), "utf8");
226
+ ctx.stdio.stdout.write(`moved #${id} to ${target}\n`);
227
+ return 0;
228
+ }
229
+ return 2;
230
+ }
231
+ };
232
+ //#endregion
233
+ export { __exportAll as i, moveConfiguredCard as n, obsidian_exports as r, configuredIdeas as t };
234
+
235
+ //# sourceMappingURL=obsidian-BHLkXx_H.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"obsidian-BHLkXx_H.mjs","names":[],"sources":["../../../../apps/cli/src/commands/obsidian/index.ts"],"sourcesContent":["import { access, mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { parse, stringify } from 'yaml';\nimport type { CommandModule } from '../../contract/index.ts';\n\nexport type ObsidianCard = { id: string; title: string; checked: boolean; column: string; line: number };\ntype Card = ObsidianCard;\n\nconst COLUMNS = ['Ideas', 'Brainstorm', 'Spec', 'Ready to build', 'Building', 'Review', 'Fix', 'Ship', 'Shipped'];\nconst STAGES = new Map([\n ['ideas', 'Ideas'],\n ['brainstorm', 'Brainstorm'],\n ['spec', 'Spec'],\n ['ready', 'Ready to build'],\n ['building', 'Building'],\n ['review', 'Review'],\n ['fix', 'Fix'],\n ['ship', 'Ship'],\n ['shipped', 'Shipped'],\n]);\n\nconst BOARD_TEMPLATE = `---\nkanban-plugin: board\n---\n\n${COLUMNS.map((column) => `## ${column}\\n`).join('\\n')}\n%% kanban:settings\n\\`\\`\\`\n{\"kanban-plugin\":\"board\",\"list-collapse\":[false,false,false,false,false,false,false,false,false]}\n\\`\\`\\`\n%%\n`;\n\nfunction parseCards(source: string): Card[] {\n const lines = source.split(/\\r?\\n/);\n let column = '';\n const cards: Card[] = [];\n lines.forEach((line, lineIndex) => {\n const heading = /^##\\s+(.+?)\\s*$/.exec(line);\n if (heading) {\n column = heading[1] ?? '';\n return;\n }\n const card = /^-\\s+\\[([ xX])\\]\\s+(.+)$/.exec(line);\n if (!card || !column) return;\n const title = card[2] ?? '';\n const tag = /#([a-z0-9][a-z0-9-]*)\\b/i.exec(title);\n if (!tag) return;\n cards.push({\n id: (tag[1] ?? '').toLowerCase(),\n title,\n checked: (card[1] ?? '').toLowerCase() === 'x',\n column,\n line: lineIndex,\n });\n });\n return cards;\n}\n\nexport async function configuredIdeas(home: string): Promise<ObsidianCard[]> {\n const resolved = await boardPath(home);\n return parseCards(await readFile(resolved.path, 'utf8')).filter((card) => card.column === 'Ideas');\n}\n\nasync function loadUserConfig(home: string): Promise<{ path: string; value: Record<string, unknown> }> {\n const path = join(home, '.cohorte', 'config.yaml');\n try {\n const value = parse(await readFile(path, 'utf8')) as Record<string, unknown>;\n return { path, value: value && typeof value === 'object' ? value : {} };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n return { path, value: {} };\n }\n}\n\nfunction configured(value: Record<string, unknown>): { vaultPath: string; board: string } | undefined {\n const integrations = value.integrations;\n if (!integrations || typeof integrations !== 'object') return undefined;\n const obsidian = (integrations as Record<string, unknown>).obsidian;\n if (!obsidian || typeof obsidian !== 'object') return undefined;\n const { vaultPath, board } = obsidian as Record<string, unknown>;\n return typeof vaultPath === 'string' && typeof board === 'string' ? { vaultPath, board } : undefined;\n}\n\nasync function boardPath(home: string): Promise<{ config: { vaultPath: string; board: string }; path: string }> {\n const loaded = await loadUserConfig(home);\n const config = configured(loaded.value);\n if (!config) throw new Error('Obsidian is not configured; run `cohorte obsidian connect <vault> <board>`');\n const path = resolve(config.vaultPath, config.board);\n await access(path);\n return { config, path };\n}\n\nfunction replaceCard(source: string, id: string, target: string, title = id): string {\n const lines = source.split(/\\r?\\n/);\n const cards = parseCards(source);\n if (!COLUMNS.includes(target)) throw new Error(`Unknown Obsidian column: ${target}`);\n const matches = cards.filter((item) => item.id === id);\n const card = matches[0];\n if (!card) {\n const heading = lines.indexOf(`## ${target}`);\n if (heading < 0) throw new Error(`Obsidian column ${target} was not found`);\n let insert = heading + 1;\n while (insert < lines.length && !(lines[insert] ?? '').startsWith('## ')) insert++;\n lines.splice(insert, 0, `- [ ] ${title} #${id}`);\n return lines.join('\\n');\n }\n for (const duplicate of matches.slice(1).sort((a, b) => b.line - a.line)) lines.splice(duplicate.line, 1);\n if (card.column === target) return lines.join('\\n');\n const line = lines[card.line] ?? '';\n lines.splice(card.line, 1);\n let heading = lines.indexOf(`## ${target}`);\n if (heading < 0) {\n if (!source.endsWith('\\n')) lines.push('');\n lines.push(`## ${target}`, '');\n heading = lines.length - 2;\n }\n let insert = heading + 1;\n while (insert < lines.length && !(lines[insert] ?? '').startsWith('## ')) insert++;\n lines.splice(insert, 0, line);\n return lines.join('\\n');\n}\n\n/** Best-effort V2-compatible board mirror used by phase entry points. A missing or unconfigured board is a no-op. */\nexport async function moveConfiguredCard(home: string, id: string, stage: string, title = id): Promise<boolean> {\n try {\n const resolved = await boardPath(home);\n const source = await readFile(resolved.path, 'utf8');\n const target = STAGES.get(stage) ?? stage;\n const next = replaceCard(source, id, target, title);\n if (next !== source) await writeFile(resolved.path, next, 'utf8');\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT' || String(error).includes('not configured')) return false;\n throw error;\n }\n}\n\nconst obsidian: CommandModule = {\n verb: 'obsidian',\n async run(ctx, args) {\n const home = ctx.env.HOME ?? ctx.cwd;\n if (args.subVerb === 'create') {\n const [vaultPath, board = 'Weave/Tasks.md'] = args.positionals;\n if (!vaultPath) return 2;\n const path = resolve(vaultPath, board);\n try {\n await access(path);\n throw new Error(`Obsidian board already exists: ${path}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, BOARD_TEMPLATE, 'utf8');\n const loaded = await loadUserConfig(home);\n const integrations = loaded.value.integrations;\n const nextIntegrations = integrations && typeof integrations === 'object' ? { ...(integrations as object) } : {};\n (nextIntegrations as Record<string, unknown>).obsidian = { vaultPath, board };\n loaded.value.integrations = nextIntegrations;\n await mkdir(dirname(loaded.path), { recursive: true });\n await writeFile(loaded.path, stringify(loaded.value), 'utf8');\n ctx.stdio.stdout.write(`created and connected ${path}\\n`);\n return 0;\n }\n if (args.subVerb === 'connect') {\n const [vaultPath, board = 'Weave/Tasks.md'] = args.positionals;\n if (!vaultPath) return 2;\n const loaded = await loadUserConfig(home);\n const integrations = loaded.value.integrations;\n const nextIntegrations = integrations && typeof integrations === 'object' ? { ...(integrations as object) } : {};\n (nextIntegrations as Record<string, unknown>).obsidian = { vaultPath, board };\n loaded.value.integrations = nextIntegrations;\n await mkdir(dirname(loaded.path), { recursive: true });\n await writeFile(loaded.path, stringify(loaded.value), 'utf8');\n ctx.stdio.stdout.write(`connected ${resolve(vaultPath, board)}\\n`);\n return 0;\n }\n if (args.subVerb === 'status') {\n const resolved = await boardPath(home);\n const cards = parseCards(await readFile(resolved.path, 'utf8'));\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify({ ...resolved.config, path: resolved.path, cards })}\\n`);\n else\n ctx.stdio.stdout.write(\n `${resolved.path}\\n${cards.map((card) => `${card.id}\\t${card.column}\\t${card.title}`).join('\\n')}\\n`,\n );\n return 0;\n }\n if (args.subVerb === 'move') {\n const [id, stage] = args.positionals;\n const target = stage ? (STAGES.get(stage) ?? stage) : undefined;\n if (!id || !target) return 2;\n const resolved = await boardPath(home);\n const source = await readFile(resolved.path, 'utf8');\n await writeFile(resolved.path, replaceCard(source, id, target), 'utf8');\n ctx.stdio.stdout.write(`moved #${id} to ${target}\\n`);\n return 0;\n }\n return 2;\n },\n};\n\nexport default obsidian;\n"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import { N as errorOf, j as CohorteError } from "./src-Cu3TxNob.mjs";
2
+ import { access, mkdir, writeFile } from "node:fs/promises";
3
+ import { dirname, join, resolve } from "node:path";
4
+ import { stringify } from "yaml";
5
+ //#region src/commands/patch/index.ts
6
+ function slugify(value) {
7
+ return value.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 64) || "patch";
8
+ }
9
+ function optionValue(args, flag) {
10
+ const index = args.indexOf(flag);
11
+ return index === -1 ? void 0 : args[index + 1];
12
+ }
13
+ const patch = {
14
+ verb: "patch",
15
+ async run(ctx, args) {
16
+ const input = args.positionals.find((value) => !value.startsWith("--"));
17
+ if (!input) return 2;
18
+ const id = slugify(optionValue(args.positionals, "--id") ?? input);
19
+ const output = resolve(ctx.cwd, optionValue(args.positionals, "--output") ?? join(".cohorte", "specs", `patch-${id}.yaml`));
20
+ const spec = {
21
+ id: `patch-${id}`,
22
+ kind: "patch",
23
+ status: "draft",
24
+ title: input,
25
+ acceptance: [`Add a regression test that reproduces and prevents: ${input}`],
26
+ surfaces: {},
27
+ openQuestions: ["What is the minimal reproducible failure?", "Which existing behavior must remain unchanged?"]
28
+ };
29
+ try {
30
+ await access(output);
31
+ throw new CohorteError(errorOf("conflict/unexpected", `refusing to overwrite existing spec ${output}`));
32
+ } catch (error) {
33
+ if (error.code !== "ENOENT") throw error;
34
+ }
35
+ await mkdir(dirname(output), { recursive: true });
36
+ await writeFile(output, stringify(spec), "utf8");
37
+ const result = {
38
+ id: spec.id,
39
+ status: spec.status,
40
+ path: output,
41
+ next: `cohorte spec freeze ${output}`
42
+ };
43
+ ctx.stdio.stdout.write(`${args.json ? JSON.stringify(result) : `created ${output}\nnext: ${result.next}`}\n`);
44
+ return 0;
45
+ }
46
+ };
47
+ //#endregion
48
+ export { patch as default };
49
+
50
+ //# sourceMappingURL=patch-sAgVqjpx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patch-sAgVqjpx.mjs","names":[],"sources":["../../../../apps/cli/src/commands/patch/index.ts"],"sourcesContent":["import { access, mkdir, writeFile } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { CohorteError, errorOf } from '@cohorte/base';\nimport { stringify } from 'yaml';\nimport type { CommandModule } from '../../contract/index.ts';\n\nfunction slugify(value: string): string {\n return (\n value\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 64) || 'patch'\n );\n}\n\nfunction optionValue(args: readonly string[], flag: string): string | undefined {\n const index = args.indexOf(flag);\n return index === -1 ? undefined : args[index + 1];\n}\n\nconst patch: CommandModule = {\n verb: 'patch',\n async run(ctx, args) {\n const input = args.positionals.find((value) => !value.startsWith('--'));\n if (!input) return 2;\n const id = slugify(optionValue(args.positionals, '--id') ?? input);\n const output = resolve(\n ctx.cwd,\n optionValue(args.positionals, '--output') ?? join('.cohorte', 'specs', `patch-${id}.yaml`),\n );\n const spec = {\n id: `patch-${id}`,\n kind: 'patch' as const,\n status: 'draft' as const,\n title: input,\n acceptance: [`Add a regression test that reproduces and prevents: ${input}`],\n surfaces: {},\n openQuestions: ['What is the minimal reproducible failure?', 'Which existing behavior must remain unchanged?'],\n };\n try {\n await access(output);\n throw new CohorteError(errorOf('conflict/unexpected', `refusing to overwrite existing spec ${output}`));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n }\n await mkdir(dirname(output), { recursive: true });\n await writeFile(output, stringify(spec), 'utf8');\n const result = { id: spec.id, status: spec.status, path: output, next: `cohorte spec freeze ${output}` };\n ctx.stdio.stdout.write(`${args.json ? JSON.stringify(result) : `created ${output}\\nnext: ${result.next}`}\\n`);\n return 0;\n },\n};\n\nexport default patch;\n"],"mappings":";;;;;AAMA,SAAS,QAAQ,OAAuB;CACtC,OACE,MACG,UAAU,MAAM,CAAC,CACjB,QAAQ,oBAAoB,EAAE,CAAC,CAC/B,YAAY,CAAC,CACb,QAAQ,eAAe,GAAG,CAAC,CAC3B,QAAQ,YAAY,EAAE,CAAC,CACvB,MAAM,GAAG,EAAE,KAAK;AAEvB;AAEA,SAAS,YAAY,MAAyB,MAAkC;CAC9E,MAAM,QAAQ,KAAK,QAAQ,IAAI;CAC/B,OAAO,UAAU,KAAK,KAAA,IAAY,KAAK,QAAQ;AACjD;AAEA,MAAM,QAAuB;CAC3B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,QAAQ,KAAK,YAAY,MAAM,UAAU,CAAC,MAAM,WAAW,IAAI,CAAC;EACtE,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,KAAK,QAAQ,YAAY,KAAK,aAAa,MAAM,KAAK,KAAK;EACjE,MAAM,SAAS,QACb,IAAI,KACJ,YAAY,KAAK,aAAa,UAAU,KAAK,KAAK,YAAY,SAAS,SAAS,GAAG,MAAM,CAC3F;EACA,MAAM,OAAO;GACX,IAAI,SAAS;GACb,MAAM;GACN,QAAQ;GACR,OAAO;GACP,YAAY,CAAC,uDAAuD,OAAO;GAC3E,UAAU,CAAC;GACX,eAAe,CAAC,6CAA6C,gDAAgD;EAC/G;EACA,IAAI;GACF,MAAM,OAAO,MAAM;GACnB,MAAM,IAAI,aAAa,QAAQ,uBAAuB,uCAAuC,QAAQ,CAAC;EACxG,SAAS,OAAO;GACd,IAAK,MAAgC,SAAS,UAAU,MAAM;EAChE;EACA,MAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;EAChD,MAAM,UAAU,QAAQ,UAAU,IAAI,GAAG,MAAM;EAC/C,MAAM,SAAS;GAAE,IAAI,KAAK;GAAI,QAAQ,KAAK;GAAQ,MAAM;GAAQ,MAAM,uBAAuB;EAAS;EACvG,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,OAAO,KAAK,UAAU,MAAM,IAAI,WAAW,OAAO,UAAU,OAAO,OAAO,GAAG;EAC5G,OAAO;CACT;AACF"}
@@ -1,9 +1,9 @@
1
1
  import { n as sha256Hex, t as canonicalJson } from "./canonical-C8UxeEmB.mjs";
2
2
  import { N as errorOf, j as CohorteError } from "./src-Cu3TxNob.mjs";
3
3
  import { n as createKeyStore, r as createTrustStore } from "./auth-BT5oVp76.mjs";
4
- import { i as resolveConfig, n as loadConfig } from "./src-DcU4IXMe.mjs";
5
- import "./src-r0ECB1UJ.mjs";
6
- import { a as buildPolicySnapshot, c as createCommandPolicy, i as createGlobMatcher, l as createProgramResolver, n as toolIntrospection, o as createPolicyEngine, r as createPathResolver, s as explainPolicy } from "./catalogue-B5uFqfzJ.mjs";
4
+ import { i as resolveConfig, n as loadConfig } from "./src-DbS9gkJy.mjs";
5
+ import "./src-Bfr1yzsn.mjs";
6
+ import { a as buildPolicySnapshot, c as createCommandPolicy, i as createGlobMatcher, l as createProgramResolver, n as toolIntrospection, o as createPolicyEngine, r as createPathResolver, s as explainPolicy } from "./catalogue-IaCJdfB8.mjs";
7
7
  import { join, resolve } from "node:path";
8
8
  import { realpathSync } from "node:fs";
9
9
  //#region src/commands/policy/index.ts
@@ -136,4 +136,4 @@ const policy = {
136
136
  //#endregion
137
137
  export { policy as default };
138
138
 
139
- //# sourceMappingURL=policy-Clypo20s.mjs.map
139
+ //# sourceMappingURL=policy-Du7WVBFX.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"policy-Clypo20s.mjs","names":[],"sources":["../../../../apps/cli/src/commands/policy/index.ts"],"sourcesContent":["// apps/cli/src/commands/policy/index.ts — DESIGN §9 verb `policy` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/policy/**`.\nimport { realpathSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { CohorteError, canonicalJson, errorOf, sha256Hex } from '@cohorte/base';\nimport { loadConfig, resolveConfig } from '@cohorte/config';\nimport {\n buildPolicySnapshot,\n createCommandPolicy,\n createGlobMatcher,\n createPathResolver,\n createPolicyEngine,\n createProgramResolver,\n explainPolicy,\n} from '@cohorte/security';\nimport { createKeyStore, createTrustStore } from '@cohorte/security/auth';\nimport type { AgentGrant, GateCall, PolicyPorts } from '@cohorte/security/contract';\nimport { toolIntrospection } from '@cohorte/tools/catalogue';\nimport type { CommandModule } from '../../contract/index.ts';\n\nfunction canonical(path: string): string {\n const absolute = resolve(path);\n try {\n return realpathSync.native(absolute);\n } catch {\n return absolute;\n }\n}\n\nfunction grantFor(root: string, argv: readonly string[]): AgentGrant {\n const tools = ['run_command'];\n const digest = sha256Hex(canonicalJson({ root, argv: [...argv] }));\n return {\n agentId: 'agt_policy_explain' as AgentGrant['agentId'],\n role: 'policy-explain',\n digest,\n tools,\n roots: { workspace: root as AgentGrant['roots']['workspace'], readOnly: [] },\n read: { include: ['**'], exclude: [] },\n write: { include: ['**'], exclude: [] },\n denyRead: { include: ['**/.cohorte/**', '**/.git/**'], exclude: [] },\n denyWrite: { include: ['**/.cohorte/**', '**/.git/**'], exclude: [] },\n commands: { default: 'deny', rules: [] },\n secrets: [],\n temporary: [],\n limits: {\n maxToolCalls: 1,\n maxCallsPerMinute: 1,\n perTool: { run_command: { timeoutMs: 120_000, maxOutputBytes: 1024 * 1024 } },\n },\n };\n}\n\nconst policy: CommandModule = {\n verb: 'policy',\n async run(ctx, args) {\n if (args.subVerb !== 'explain') return 2;\n const argv = args.positionals.filter((value) => value !== '--');\n if (argv.length === 0) return 2;\n\n const home = ctx.env.HOME ?? ctx.cwd;\n const projectKeyId = sha256Hex(ctx.cwd).slice(0, 24);\n const keys = createKeyStore({ directory: join(home, '.cohorte', 'keys') });\n const trustStore = createTrustStore({ directory: join(home, '.cohorte', 'trust'), keys });\n const loaded = await loadConfig({ cwd: ctx.cwd, home });\n const resolved = await resolveConfig(loaded, { trustStore, projectKeyId });\n if (resolved.status === 'untrusted') {\n throw new CohorteError(\n errorOf(\n 'security/project-policy-untrusted',\n `project policy is untrusted (${resolved.loosenedKeys.join(', ') || 'unknown key'})`,\n ),\n );\n }\n\n const root = canonical(loaded.projectRoot);\n const pathResolver = createPathResolver({\n roots: [root as never],\n protectedRoots: [canonical(join(root, '.cohorte')) as never],\n symlinks: resolved.config.policy.symlinks,\n });\n const pathDirs = (ctx.env.PATH ?? '').split(':').filter(Boolean).map(canonical);\n const programs = createProgramResolver({ pathDirs });\n const branches: PolicyPorts['branches'] = {\n branchOf: () => ({ kind: 'detached-or-unknown', protected: true }),\n };\n const commands = createCommandPolicy({ programs, branches });\n const engine = createPolicyEngine({ tools: toolIntrospection, globs: createGlobMatcher(), commands });\n const policySnapshot = buildPolicySnapshot(resolved.config, loaded.ownership, { sandboxLevel: 'L0-process' });\n const ports: PolicyPorts = {\n paths: pathResolver,\n branches,\n budgets: { remaining: () => ({}), callsInLastMinute: () => 0 },\n programs,\n clock: ctx.clock,\n };\n const call: GateCall = {\n runId: 'run_policy_explain' as GateCall['runId'],\n agentId: 'agt_policy_explain' as GateCall['agentId'],\n incarnation: 1,\n toolCallId: 'tool_policy_explain' as GateCall['toolCallId'],\n tool: 'run_command',\n input: { argv, cwd: root, timeoutMs: 120_000 },\n phase: 'PREFLIGHT',\n role: 'policy-explain',\n };\n const verdict = explainPolicy(engine, call, grantFor(root, argv), policySnapshot, ports);\n ctx.stdio.stdout.write(`${JSON.stringify(verdict)}\\n`);\n return 0;\n },\n};\n\nexport default policy;\n"],"mappings":"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"}
1
+ {"version":3,"file":"policy-Du7WVBFX.mjs","names":[],"sources":["../../../../apps/cli/src/commands/policy/index.ts"],"sourcesContent":["// apps/cli/src/commands/policy/index.ts — DESIGN §9 verb `policy` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/policy/**`.\nimport { realpathSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { CohorteError, canonicalJson, errorOf, sha256Hex } from '@cohorte/base';\nimport { loadConfig, resolveConfig } from '@cohorte/config';\nimport {\n buildPolicySnapshot,\n createCommandPolicy,\n createGlobMatcher,\n createPathResolver,\n createPolicyEngine,\n createProgramResolver,\n explainPolicy,\n} from '@cohorte/security';\nimport { createKeyStore, createTrustStore } from '@cohorte/security/auth';\nimport type { AgentGrant, GateCall, PolicyPorts } from '@cohorte/security/contract';\nimport { toolIntrospection } from '@cohorte/tools/catalogue';\nimport type { CommandModule } from '../../contract/index.ts';\n\nfunction canonical(path: string): string {\n const absolute = resolve(path);\n try {\n return realpathSync.native(absolute);\n } catch {\n return absolute;\n }\n}\n\nfunction grantFor(root: string, argv: readonly string[]): AgentGrant {\n const tools = ['run_command'];\n const digest = sha256Hex(canonicalJson({ root, argv: [...argv] }));\n return {\n agentId: 'agt_policy_explain' as AgentGrant['agentId'],\n role: 'policy-explain',\n digest,\n tools,\n roots: { workspace: root as AgentGrant['roots']['workspace'], readOnly: [] },\n read: { include: ['**'], exclude: [] },\n write: { include: ['**'], exclude: [] },\n denyRead: { include: ['**/.cohorte/**', '**/.git/**'], exclude: [] },\n denyWrite: { include: ['**/.cohorte/**', '**/.git/**'], exclude: [] },\n commands: { default: 'deny', rules: [] },\n secrets: [],\n temporary: [],\n limits: {\n maxToolCalls: 1,\n maxCallsPerMinute: 1,\n perTool: { run_command: { timeoutMs: 120_000, maxOutputBytes: 1024 * 1024 } },\n },\n };\n}\n\nconst policy: CommandModule = {\n verb: 'policy',\n async run(ctx, args) {\n if (args.subVerb !== 'explain') return 2;\n const argv = args.positionals.filter((value) => value !== '--');\n if (argv.length === 0) return 2;\n\n const home = ctx.env.HOME ?? ctx.cwd;\n const projectKeyId = sha256Hex(ctx.cwd).slice(0, 24);\n const keys = createKeyStore({ directory: join(home, '.cohorte', 'keys') });\n const trustStore = createTrustStore({ directory: join(home, '.cohorte', 'trust'), keys });\n const loaded = await loadConfig({ cwd: ctx.cwd, home });\n const resolved = await resolveConfig(loaded, { trustStore, projectKeyId });\n if (resolved.status === 'untrusted') {\n throw new CohorteError(\n errorOf(\n 'security/project-policy-untrusted',\n `project policy is untrusted (${resolved.loosenedKeys.join(', ') || 'unknown key'})`,\n ),\n );\n }\n\n const root = canonical(loaded.projectRoot);\n const pathResolver = createPathResolver({\n roots: [root as never],\n protectedRoots: [canonical(join(root, '.cohorte')) as never],\n symlinks: resolved.config.policy.symlinks,\n });\n const pathDirs = (ctx.env.PATH ?? '').split(':').filter(Boolean).map(canonical);\n const programs = createProgramResolver({ pathDirs });\n const branches: PolicyPorts['branches'] = {\n branchOf: () => ({ kind: 'detached-or-unknown', protected: true }),\n };\n const commands = createCommandPolicy({ programs, branches });\n const engine = createPolicyEngine({ tools: toolIntrospection, globs: createGlobMatcher(), commands });\n const policySnapshot = buildPolicySnapshot(resolved.config, loaded.ownership, { sandboxLevel: 'L0-process' });\n const ports: PolicyPorts = {\n paths: pathResolver,\n branches,\n budgets: { remaining: () => ({}), callsInLastMinute: () => 0 },\n programs,\n clock: ctx.clock,\n };\n const call: GateCall = {\n runId: 'run_policy_explain' as GateCall['runId'],\n agentId: 'agt_policy_explain' as GateCall['agentId'],\n incarnation: 1,\n toolCallId: 'tool_policy_explain' as GateCall['toolCallId'],\n tool: 'run_command',\n input: { argv, cwd: root, timeoutMs: 120_000 },\n phase: 'PREFLIGHT',\n role: 'policy-explain',\n };\n const verdict = explainPolicy(engine, call, grantFor(root, argv), policySnapshot, ports);\n ctx.stdio.stdout.write(`${JSON.stringify(verdict)}\\n`);\n return 0;\n },\n};\n\nexport default policy;\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { s as DEFAULT_CONFIG } from "./schema-C9QbUW4H.mjs";
2
- import { l as deriveDesiredState, n as planReconcile, t as applyReconcile } from "./src-CmFjh4M0.mjs";
1
+ import { s as DEFAULT_CONFIG } from "./schema-Bq9qtgsd.mjs";
2
+ import { l as deriveDesiredState, n as planReconcile, t as applyReconcile } from "./src-DNsLSxgm.mjs";
3
3
  import { t as scanRepository } from "./scan-C5uDr7Yq.mjs";
4
4
  //#region src/commands/reconcile/index.ts
5
5
  const reconcile = {
@@ -47,4 +47,4 @@ const reconcile = {
47
47
  //#endregion
48
48
  export { reconcile as default };
49
49
 
50
- //# sourceMappingURL=reconcile-czNaLOP6.mjs.map
50
+ //# sourceMappingURL=reconcile-BHn66X3C.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"reconcile-czNaLOP6.mjs","names":[],"sources":["../../../../apps/cli/src/commands/reconcile/index.ts"],"sourcesContent":["import { DEFAULT_CONFIG } from '@cohorte/config/schema';\nimport { applyReconcile, deriveDesiredState, planReconcile, scanRepository } from '@cohorte/project-model';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst reconcile: CommandModule = {\n verb: 'reconcile',\n async run(ctx, args) {\n const model = await scanRepository(ctx.cwd, { clock: ctx.clock, toolVersion: '3.0.0' });\n const plan = await planReconcile({\n root: ctx.cwd,\n scan: (root) => scanRepository(root, { clock: ctx.clock, toolVersion: '3.0.0' }),\n cohorteVersion: '3.0.0',\n clock: ctx.clock,\n });\n if (args.positionals.includes('--apply')) {\n const result = await applyReconcile({\n root: ctx.cwd,\n plan,\n desired: deriveDesiredState({ model, config: DEFAULT_CONFIG, cohorteVersion: '3.0.0', skills: {} }),\n backup: !args.positionals.includes('--no-backup'),\n clock: ctx.clock,\n });\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify({ plan, result })}\\n`);\n else ctx.stdio.stdout.write(`applied: ${result.applied.join(', ') || 'none'}\\n`);\n return 0;\n }\n if (!args.positionals.includes('--plan')) return 2;\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify(plan)}\\n`);\n else ctx.stdio.stdout.write(`${plan.operations.length} operation(s) planned\\n`);\n return 0;\n },\n};\n\nexport default reconcile;\n"],"mappings":";;;;AAIA,MAAM,YAA2B;CAC/B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,QAAQ,MAAM,eAAe,IAAI,KAAK;GAAE,OAAO,IAAI;GAAO,aAAa;EAAQ,CAAC;EACtF,MAAM,OAAO,MAAM,cAAc;GAC/B,MAAM,IAAI;GACV,OAAO,SAAS,eAAe,MAAM;IAAE,OAAO,IAAI;IAAO,aAAa;GAAQ,CAAC;GAC/E,gBAAgB;GAChB,OAAO,IAAI;EACb,CAAC;EACD,IAAI,KAAK,YAAY,SAAS,SAAS,GAAG;GACxC,MAAM,SAAS,MAAM,eAAe;IAClC,MAAM,IAAI;IACV;IACA,SAAS,mBAAmB;KAAE;KAAO,QAAQ;KAAgB,gBAAgB;KAAS,QAAQ,CAAC;IAAE,CAAC;IAClG,QAAQ,CAAC,KAAK,YAAY,SAAS,aAAa;IAChD,OAAO,IAAI;GACb,CAAC;GACD,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU;IAAE;IAAM;GAAO,CAAC,EAAE,GAAG;QACxE,IAAI,MAAM,OAAO,MAAM,YAAY,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO,GAAG;GAC/E,OAAO;EACT;EACA,IAAI,CAAC,KAAK,YAAY,SAAS,QAAQ,GAAG,OAAO;EACjD,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,IAAI,EAAE,GAAG;OAC5D,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,WAAW,OAAO,wBAAwB;EAC9E,OAAO;CACT;AACF"}
1
+ {"version":3,"file":"reconcile-BHn66X3C.mjs","names":[],"sources":["../../../../apps/cli/src/commands/reconcile/index.ts"],"sourcesContent":["import { DEFAULT_CONFIG } from '@cohorte/config/schema';\nimport { applyReconcile, deriveDesiredState, planReconcile, scanRepository } from '@cohorte/project-model';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst reconcile: CommandModule = {\n verb: 'reconcile',\n async run(ctx, args) {\n const model = await scanRepository(ctx.cwd, { clock: ctx.clock, toolVersion: '3.0.0' });\n const plan = await planReconcile({\n root: ctx.cwd,\n scan: (root) => scanRepository(root, { clock: ctx.clock, toolVersion: '3.0.0' }),\n cohorteVersion: '3.0.0',\n clock: ctx.clock,\n });\n if (args.positionals.includes('--apply')) {\n const result = await applyReconcile({\n root: ctx.cwd,\n plan,\n desired: deriveDesiredState({ model, config: DEFAULT_CONFIG, cohorteVersion: '3.0.0', skills: {} }),\n backup: !args.positionals.includes('--no-backup'),\n clock: ctx.clock,\n });\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify({ plan, result })}\\n`);\n else ctx.stdio.stdout.write(`applied: ${result.applied.join(', ') || 'none'}\\n`);\n return 0;\n }\n if (!args.positionals.includes('--plan')) return 2;\n if (args.json) ctx.stdio.stdout.write(`${JSON.stringify(plan)}\\n`);\n else ctx.stdio.stdout.write(`${plan.operations.length} operation(s) planned\\n`);\n return 0;\n },\n};\n\nexport default reconcile;\n"],"mappings":";;;;AAIA,MAAM,YAA2B;CAC/B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,QAAQ,MAAM,eAAe,IAAI,KAAK;GAAE,OAAO,IAAI;GAAO,aAAa;EAAQ,CAAC;EACtF,MAAM,OAAO,MAAM,cAAc;GAC/B,MAAM,IAAI;GACV,OAAO,SAAS,eAAe,MAAM;IAAE,OAAO,IAAI;IAAO,aAAa;GAAQ,CAAC;GAC/E,gBAAgB;GAChB,OAAO,IAAI;EACb,CAAC;EACD,IAAI,KAAK,YAAY,SAAS,SAAS,GAAG;GACxC,MAAM,SAAS,MAAM,eAAe;IAClC,MAAM,IAAI;IACV;IACA,SAAS,mBAAmB;KAAE;KAAO,QAAQ;KAAgB,gBAAgB;KAAS,QAAQ,CAAC;IAAE,CAAC;IAClG,QAAQ,CAAC,KAAK,YAAY,SAAS,aAAa;IAChD,OAAO,IAAI;GACb,CAAC;GACD,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU;IAAE;IAAM;GAAO,CAAC,EAAE,GAAG;QACxE,IAAI,MAAM,OAAO,MAAM,YAAY,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO,GAAG;GAC/E,OAAO;EACT;EACA,IAAI,CAAC,KAAK,YAAY,SAAS,QAAQ,GAAG,OAAO;EACjD,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,IAAI,EAAE,GAAG;OAC5D,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,WAAW,OAAO,wBAAwB;EAC9E,OAAO;CACT;AACF"}
@@ -0,0 +1,153 @@
1
+ import { r as specContentSha256 } from "./schema-Bq9qtgsd.mjs";
2
+ import { t as run } from "./run-NGAxdsIX.mjs";
3
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { parse, stringify } from "yaml";
6
+ import { execFile } from "node:child_process";
7
+ import { promisify } from "node:util";
8
+ //#region src/commands/refactor/index.ts
9
+ const exec = promisify(execFile);
10
+ async function configuredGates(root) {
11
+ try {
12
+ const source = await readFile(join(root, "PIPELINE.md"), "utf8");
13
+ const block = /```yaml pipeline-profile\s*\n([\s\S]*?)\n```/u.exec(source)?.[1];
14
+ const commands = block ? parse(block).commands : void 0;
15
+ if (!commands) return [];
16
+ return [
17
+ "format",
18
+ "lint",
19
+ "typecheck",
20
+ "test"
21
+ ].map((key) => commands[key]).filter((value) => typeof value === "string" && value.length > 0 && !value.startsWith("<"));
22
+ } catch {
23
+ return [];
24
+ }
25
+ }
26
+ async function verifyDomain(root, domain) {
27
+ const commands = await configuredGates(root);
28
+ if (!commands.length) return 0;
29
+ const results = [];
30
+ let status = 0;
31
+ for (const command of commands) try {
32
+ const result = await exec("sh", ["-lc", command], {
33
+ cwd: root,
34
+ maxBuffer: 2e6
35
+ });
36
+ results.push(`$ ${command}\n${result.stdout || "(no output)"}${result.stderr || ""}`);
37
+ } catch (error) {
38
+ const failure = error;
39
+ results.push(`$ ${command}\n${failure.stdout ?? ""}${failure.stderr ?? failure.message ?? String(error)}`);
40
+ status = 15;
41
+ }
42
+ await mkdir(join(root, "specs", "reports"), { recursive: true });
43
+ await writeFile(join(root, "specs", "reports", `refactor-verify.${domain}.txt`), `${results.join("\n\n")}\n`, "utf8");
44
+ return status;
45
+ }
46
+ const refactor = {
47
+ verb: "refactor",
48
+ async run(ctx, args) {
49
+ const backlogPath = join(ctx.cwd, "specs", "refactor-backlog.md");
50
+ let source;
51
+ try {
52
+ source = await readFile(backlogPath, "utf8");
53
+ } catch {
54
+ ctx.stdio.stderr.write(`backlog not found: ${backlogPath}\n`);
55
+ return 1;
56
+ }
57
+ const requested = args.positionals.filter((value) => !value.startsWith("--"));
58
+ const headings = [...source.matchAll(/^##\s+([^\n]+)$/gmu)];
59
+ const domains = requested.includes("all") || requested.length === 0 ? headings.map((match) => match[1]?.trim()).filter((x) => Boolean(x)) : requested;
60
+ if (!domains.length) return 2;
61
+ const completed = [];
62
+ const outcomes = [];
63
+ await mkdir(join(ctx.cwd, "specs", "reports"), { recursive: true });
64
+ const runDomain = async (domain) => {
65
+ const start = headings.find((match) => match[1]?.trim() === domain)?.index ?? -1;
66
+ const next = start < 0 ? -1 : source.indexOf("\n## ", start + 1);
67
+ const tasks = (start < 0 ? "" : source.slice(start, next < 0 ? source.length : next)).split(/\r?\n/u).filter((line) => /^- \[ \]/u.test(line));
68
+ if (!tasks.length) return 0;
69
+ if (tasks.length < 5) {
70
+ outcomes.push({
71
+ domain,
72
+ tasks,
73
+ status: 0,
74
+ attempts: 0,
75
+ skipped: true,
76
+ reason: "small backlog: use the conversational refactor workflow"
77
+ });
78
+ return 0;
79
+ }
80
+ const id = `refactor-${domain.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-|-$/gu, "")}`;
81
+ const draft = {
82
+ id,
83
+ kind: "feature",
84
+ status: "draft",
85
+ title: `Refactor ${domain}`,
86
+ acceptance: tasks.map((task) => task.replace(/^- \[ \]\s*/u, "")),
87
+ surfaces: { [domain]: { tasks } },
88
+ openQuestions: []
89
+ };
90
+ const spec = {
91
+ ...draft,
92
+ status: "frozen",
93
+ sha256: specContentSha256(draft)
94
+ };
95
+ const path = join(ctx.cwd, ".cohorte", "specs", `${id}.yaml`);
96
+ await mkdir(join(ctx.cwd, ".cohorte", "specs"), { recursive: true });
97
+ await writeFile(path, stringify(spec), "utf8");
98
+ const first = await run.run(ctx, {
99
+ ...args,
100
+ positionals: [
101
+ path,
102
+ "--profile",
103
+ "feature",
104
+ "--phases",
105
+ "BUILD,TEST,REVIEW",
106
+ "--with-fix"
107
+ ]
108
+ });
109
+ const firstGates = first === 0 ? await verifyDomain(ctx.cwd, domain) : 0;
110
+ const result = first === 3 || firstGates !== 0 ? await run.run(ctx, {
111
+ ...args,
112
+ positionals: [
113
+ path,
114
+ "--profile",
115
+ "feature",
116
+ "--phases",
117
+ "BUILD,TEST,REVIEW",
118
+ "--with-fix"
119
+ ]
120
+ }) : first;
121
+ const finalGates = result === 0 ? await verifyDomain(ctx.cwd, domain) : 0;
122
+ const status = finalGates !== 0 ? finalGates : result;
123
+ outcomes.push({
124
+ domain,
125
+ spec: path,
126
+ tasks,
127
+ status,
128
+ attempts: first === 3 || firstGates !== 0 ? 2 : 1
129
+ });
130
+ if (status === 0) completed.push({
131
+ domain,
132
+ tasks
133
+ });
134
+ return status;
135
+ };
136
+ const ordered = domains.includes("shared") ? ["shared", ...domains.filter((domain) => domain !== "shared")] : domains;
137
+ const sharedStatus = ordered[0] === "shared" ? await runDomain("shared") : 0;
138
+ const parallelDomains = ordered[0] === "shared" ? ordered.slice(1) : ordered;
139
+ const statuses = sharedStatus === 0 ? await Promise.all(parallelDomains.map((domain) => runDomain(domain))) : [];
140
+ for (const item of completed) source = source.split(/\r?\n/u).map((line) => line.startsWith("- [ ] ") && item.tasks.includes(line) ? line.replace("- [ ] ", "- [x] ") : line).join("\n");
141
+ await writeFile(backlogPath, `${source}\n`, "utf8");
142
+ await writeFile(join(ctx.cwd, "specs", "reports", "refactor.json"), `${JSON.stringify({
143
+ generatedAt: ctx.clock.now(),
144
+ domains,
145
+ outcomes
146
+ }, null, 2)}\n`, "utf8");
147
+ return Math.max(sharedStatus, ...statuses, 0);
148
+ }
149
+ };
150
+ //#endregion
151
+ export { refactor as default };
152
+
153
+ //# sourceMappingURL=refactor-CoNoqLZr.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refactor-CoNoqLZr.mjs","names":[],"sources":["../../../../apps/cli/src/commands/refactor/index.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { promisify } from 'node:util';\nimport { specContentSha256 } from '@cohorte/config/schema';\nimport { parse, stringify } from 'yaml';\nimport type { CommandModule } from '../../contract/index.ts';\nimport run from '../run/index.ts';\n\nconst exec = promisify(execFile);\n\nasync function configuredGates(root: string): Promise<string[]> {\n try {\n const source = await readFile(join(root, 'PIPELINE.md'), 'utf8');\n const block = /```yaml pipeline-profile\\s*\\n([\\s\\S]*?)\\n```/u.exec(source)?.[1];\n const commands = block ? (parse(block) as { commands?: Record<string, unknown> }).commands : undefined;\n if (!commands) return [];\n return ['format', 'lint', 'typecheck', 'test']\n .map((key) => commands[key])\n .filter((value): value is string => typeof value === 'string' && value.length > 0 && !value.startsWith('<'));\n } catch {\n return [];\n }\n}\n\nasync function verifyDomain(root: string, domain: string): Promise<number> {\n const commands = await configuredGates(root);\n if (!commands.length) return 0;\n const results: string[] = [];\n let status = 0;\n for (const command of commands) {\n try {\n const result = await exec('sh', ['-lc', command], { cwd: root, maxBuffer: 2_000_000 });\n results.push(`$ ${command}\\n${result.stdout || '(no output)'}${result.stderr || ''}`);\n } catch (error) {\n const failure = error as { stdout?: string; stderr?: string; message?: string };\n results.push(`$ ${command}\\n${failure.stdout ?? ''}${failure.stderr ?? failure.message ?? String(error)}`);\n status = 15;\n }\n }\n await mkdir(join(root, 'specs', 'reports'), { recursive: true });\n await writeFile(join(root, 'specs', 'reports', `refactor-verify.${domain}.txt`), `${results.join('\\n\\n')}\\n`, 'utf8');\n return status;\n}\n\nconst refactor: CommandModule = {\n verb: 'refactor',\n async run(ctx, args) {\n const backlogPath = join(ctx.cwd, 'specs', 'refactor-backlog.md');\n let source: string;\n try {\n source = await readFile(backlogPath, 'utf8');\n } catch {\n ctx.stdio.stderr.write(`backlog not found: ${backlogPath}\\n`);\n return 1;\n }\n const requested = args.positionals.filter((value) => !value.startsWith('--'));\n const headings = [...source.matchAll(/^##\\s+([^\\n]+)$/gmu)];\n const domains =\n requested.includes('all') || requested.length === 0\n ? headings.map((match) => match[1]?.trim()).filter((x): x is string => Boolean(x))\n : requested;\n if (!domains.length) return 2;\n const completed: Array<{ domain: string; tasks: string[] }> = [];\n const outcomes: Array<{\n domain: string;\n spec?: string;\n tasks: string[];\n status: number;\n attempts: number;\n skipped?: boolean;\n reason?: string;\n }> = [];\n await mkdir(join(ctx.cwd, 'specs', 'reports'), { recursive: true });\n const runDomain = async (domain: string): Promise<number> => {\n const heading = headings.find((match) => match[1]?.trim() === domain);\n const start = heading?.index ?? -1;\n const next = start < 0 ? -1 : source.indexOf('\\n## ', start + 1);\n const block = start < 0 ? '' : source.slice(start, next < 0 ? source.length : next);\n const tasks = block.split(/\\r?\\n/u).filter((line) => /^- \\[ \\]/u.test(line));\n if (!tasks.length) return 0;\n if (tasks.length < 5) {\n outcomes.push({\n domain,\n tasks,\n status: 0,\n attempts: 0,\n skipped: true,\n reason: 'small backlog: use the conversational refactor workflow',\n });\n return 0;\n }\n const id = `refactor-${domain\n .toLowerCase()\n .replace(/[^a-z0-9]+/gu, '-')\n .replace(/^-|-$/gu, '')}`;\n const draft = {\n id,\n kind: 'feature' as const,\n status: 'draft' as const,\n title: `Refactor ${domain}`,\n acceptance: tasks.map((task) => task.replace(/^- \\[ \\]\\s*/u, '')),\n surfaces: { [domain]: { tasks } },\n openQuestions: [],\n };\n const spec = { ...draft, status: 'frozen' as const, sha256: specContentSha256(draft) };\n const path = join(ctx.cwd, '.cohorte', 'specs', `${id}.yaml`);\n await mkdir(join(ctx.cwd, '.cohorte', 'specs'), { recursive: true });\n await writeFile(path, stringify(spec), 'utf8');\n const first = await run.run(ctx, {\n ...args,\n positionals: [path, '--profile', 'feature', '--phases', 'BUILD,TEST,REVIEW', '--with-fix'],\n });\n const firstGates = first === 0 ? await verifyDomain(ctx.cwd, domain) : 0;\n const result =\n first === 3 || firstGates !== 0\n ? await run.run(ctx, {\n ...args,\n positionals: [path, '--profile', 'feature', '--phases', 'BUILD,TEST,REVIEW', '--with-fix'],\n })\n : first;\n const finalGates = result === 0 ? await verifyDomain(ctx.cwd, domain) : 0;\n const status = finalGates !== 0 ? finalGates : result;\n outcomes.push({ domain, spec: path, tasks, status, attempts: first === 3 || firstGates !== 0 ? 2 : 1 });\n if (status === 0) {\n completed.push({ domain, tasks });\n }\n return status;\n };\n\n // V2 deliberately serialises the shared contract slice, then fans out\n // disjoint surfaces. Keeping that ordering avoids parallel agents editing\n // the same contract while retaining the wall-clock win for independent\n // domains.\n const ordered = domains.includes('shared')\n ? ['shared', ...domains.filter((domain) => domain !== 'shared')]\n : domains;\n const sharedStatus = ordered[0] === 'shared' ? await runDomain('shared') : 0;\n const parallelDomains = ordered[0] === 'shared' ? ordered.slice(1) : ordered;\n const statuses = sharedStatus === 0 ? await Promise.all(parallelDomains.map((domain) => runDomain(domain))) : [];\n for (const item of completed) {\n source = source\n .split(/\\r?\\n/u)\n .map((line) =>\n line.startsWith('- [ ] ') && item.tasks.includes(line) ? line.replace('- [ ] ', '- [x] ') : line,\n )\n .join('\\n');\n }\n await writeFile(backlogPath, `${source}\\n`, 'utf8');\n await writeFile(\n join(ctx.cwd, 'specs', 'reports', 'refactor.json'),\n `${JSON.stringify({ generatedAt: ctx.clock.now(), domains, outcomes }, null, 2)}\\n`,\n 'utf8',\n );\n return Math.max(sharedStatus, ...statuses, 0);\n },\n};\n\nexport default refactor;\n"],"mappings":"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"}