cohorte 3.0.0-dev.6 → 3.0.0-dev.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -392
- package/assets/manifest.json +14 -4
- package/assets/prompts/agents/brainstormer.md +3 -0
- package/assets/prompts/agents/spec-author.md +3 -0
- package/assets/schemas/commands.schema.json +7 -0
- package/dist/bundle-manifest.json +72 -50
- package/dist/chunks/align-ds-r_X_1aQ_.mjs +93 -0
- package/dist/chunks/align-ds-r_X_1aQ_.mjs.map +1 -0
- package/dist/chunks/audit-B4ZWQ_DI.mjs +179 -0
- package/dist/chunks/audit-B4ZWQ_DI.mjs.map +1 -0
- package/dist/chunks/brainstorm-SJwOIEif.mjs +123 -0
- package/dist/chunks/brainstorm-SJwOIEif.mjs.map +1 -0
- package/dist/chunks/build-C_-mbZfD.mjs +19 -0
- package/dist/chunks/build-C_-mbZfD.mjs.map +1 -0
- package/dist/chunks/{catalogue-DzsslCSN.mjs → catalogue-IaCJdfB8.mjs} +4 -4
- package/dist/chunks/{catalogue-DzsslCSN.mjs.map → catalogue-IaCJdfB8.mjs.map} +1 -1
- package/dist/chunks/{compose-ckM7eAJ_.mjs → compose-DRKjQcn0.mjs} +42 -23
- package/dist/chunks/compose-DRKjQcn0.mjs.map +1 -0
- package/dist/chunks/{config-DcGPL3i7.mjs → config-Cqu5XQoP.mjs} +2 -2
- package/dist/chunks/{config-DcGPL3i7.mjs.map → config-Cqu5XQoP.mjs.map} +1 -1
- package/dist/chunks/{contract-DiWla5G9.mjs → contract-DjssDPpS.mjs} +45 -25
- package/dist/chunks/contract-DjssDPpS.mjs.map +1 -0
- package/dist/chunks/{diff-D_0hBwHl.mjs → diff-Qw0II0sj.mjs} +2 -2
- package/dist/chunks/{diff-D_0hBwHl.mjs.map → diff-Qw0II0sj.mjs.map} +1 -1
- package/dist/chunks/{discover-BBiluyl4.mjs → discover-BZPolSZG.mjs} +2 -2
- package/dist/chunks/{discover-BBiluyl4.mjs.map → discover-BZPolSZG.mjs.map} +1 -1
- package/dist/chunks/{doctor-BAcemCDr.mjs → doctor-DcDFPvQM.mjs} +6 -6
- package/dist/chunks/{doctor-BAcemCDr.mjs.map → doctor-DcDFPvQM.mjs.map} +1 -1
- package/dist/chunks/fix-C9roGiQz.mjs +82 -0
- package/dist/chunks/fix-C9roGiQz.mjs.map +1 -0
- package/dist/chunks/fleet-yWHQY2ya.mjs +297 -0
- package/dist/chunks/fleet-yWHQY2ya.mjs.map +1 -0
- package/dist/chunks/{init-DfOKw-rD.mjs → init--FxxkrcT.mjs} +2 -2
- package/dist/chunks/{init-DfOKw-rD.mjs.map → init--FxxkrcT.mjs.map} +1 -1
- package/dist/chunks/intake-C1pesxCJ.mjs +12 -0
- package/dist/chunks/intake-C1pesxCJ.mjs.map +1 -0
- package/dist/chunks/loop-BWsUpyus.mjs +212 -0
- package/dist/chunks/loop-BWsUpyus.mjs.map +1 -0
- package/dist/chunks/{migrate-D3-4beNR.mjs → migrate-DuYCAbE3.mjs} +2 -2
- package/dist/chunks/{migrate-D3-4beNR.mjs.map → migrate-DuYCAbE3.mjs.map} +1 -1
- package/dist/chunks/{obsidian-D1jf1sTR.mjs → obsidian-BHLkXx_H.mjs} +50 -6
- package/dist/chunks/obsidian-BHLkXx_H.mjs.map +1 -0
- package/dist/chunks/patch-sAgVqjpx.mjs +50 -0
- package/dist/chunks/patch-sAgVqjpx.mjs.map +1 -0
- package/dist/chunks/{policy-Y65MYKzn.mjs → policy-Du7WVBFX.mjs} +4 -4
- package/dist/chunks/{policy-Y65MYKzn.mjs.map → policy-Du7WVBFX.mjs.map} +1 -1
- package/dist/chunks/{reconcile-B6mGZWtp.mjs → reconcile-BHn66X3C.mjs} +3 -3
- package/dist/chunks/{reconcile-B6mGZWtp.mjs.map → reconcile-BHn66X3C.mjs.map} +1 -1
- package/dist/chunks/refactor-DV3RfGjk.mjs +153 -0
- package/dist/chunks/refactor-DV3RfGjk.mjs.map +1 -0
- package/dist/chunks/retro-Dr-2RTNN.mjs +78 -0
- package/dist/chunks/retro-Dr-2RTNN.mjs.map +1 -0
- package/dist/chunks/review-ZsBqp3vZ.mjs +35 -0
- package/dist/chunks/review-ZsBqp3vZ.mjs.map +1 -0
- package/dist/chunks/{run-BInPXOcm.mjs → run-BGabwbDL.mjs} +32 -5
- package/dist/chunks/run-BGabwbDL.mjs.map +1 -0
- package/dist/chunks/{schema-hSyIURjN.mjs → schema-Bq9qtgsd.mjs} +2 -2
- package/dist/chunks/{schema-hSyIURjN.mjs.map → schema-Bq9qtgsd.mjs.map} +1 -1
- package/dist/chunks/ship-BizfUe62.mjs +140 -0
- package/dist/chunks/ship-BizfUe62.mjs.map +1 -0
- package/dist/chunks/spec-C2h3U64g.mjs +65 -0
- package/dist/chunks/spec-C2h3U64g.mjs.map +1 -0
- package/dist/chunks/spec-path-tptqR7W8.mjs +10 -0
- package/dist/chunks/spec-path-tptqR7W8.mjs.map +1 -0
- package/dist/chunks/{src-C7hs8Bjw.mjs → src-Bfr1yzsn.mjs} +3 -3
- package/dist/chunks/{src-C7hs8Bjw.mjs.map → src-Bfr1yzsn.mjs.map} +1 -1
- package/dist/chunks/{src-Daa5lIcP.mjs → src-CPW2_Ons.mjs} +101 -17
- package/dist/chunks/src-CPW2_Ons.mjs.map +1 -0
- package/dist/chunks/{src-DMrQ5m6I.mjs → src-DNsLSxgm.mjs} +2 -2
- package/dist/chunks/{src-DMrQ5m6I.mjs.map → src-DNsLSxgm.mjs.map} +1 -1
- package/dist/chunks/{src-BnlNkd3S.mjs → src-DbS9gkJy.mjs} +2 -2
- package/dist/chunks/{src-BnlNkd3S.mjs.map → src-DbS9gkJy.mjs.map} +1 -1
- package/dist/chunks/{src-s7YRvk0t.mjs → src-yi5whv3n.mjs} +4 -2
- package/dist/chunks/src-yi5whv3n.mjs.map +1 -0
- package/dist/chunks/update-pipeline-Du-Gu1Pl.mjs +56 -0
- package/dist/chunks/update-pipeline-Du-Gu1Pl.mjs.map +1 -0
- package/dist/cli.mjs +29 -19
- package/dist/cli.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/chunks/brainstorm-kBUiZLce.mjs +0 -7
- package/dist/chunks/brainstorm-kBUiZLce.mjs.map +0 -1
- package/dist/chunks/compose-ckM7eAJ_.mjs.map +0 -1
- package/dist/chunks/contract-DiWla5G9.mjs.map +0 -1
- package/dist/chunks/fix-D4Tj8RVA.mjs +0 -18
- package/dist/chunks/fix-D4Tj8RVA.mjs.map +0 -1
- package/dist/chunks/obsidian-D1jf1sTR.mjs.map +0 -1
- package/dist/chunks/review-BDdjb6kB.mjs +0 -17
- package/dist/chunks/review-BDdjb6kB.mjs.map +0 -1
- package/dist/chunks/run-BInPXOcm.mjs.map +0 -1
- package/dist/chunks/ship-DTuLGoaJ.mjs +0 -19
- package/dist/chunks/ship-DTuLGoaJ.mjs.map +0 -1
- package/dist/chunks/spec-MVP9y8dN.mjs +0 -20
- package/dist/chunks/spec-MVP9y8dN.mjs.map +0 -1
- package/dist/chunks/src-Daa5lIcP.mjs.map +0 -1
- package/dist/chunks/src-s7YRvk0t.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate-
|
|
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"}
|
|
@@ -1,7 +1,24 @@
|
|
|
1
1
|
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
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
|
|
4
16
|
//#region src/commands/obsidian/index.ts
|
|
17
|
+
var obsidian_exports = /* @__PURE__ */ __exportAll({
|
|
18
|
+
configuredIdeas: () => configuredIdeas,
|
|
19
|
+
default: () => obsidian,
|
|
20
|
+
moveConfiguredCard: () => moveConfiguredCard
|
|
21
|
+
});
|
|
5
22
|
const COLUMNS = [
|
|
6
23
|
"Ideas",
|
|
7
24
|
"Brainstorm",
|
|
@@ -60,6 +77,10 @@ function parseCards(source) {
|
|
|
60
77
|
});
|
|
61
78
|
return cards;
|
|
62
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
|
+
}
|
|
63
84
|
async function loadUserConfig(home) {
|
|
64
85
|
const path = join(home, ".cohorte", "config.yaml");
|
|
65
86
|
try {
|
|
@@ -97,12 +118,22 @@ async function boardPath(home) {
|
|
|
97
118
|
path
|
|
98
119
|
};
|
|
99
120
|
}
|
|
100
|
-
function replaceCard(source, id, target) {
|
|
121
|
+
function replaceCard(source, id, target, title = id) {
|
|
101
122
|
const lines = source.split(/\r?\n/);
|
|
102
|
-
const
|
|
103
|
-
if (!card) throw new Error(`Obsidian card #${id} was not found`);
|
|
123
|
+
const cards = parseCards(source);
|
|
104
124
|
if (!COLUMNS.includes(target)) throw new Error(`Unknown Obsidian column: ${target}`);
|
|
105
|
-
|
|
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");
|
|
106
137
|
const line = lines[card.line] ?? "";
|
|
107
138
|
lines.splice(card.line, 1);
|
|
108
139
|
let heading = lines.indexOf(`## ${target}`);
|
|
@@ -116,6 +147,19 @@ function replaceCard(source, id, target) {
|
|
|
116
147
|
lines.splice(insert, 0, line);
|
|
117
148
|
return lines.join("\n");
|
|
118
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
|
+
}
|
|
119
163
|
const obsidian = {
|
|
120
164
|
verb: "obsidian",
|
|
121
165
|
async run(ctx, args) {
|
|
@@ -186,6 +230,6 @@ const obsidian = {
|
|
|
186
230
|
}
|
|
187
231
|
};
|
|
188
232
|
//#endregion
|
|
189
|
-
export {
|
|
233
|
+
export { __exportAll as i, moveConfiguredCard as n, obsidian_exports as r, configuredIdeas as t };
|
|
190
234
|
|
|
191
|
-
//# sourceMappingURL=obsidian-
|
|
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":";;;;;;;;;;;;;;;;;;;;;AAQA,MAAM,UAAU;CAAC;CAAS;CAAc;CAAQ;CAAkB;CAAY;CAAU;CAAO;CAAQ;AAAS;AAChH,MAAM,yBAAS,IAAI,IAAI;CACrB,CAAC,SAAS,OAAO;CACjB,CAAC,cAAc,YAAY;CAC3B,CAAC,QAAQ,MAAM;CACf,CAAC,SAAS,gBAAgB;CAC1B,CAAC,YAAY,UAAU;CACvB,CAAC,UAAU,QAAQ;CACnB,CAAC,OAAO,KAAK;CACb,CAAC,QAAQ,MAAM;CACf,CAAC,WAAW,SAAS;AACvB,CAAC;AAED,MAAM,iBAAiB;;;;EAIrB,QAAQ,KAAK,WAAW,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE;;;;;;;AAQvD,SAAS,WAAW,QAAwB;CAC1C,MAAM,QAAQ,OAAO,MAAM,OAAO;CAClC,IAAI,SAAS;CACb,MAAM,QAAgB,CAAC;CACvB,MAAM,SAAS,MAAM,cAAc;EACjC,MAAM,UAAU,kBAAkB,KAAK,IAAI;EAC3C,IAAI,SAAS;GACX,SAAS,QAAQ,MAAM;GACvB;EACF;EACA,MAAM,OAAO,2BAA2B,KAAK,IAAI;EACjD,IAAI,CAAC,QAAQ,CAAC,QAAQ;EACtB,MAAM,QAAQ,KAAK,MAAM;EACzB,MAAM,MAAM,2BAA2B,KAAK,KAAK;EACjD,IAAI,CAAC,KAAK;EACV,MAAM,KAAK;GACT,KAAK,IAAI,MAAM,GAAA,CAAI,YAAY;GAC/B;GACA,UAAU,KAAK,MAAM,GAAA,CAAI,YAAY,MAAM;GAC3C;GACA,MAAM;EACR,CAAC;CACH,CAAC;CACD,OAAO;AACT;AAEA,eAAsB,gBAAgB,MAAuC;CAC3E,MAAM,WAAW,MAAM,UAAU,IAAI;CACrC,OAAO,WAAW,MAAM,SAAS,SAAS,MAAM,MAAM,CAAC,CAAC,CAAC,QAAQ,SAAS,KAAK,WAAW,OAAO;AACnG;AAEA,eAAe,eAAe,MAAyE;CACrG,MAAM,OAAO,KAAK,MAAM,YAAY,aAAa;CACjD,IAAI;EACF,MAAM,QAAQ,MAAM,MAAM,SAAS,MAAM,MAAM,CAAC;EAChD,OAAO;GAAE;GAAM,OAAO,SAAS,OAAO,UAAU,WAAW,QAAQ,CAAC;EAAE;CACxE,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAAU,MAAM;EAC9D,OAAO;GAAE;GAAM,OAAO,CAAC;EAAE;CAC3B;AACF;AAEA,SAAS,WAAW,OAAkF;CACpG,MAAM,eAAe,MAAM;CAC3B,IAAI,CAAC,gBAAgB,OAAO,iBAAiB,UAAU,OAAO,KAAA;CAC9D,MAAM,WAAY,aAAyC;CAC3D,IAAI,CAAC,YAAY,OAAO,aAAa,UAAU,OAAO,KAAA;CACtD,MAAM,EAAE,WAAW,UAAU;CAC7B,OAAO,OAAO,cAAc,YAAY,OAAO,UAAU,WAAW;EAAE;EAAW;CAAM,IAAI,KAAA;AAC7F;AAEA,eAAe,UAAU,MAAuF;CAE9G,MAAM,SAAS,YAAW,MADL,eAAe,IAAI,EAAA,CACP,KAAK;CACtC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,4EAA4E;CACzG,MAAM,OAAO,QAAQ,OAAO,WAAW,OAAO,KAAK;CACnD,MAAM,OAAO,IAAI;CACjB,OAAO;EAAE;EAAQ;CAAK;AACxB;AAEA,SAAS,YAAY,QAAgB,IAAY,QAAgB,QAAQ,IAAY;CACnF,MAAM,QAAQ,OAAO,MAAM,OAAO;CAClC,MAAM,QAAQ,WAAW,MAAM;CAC/B,IAAI,CAAC,QAAQ,SAAS,MAAM,GAAG,MAAM,IAAI,MAAM,4BAA4B,QAAQ;CACnF,MAAM,UAAU,MAAM,QAAQ,SAAS,KAAK,OAAO,EAAE;CACrD,MAAM,OAAO,QAAQ;CACrB,IAAI,CAAC,MAAM;EACT,MAAM,UAAU,MAAM,QAAQ,MAAM,QAAQ;EAC5C,IAAI,UAAU,GAAG,MAAM,IAAI,MAAM,mBAAmB,OAAO,eAAe;EAC1E,IAAI,SAAS,UAAU;EACvB,OAAO,SAAS,MAAM,UAAU,EAAE,MAAM,WAAW,GAAA,CAAI,WAAW,KAAK,GAAG;EAC1E,MAAM,OAAO,QAAQ,GAAG,SAAS,MAAM,KAAK,IAAI;EAChD,OAAO,MAAM,KAAK,IAAI;CACxB;CACA,KAAK,MAAM,aAAa,QAAQ,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI,GAAG,MAAM,OAAO,UAAU,MAAM,CAAC;CACxG,IAAI,KAAK,WAAW,QAAQ,OAAO,MAAM,KAAK,IAAI;CAClD,MAAM,OAAO,MAAM,KAAK,SAAS;CACjC,MAAM,OAAO,KAAK,MAAM,CAAC;CACzB,IAAI,UAAU,MAAM,QAAQ,MAAM,QAAQ;CAC1C,IAAI,UAAU,GAAG;EACf,IAAI,CAAC,OAAO,SAAS,IAAI,GAAG,MAAM,KAAK,EAAE;EACzC,MAAM,KAAK,MAAM,UAAU,EAAE;EAC7B,UAAU,MAAM,SAAS;CAC3B;CACA,IAAI,SAAS,UAAU;CACvB,OAAO,SAAS,MAAM,UAAU,EAAE,MAAM,WAAW,GAAA,CAAI,WAAW,KAAK,GAAG;CAC1E,MAAM,OAAO,QAAQ,GAAG,IAAI;CAC5B,OAAO,MAAM,KAAK,IAAI;AACxB;;AAGA,eAAsB,mBAAmB,MAAc,IAAY,OAAe,QAAQ,IAAsB;CAC9G,IAAI;EACF,MAAM,WAAW,MAAM,UAAU,IAAI;EACrC,MAAM,SAAS,MAAM,SAAS,SAAS,MAAM,MAAM;EAEnD,MAAM,OAAO,YAAY,QAAQ,IADlB,OAAO,IAAI,KAAK,KAAK,OACS,KAAK;EAClD,IAAI,SAAS,QAAQ,MAAM,UAAU,SAAS,MAAM,MAAM,MAAM;EAChE,OAAO;CACT,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,YAAY,OAAO,KAAK,CAAC,CAAC,SAAS,gBAAgB,GAAG,OAAO;EAC3G,MAAM;CACR;AACF;AAEA,MAAM,WAA0B;CAC9B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,OAAO,IAAI,IAAI,QAAQ,IAAI;EACjC,IAAI,KAAK,YAAY,UAAU;GAC7B,MAAM,CAAC,WAAW,QAAQ,oBAAoB,KAAK;GACnD,IAAI,CAAC,WAAW,OAAO;GACvB,MAAM,OAAO,QAAQ,WAAW,KAAK;GACrC,IAAI;IACF,MAAM,OAAO,IAAI;IACjB,MAAM,IAAI,MAAM,kCAAkC,MAAM;GAC1D,SAAS,OAAO;IACd,IAAK,MAAgC,SAAS,UAAU,MAAM;GAChE;GACA,MAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;GAC9C,MAAM,UAAU,MAAM,gBAAgB,MAAM;GAC5C,MAAM,SAAS,MAAM,eAAe,IAAI;GACxC,MAAM,eAAe,OAAO,MAAM;GAClC,MAAM,mBAAmB,gBAAgB,OAAO,iBAAiB,WAAW,EAAE,GAAI,aAAwB,IAAI,CAAC;GAC/G,iBAA8C,WAAW;IAAE;IAAW;GAAM;GAC5E,OAAO,MAAM,eAAe;GAC5B,MAAM,MAAM,QAAQ,OAAO,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;GACrD,MAAM,UAAU,OAAO,MAAM,UAAU,OAAO,KAAK,GAAG,MAAM;GAC5D,IAAI,MAAM,OAAO,MAAM,yBAAyB,KAAK,GAAG;GACxD,OAAO;EACT;EACA,IAAI,KAAK,YAAY,WAAW;GAC9B,MAAM,CAAC,WAAW,QAAQ,oBAAoB,KAAK;GACnD,IAAI,CAAC,WAAW,OAAO;GACvB,MAAM,SAAS,MAAM,eAAe,IAAI;GACxC,MAAM,eAAe,OAAO,MAAM;GAClC,MAAM,mBAAmB,gBAAgB,OAAO,iBAAiB,WAAW,EAAE,GAAI,aAAwB,IAAI,CAAC;GAC/G,iBAA8C,WAAW;IAAE;IAAW;GAAM;GAC5E,OAAO,MAAM,eAAe;GAC5B,MAAM,MAAM,QAAQ,OAAO,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;GACrD,MAAM,UAAU,OAAO,MAAM,UAAU,OAAO,KAAK,GAAG,MAAM;GAC5D,IAAI,MAAM,OAAO,MAAM,aAAa,QAAQ,WAAW,KAAK,EAAE,GAAG;GACjE,OAAO;EACT;EACA,IAAI,KAAK,YAAY,UAAU;GAC7B,MAAM,WAAW,MAAM,UAAU,IAAI;GACrC,MAAM,QAAQ,WAAW,MAAM,SAAS,SAAS,MAAM,MAAM,CAAC;GAC9D,IAAI,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU;IAAE,GAAG,SAAS;IAAQ,MAAM,SAAS;IAAM;GAAM,CAAC,EAAE,GAAG;QAE7G,IAAI,MAAM,OAAO,MACf,GAAG,SAAS,KAAK,IAAI,MAAM,KAAK,SAAS,GAAG,KAAK,GAAG,IAAI,KAAK,OAAO,IAAI,KAAK,OAAO,CAAC,CAAC,KAAK,IAAI,EAAE,GACnG;GACF,OAAO;EACT;EACA,IAAI,KAAK,YAAY,QAAQ;GAC3B,MAAM,CAAC,IAAI,SAAS,KAAK;GACzB,MAAM,SAAS,QAAS,OAAO,IAAI,KAAK,KAAK,QAAS,KAAA;GACtD,IAAI,CAAC,MAAM,CAAC,QAAQ,OAAO;GAC3B,MAAM,WAAW,MAAM,UAAU,IAAI;GACrC,MAAM,SAAS,MAAM,SAAS,SAAS,MAAM,MAAM;GACnD,MAAM,UAAU,SAAS,MAAM,YAAY,QAAQ,IAAI,MAAM,GAAG,MAAM;GACtE,IAAI,MAAM,OAAO,MAAM,UAAU,GAAG,MAAM,OAAO,GAAG;GACpD,OAAO;EACT;EACA,OAAO;CACT;AACF"}
|
|
@@ -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-
|
|
5
|
-
import "./src-
|
|
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-
|
|
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-
|
|
139
|
+
//# sourceMappingURL=policy-Du7WVBFX.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy-
|
|
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-
|
|
2
|
-
import { l as deriveDesiredState, n as planReconcile, t as applyReconcile } from "./src-
|
|
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-
|
|
50
|
+
//# sourceMappingURL=reconcile-BHn66X3C.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reconcile-
|
|
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-BGabwbDL.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-DV3RfGjk.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refactor-DV3RfGjk.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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"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { appendFile, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
//#region src/commands/retro/index.ts
|
|
4
|
+
const normalise = (line) => line.replace(/^-\s+\[[ xX]\]\s+/u, "").replace(/\b[A-Za-z0-9_./-]+:\d+\b/gu, "<file>").replace(/\s+/gu, " ").trim().toLowerCase();
|
|
5
|
+
const listFiles = async (dir) => {
|
|
6
|
+
try {
|
|
7
|
+
return (await readdir(dir, { withFileTypes: true })).filter((x) => x.isFile()).map((x) => join(dir, x.name));
|
|
8
|
+
} catch {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
const retro = {
|
|
13
|
+
verb: "retro",
|
|
14
|
+
async run(ctx, args) {
|
|
15
|
+
const reportDir = join(ctx.cwd, "specs", "reports");
|
|
16
|
+
let files = [...await listFiles(reportDir), ...await listFiles(join(ctx.cwd, "specs"))].filter((file) => !file.endsWith("_decisions.md"));
|
|
17
|
+
if (args.positionals.find((value, index) => value === "last" && args.positionals[index + 1])) {
|
|
18
|
+
const count = Number(args.positionals[args.positionals.indexOf("last") + 1]);
|
|
19
|
+
if (!Number.isInteger(count) || count < 1) return 2;
|
|
20
|
+
files = files.sort().slice(-count);
|
|
21
|
+
}
|
|
22
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
23
|
+
for (const file of files) {
|
|
24
|
+
let source = "";
|
|
25
|
+
try {
|
|
26
|
+
source = await readFile(file, "utf8");
|
|
27
|
+
} catch {
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
for (const line of source.split(/\r?\n/u).filter((x) => /\b(CRITICAL|HIGH|MEDIUM|LOW)\b|blocking_items|Remediation/iu.test(x))) {
|
|
31
|
+
const key = normalise(line);
|
|
32
|
+
if (key.length < 12) continue;
|
|
33
|
+
const item = grouped.get(key) ?? {
|
|
34
|
+
key,
|
|
35
|
+
count: 0,
|
|
36
|
+
evidence: [],
|
|
37
|
+
rule: `Enforce: ${line.trim()}`
|
|
38
|
+
};
|
|
39
|
+
item.count++;
|
|
40
|
+
if (item.evidence.length < 5) item.evidence.push(`${file.replace(`${ctx.cwd}/`, "")} · ${line.trim()}`);
|
|
41
|
+
grouped.set(key, item);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const patterns = [...grouped.values()].map((pattern) => ({
|
|
45
|
+
...pattern,
|
|
46
|
+
count: new Set(pattern.evidence.map((value) => value.split(" · ")[0])).size
|
|
47
|
+
})).filter((x) => x.count >= 2).sort((a, b) => b.count - a.count);
|
|
48
|
+
const result = {
|
|
49
|
+
patterns,
|
|
50
|
+
evidenceFiles: files.map((x) => x.replace(`${ctx.cwd}/`, ""))
|
|
51
|
+
};
|
|
52
|
+
await mkdir(reportDir, { recursive: true });
|
|
53
|
+
await writeFile(join(reportDir, "retro-scan.txt"), `${ctx.clock.now()}\n${patterns.map((pattern) => `${pattern.count}x ${pattern.rule}\n${pattern.evidence.join("\n")}`).join("\n")}\n`, "utf8");
|
|
54
|
+
if (!args.positionals.includes("--apply")) {
|
|
55
|
+
ctx.stdio.stdout.write(`${args.json ? JSON.stringify(result) : patterns.length ? patterns.map((x) => `${x.count}x · ${x.rule}`).join("\n") : "no recurring review patterns found"}\n`);
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
const rules = args.positionals.flatMap((value, index, all) => value === "--rule" && all[index + 1] ? [all[index + 1]] : []);
|
|
59
|
+
if (!rules.length) return 2;
|
|
60
|
+
const pipeline = join(ctx.cwd, "PIPELINE.md");
|
|
61
|
+
let source = "";
|
|
62
|
+
try {
|
|
63
|
+
source = await readFile(pipeline, "utf8");
|
|
64
|
+
} catch {
|
|
65
|
+
source = "# Cohorte Pipeline\n\n## Conventions\n\n";
|
|
66
|
+
}
|
|
67
|
+
if (!/^## Conventions\s*$/mu.test(source)) source += `${source.endsWith("\n") ? "" : "\n"}\n## Conventions\n\n`;
|
|
68
|
+
await writeFile(pipeline, `${source}${source.endsWith("\n") ? "" : "\n"}${rules.map((x) => `- ${x}`).join("\n")}\n`, "utf8");
|
|
69
|
+
await mkdir(join(ctx.cwd, "specs"), { recursive: true });
|
|
70
|
+
await appendFile(join(ctx.cwd, "specs", "_decisions.md"), `${ctx.clock.now().slice(0, 10)} · conventions · ${rules.join("; ")} — because retro ratification\n`);
|
|
71
|
+
ctx.stdio.stdout.write(`applied ${rules.length} convention(s); run cohorte update-pipeline to refresh agents\n`);
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
export { retro as default };
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=retro-Dr-2RTNN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"retro-Dr-2RTNN.mjs","names":[],"sources":["../../../../apps/cli/src/commands/retro/index.ts"],"sourcesContent":["import { appendFile, mkdir, readdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport type { CommandModule } from '../../contract/index.ts';\n\ntype Pattern = { key: string; count: number; evidence: string[]; rule: string };\nconst normalise = (line: string) =>\n line\n .replace(/^-\\s+\\[[ xX]\\]\\s+/u, '')\n .replace(/\\b[A-Za-z0-9_./-]+:\\d+\\b/gu, '<file>')\n .replace(/\\s+/gu, ' ')\n .trim()\n .toLowerCase();\nconst listFiles = async (dir: string) => {\n try {\n return (await readdir(dir, { withFileTypes: true })).filter((x) => x.isFile()).map((x) => join(dir, x.name));\n } catch {\n return [];\n }\n};\n\nconst retro: CommandModule = {\n verb: 'retro',\n async run(ctx, args) {\n const reportDir = join(ctx.cwd, 'specs', 'reports');\n let files = [...(await listFiles(reportDir)), ...(await listFiles(join(ctx.cwd, 'specs')))].filter(\n (file) => !file.endsWith('_decisions.md'),\n );\n const last = args.positionals.find((value, index) => value === 'last' && args.positionals[index + 1]);\n if (last) {\n const count = Number(args.positionals[args.positionals.indexOf('last') + 1]);\n if (!Number.isInteger(count) || count < 1) return 2;\n files = files.sort().slice(-count);\n }\n const grouped = new Map<string, Pattern>();\n for (const file of files) {\n let source = '';\n try {\n source = await readFile(file, 'utf8');\n } catch {\n continue;\n }\n for (const line of source\n .split(/\\r?\\n/u)\n .filter((x) => /\\b(CRITICAL|HIGH|MEDIUM|LOW)\\b|blocking_items|Remediation/iu.test(x))) {\n const key = normalise(line);\n if (key.length < 12) continue;\n const item = grouped.get(key) ?? { key, count: 0, evidence: [], rule: `Enforce: ${line.trim()}` };\n item.count++;\n if (item.evidence.length < 5) item.evidence.push(`${file.replace(`${ctx.cwd}/`, '')} · ${line.trim()}`);\n grouped.set(key, item);\n }\n }\n const patterns = [...grouped.values()]\n .map((pattern) => ({ ...pattern, count: new Set(pattern.evidence.map((value) => value.split(' · ')[0])).size }))\n .filter((x) => x.count >= 2)\n .sort((a, b) => b.count - a.count);\n const result = { patterns, evidenceFiles: files.map((x) => x.replace(`${ctx.cwd}/`, '')) };\n await mkdir(reportDir, { recursive: true });\n await writeFile(\n join(reportDir, 'retro-scan.txt'),\n `${ctx.clock.now()}\\n${patterns.map((pattern) => `${pattern.count}x ${pattern.rule}\\n${pattern.evidence.join('\\n')}`).join('\\n')}\\n`,\n 'utf8',\n );\n if (!args.positionals.includes('--apply')) {\n ctx.stdio.stdout.write(\n `${args.json ? JSON.stringify(result) : patterns.length ? patterns.map((x) => `${x.count}x · ${x.rule}`).join('\\n') : 'no recurring review patterns found'}\\n`,\n );\n return 0;\n }\n const rules = args.positionals.flatMap((value, index, all) =>\n value === '--rule' && all[index + 1] ? [all[index + 1] as string] : [],\n );\n if (!rules.length) return 2;\n const pipeline = join(ctx.cwd, 'PIPELINE.md');\n let source = '';\n try {\n source = await readFile(pipeline, 'utf8');\n } catch {\n source = '# Cohorte Pipeline\\n\\n## Conventions\\n\\n';\n }\n if (!/^## Conventions\\s*$/mu.test(source)) source += `${source.endsWith('\\n') ? '' : '\\n'}\\n## Conventions\\n\\n`;\n await writeFile(\n pipeline,\n `${source}${source.endsWith('\\n') ? '' : '\\n'}${rules.map((x) => `- ${x}`).join('\\n')}\\n`,\n 'utf8',\n );\n await mkdir(join(ctx.cwd, 'specs'), { recursive: true });\n await appendFile(\n join(ctx.cwd, 'specs', '_decisions.md'),\n `${ctx.clock.now().slice(0, 10)} · conventions · ${rules.join('; ')} — because retro ratification\\n`,\n );\n ctx.stdio.stdout.write(`applied ${rules.length} convention(s); run cohorte update-pipeline to refresh agents\\n`);\n return 0;\n },\n};\nexport default retro;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { t as resolveSpecPath } from "./spec-path-tptqR7W8.mjs";
|
|
2
|
+
//#region src/commands/review/index.ts
|
|
3
|
+
const review = {
|
|
4
|
+
verb: "review",
|
|
5
|
+
async run(ctx, args) {
|
|
6
|
+
const valueAfter = (flag) => {
|
|
7
|
+
const index = args.positionals.indexOf(flag);
|
|
8
|
+
return index >= 0 ? args.positionals[index + 1] : void 0;
|
|
9
|
+
};
|
|
10
|
+
const target = args.positionals.find((value, index) => !value.startsWith("--") && args.positionals[index - 1] !== "--ref" && args.positionals[index - 1] !== "--base" && args.positionals[index - 1] !== "--head" && args.positionals[index - 1] !== "--pr");
|
|
11
|
+
const ref = valueAfter("--ref");
|
|
12
|
+
const base = valueAfter("--base");
|
|
13
|
+
const head = valueAfter("--head");
|
|
14
|
+
const pr = valueAfter("--pr");
|
|
15
|
+
const surfaces = args.positionals.flatMap((value, index) => value === "--surface" && args.positionals[index + 1] ? [args.positionals[index + 1]] : []).concat((valueAfter("--surfaces") ?? "").split(",").filter(Boolean));
|
|
16
|
+
if (args.positionals.includes("--pr") && !pr) return 2;
|
|
17
|
+
const reviewTarget = pr ? { ref: `refs/pull/${pr}/head` } : base || head ? {
|
|
18
|
+
base: base ?? "HEAD~1",
|
|
19
|
+
head: head ?? "HEAD"
|
|
20
|
+
} : ref ? { ref } : target?.startsWith("run_") ? { runId: target } : target?.includes("/") || target?.startsWith("refs/") ? { ref: target } : void 0;
|
|
21
|
+
const result = await ctx.controller.send("start", {
|
|
22
|
+
profile: "review",
|
|
23
|
+
unattended: false,
|
|
24
|
+
...surfaces.length > 0 ? { surfaces } : {},
|
|
25
|
+
...reviewTarget ? { reviewTarget } : {},
|
|
26
|
+
...!reviewTarget && target ? { spec: { path: resolveSpecPath(ctx.cwd, target) } } : {}
|
|
27
|
+
});
|
|
28
|
+
ctx.stdio.stdout.write(`${JSON.stringify(result)}\n`);
|
|
29
|
+
return result.status === "rejected" ? 3 : result.status === "pending" ? 4 : 0;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { review as default };
|
|
34
|
+
|
|
35
|
+
//# sourceMappingURL=review-ZsBqp3vZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-ZsBqp3vZ.mjs","names":[],"sources":["../../../../apps/cli/src/commands/review/index.ts"],"sourcesContent":["import type { CommandModule } from '../../contract/index.ts';\nimport { resolveSpecPath } from '../../project/spec-path.ts';\n\nconst review: CommandModule = {\n verb: 'review',\n async run(ctx, args) {\n const valueAfter = (flag: string): string | undefined => {\n const index = args.positionals.indexOf(flag);\n return index >= 0 ? args.positionals[index + 1] : undefined;\n };\n const target = args.positionals.find(\n (value, index) =>\n !value.startsWith('--') &&\n args.positionals[index - 1] !== '--ref' &&\n args.positionals[index - 1] !== '--base' &&\n args.positionals[index - 1] !== '--head' &&\n args.positionals[index - 1] !== '--pr',\n );\n const ref = valueAfter('--ref');\n const base = valueAfter('--base');\n const head = valueAfter('--head');\n const pr = valueAfter('--pr');\n const surfaces = args.positionals\n .flatMap((value, index) =>\n value === '--surface' && args.positionals[index + 1] ? [args.positionals[index + 1] as never] : [],\n )\n .concat((valueAfter('--surfaces') ?? '').split(',').filter(Boolean) as never[]);\n if (args.positionals.includes('--pr') && !pr) return 2;\n const reviewTarget: { ref: string } | { base: string; head: string } | { runId: never } | undefined = pr\n ? { ref: `refs/pull/${pr}/head` }\n : base || head\n ? { base: base ?? 'HEAD~1', head: head ?? 'HEAD' }\n : ref\n ? { ref }\n : target?.startsWith('run_')\n ? { runId: target as never }\n : target?.includes('/') || target?.startsWith('refs/')\n ? { ref: target }\n : undefined;\n const result = await ctx.controller.send('start', {\n profile: 'review',\n unattended: false,\n ...(surfaces.length > 0 ? { surfaces } : {}),\n ...(reviewTarget ? { reviewTarget } : {}),\n ...(!reviewTarget && target ? { spec: { path: resolveSpecPath(ctx.cwd, target) } } : {}),\n });\n ctx.stdio.stdout.write(`${JSON.stringify(result)}\\n`);\n return result.status === 'rejected' ? 3 : result.status === 'pending' ? 4 : 0;\n },\n};\n\nexport default review;\n"],"mappings":";;AAGA,MAAM,SAAwB;CAC5B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,cAAc,SAAqC;GACvD,MAAM,QAAQ,KAAK,YAAY,QAAQ,IAAI;GAC3C,OAAO,SAAS,IAAI,KAAK,YAAY,QAAQ,KAAK,KAAA;EACpD;EACA,MAAM,SAAS,KAAK,YAAY,MAC7B,OAAO,UACN,CAAC,MAAM,WAAW,IAAI,KACtB,KAAK,YAAY,QAAQ,OAAO,WAChC,KAAK,YAAY,QAAQ,OAAO,YAChC,KAAK,YAAY,QAAQ,OAAO,YAChC,KAAK,YAAY,QAAQ,OAAO,MACpC;EACA,MAAM,MAAM,WAAW,OAAO;EAC9B,MAAM,OAAO,WAAW,QAAQ;EAChC,MAAM,OAAO,WAAW,QAAQ;EAChC,MAAM,KAAK,WAAW,MAAM;EAC5B,MAAM,WAAW,KAAK,YACnB,SAAS,OAAO,UACf,UAAU,eAAe,KAAK,YAAY,QAAQ,KAAK,CAAC,KAAK,YAAY,QAAQ,EAAW,IAAI,CAAC,CACnG,CAAC,CACA,QAAQ,WAAW,YAAY,KAAK,GAAA,CAAI,MAAM,GAAG,CAAC,CAAC,OAAO,OAAO,CAAY;EAChF,IAAI,KAAK,YAAY,SAAS,MAAM,KAAK,CAAC,IAAI,OAAO;EACrD,MAAM,eAAgG,KAClG,EAAE,KAAK,aAAa,GAAG,OAAO,IAC9B,QAAQ,OACN;GAAE,MAAM,QAAQ;GAAU,MAAM,QAAQ;EAAO,IAC/C,MACE,EAAE,IAAI,IACN,QAAQ,WAAW,MAAM,IACvB,EAAE,OAAO,OAAgB,IACzB,QAAQ,SAAS,GAAG,KAAK,QAAQ,WAAW,OAAO,IACjD,EAAE,KAAK,OAAO,IACd,KAAA;EACZ,MAAM,SAAS,MAAM,IAAI,WAAW,KAAK,SAAS;GAChD,SAAS;GACT,YAAY;GACZ,GAAI,SAAS,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;GAC1C,GAAI,eAAe,EAAE,aAAa,IAAI,CAAC;GACvC,GAAI,CAAC,gBAAgB,SAAS,EAAE,MAAM,EAAE,MAAM,gBAAgB,IAAI,KAAK,MAAM,EAAE,EAAE,IAAI,CAAC;EACxF,CAAC;EACD,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;EACpD,OAAO,OAAO,WAAW,aAAa,IAAI,OAAO,WAAW,YAAY,IAAI;CAC9E;AACF"}
|