cleargate 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +11 -1
- package/dist/MANIFEST.json +40 -26
- package/dist/chunk-HZPJ5QX4.js +459 -0
- package/dist/chunk-HZPJ5QX4.js.map +1 -0
- package/dist/cli.cjs +419 -202
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +387 -513
- package/dist/cli.js.map +1 -1
- package/dist/lib/lifecycle-reconcile.cjs +497 -0
- package/dist/lib/lifecycle-reconcile.cjs.map +1 -0
- package/dist/lib/lifecycle-reconcile.d.cts +136 -0
- package/dist/lib/lifecycle-reconcile.d.ts +136 -0
- package/dist/lib/lifecycle-reconcile.js +20 -0
- package/dist/lib/lifecycle-reconcile.js.map +1 -0
- package/dist/templates/cleargate-planning/.claude/agents/architect.md +55 -2
- package/dist/templates/cleargate-planning/.claude/agents/developer.md +22 -0
- package/dist/templates/cleargate-planning/.claude/agents/devops.md +249 -0
- package/dist/templates/cleargate-planning/.claude/agents/qa.md +41 -0
- package/dist/templates/cleargate-planning/.claude/agents/reporter.md +44 -8
- package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +21 -0
- package/dist/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +12 -1
- package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +21 -1
- package/dist/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +200 -29
- package/dist/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +160 -0
- package/dist/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +41 -9
- package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +98 -16
- package/dist/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +3 -3
- package/dist/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +86 -10
- package/dist/templates/cleargate-planning/.cleargate/scripts/run_script.sh +173 -87
- package/dist/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +150 -22
- package/dist/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +20 -20
- package/dist/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +32 -8
- package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +12 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +3 -0
- package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +3 -0
- package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +3 -0
- package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +3 -0
- package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +1 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/sprint_context.md +8 -0
- package/dist/templates/cleargate-planning/.cleargate/templates/story.md +3 -0
- package/dist/templates/cleargate-planning/CLAUDE.md +3 -1
- package/dist/templates/cleargate-planning/MANIFEST.json +40 -26
- package/package.json +8 -5
- package/templates/cleargate-planning/.claude/agents/architect.md +55 -2
- package/templates/cleargate-planning/.claude/agents/developer.md +22 -0
- package/templates/cleargate-planning/.claude/agents/devops.md +249 -0
- package/templates/cleargate-planning/.claude/agents/qa.md +41 -0
- package/templates/cleargate-planning/.claude/agents/reporter.md +44 -8
- package/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +21 -0
- package/templates/cleargate-planning/.claude/hooks/stamp-and-gate.sh +12 -1
- package/templates/cleargate-planning/.claude/hooks/token-ledger.sh +21 -1
- package/templates/cleargate-planning/.claude/skills/sprint-execution/SKILL.md +200 -29
- package/templates/cleargate-planning/.cleargate/knowledge/mid-sprint-triage-rubric.md +160 -0
- package/templates/cleargate-planning/.cleargate/knowledge/readiness-gates.md +41 -9
- package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +98 -16
- package/templates/cleargate-planning/.cleargate/scripts/gate-checks.json +3 -3
- package/templates/cleargate-planning/.cleargate/scripts/init_sprint.mjs +86 -10
- package/templates/cleargate-planning/.cleargate/scripts/run_script.sh +173 -87
- package/templates/cleargate-planning/.cleargate/scripts/suggest_improvements.mjs +150 -22
- package/templates/cleargate-planning/.cleargate/scripts/test/test_flashcard_gate.sh +20 -20
- package/templates/cleargate-planning/.cleargate/scripts/validate_state.mjs +32 -8
- package/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +12 -1
- package/templates/cleargate-planning/.cleargate/templates/Bug.md +3 -0
- package/templates/cleargate-planning/.cleargate/templates/CR.md +3 -0
- package/templates/cleargate-planning/.cleargate/templates/epic.md +3 -0
- package/templates/cleargate-planning/.cleargate/templates/hotfix.md +3 -0
- package/templates/cleargate-planning/.cleargate/templates/initiative.md +1 -1
- package/templates/cleargate-planning/.cleargate/templates/sprint_context.md +8 -0
- package/templates/cleargate-planning/.cleargate/templates/story.md +3 -0
- package/templates/cleargate-planning/CLAUDE.md +3 -1
- package/templates/cleargate-planning/MANIFEST.json +40 -26
package/dist/cli.cjs
CHANGED
|
@@ -696,10 +696,10 @@ var import_commander = require("commander");
|
|
|
696
696
|
// package.json
|
|
697
697
|
var package_default = {
|
|
698
698
|
name: "cleargate",
|
|
699
|
-
version: "0.
|
|
699
|
+
version: "0.11.0",
|
|
700
700
|
private: false,
|
|
701
701
|
type: "module",
|
|
702
|
-
description: "Planning framework for Claude Code agents \u2014 sprint/epic/story protocol,
|
|
702
|
+
description: "Planning framework for Claude Code agents \u2014 sprint/epic/story protocol, five-role agent team (architect/developer/qa/devops/reporter), Karpathy-style awareness wiki.",
|
|
703
703
|
license: "MIT",
|
|
704
704
|
bin: {
|
|
705
705
|
cleargate: "dist/cli.js"
|
|
@@ -743,9 +743,12 @@ var package_default = {
|
|
|
743
743
|
build: "tsup",
|
|
744
744
|
dev: "tsup --watch",
|
|
745
745
|
typecheck: "tsc --noEmit",
|
|
746
|
-
|
|
747
|
-
test: "
|
|
748
|
-
"test:
|
|
746
|
+
test: "tsx --test --test-reporter=spec 'test/**/*.node.test.ts'",
|
|
747
|
+
"test:file": "tsx --test --test-reporter=spec",
|
|
748
|
+
"test:vitest": "npm run build && vitest run",
|
|
749
|
+
"test:vitest:watch": "vitest",
|
|
750
|
+
"test:node": "tsx --test --test-reporter=spec 'test/**/*.node.test.ts'",
|
|
751
|
+
"test:node:file": "tsx --test --test-reporter=spec"
|
|
749
752
|
},
|
|
750
753
|
dependencies: {
|
|
751
754
|
"@napi-rs/keyring": "^1.2.0",
|
|
@@ -1991,7 +1994,20 @@ var HOOK_FILES_WITH_PIN = /* @__PURE__ */ new Set([
|
|
|
1991
1994
|
".claude/hooks/stamp-and-gate.sh",
|
|
1992
1995
|
".claude/hooks/session-start.sh"
|
|
1993
1996
|
]);
|
|
1994
|
-
var SKIP_FILES = /* @__PURE__ */ new Set(["CLAUDE.md"]);
|
|
1997
|
+
var SKIP_FILES = /* @__PURE__ */ new Set(["CLAUDE.md", "MANIFEST.json"]);
|
|
1998
|
+
var FIRST_INSTALL_ONLY = [
|
|
1999
|
+
".gitignore",
|
|
2000
|
+
".cleargate/FLASHCARD.md",
|
|
2001
|
+
/^\.cleargate\/scripts\//
|
|
2002
|
+
];
|
|
2003
|
+
function isFirstInstallOnly(relPath) {
|
|
2004
|
+
for (const pattern of FIRST_INSTALL_ONLY) {
|
|
2005
|
+
if (typeof pattern === "string" ? pattern === relPath : pattern.test(relPath)) {
|
|
2006
|
+
return true;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
return false;
|
|
2010
|
+
}
|
|
1995
2011
|
function listFilesRecursive(dir) {
|
|
1996
2012
|
const results = [];
|
|
1997
2013
|
function walk(current, rel) {
|
|
@@ -2045,6 +2061,14 @@ function copyPayload(payloadDir, targetCwd, opts) {
|
|
|
2045
2061
|
report.actions.push({ action: "skipped", relPath });
|
|
2046
2062
|
continue;
|
|
2047
2063
|
}
|
|
2064
|
+
if (isFirstInstallOnly(relPath)) {
|
|
2065
|
+
if (needsExec && process.platform !== "win32") {
|
|
2066
|
+
fs7.chmodSync(dstPath, 493);
|
|
2067
|
+
}
|
|
2068
|
+
report.skipped++;
|
|
2069
|
+
report.actions.push({ action: "skipped", relPath });
|
|
2070
|
+
continue;
|
|
2071
|
+
}
|
|
2048
2072
|
fs7.writeFileSync(dstPath, srcBuffer);
|
|
2049
2073
|
if (needsExec && process.platform !== "win32") {
|
|
2050
2074
|
fs7.chmodSync(dstPath, 493);
|
|
@@ -2183,7 +2207,8 @@ var PREFIX_MAP = [
|
|
|
2183
2207
|
{ prefix: "SPRINT-", type: "sprint", bucket: "sprints" },
|
|
2184
2208
|
{ prefix: "PROPOSAL-", type: "proposal", bucket: "proposals" },
|
|
2185
2209
|
{ prefix: "CR-", type: "cr", bucket: "crs" },
|
|
2186
|
-
{ prefix: "BUG-", type: "bug", bucket: "bugs" }
|
|
2210
|
+
{ prefix: "BUG-", type: "bug", bucket: "bugs" },
|
|
2211
|
+
{ prefix: "INITIATIVE-", type: "initiative", bucket: "initiatives" }
|
|
2187
2212
|
];
|
|
2188
2213
|
function deriveBucket(filename) {
|
|
2189
2214
|
const base = filename.includes("/") ? filename.split("/").pop() : filename;
|
|
@@ -4223,14 +4248,18 @@ var FM_KEY_MAP = [
|
|
|
4223
4248
|
{ key: "epic_id", type: "epic" },
|
|
4224
4249
|
{ key: "proposal_id", type: "proposal" },
|
|
4225
4250
|
{ key: "cr_id", type: "cr" },
|
|
4226
|
-
{ key: "bug_id", type: "bug" }
|
|
4251
|
+
{ key: "bug_id", type: "bug" },
|
|
4252
|
+
{ key: "initiative_id", type: "initiative" },
|
|
4253
|
+
{ key: "sprint_id", type: "sprint" }
|
|
4227
4254
|
];
|
|
4228
4255
|
var PREFIX_MAP2 = [
|
|
4229
4256
|
{ prefix: "STORY-", type: "story" },
|
|
4230
4257
|
{ prefix: "EPIC-", type: "epic" },
|
|
4231
4258
|
{ prefix: "PROPOSAL-", type: "proposal" },
|
|
4232
4259
|
{ prefix: "CR-", type: "cr" },
|
|
4233
|
-
{ prefix: "BUG-", type: "bug" }
|
|
4260
|
+
{ prefix: "BUG-", type: "bug" },
|
|
4261
|
+
{ prefix: "INITIATIVE-", type: "initiative" },
|
|
4262
|
+
{ prefix: "SPRINT-", type: "sprint" }
|
|
4234
4263
|
];
|
|
4235
4264
|
function detectWorkItemTypeFromFm(fm) {
|
|
4236
4265
|
for (const { key, type } of FM_KEY_MAP) {
|
|
@@ -4255,7 +4284,9 @@ var WORK_ITEM_TRANSITIONS = {
|
|
|
4255
4284
|
epic: ["ready-for-decomposition", "ready-for-coding"],
|
|
4256
4285
|
story: ["ready-for-execution"],
|
|
4257
4286
|
cr: ["ready-to-apply"],
|
|
4258
|
-
bug: ["ready-for-fix"]
|
|
4287
|
+
bug: ["ready-for-fix"],
|
|
4288
|
+
initiative: ["ready-for-decomposition"],
|
|
4289
|
+
sprint: ["ready-for-execution"]
|
|
4259
4290
|
};
|
|
4260
4291
|
|
|
4261
4292
|
// src/wiki/lint-checks.ts
|
|
@@ -5868,7 +5899,7 @@ async function doctorHandler(flags, cli) {
|
|
|
5868
5899
|
// src/commands/gate.ts
|
|
5869
5900
|
init_cjs_shims();
|
|
5870
5901
|
var fs32 = __toESM(require("fs"), 1);
|
|
5871
|
-
var
|
|
5902
|
+
var path34 = __toESM(require("path"), 1);
|
|
5872
5903
|
var import_node_child_process8 = require("child_process");
|
|
5873
5904
|
|
|
5874
5905
|
// src/commands/execution-mode.ts
|
|
@@ -5957,13 +5988,21 @@ function printInertAndExit(stdoutFn, exitFn) {
|
|
|
5957
5988
|
return exitFn(0);
|
|
5958
5989
|
}
|
|
5959
5990
|
|
|
5991
|
+
// src/lib/script-paths.ts
|
|
5992
|
+
init_cjs_shims();
|
|
5993
|
+
var path32 = __toESM(require("path"), 1);
|
|
5994
|
+
function resolveCleargateScript(opts, scriptName) {
|
|
5995
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
5996
|
+
return path32.join(cwd, ".cleargate", "scripts", scriptName);
|
|
5997
|
+
}
|
|
5998
|
+
|
|
5960
5999
|
// src/commands/gate.ts
|
|
5961
6000
|
var import_js_yaml6 = __toESM(require("js-yaml"), 1);
|
|
5962
6001
|
|
|
5963
6002
|
// src/lib/readiness-predicates.ts
|
|
5964
6003
|
init_cjs_shims();
|
|
5965
6004
|
var fs30 = __toESM(require("fs"), 1);
|
|
5966
|
-
var
|
|
6005
|
+
var path33 = __toESM(require("path"), 1);
|
|
5967
6006
|
function parsePredicate(src) {
|
|
5968
6007
|
const s = src.trim();
|
|
5969
6008
|
const fmMatch = s.match(
|
|
@@ -5995,7 +6034,7 @@ function parsePredicate(src) {
|
|
|
5995
6034
|
return { kind: "body-contains", needle: bodyMatch[1], negated: false };
|
|
5996
6035
|
}
|
|
5997
6036
|
const sectionMatch = s.match(
|
|
5998
|
-
/^section\((\d+)\) has (≥|>=|==|>)(\d+) (checked-checkbox|unchecked-checkbox|listed-item)$/
|
|
6037
|
+
/^section\((\d+)\) has (≥|>=|==|>)(\d+) (checked-checkbox|unchecked-checkbox|listed-item|declared-item)$/
|
|
5999
6038
|
);
|
|
6000
6039
|
if (sectionMatch) {
|
|
6001
6040
|
const index = parseInt(sectionMatch[1], 10);
|
|
@@ -6023,6 +6062,9 @@ function parsePredicate(src) {
|
|
|
6023
6062
|
const value = statusMatch[2].trim().replace(/^['"]|['"]$/g, "");
|
|
6024
6063
|
return { kind: "status-of", id, value };
|
|
6025
6064
|
}
|
|
6065
|
+
if (s === "existing-surfaces-verified") {
|
|
6066
|
+
return { kind: "existing-surfaces-verified" };
|
|
6067
|
+
}
|
|
6026
6068
|
throw new Error(`unsupported predicate shape: ${src}`);
|
|
6027
6069
|
}
|
|
6028
6070
|
function parseValue(raw) {
|
|
@@ -6051,6 +6093,8 @@ function evaluate(predicate, doc, opts) {
|
|
|
6051
6093
|
return evalLinkTargetExists(parsed, opts);
|
|
6052
6094
|
case "status-of":
|
|
6053
6095
|
return evalStatusOf(parsed, opts, projectRoot);
|
|
6096
|
+
case "existing-surfaces-verified":
|
|
6097
|
+
return evalExistingSurfacesVerified(doc, projectRoot);
|
|
6054
6098
|
}
|
|
6055
6099
|
}
|
|
6056
6100
|
function evalFrontmatter(parsed, doc, projectRoot) {
|
|
@@ -6127,8 +6171,14 @@ function compareValues(actual, op, expected) {
|
|
|
6127
6171
|
}
|
|
6128
6172
|
function resolveLinkedPath(ref, docAbsPath, projectRoot) {
|
|
6129
6173
|
const candidates = [
|
|
6130
|
-
|
|
6131
|
-
|
|
6174
|
+
path33.resolve(path33.dirname(docAbsPath), ref),
|
|
6175
|
+
// 1. relative to citer
|
|
6176
|
+
path33.resolve(projectRoot, ref),
|
|
6177
|
+
// 2. project root
|
|
6178
|
+
path33.resolve(projectRoot, ".cleargate", "delivery", "pending-sync", ref),
|
|
6179
|
+
// 3. live
|
|
6180
|
+
path33.resolve(projectRoot, ".cleargate", "delivery", "archive", ref)
|
|
6181
|
+
// 4. archived
|
|
6132
6182
|
];
|
|
6133
6183
|
for (const candidate of candidates) {
|
|
6134
6184
|
if (!candidate.startsWith(projectRoot)) continue;
|
|
@@ -6265,6 +6315,9 @@ function evalSection(parsed, doc) {
|
|
|
6265
6315
|
case "listed-item":
|
|
6266
6316
|
actualCount = (sectionContent.match(/^\s*- /gm) || []).length;
|
|
6267
6317
|
break;
|
|
6318
|
+
case "declared-item":
|
|
6319
|
+
actualCount = countDeclaredItems(sectionContent);
|
|
6320
|
+
break;
|
|
6268
6321
|
}
|
|
6269
6322
|
const pass = applyCountOp(actualCount, parsed.count.op, parsed.count.n);
|
|
6270
6323
|
const opStr = parsed.count.op === ">=" ? "\u2265" : parsed.count.op;
|
|
@@ -6281,9 +6334,39 @@ function applyCountOp(actual, op, n) {
|
|
|
6281
6334
|
return actual > n;
|
|
6282
6335
|
}
|
|
6283
6336
|
}
|
|
6337
|
+
function countDeclaredItems(sectionContent) {
|
|
6338
|
+
const lines = sectionContent.split("\n");
|
|
6339
|
+
let count = 0;
|
|
6340
|
+
let inTable = false;
|
|
6341
|
+
for (const line of lines) {
|
|
6342
|
+
if (/^\s*- /.test(line)) {
|
|
6343
|
+
count++;
|
|
6344
|
+
inTable = false;
|
|
6345
|
+
continue;
|
|
6346
|
+
}
|
|
6347
|
+
if (/^\|.+\|/.test(line)) {
|
|
6348
|
+
if (/^\|[\s\-:]+\|[\s\-:|]*$/.test(line.replace(/\s/g, ""))) {
|
|
6349
|
+
inTable = true;
|
|
6350
|
+
continue;
|
|
6351
|
+
}
|
|
6352
|
+
if (inTable) {
|
|
6353
|
+
count++;
|
|
6354
|
+
}
|
|
6355
|
+
continue;
|
|
6356
|
+
}
|
|
6357
|
+
if (inTable && !/^\|/.test(line)) {
|
|
6358
|
+
inTable = false;
|
|
6359
|
+
}
|
|
6360
|
+
if (/^(\*{1,2}|_{1,2})?[A-Z][^|*\n]*(\*{1,2}|_{1,2})?:/.test(line.trim())) {
|
|
6361
|
+
count++;
|
|
6362
|
+
continue;
|
|
6363
|
+
}
|
|
6364
|
+
}
|
|
6365
|
+
return count;
|
|
6366
|
+
}
|
|
6284
6367
|
function evalFileExists(parsed, projectRoot) {
|
|
6285
|
-
const resolved =
|
|
6286
|
-
if (!resolved.startsWith(projectRoot +
|
|
6368
|
+
const resolved = path33.resolve(projectRoot, parsed.path);
|
|
6369
|
+
if (!resolved.startsWith(projectRoot + path33.sep) && resolved !== projectRoot) {
|
|
6287
6370
|
return {
|
|
6288
6371
|
pass: false,
|
|
6289
6372
|
detail: `path '${parsed.path}' resolves outside project root (sandbox violation)`
|
|
@@ -6297,7 +6380,7 @@ function evalFileExists(parsed, projectRoot) {
|
|
|
6297
6380
|
}
|
|
6298
6381
|
function evalLinkTargetExists(parsed, opts) {
|
|
6299
6382
|
const projectRoot = opts?.projectRoot ?? process.cwd();
|
|
6300
|
-
const wikiIndexPath = opts?.wikiIndexPath ??
|
|
6383
|
+
const wikiIndexPath = opts?.wikiIndexPath ?? path33.join(projectRoot, ".cleargate", "wiki", "index.md");
|
|
6301
6384
|
if (!wikiIndexPath.startsWith(projectRoot)) {
|
|
6302
6385
|
return { pass: false, detail: "wikiIndexPath resolves outside project root" };
|
|
6303
6386
|
}
|
|
@@ -6314,7 +6397,7 @@ function evalLinkTargetExists(parsed, opts) {
|
|
|
6314
6397
|
};
|
|
6315
6398
|
}
|
|
6316
6399
|
function evalStatusOf(parsed, opts, projectRoot) {
|
|
6317
|
-
const wikiIndexPath = opts?.wikiIndexPath ??
|
|
6400
|
+
const wikiIndexPath = opts?.wikiIndexPath ?? path33.join(projectRoot, ".cleargate", "wiki", "index.md");
|
|
6318
6401
|
if (!wikiIndexPath.startsWith(projectRoot)) {
|
|
6319
6402
|
return { pass: false, detail: "wikiIndexPath resolves outside project root" };
|
|
6320
6403
|
}
|
|
@@ -6331,7 +6414,7 @@ function evalStatusOf(parsed, opts, projectRoot) {
|
|
|
6331
6414
|
return { pass: false, detail: `[[${parsed.id}]] not found in wiki index` };
|
|
6332
6415
|
}
|
|
6333
6416
|
const rawPath = rowMatch[1].trim();
|
|
6334
|
-
const fullPath =
|
|
6417
|
+
const fullPath = path33.resolve(projectRoot, rawPath);
|
|
6335
6418
|
if (!fullPath.startsWith(projectRoot)) {
|
|
6336
6419
|
return { pass: false, detail: `wiki path for ${parsed.id} resolves outside project root` };
|
|
6337
6420
|
}
|
|
@@ -6346,6 +6429,60 @@ function evalStatusOf(parsed, opts, projectRoot) {
|
|
|
6346
6429
|
detail: pass ? `status-of([[${parsed.id}]]) == ${parsed.value}` : `status-of([[${parsed.id}]]) is '${status}', expected '${parsed.value}'`
|
|
6347
6430
|
};
|
|
6348
6431
|
}
|
|
6432
|
+
function evalExistingSurfacesVerified(doc, projectRoot) {
|
|
6433
|
+
const body = doc.body;
|
|
6434
|
+
const rawParts = body.split(/^(?=## )/m);
|
|
6435
|
+
let sectionContent;
|
|
6436
|
+
for (const part of rawParts) {
|
|
6437
|
+
if (part.startsWith("## Existing Surfaces")) {
|
|
6438
|
+
sectionContent = part;
|
|
6439
|
+
break;
|
|
6440
|
+
}
|
|
6441
|
+
}
|
|
6442
|
+
if (!sectionContent) {
|
|
6443
|
+
return {
|
|
6444
|
+
pass: true,
|
|
6445
|
+
detail: `not-applicable: ## Existing Surfaces section absent \u2014 reuse-audit-recorded already failing`
|
|
6446
|
+
};
|
|
6447
|
+
}
|
|
6448
|
+
const PATH_RE = /[a-zA-Z0-9_./-]+\.[a-zA-Z]{1,5}(?::[a-zA-Z_][a-zA-Z0-9_]*)?/g;
|
|
6449
|
+
const rawMatches = sectionContent.match(PATH_RE) ?? [];
|
|
6450
|
+
const paths = [...new Set(rawMatches.map((m) => m.replace(/:([a-zA-Z_][a-zA-Z0-9_]*)$/, "")))];
|
|
6451
|
+
if (paths.length === 0) {
|
|
6452
|
+
const SENTINEL_RE = /no overlap found|no existing surface|no prior implementation|audit returned empty/i;
|
|
6453
|
+
if (SENTINEL_RE.test(sectionContent)) {
|
|
6454
|
+
return {
|
|
6455
|
+
pass: true,
|
|
6456
|
+
detail: `## Existing Surfaces contains no path citations; sentinel phrase present \u2014 audit explicitly empty`
|
|
6457
|
+
};
|
|
6458
|
+
}
|
|
6459
|
+
return {
|
|
6460
|
+
pass: false,
|
|
6461
|
+
detail: `'## Existing Surfaces' has no path citations and no "no overlap found" sentinel`
|
|
6462
|
+
};
|
|
6463
|
+
}
|
|
6464
|
+
const missing = [];
|
|
6465
|
+
for (const p of paths) {
|
|
6466
|
+
const resolved = path33.resolve(projectRoot, p);
|
|
6467
|
+
if (!resolved.startsWith(projectRoot + path33.sep) && resolved !== projectRoot) {
|
|
6468
|
+
missing.push(p);
|
|
6469
|
+
continue;
|
|
6470
|
+
}
|
|
6471
|
+
if (!fs30.existsSync(resolved)) {
|
|
6472
|
+
missing.push(p);
|
|
6473
|
+
}
|
|
6474
|
+
}
|
|
6475
|
+
if (missing.length > 0) {
|
|
6476
|
+
return {
|
|
6477
|
+
pass: false,
|
|
6478
|
+
detail: `cited paths do not exist on disk: ${missing.join(", ")}`
|
|
6479
|
+
};
|
|
6480
|
+
}
|
|
6481
|
+
return {
|
|
6482
|
+
pass: true,
|
|
6483
|
+
detail: `all ${paths.length} cited path${paths.length === 1 ? "" : "s"} exist on disk`
|
|
6484
|
+
};
|
|
6485
|
+
}
|
|
6349
6486
|
|
|
6350
6487
|
// src/lib/frontmatter-cache.ts
|
|
6351
6488
|
init_cjs_shims();
|
|
@@ -6470,7 +6607,7 @@ async function gateCheckHandler(file, opts, cli) {
|
|
|
6470
6607
|
const exitFn = cli?.exit ?? ((code) => process.exit(code));
|
|
6471
6608
|
const cwd = cli?.cwd ?? process.cwd();
|
|
6472
6609
|
const nowFn = cli?.now ?? (() => /* @__PURE__ */ new Date());
|
|
6473
|
-
const absPath =
|
|
6610
|
+
const absPath = path34.isAbsolute(file) ? file : path34.resolve(cwd, file);
|
|
6474
6611
|
if (!fs32.existsSync(absPath)) {
|
|
6475
6612
|
stderrFn(`[cleargate gate] error: file not found: ${absPath}`);
|
|
6476
6613
|
return exitFn(1);
|
|
@@ -6496,7 +6633,7 @@ async function gateCheckHandler(file, opts, cli) {
|
|
|
6496
6633
|
return exitFn(1);
|
|
6497
6634
|
}
|
|
6498
6635
|
const projectRoot = cwd;
|
|
6499
|
-
const gatesDocPath = cli?.gatesDocPath ??
|
|
6636
|
+
const gatesDocPath = cli?.gatesDocPath ?? path34.join(projectRoot, ".cleargate", "knowledge", "readiness-gates.md");
|
|
6500
6637
|
if (!fs32.existsSync(gatesDocPath)) {
|
|
6501
6638
|
stderrFn(`[cleargate gate] error: readiness-gates.md not found at: ${gatesDocPath}`);
|
|
6502
6639
|
return exitFn(1);
|
|
@@ -6520,7 +6657,6 @@ async function gateCheckHandler(file, opts, cli) {
|
|
|
6520
6657
|
const wikiIndexPath = cli?.wikiIndexPath;
|
|
6521
6658
|
const parsedDoc = { fm, body, absPath };
|
|
6522
6659
|
const evalOpts = { projectRoot, ...wikiIndexPath ? { wikiIndexPath } : {} };
|
|
6523
|
-
const failingCriteria = [];
|
|
6524
6660
|
const allResults = [];
|
|
6525
6661
|
for (const criterion of gate2.criteria) {
|
|
6526
6662
|
let result;
|
|
@@ -6529,9 +6665,32 @@ async function gateCheckHandler(file, opts, cli) {
|
|
|
6529
6665
|
} catch (err) {
|
|
6530
6666
|
result = { pass: false, detail: `predicate error: ${String(err)}` };
|
|
6531
6667
|
}
|
|
6532
|
-
allResults.push({ id: criterion.id, ...result });
|
|
6533
|
-
|
|
6534
|
-
|
|
6668
|
+
allResults.push({ id: criterion.id, ...result, or_group: criterion.or_group });
|
|
6669
|
+
}
|
|
6670
|
+
const failingCriteria = [];
|
|
6671
|
+
const orGroups = /* @__PURE__ */ new Map();
|
|
6672
|
+
for (const r of allResults) {
|
|
6673
|
+
if (r.or_group) {
|
|
6674
|
+
const existing = orGroups.get(r.or_group) ?? [];
|
|
6675
|
+
existing.push(r);
|
|
6676
|
+
orGroups.set(r.or_group, existing);
|
|
6677
|
+
}
|
|
6678
|
+
}
|
|
6679
|
+
for (const r of allResults) {
|
|
6680
|
+
if (r.or_group) {
|
|
6681
|
+
const groupMembers = orGroups.get(r.or_group);
|
|
6682
|
+
const isFirstMember = groupMembers[0].id === r.id;
|
|
6683
|
+
if (isFirstMember) {
|
|
6684
|
+
const anyPasses = groupMembers.some((m) => m.pass);
|
|
6685
|
+
if (!anyPasses) {
|
|
6686
|
+
const details = groupMembers.map((m) => `${m.id}: ${m.detail}`).join("; ");
|
|
6687
|
+
failingCriteria.push({ id: r.or_group, detail: `OR-group failed \u2014 all alternatives failed: ${details}` });
|
|
6688
|
+
}
|
|
6689
|
+
}
|
|
6690
|
+
} else {
|
|
6691
|
+
if (!r.pass) {
|
|
6692
|
+
failingCriteria.push({ id: r.id, detail: r.detail });
|
|
6693
|
+
}
|
|
6535
6694
|
}
|
|
6536
6695
|
}
|
|
6537
6696
|
const overallPass = failingCriteria.length === 0;
|
|
@@ -6548,15 +6707,15 @@ async function gateCheckHandler(file, opts, cli) {
|
|
|
6548
6707
|
if (overallPass) {
|
|
6549
6708
|
stdoutFn(`\u2705 ${detectedType}.${transition} passed (${gate2.criteria.length} criteria)`);
|
|
6550
6709
|
} else {
|
|
6551
|
-
for (const
|
|
6552
|
-
if (
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
}
|
|
6556
|
-
stdoutFn(`\u274C ${r.id}: ${r.detail}`);
|
|
6557
|
-
}
|
|
6710
|
+
for (const fc of failingCriteria) {
|
|
6711
|
+
if (isAdvisory) {
|
|
6712
|
+
stdoutFn(`\u26A0 ${fc.id}: ${fc.detail} (advisory)`);
|
|
6713
|
+
} else {
|
|
6714
|
+
stdoutFn(`\u274C ${fc.id}: ${fc.detail}`);
|
|
6558
6715
|
}
|
|
6559
|
-
|
|
6716
|
+
}
|
|
6717
|
+
if (opts.verbose) {
|
|
6718
|
+
for (const r of allResults) {
|
|
6560
6719
|
stdoutFn(` [${r.pass ? "pass" : "fail"}] ${r.id}: ${r.detail}`);
|
|
6561
6720
|
}
|
|
6562
6721
|
}
|
|
@@ -6570,7 +6729,7 @@ async function gateExplainHandler(file, cli) {
|
|
|
6570
6729
|
const stderrFn = cli?.stderr ?? ((s) => process.stderr.write(s + "\n"));
|
|
6571
6730
|
const exitFn = cli?.exit ?? ((code) => process.exit(code));
|
|
6572
6731
|
const cwd = cli?.cwd ?? process.cwd();
|
|
6573
|
-
const absPath =
|
|
6732
|
+
const absPath = path34.isAbsolute(file) ? file : path34.resolve(cwd, file);
|
|
6574
6733
|
if (!fs32.existsSync(absPath)) {
|
|
6575
6734
|
stderrFn(`[cleargate gate] error: file not found: ${absPath}`);
|
|
6576
6735
|
return exitFn(1);
|
|
@@ -6603,7 +6762,7 @@ async function gateExplainHandler(file, cli) {
|
|
|
6603
6762
|
function resolveRunScriptForGate(opts) {
|
|
6604
6763
|
if (opts.runScriptPath) return opts.runScriptPath;
|
|
6605
6764
|
const cwd = opts.cwd ?? process.cwd();
|
|
6606
|
-
return
|
|
6765
|
+
return path34.join(cwd, ".cleargate", "scripts", "run_script.sh");
|
|
6607
6766
|
}
|
|
6608
6767
|
function gateQaHandler(opts, cli) {
|
|
6609
6768
|
const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
|
|
@@ -6619,9 +6778,11 @@ function gateQaHandler(opts, cli) {
|
|
|
6619
6778
|
return printInertAndExit(stdoutFn, exitFn);
|
|
6620
6779
|
}
|
|
6621
6780
|
const runScript = resolveRunScriptForGate(cli ?? {});
|
|
6781
|
+
const qaCwd = cli?.cwd ?? process.cwd();
|
|
6782
|
+
const gateRunnerPath = resolveCleargateScript({ cwd: qaCwd }, "pre_gate_runner.sh");
|
|
6622
6783
|
const result = spawnFn(
|
|
6623
6784
|
"bash",
|
|
6624
|
-
[runScript, "
|
|
6785
|
+
[runScript, "bash", gateRunnerPath, "qa", opts.worktree, opts.branch],
|
|
6625
6786
|
{ stdio: "inherit" }
|
|
6626
6787
|
);
|
|
6627
6788
|
if (result.error) {
|
|
@@ -6645,9 +6806,11 @@ function gateArchHandler(opts, cli) {
|
|
|
6645
6806
|
return printInertAndExit(stdoutFn, exitFn);
|
|
6646
6807
|
}
|
|
6647
6808
|
const runScript = resolveRunScriptForGate(cli ?? {});
|
|
6809
|
+
const archCwd = cli?.cwd ?? process.cwd();
|
|
6810
|
+
const archGateRunnerPath = resolveCleargateScript({ cwd: archCwd }, "pre_gate_runner.sh");
|
|
6648
6811
|
const result = spawnFn(
|
|
6649
6812
|
"bash",
|
|
6650
|
-
[runScript, "
|
|
6813
|
+
[runScript, "bash", archGateRunnerPath, "arch", opts.worktree, opts.branch],
|
|
6651
6814
|
{ stdio: "inherit" }
|
|
6652
6815
|
);
|
|
6653
6816
|
if (result.error) {
|
|
@@ -6698,14 +6861,14 @@ function gateRunHandler(name, opts, cli) {
|
|
|
6698
6861
|
// src/commands/sprint.ts
|
|
6699
6862
|
init_cjs_shims();
|
|
6700
6863
|
var fs34 = __toESM(require("fs"), 1);
|
|
6701
|
-
var
|
|
6864
|
+
var path36 = __toESM(require("path"), 1);
|
|
6702
6865
|
var import_node_child_process11 = require("child_process");
|
|
6703
6866
|
var import_js_yaml7 = __toESM(require("js-yaml"), 1);
|
|
6704
6867
|
|
|
6705
6868
|
// src/lib/lifecycle-reconcile.ts
|
|
6706
6869
|
init_cjs_shims();
|
|
6707
6870
|
var fs33 = __toESM(require("fs"), 1);
|
|
6708
|
-
var
|
|
6871
|
+
var path35 = __toESM(require("path"), 1);
|
|
6709
6872
|
var import_node_child_process10 = require("child_process");
|
|
6710
6873
|
var VERB_STATUS_MAP = {
|
|
6711
6874
|
feat: {
|
|
@@ -6765,7 +6928,7 @@ function findArtifactFile(deliveryRoot, id) {
|
|
|
6765
6928
|
{ rel: "archive", inArchive: true }
|
|
6766
6929
|
];
|
|
6767
6930
|
for (const { rel, inArchive } of dirs) {
|
|
6768
|
-
const dir =
|
|
6931
|
+
const dir = path35.join(deliveryRoot, rel);
|
|
6769
6932
|
let entries;
|
|
6770
6933
|
try {
|
|
6771
6934
|
entries = fs33.readdirSync(dir);
|
|
@@ -6776,7 +6939,7 @@ function findArtifactFile(deliveryRoot, id) {
|
|
|
6776
6939
|
(e) => (e.startsWith(prefix) || e === `${id}.md`) && e.endsWith(".md")
|
|
6777
6940
|
);
|
|
6778
6941
|
if (match) {
|
|
6779
|
-
const absPath =
|
|
6942
|
+
const absPath = path35.join(dir, match);
|
|
6780
6943
|
return { absPath, inArchive, relPath: `${rel}/${match}` };
|
|
6781
6944
|
}
|
|
6782
6945
|
}
|
|
@@ -6894,8 +7057,8 @@ function reconcileDecomposition(opts) {
|
|
|
6894
7057
|
}
|
|
6895
7058
|
const epics = Array.isArray(fm["epics"]) ? fm["epics"].map(String) : [];
|
|
6896
7059
|
const proposals = Array.isArray(fm["proposals"]) ? fm["proposals"].map(String) : [];
|
|
6897
|
-
const pendingDir =
|
|
6898
|
-
const archiveDir =
|
|
7060
|
+
const pendingDir = path35.join(deliveryRoot, "pending-sync");
|
|
7061
|
+
const archiveDir = path35.join(deliveryRoot, "archive");
|
|
6899
7062
|
function listMdFiles(dir) {
|
|
6900
7063
|
try {
|
|
6901
7064
|
return fs33.readdirSync(dir).filter((f) => f.endsWith(".md"));
|
|
@@ -6970,7 +7133,7 @@ function findChildStories(epicId, pendingDir, pendingFiles, archiveDir, archiveF
|
|
|
6970
7133
|
for (const f of files) {
|
|
6971
7134
|
if (!f.startsWith(storyPrefix) && !f.startsWith("STORY-")) continue;
|
|
6972
7135
|
if (!f.includes(storyPrefix)) continue;
|
|
6973
|
-
const absPath =
|
|
7136
|
+
const absPath = path35.join(dir, f);
|
|
6974
7137
|
try {
|
|
6975
7138
|
const raw = fs33.readFileSync(absPath, "utf8");
|
|
6976
7139
|
const { fm } = parseFrontmatter(raw);
|
|
@@ -6987,7 +7150,7 @@ function findChildStories(epicId, pendingDir, pendingFiles, archiveDir, archiveF
|
|
|
6987
7150
|
function findDecomposedEpic(proposalId, pendingDir, pendingFiles) {
|
|
6988
7151
|
for (const f of pendingFiles) {
|
|
6989
7152
|
if (!f.startsWith("EPIC-")) continue;
|
|
6990
|
-
const absPath =
|
|
7153
|
+
const absPath = path35.join(pendingDir, f);
|
|
6991
7154
|
try {
|
|
6992
7155
|
const raw = fs33.readFileSync(absPath, "utf8");
|
|
6993
7156
|
const { fm } = parseFrontmatter(raw);
|
|
@@ -7015,7 +7178,7 @@ var TERMINAL_STATUSES2 = /* @__PURE__ */ new Set(["Completed", "Done", "Abandone
|
|
|
7015
7178
|
function resolveRunScript(opts) {
|
|
7016
7179
|
if (opts.runScriptPath) return opts.runScriptPath;
|
|
7017
7180
|
const cwd = opts.cwd ?? process.cwd();
|
|
7018
|
-
return
|
|
7181
|
+
return path36.join(cwd, ".cleargate", "scripts", "run_script.sh");
|
|
7019
7182
|
}
|
|
7020
7183
|
function defaultExit(code) {
|
|
7021
7184
|
return process.exit(code);
|
|
@@ -7034,17 +7197,17 @@ function sprintInitHandler(opts, cli) {
|
|
|
7034
7197
|
if (mode === "v1") {
|
|
7035
7198
|
return printInertAndExit(stdoutFn, exitFn);
|
|
7036
7199
|
}
|
|
7037
|
-
const deliveryRoot =
|
|
7200
|
+
const deliveryRoot = path36.join(cwd, ".cleargate", "delivery");
|
|
7038
7201
|
let lifecycleInitMode = "warn";
|
|
7039
7202
|
let sprintPlanPath = null;
|
|
7040
|
-
const pendingDir =
|
|
7203
|
+
const pendingDir = path36.join(deliveryRoot, "pending-sync");
|
|
7041
7204
|
try {
|
|
7042
7205
|
const entries = fs34.readdirSync(pendingDir);
|
|
7043
7206
|
const sprintFile = entries.find(
|
|
7044
7207
|
(e) => (e.startsWith(`${opts.sprintId}_`) || e === `${opts.sprintId}.md`) && e.endsWith(".md")
|
|
7045
7208
|
);
|
|
7046
7209
|
if (sprintFile) {
|
|
7047
|
-
sprintPlanPath =
|
|
7210
|
+
sprintPlanPath = path36.join(pendingDir, sprintFile);
|
|
7048
7211
|
const raw = fs34.readFileSync(sprintPlanPath, "utf8");
|
|
7049
7212
|
const { fm } = parseFileFrontmatter(raw);
|
|
7050
7213
|
if (fm["lifecycle_init_mode"] === "block") {
|
|
@@ -7128,8 +7291,12 @@ ${waiverLine}` : waiverLine;
|
|
|
7128
7291
|
}
|
|
7129
7292
|
}
|
|
7130
7293
|
const runScript = resolveRunScript(cli ?? {});
|
|
7131
|
-
const
|
|
7132
|
-
const result = spawnFn(
|
|
7294
|
+
const scriptPath = resolveCleargateScript({ cwd }, "init_sprint.mjs");
|
|
7295
|
+
const result = spawnFn(
|
|
7296
|
+
"bash",
|
|
7297
|
+
[runScript, "node", scriptPath, opts.sprintId, "--stories", opts.stories],
|
|
7298
|
+
{ stdio: "inherit" }
|
|
7299
|
+
);
|
|
7133
7300
|
if (result.error) {
|
|
7134
7301
|
stderrFn(`[cleargate sprint init] error: ${result.error.message}`);
|
|
7135
7302
|
return exitFn(1);
|
|
@@ -7153,11 +7320,13 @@ function sprintCloseHandler(opts, cli) {
|
|
|
7153
7320
|
return printInertAndExit(stdoutFn, exitFn);
|
|
7154
7321
|
}
|
|
7155
7322
|
const runScript = resolveRunScript(cli ?? {});
|
|
7156
|
-
const
|
|
7323
|
+
const closeCwd = cli?.cwd ?? process.cwd();
|
|
7324
|
+
const closeScriptPath = resolveCleargateScript({ cwd: closeCwd }, "close_sprint.mjs");
|
|
7325
|
+
const closeArgs = [runScript, "node", closeScriptPath, opts.sprintId];
|
|
7157
7326
|
if (opts.assumeAck === true) {
|
|
7158
|
-
|
|
7327
|
+
closeArgs.push("--assume-ack");
|
|
7159
7328
|
}
|
|
7160
|
-
const result = spawnFn("bash",
|
|
7329
|
+
const result = spawnFn("bash", closeArgs, { stdio: "inherit" });
|
|
7161
7330
|
if (result.error) {
|
|
7162
7331
|
stderrFn(`[cleargate sprint close] error: ${result.error.message}`);
|
|
7163
7332
|
return exitFn(1);
|
|
@@ -7170,20 +7339,20 @@ function reconcileLifecycleCliHandler(opts, cli) {
|
|
|
7170
7339
|
const stderrFn = cli?.stderr ?? ((s) => process.stderr.write(s + "\n"));
|
|
7171
7340
|
const exitFn = cli?.exit ?? defaultExit;
|
|
7172
7341
|
const cwd = cli?.cwd ?? process.cwd();
|
|
7173
|
-
const deliveryRoot =
|
|
7342
|
+
const deliveryRoot = path36.join(cwd, ".cleargate", "delivery");
|
|
7174
7343
|
let since;
|
|
7175
7344
|
let until;
|
|
7176
7345
|
if (opts.since) {
|
|
7177
7346
|
since = new Date(opts.since);
|
|
7178
7347
|
} else {
|
|
7179
7348
|
try {
|
|
7180
|
-
const pendingDir =
|
|
7349
|
+
const pendingDir = path36.join(deliveryRoot, "pending-sync");
|
|
7181
7350
|
const entries = fs34.readdirSync(pendingDir);
|
|
7182
7351
|
const sprintFile = entries.find(
|
|
7183
7352
|
(e) => (e.startsWith(`${opts.sprintId}_`) || e === `${opts.sprintId}.md`) && e.endsWith(".md")
|
|
7184
7353
|
);
|
|
7185
7354
|
if (sprintFile) {
|
|
7186
|
-
const raw = fs34.readFileSync(
|
|
7355
|
+
const raw = fs34.readFileSync(path36.join(pendingDir, sprintFile), "utf8");
|
|
7187
7356
|
const { fm } = parseFileFrontmatter(raw);
|
|
7188
7357
|
const startDate = fm["start_date"];
|
|
7189
7358
|
since = typeof startDate === "string" ? new Date(startDate) : new Date(Date.now() - 90 * 24 * 60 * 60 * 1e3);
|
|
@@ -7339,7 +7508,7 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7339
7508
|
if (mode === "v1") {
|
|
7340
7509
|
return printInertAndExit(stdoutFn, exitFn);
|
|
7341
7510
|
}
|
|
7342
|
-
const stateFile =
|
|
7511
|
+
const stateFile = path36.join(cwd, ".cleargate", "sprint-runs", opts.sprintId, "state.json");
|
|
7343
7512
|
if (!fs34.existsSync(stateFile)) {
|
|
7344
7513
|
stderrFn(`[cleargate sprint archive] state.json not found at ${stateFile}`);
|
|
7345
7514
|
return exitFn(1);
|
|
@@ -7358,12 +7527,12 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7358
7527
|
return exitFn(1);
|
|
7359
7528
|
}
|
|
7360
7529
|
const stateStories = state2.stories ?? {};
|
|
7361
|
-
const pendingDir =
|
|
7362
|
-
const archiveDir =
|
|
7530
|
+
const pendingDir = path36.join(cwd, ".cleargate", "delivery", "pending-sync");
|
|
7531
|
+
const archiveDir = path36.join(cwd, ".cleargate", "delivery", "archive");
|
|
7363
7532
|
let sprintFile = null;
|
|
7364
7533
|
for (const entry of fs34.readdirSync(pendingDir)) {
|
|
7365
7534
|
if ((entry.startsWith(`${opts.sprintId}_`) || entry === `${opts.sprintId}.md`) && entry.endsWith(".md")) {
|
|
7366
|
-
sprintFile =
|
|
7535
|
+
sprintFile = path36.join(pendingDir, entry);
|
|
7367
7536
|
break;
|
|
7368
7537
|
}
|
|
7369
7538
|
}
|
|
@@ -7379,7 +7548,7 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7379
7548
|
if (sprintFile) {
|
|
7380
7549
|
plan.push({
|
|
7381
7550
|
src: sprintFile,
|
|
7382
|
-
destName:
|
|
7551
|
+
destName: path36.basename(sprintFile),
|
|
7383
7552
|
status: "Completed"
|
|
7384
7553
|
});
|
|
7385
7554
|
}
|
|
@@ -7387,7 +7556,7 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7387
7556
|
for (const entry of fs34.readdirSync(pendingDir)) {
|
|
7388
7557
|
if ((entry.startsWith(`${epicId}_`) || entry === `${epicId}.md`) && entry.endsWith(".md")) {
|
|
7389
7558
|
plan.push({
|
|
7390
|
-
src:
|
|
7559
|
+
src: path36.join(pendingDir, entry),
|
|
7391
7560
|
destName: entry,
|
|
7392
7561
|
status: "Approved"
|
|
7393
7562
|
});
|
|
@@ -7399,7 +7568,7 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7399
7568
|
for (const entry of fs34.readdirSync(pendingDir)) {
|
|
7400
7569
|
if ((entry.startsWith(`${storyId}_`) || entry === `${storyId}.md`) && entry.endsWith(".md")) {
|
|
7401
7570
|
plan.push({
|
|
7402
|
-
src:
|
|
7571
|
+
src: path36.join(pendingDir, entry),
|
|
7403
7572
|
destName: entry,
|
|
7404
7573
|
status: "Done"
|
|
7405
7574
|
});
|
|
@@ -7413,7 +7582,7 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7413
7582
|
const orphans = [];
|
|
7414
7583
|
for (const entry of fs34.readdirSync(pendingDir)) {
|
|
7415
7584
|
if (!entry.startsWith("STORY-") || !entry.endsWith(".md")) continue;
|
|
7416
|
-
const candidate =
|
|
7585
|
+
const candidate = path36.join(pendingDir, entry);
|
|
7417
7586
|
if (planSrcs.has(candidate)) continue;
|
|
7418
7587
|
let raw;
|
|
7419
7588
|
try {
|
|
@@ -7434,18 +7603,18 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7434
7603
|
}
|
|
7435
7604
|
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
7436
7605
|
const sprintBranch = deriveSprintBranchForArchive(opts.sprintId);
|
|
7437
|
-
const activePath =
|
|
7606
|
+
const activePath = path36.join(cwd, ".cleargate", "sprint-runs", ".active");
|
|
7438
7607
|
if (opts.dryRun) {
|
|
7439
7608
|
stdoutFn(`[dry-run] Sprint archive plan for ${opts.sprintId}:`);
|
|
7440
7609
|
stdoutFn(` Sprint branch: ${sprintBranch}`);
|
|
7441
7610
|
stdoutFn(` Files to archive (${plan.length}):`);
|
|
7442
7611
|
for (const entry of plan) {
|
|
7443
7612
|
stdoutFn(
|
|
7444
|
-
` ${
|
|
7613
|
+
` ${path36.basename(entry.src)} \u2192 archive/${entry.destName} [stamp: status=${entry.status}, completed_at=<now>]`
|
|
7445
7614
|
);
|
|
7446
7615
|
}
|
|
7447
7616
|
if (orphans.length > 0) {
|
|
7448
|
-
stdoutFn(` Orphan files (${orphans.length}): ${orphans.map((o) =>
|
|
7617
|
+
stdoutFn(` Orphan files (${orphans.length}): ${orphans.map((o) => path36.basename(o)).join(", ")}`);
|
|
7449
7618
|
}
|
|
7450
7619
|
stdoutFn(` .active \u2192 "" (truncate)`);
|
|
7451
7620
|
stdoutFn(` git checkout main`);
|
|
@@ -7454,7 +7623,7 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7454
7623
|
return exitFn(0);
|
|
7455
7624
|
}
|
|
7456
7625
|
let sprintFileSnapshot = null;
|
|
7457
|
-
const wikiRoot =
|
|
7626
|
+
const wikiRoot = path36.join(cwd, ".cleargate", "wiki");
|
|
7458
7627
|
const wikiInitialised = fs34.existsSync(wikiRoot);
|
|
7459
7628
|
if (sprintFile && fs34.existsSync(sprintFile)) {
|
|
7460
7629
|
const { previousContent } = stampSprintClose(sprintFile, () => completedAt);
|
|
@@ -7489,7 +7658,7 @@ async function sprintArchiveHandler(opts, cli) {
|
|
|
7489
7658
|
}
|
|
7490
7659
|
const raw = fs34.readFileSync(entry.src, "utf8");
|
|
7491
7660
|
const stamped = stampFile(raw, entry.status, completedAt);
|
|
7492
|
-
const dest =
|
|
7661
|
+
const dest = path36.join(archiveDir, entry.destName);
|
|
7493
7662
|
atomicWriteStr(entry.src, stamped);
|
|
7494
7663
|
fs34.renameSync(entry.src, dest);
|
|
7495
7664
|
stdoutFn(`archived: ${entry.destName}`);
|
|
@@ -7550,11 +7719,11 @@ function checkPrevSprintCompleted(sprintId, cwd) {
|
|
|
7550
7719
|
const prevNum = sprintNum - 1;
|
|
7551
7720
|
const prevId = `SPRINT-${String(prevNum).padStart(2, "0")}`;
|
|
7552
7721
|
const prevIdAlt = `SPRINT-${prevNum}`;
|
|
7553
|
-
const sprintRunsBase =
|
|
7722
|
+
const sprintRunsBase = path36.join(cwd, ".cleargate", "sprint-runs");
|
|
7554
7723
|
let stateJson = null;
|
|
7555
7724
|
let resolvedPrevId = prevId;
|
|
7556
7725
|
for (const pid of [prevId, prevIdAlt]) {
|
|
7557
|
-
const stateFile =
|
|
7726
|
+
const stateFile = path36.join(sprintRunsBase, pid, "state.json");
|
|
7558
7727
|
if (fs34.existsSync(stateFile)) {
|
|
7559
7728
|
try {
|
|
7560
7729
|
const raw = fs34.readFileSync(stateFile, "utf8");
|
|
@@ -7660,8 +7829,8 @@ function checkMainClean(cwd, execFn) {
|
|
|
7660
7829
|
}
|
|
7661
7830
|
function findSprintFile(sprintId, cwd) {
|
|
7662
7831
|
const searchDirs = [
|
|
7663
|
-
|
|
7664
|
-
|
|
7832
|
+
path36.join(cwd, ".cleargate", "delivery", "pending-sync"),
|
|
7833
|
+
path36.join(cwd, ".cleargate", "delivery", "archive")
|
|
7665
7834
|
];
|
|
7666
7835
|
for (const dir of searchDirs) {
|
|
7667
7836
|
if (!fs34.existsSync(dir)) continue;
|
|
@@ -7674,7 +7843,7 @@ function findSprintFile(sprintId, cwd) {
|
|
|
7674
7843
|
const prefix = `${sprintId}_`;
|
|
7675
7844
|
for (const entry of entries) {
|
|
7676
7845
|
if ((entry.startsWith(prefix) || entry === `${sprintId}.md`) && entry.endsWith(".md")) {
|
|
7677
|
-
return
|
|
7846
|
+
return path36.join(dir, entry);
|
|
7678
7847
|
}
|
|
7679
7848
|
}
|
|
7680
7849
|
}
|
|
@@ -7682,8 +7851,8 @@ function findSprintFile(sprintId, cwd) {
|
|
|
7682
7851
|
}
|
|
7683
7852
|
function findWorkItemFileLocal(cwd, workItemId) {
|
|
7684
7853
|
const searchDirs = [
|
|
7685
|
-
|
|
7686
|
-
|
|
7854
|
+
path36.join(cwd, ".cleargate", "delivery", "pending-sync"),
|
|
7855
|
+
path36.join(cwd, ".cleargate", "delivery", "archive")
|
|
7687
7856
|
];
|
|
7688
7857
|
const prefix = `${workItemId}_`;
|
|
7689
7858
|
for (const dir of searchDirs) {
|
|
@@ -7694,7 +7863,7 @@ function findWorkItemFileLocal(cwd, workItemId) {
|
|
|
7694
7863
|
continue;
|
|
7695
7864
|
}
|
|
7696
7865
|
const match = entries.find((e) => (e.startsWith(prefix) || e === `${workItemId}.md`) && e.endsWith(".md"));
|
|
7697
|
-
if (match) return
|
|
7866
|
+
if (match) return path36.join(dir, match);
|
|
7698
7867
|
}
|
|
7699
7868
|
return null;
|
|
7700
7869
|
}
|
|
@@ -7725,7 +7894,7 @@ function readCachedGateSync(absPath) {
|
|
|
7725
7894
|
return null;
|
|
7726
7895
|
}
|
|
7727
7896
|
function extractInScopeWorkItemIds(sprintFilePath, cwd, execFn) {
|
|
7728
|
-
const scriptPath =
|
|
7897
|
+
const scriptPath = path36.join(cwd, ".cleargate", "scripts", "assert_story_files.mjs");
|
|
7729
7898
|
const cmd = `node "${scriptPath}" "${sprintFilePath}" --emit-json`;
|
|
7730
7899
|
let stdout;
|
|
7731
7900
|
try {
|
|
@@ -7862,6 +8031,41 @@ function checkPerItemReadinessGates(sprintId, cwd, execFn, mode) {
|
|
|
7862
8031
|
Run: cleargate gate check <file> -v for each`
|
|
7863
8032
|
};
|
|
7864
8033
|
}
|
|
8034
|
+
function refreshScopedGateCaches(sprintId, cwd, execFn) {
|
|
8035
|
+
const result = { refreshed: [], skipped: [], errors: [] };
|
|
8036
|
+
const sprintFilePath = findSprintFile(sprintId, cwd);
|
|
8037
|
+
if (!sprintFilePath) {
|
|
8038
|
+
return result;
|
|
8039
|
+
}
|
|
8040
|
+
const childIds = extractInScopeWorkItemIds(sprintFilePath, cwd, execFn);
|
|
8041
|
+
if (!childIds || childIds.length === 0) {
|
|
8042
|
+
return result;
|
|
8043
|
+
}
|
|
8044
|
+
for (const id of childIds) {
|
|
8045
|
+
const absPath = findWorkItemFileLocal(cwd, id);
|
|
8046
|
+
if (!absPath) {
|
|
8047
|
+
continue;
|
|
8048
|
+
}
|
|
8049
|
+
let status = "";
|
|
8050
|
+
try {
|
|
8051
|
+
const raw = fs34.readFileSync(absPath, "utf8");
|
|
8052
|
+
const { fm } = parseFrontmatter(raw);
|
|
8053
|
+
status = String(fm["status"] ?? "");
|
|
8054
|
+
} catch {
|
|
8055
|
+
}
|
|
8056
|
+
if (TERMINAL_STATUSES2.has(status)) {
|
|
8057
|
+
result.skipped.push(id);
|
|
8058
|
+
continue;
|
|
8059
|
+
}
|
|
8060
|
+
try {
|
|
8061
|
+
execFn(`cleargate gate check "${absPath}"`, { cwd, encoding: "utf8" });
|
|
8062
|
+
result.refreshed.push(id);
|
|
8063
|
+
} catch (err) {
|
|
8064
|
+
result.errors.push({ id, message: String(err) });
|
|
8065
|
+
}
|
|
8066
|
+
}
|
|
8067
|
+
return result;
|
|
8068
|
+
}
|
|
7865
8069
|
function emitPunchList(sprintId, results, stdoutFn, stderrFn) {
|
|
7866
8070
|
const failures = results.filter((r) => !r.pass && !r.skipped);
|
|
7867
8071
|
if (failures.length === 0) {
|
|
@@ -7893,6 +8097,13 @@ function sprintPreflightHandler(opts, cli) {
|
|
|
7893
8097
|
}
|
|
7894
8098
|
const execFn = cli?.execFn ?? ((cmd, execOpts) => (0, import_node_child_process11.execSync)(cmd, { ...execOpts, stdio: "pipe" }));
|
|
7895
8099
|
const mode = readSprintExecutionMode(opts.sprintId, { cwd });
|
|
8100
|
+
const refresh = refreshScopedGateCaches(opts.sprintId, cwd, execFn);
|
|
8101
|
+
stdoutFn(`Step 0: refreshed ${refresh.refreshed.length} items, ${refresh.errors.length} errors.
|
|
8102
|
+
`);
|
|
8103
|
+
for (const e of refresh.errors) {
|
|
8104
|
+
stdoutFn(` - ${e.id}: ${e.message}
|
|
8105
|
+
`);
|
|
8106
|
+
}
|
|
7896
8107
|
const results = [
|
|
7897
8108
|
checkPrevSprintCompleted(opts.sprintId, cwd),
|
|
7898
8109
|
checkNoLeftoverWorktrees(cwd, execFn),
|
|
@@ -7911,7 +8122,7 @@ function sprintPreflightHandler(opts, cli) {
|
|
|
7911
8122
|
// src/commands/story.ts
|
|
7912
8123
|
init_cjs_shims();
|
|
7913
8124
|
var fs35 = __toESM(require("fs"), 1);
|
|
7914
|
-
var
|
|
8125
|
+
var path37 = __toESM(require("path"), 1);
|
|
7915
8126
|
var import_node_child_process12 = require("child_process");
|
|
7916
8127
|
function defaultExit2(code) {
|
|
7917
8128
|
return process.exit(code);
|
|
@@ -7919,7 +8130,7 @@ function defaultExit2(code) {
|
|
|
7919
8130
|
function resolveRunScript2(opts) {
|
|
7920
8131
|
if (opts.runScriptPath) return opts.runScriptPath;
|
|
7921
8132
|
const cwd = opts.cwd ?? process.cwd();
|
|
7922
|
-
return
|
|
8133
|
+
return path37.join(cwd, ".cleargate", "scripts", "run_script.sh");
|
|
7923
8134
|
}
|
|
7924
8135
|
function deriveSprintBranch(sprintId) {
|
|
7925
8136
|
const match = /^SPRINT-(\d+)/.exec(sprintId);
|
|
@@ -7932,7 +8143,7 @@ function atomicWriteString(filePath, text) {
|
|
|
7932
8143
|
fs35.renameSync(tmpFile, filePath);
|
|
7933
8144
|
}
|
|
7934
8145
|
function stateJsonPath(cwd, sprintId) {
|
|
7935
|
-
return
|
|
8146
|
+
return path37.join(cwd, ".cleargate", "sprint-runs", sprintId, "state.json");
|
|
7936
8147
|
}
|
|
7937
8148
|
function storyStartHandler(opts, cli) {
|
|
7938
8149
|
const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
|
|
@@ -7949,7 +8160,7 @@ function storyStartHandler(opts, cli) {
|
|
|
7949
8160
|
return printInertAndExit(stdoutFn, exitFn);
|
|
7950
8161
|
}
|
|
7951
8162
|
const sprintBranch = deriveSprintBranch(sprintId);
|
|
7952
|
-
const worktreePath =
|
|
8163
|
+
const worktreePath = path37.join(cwd, ".worktrees", opts.storyId);
|
|
7953
8164
|
const storyBranch = `story/${opts.storyId}`;
|
|
7954
8165
|
const step1 = spawnFn(
|
|
7955
8166
|
"git",
|
|
@@ -7966,9 +8177,10 @@ function storyStartHandler(opts, cli) {
|
|
|
7966
8177
|
return exitFn(step1.status ?? 1);
|
|
7967
8178
|
}
|
|
7968
8179
|
const runScript = resolveRunScript2(cli ?? { cwd });
|
|
8180
|
+
const updateStateScript = resolveCleargateScript({ cwd }, "update_state.mjs");
|
|
7969
8181
|
const step2 = spawnFn(
|
|
7970
8182
|
"bash",
|
|
7971
|
-
[runScript, "
|
|
8183
|
+
[runScript, "node", updateStateScript, opts.storyId, "Bouncing"],
|
|
7972
8184
|
{ stdio: "pipe", cwd, encoding: "utf8" }
|
|
7973
8185
|
);
|
|
7974
8186
|
if (step2.error) {
|
|
@@ -8028,7 +8240,7 @@ function storyCompleteHandler(opts, cli) {
|
|
|
8028
8240
|
}
|
|
8029
8241
|
const sprintBranch = deriveSprintBranch(sprintId);
|
|
8030
8242
|
const storyBranch = `story/${opts.storyId}`;
|
|
8031
|
-
const worktreeRel =
|
|
8243
|
+
const worktreeRel = path37.join(".worktrees", opts.storyId);
|
|
8032
8244
|
const step1 = spawnFn(
|
|
8033
8245
|
"git",
|
|
8034
8246
|
["rev-list", "--count", `${sprintBranch}..${storyBranch}`],
|
|
@@ -8106,9 +8318,10 @@ function storyCompleteHandler(opts, cli) {
|
|
|
8106
8318
|
return exitFn(step5.status ?? 1);
|
|
8107
8319
|
}
|
|
8108
8320
|
const runScript = resolveRunScript2(cli ?? { cwd });
|
|
8321
|
+
const updateStateDoneScript = resolveCleargateScript({ cwd }, "update_state.mjs");
|
|
8109
8322
|
const step6 = spawnFn(
|
|
8110
8323
|
"bash",
|
|
8111
|
-
[runScript, "
|
|
8324
|
+
[runScript, "node", updateStateDoneScript, opts.storyId, "Done"],
|
|
8112
8325
|
{ stdio: "pipe", cwd, encoding: "utf8" }
|
|
8113
8326
|
);
|
|
8114
8327
|
if (step6.error) {
|
|
@@ -8126,7 +8339,7 @@ function storyCompleteHandler(opts, cli) {
|
|
|
8126
8339
|
|
|
8127
8340
|
// src/commands/state.ts
|
|
8128
8341
|
init_cjs_shims();
|
|
8129
|
-
var
|
|
8342
|
+
var path38 = __toESM(require("path"), 1);
|
|
8130
8343
|
var import_node_child_process13 = require("child_process");
|
|
8131
8344
|
function defaultExit3(code) {
|
|
8132
8345
|
return process.exit(code);
|
|
@@ -8134,7 +8347,7 @@ function defaultExit3(code) {
|
|
|
8134
8347
|
function resolveRunScript3(opts) {
|
|
8135
8348
|
if (opts.runScriptPath) return opts.runScriptPath;
|
|
8136
8349
|
const cwd = opts.cwd ?? process.cwd();
|
|
8137
|
-
return
|
|
8350
|
+
return path38.join(cwd, ".cleargate", "scripts", "run_script.sh");
|
|
8138
8351
|
}
|
|
8139
8352
|
function stateUpdateHandler(opts, cli) {
|
|
8140
8353
|
const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
|
|
@@ -8151,9 +8364,11 @@ function stateUpdateHandler(opts, cli) {
|
|
|
8151
8364
|
return printInertAndExit(stdoutFn, exitFn);
|
|
8152
8365
|
}
|
|
8153
8366
|
const runScript = resolveRunScript3(cli ?? {});
|
|
8367
|
+
const updateCwd = cli?.cwd ?? process.cwd();
|
|
8368
|
+
const updateScriptPath = resolveCleargateScript({ cwd: updateCwd }, "update_state.mjs");
|
|
8154
8369
|
const result = spawnFn(
|
|
8155
8370
|
"bash",
|
|
8156
|
-
[runScript, "
|
|
8371
|
+
[runScript, "node", updateScriptPath, opts.storyId, opts.newState],
|
|
8157
8372
|
{ stdio: "inherit" }
|
|
8158
8373
|
);
|
|
8159
8374
|
if (result.error) {
|
|
@@ -8176,9 +8391,11 @@ function stateValidateHandler(opts, cli) {
|
|
|
8176
8391
|
return printInertAndExit(stdoutFn, exitFn);
|
|
8177
8392
|
}
|
|
8178
8393
|
const runScript = resolveRunScript3(cli ?? {});
|
|
8394
|
+
const validateCwd = cli?.cwd ?? process.cwd();
|
|
8395
|
+
const validateScriptPath = resolveCleargateScript({ cwd: validateCwd }, "validate_state.mjs");
|
|
8179
8396
|
const result = spawnFn(
|
|
8180
8397
|
"bash",
|
|
8181
|
-
[runScript, "
|
|
8398
|
+
[runScript, "node", validateScriptPath, opts.sprintId],
|
|
8182
8399
|
{ stdio: "inherit" }
|
|
8183
8400
|
);
|
|
8184
8401
|
if (result.error) {
|
|
@@ -8192,20 +8409,20 @@ function stateValidateHandler(opts, cli) {
|
|
|
8192
8409
|
// src/commands/stamp-tokens.ts
|
|
8193
8410
|
init_cjs_shims();
|
|
8194
8411
|
var fs37 = __toESM(require("fs"), 1);
|
|
8195
|
-
var
|
|
8412
|
+
var path40 = __toESM(require("path"), 1);
|
|
8196
8413
|
|
|
8197
8414
|
// src/lib/ledger-reader.ts
|
|
8198
8415
|
init_cjs_shims();
|
|
8199
8416
|
var fs36 = __toESM(require("fs"), 1);
|
|
8200
|
-
var
|
|
8417
|
+
var path39 = __toESM(require("path"), 1);
|
|
8201
8418
|
function findSprintRunsRoot(startDir) {
|
|
8202
8419
|
let dir = startDir;
|
|
8203
8420
|
while (true) {
|
|
8204
|
-
const candidate =
|
|
8421
|
+
const candidate = path39.join(dir, ".cleargate", "sprint-runs");
|
|
8205
8422
|
if (fs36.existsSync(candidate)) {
|
|
8206
8423
|
return candidate;
|
|
8207
8424
|
}
|
|
8208
|
-
const parent =
|
|
8425
|
+
const parent = path39.dirname(dir);
|
|
8209
8426
|
if (parent === dir) {
|
|
8210
8427
|
return null;
|
|
8211
8428
|
}
|
|
@@ -8264,7 +8481,7 @@ function readLedgerForWorkItem(workItemId, opts = {}) {
|
|
|
8264
8481
|
let ledgerFiles;
|
|
8265
8482
|
try {
|
|
8266
8483
|
const entries = fs36.readdirSync(sprintRunsRoot, { withFileTypes: true });
|
|
8267
|
-
ledgerFiles = entries.filter((e) => e.isDirectory()).map((e) =>
|
|
8484
|
+
ledgerFiles = entries.filter((e) => e.isDirectory()).map((e) => path39.join(sprintRunsRoot, e.name, "token-ledger.jsonl")).filter((f) => fs36.existsSync(f));
|
|
8268
8485
|
} catch {
|
|
8269
8486
|
return [];
|
|
8270
8487
|
}
|
|
@@ -8323,7 +8540,7 @@ async function stampTokensHandler(file, opts, cli) {
|
|
|
8323
8540
|
});
|
|
8324
8541
|
const nowFn = cli?.now ?? (() => /* @__PURE__ */ new Date());
|
|
8325
8542
|
const cwd = cli?.cwd ?? process.cwd();
|
|
8326
|
-
const absPath =
|
|
8543
|
+
const absPath = path40.isAbsolute(file) ? file : path40.resolve(cwd, file);
|
|
8327
8544
|
if (/\/\.cleargate\/delivery\/archive\//.test(absPath)) {
|
|
8328
8545
|
stdoutFn(`[frozen] ${absPath}`);
|
|
8329
8546
|
exitFn(0);
|
|
@@ -8413,21 +8630,21 @@ async function stampTokensHandler(file, opts, cli) {
|
|
|
8413
8630
|
exitFn(0);
|
|
8414
8631
|
}
|
|
8415
8632
|
function extractWorkItemId(fm, absPath) {
|
|
8416
|
-
const idKeys = ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id"];
|
|
8633
|
+
const idKeys = ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id", "initiative_id", "sprint_id"];
|
|
8417
8634
|
for (const key of idKeys) {
|
|
8418
8635
|
const val = fm[key];
|
|
8419
8636
|
if (typeof val === "string" && val.trim() !== "") {
|
|
8420
8637
|
return val.trim();
|
|
8421
8638
|
}
|
|
8422
8639
|
}
|
|
8423
|
-
const basename13 =
|
|
8424
|
-
const match = basename13.match(/^(STORY|EPIC|PROPOSAL|CR|BUG)-\d+(-\d+)?/i);
|
|
8640
|
+
const basename13 = path40.basename(absPath);
|
|
8641
|
+
const match = basename13.match(/^(STORY|EPIC|PROPOSAL|CR|BUG|INITIATIVE|SPRINT)-\d+(-\d+)?/i);
|
|
8425
8642
|
if (match) {
|
|
8426
8643
|
return match[0].toUpperCase();
|
|
8427
8644
|
}
|
|
8428
8645
|
const typeFromPath = detectWorkItemType(absPath);
|
|
8429
8646
|
if (typeFromPath) {
|
|
8430
|
-
const idMatch = basename13.match(/((?:STORY|EPIC|PROPOSAL|CR|BUG)-\d+(?:-\d+)?)/i);
|
|
8647
|
+
const idMatch = basename13.match(/((?:STORY|EPIC|PROPOSAL|CR|BUG|INITIATIVE|SPRINT)-\d+(?:-\d+)?)/i);
|
|
8431
8648
|
if (idMatch) {
|
|
8432
8649
|
return idMatch[1].toUpperCase();
|
|
8433
8650
|
}
|
|
@@ -8527,7 +8744,7 @@ ${body}`;
|
|
|
8527
8744
|
init_cjs_shims();
|
|
8528
8745
|
var fs38 = __toESM(require("fs"), 1);
|
|
8529
8746
|
var fsp = __toESM(require("fs/promises"), 1);
|
|
8530
|
-
var
|
|
8747
|
+
var path41 = __toESM(require("path"), 1);
|
|
8531
8748
|
|
|
8532
8749
|
// src/lib/changelog.ts
|
|
8533
8750
|
init_cjs_shims();
|
|
@@ -8719,7 +8936,7 @@ async function writeAtomic2(filePath, content) {
|
|
|
8719
8936
|
await fsp.rename(tmpPath, filePath);
|
|
8720
8937
|
}
|
|
8721
8938
|
async function updateSnapshotEntry(projectRoot, filePath, newSha) {
|
|
8722
|
-
const snapshotPath =
|
|
8939
|
+
const snapshotPath = path41.join(projectRoot, ".cleargate", ".install-manifest.json");
|
|
8723
8940
|
let snapshot;
|
|
8724
8941
|
try {
|
|
8725
8942
|
const raw = await fsp.readFile(snapshotPath, "utf-8");
|
|
@@ -8736,17 +8953,17 @@ async function updateSnapshotEntry(projectRoot, filePath, newSha) {
|
|
|
8736
8953
|
await writeAtomic2(snapshotPath, JSON.stringify(updated, null, 2) + "\n");
|
|
8737
8954
|
}
|
|
8738
8955
|
function isClaudeMd(filePath) {
|
|
8739
|
-
return
|
|
8956
|
+
return path41.basename(filePath) === "CLAUDE.md";
|
|
8740
8957
|
}
|
|
8741
8958
|
function isSettingsJson(filePath) {
|
|
8742
|
-
return
|
|
8959
|
+
return path41.basename(filePath) === "settings.json" && filePath.includes(".claude");
|
|
8743
8960
|
}
|
|
8744
8961
|
async function applyAlwaysOverwrite(entry, projectRoot, packageRoot, stdout) {
|
|
8745
|
-
const targetPath =
|
|
8746
|
-
const sourcePath =
|
|
8962
|
+
const targetPath = path41.join(projectRoot, entry.path);
|
|
8963
|
+
const sourcePath = path41.join(packageRoot, entry.path);
|
|
8747
8964
|
try {
|
|
8748
8965
|
const pkgContent = await fsp.readFile(sourcePath, "utf-8");
|
|
8749
|
-
await fsp.mkdir(
|
|
8966
|
+
await fsp.mkdir(path41.dirname(targetPath), { recursive: true });
|
|
8750
8967
|
await writeAtomic2(targetPath, pkgContent);
|
|
8751
8968
|
await updateSnapshotEntry(projectRoot, entry.path, entry.sha256);
|
|
8752
8969
|
stdout(`[always] overwritten: ${entry.path}`);
|
|
@@ -8756,8 +8973,8 @@ async function applyAlwaysOverwrite(entry, projectRoot, packageRoot, stdout) {
|
|
|
8756
8973
|
}
|
|
8757
8974
|
async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, currentSha, flags, opts) {
|
|
8758
8975
|
const { stdout, stderr, promptMergeChoiceFn, openInEditorFn, stdin } = opts;
|
|
8759
|
-
const targetPath =
|
|
8760
|
-
const sourcePath =
|
|
8976
|
+
const targetPath = path41.join(projectRoot, entry.path);
|
|
8977
|
+
const sourcePath = path41.join(packageRoot, entry.path);
|
|
8761
8978
|
let ours = "";
|
|
8762
8979
|
let theirs = "";
|
|
8763
8980
|
try {
|
|
@@ -8820,7 +9037,7 @@ async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, curre
|
|
|
8820
9037
|
mergedContent = theirs;
|
|
8821
9038
|
}
|
|
8822
9039
|
}
|
|
8823
|
-
await fsp.mkdir(
|
|
9040
|
+
await fsp.mkdir(path41.dirname(targetPath), { recursive: true });
|
|
8824
9041
|
await writeAtomic2(targetPath, mergedContent);
|
|
8825
9042
|
const newSha2 = hashNormalized(mergedContent);
|
|
8826
9043
|
await updateSnapshotEntry(projectRoot, entry.path, newSha2);
|
|
@@ -8832,7 +9049,7 @@ async function applyMerge3Way(entry, projectRoot, packageRoot, installSha, curre
|
|
|
8832
9049
|
${ours}=======
|
|
8833
9050
|
${theirs}>>>>>>> theirs (upstream)
|
|
8834
9051
|
`;
|
|
8835
|
-
await fsp.mkdir(
|
|
9052
|
+
await fsp.mkdir(path41.dirname(mergeFilePath), { recursive: true });
|
|
8836
9053
|
await writeAtomic2(mergeFilePath, conflictContent);
|
|
8837
9054
|
try {
|
|
8838
9055
|
const result = await openInEditorFn(mergeFilePath);
|
|
@@ -8892,8 +9109,8 @@ async function upgradeHandler(flags, cli) {
|
|
|
8892
9109
|
const installedVersion = installSnapshot?.cleargate_version ?? pkgManifest.cleargate_version;
|
|
8893
9110
|
const targetVersion = pkgManifest.cleargate_version;
|
|
8894
9111
|
if (installedVersion !== targetVersion) {
|
|
8895
|
-
const pkgRoot = cli?.packageRoot ??
|
|
8896
|
-
const changelogPath =
|
|
9112
|
+
const pkgRoot = cli?.packageRoot ?? path41.join(path41.dirname(new URL(importMetaUrl).pathname), "..", "..");
|
|
9113
|
+
const changelogPath = path41.join(pkgRoot, "CHANGELOG.md");
|
|
8897
9114
|
try {
|
|
8898
9115
|
const changelogContent = fs38.readFileSync(changelogPath, "utf-8");
|
|
8899
9116
|
const sections = sliceChangelog(changelogContent, installedVersion, targetVersion);
|
|
@@ -8988,7 +9205,7 @@ async function upgradeHandler(flags, cli) {
|
|
|
8988
9205
|
init_cjs_shims();
|
|
8989
9206
|
var fs39 = __toESM(require("fs"), 1);
|
|
8990
9207
|
var fsp2 = __toESM(require("fs/promises"), 1);
|
|
8991
|
-
var
|
|
9208
|
+
var path42 = __toESM(require("path"), 1);
|
|
8992
9209
|
var import_node_child_process15 = require("child_process");
|
|
8993
9210
|
var USER_ARTIFACT_TIERS = ["user-artifact"];
|
|
8994
9211
|
var FRAMEWORK_TIERS = ["protocol", "template", "agent", "hook", "skill", "cli-config", "derived"];
|
|
@@ -9014,7 +9231,7 @@ function shouldPreserve(entry, preserveSet, removeSet) {
|
|
|
9014
9231
|
return false;
|
|
9015
9232
|
}
|
|
9016
9233
|
function resolveProjectName(target) {
|
|
9017
|
-
const pkgPath =
|
|
9234
|
+
const pkgPath = path42.join(target, "package.json");
|
|
9018
9235
|
if (fs39.existsSync(pkgPath)) {
|
|
9019
9236
|
try {
|
|
9020
9237
|
const raw = fs39.readFileSync(pkgPath, "utf-8");
|
|
@@ -9025,7 +9242,7 @@ function resolveProjectName(target) {
|
|
|
9025
9242
|
} catch {
|
|
9026
9243
|
}
|
|
9027
9244
|
}
|
|
9028
|
-
return
|
|
9245
|
+
return path42.basename(target);
|
|
9029
9246
|
}
|
|
9030
9247
|
function detectUncommittedChanges(target, manifestPaths, gitRunner) {
|
|
9031
9248
|
const run = gitRunner ?? ((args) => {
|
|
@@ -9054,7 +9271,7 @@ function detectUncommittedChanges(target, manifestPaths, gitRunner) {
|
|
|
9054
9271
|
return changedFiles.filter((f) => manifestSet.has(f));
|
|
9055
9272
|
}
|
|
9056
9273
|
async function removeFromPackageJson(target, dryRun) {
|
|
9057
|
-
const pkgPath =
|
|
9274
|
+
const pkgPath = path42.join(target, "package.json");
|
|
9058
9275
|
if (!fs39.existsSync(pkgPath)) return false;
|
|
9059
9276
|
let raw;
|
|
9060
9277
|
try {
|
|
@@ -9116,10 +9333,10 @@ async function uninstallHandler(opts) {
|
|
|
9116
9333
|
for (const t of FRAMEWORK_TIERS) removeSet.add(t);
|
|
9117
9334
|
for (const u of USER_ARTIFACT_TIERS) removeSet.add(u);
|
|
9118
9335
|
}
|
|
9119
|
-
const target = opts.path ?
|
|
9120
|
-
const cleargateDir =
|
|
9121
|
-
const manifestPath =
|
|
9122
|
-
const uninstalledPath =
|
|
9336
|
+
const target = opts.path ? path42.resolve(opts.path) : cwd;
|
|
9337
|
+
const cleargateDir = path42.join(target, ".cleargate");
|
|
9338
|
+
const manifestPath = path42.join(cleargateDir, ".install-manifest.json");
|
|
9339
|
+
const uninstalledPath = path42.join(cleargateDir, ".uninstalled");
|
|
9123
9340
|
if (!fs39.existsSync(manifestPath)) {
|
|
9124
9341
|
if (fs39.existsSync(uninstalledPath)) {
|
|
9125
9342
|
stdout("already uninstalled");
|
|
@@ -9152,7 +9369,7 @@ async function uninstallHandler(opts) {
|
|
|
9152
9369
|
return;
|
|
9153
9370
|
}
|
|
9154
9371
|
}
|
|
9155
|
-
const claudeMdPath =
|
|
9372
|
+
const claudeMdPath = path42.join(target, "CLAUDE.md");
|
|
9156
9373
|
let claudeMdContent = null;
|
|
9157
9374
|
if (fs39.existsSync(claudeMdPath)) {
|
|
9158
9375
|
claudeMdContent = fs39.readFileSync(claudeMdPath, "utf-8");
|
|
@@ -9171,7 +9388,7 @@ async function uninstallHandler(opts) {
|
|
|
9171
9388
|
const toPreserve = [];
|
|
9172
9389
|
const toSkip = [];
|
|
9173
9390
|
for (const entry of snapshot.files) {
|
|
9174
|
-
const filePath =
|
|
9391
|
+
const filePath = path42.join(target, entry.path);
|
|
9175
9392
|
if (!fs39.existsSync(filePath)) {
|
|
9176
9393
|
toSkip.push(entry);
|
|
9177
9394
|
continue;
|
|
@@ -9229,7 +9446,7 @@ async function uninstallHandler(opts) {
|
|
|
9229
9446
|
const removedPaths = [];
|
|
9230
9447
|
const preservedPaths = [];
|
|
9231
9448
|
for (const entry of toRemove) {
|
|
9232
|
-
const filePath =
|
|
9449
|
+
const filePath = path42.join(target, entry.path);
|
|
9233
9450
|
await removeFile(filePath);
|
|
9234
9451
|
removedPaths.push(entry.path);
|
|
9235
9452
|
}
|
|
@@ -9245,7 +9462,7 @@ async function uninstallHandler(opts) {
|
|
|
9245
9462
|
stderr(`Warning: could not strip CLAUDE.md block: ${err.message}`);
|
|
9246
9463
|
}
|
|
9247
9464
|
}
|
|
9248
|
-
const settingsPath =
|
|
9465
|
+
const settingsPath = path42.join(target, ".claude", "settings.json");
|
|
9249
9466
|
if (fs39.existsSync(settingsPath)) {
|
|
9250
9467
|
try {
|
|
9251
9468
|
const raw = fs39.readFileSync(settingsPath, "utf-8");
|
|
@@ -9263,7 +9480,7 @@ async function uninstallHandler(opts) {
|
|
|
9263
9480
|
stdout("Removed @cleargate/cli from package.json. Run `npm install` to update package-lock.json.");
|
|
9264
9481
|
}
|
|
9265
9482
|
await removeFile(manifestPath);
|
|
9266
|
-
await removeFile(
|
|
9483
|
+
await removeFile(path42.join(cleargateDir, ".drift-state.json"));
|
|
9267
9484
|
const marker = {
|
|
9268
9485
|
uninstalled_at: now().toISOString(),
|
|
9269
9486
|
prior_version: snapshot.cleargate_version,
|
|
@@ -9288,16 +9505,16 @@ async function uninstallHandler(opts) {
|
|
|
9288
9505
|
// src/commands/sync.ts
|
|
9289
9506
|
init_cjs_shims();
|
|
9290
9507
|
var fsPromises8 = __toESM(require("fs/promises"), 1);
|
|
9291
|
-
var
|
|
9508
|
+
var path50 = __toESM(require("path"), 1);
|
|
9292
9509
|
|
|
9293
9510
|
// src/lib/sync-log.ts
|
|
9294
9511
|
init_cjs_shims();
|
|
9295
9512
|
var fs40 = __toESM(require("fs"), 1);
|
|
9296
9513
|
var fsPromises2 = __toESM(require("fs/promises"), 1);
|
|
9297
|
-
var
|
|
9514
|
+
var path43 = __toESM(require("path"), 1);
|
|
9298
9515
|
function resolveActiveSprintDir(projectRoot, _opts) {
|
|
9299
|
-
const sprintRunsRoot =
|
|
9300
|
-
const offSprint =
|
|
9516
|
+
const sprintRunsRoot = path43.join(projectRoot, ".cleargate", "sprint-runs");
|
|
9517
|
+
const offSprint = path43.join(sprintRunsRoot, "_off-sprint");
|
|
9301
9518
|
if (!fs40.existsSync(sprintRunsRoot)) {
|
|
9302
9519
|
fs40.mkdirSync(sprintRunsRoot, { recursive: true });
|
|
9303
9520
|
fs40.mkdirSync(offSprint, { recursive: true });
|
|
@@ -9305,7 +9522,7 @@ function resolveActiveSprintDir(projectRoot, _opts) {
|
|
|
9305
9522
|
}
|
|
9306
9523
|
const entries = fs40.readdirSync(sprintRunsRoot, { withFileTypes: true });
|
|
9307
9524
|
const sprintDirs = entries.filter((e) => e.isDirectory() && e.name !== "_off-sprint").map((e) => {
|
|
9308
|
-
const fullPath =
|
|
9525
|
+
const fullPath = path43.join(sprintRunsRoot, e.name);
|
|
9309
9526
|
const stat = fs40.statSync(fullPath);
|
|
9310
9527
|
return { name: e.name, fullPath, mtimeMs: stat.mtimeMs };
|
|
9311
9528
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
@@ -9322,7 +9539,7 @@ function redactDetail(detail) {
|
|
|
9322
9539
|
return detail.replace(/eyJ[A-Za-z0-9._-]+/g, "[REDACTED]");
|
|
9323
9540
|
}
|
|
9324
9541
|
async function appendSyncLog(sprintRoot, entry) {
|
|
9325
|
-
const logPath =
|
|
9542
|
+
const logPath = path43.join(sprintRoot, "sync-log.jsonl");
|
|
9326
9543
|
await fsPromises2.mkdir(sprintRoot, { recursive: true });
|
|
9327
9544
|
const safeEntry = {
|
|
9328
9545
|
...entry,
|
|
@@ -9332,7 +9549,7 @@ async function appendSyncLog(sprintRoot, entry) {
|
|
|
9332
9549
|
await fsPromises2.appendFile(logPath, line, { encoding: "utf8" });
|
|
9333
9550
|
}
|
|
9334
9551
|
async function readSyncLog(sprintRoot, filters) {
|
|
9335
|
-
const logPath =
|
|
9552
|
+
const logPath = path43.join(sprintRoot, "sync-log.jsonl");
|
|
9336
9553
|
let raw;
|
|
9337
9554
|
try {
|
|
9338
9555
|
raw = await fsPromises2.readFile(logPath, "utf8");
|
|
@@ -9438,7 +9655,7 @@ function classify2(local, remote, since) {
|
|
|
9438
9655
|
init_cjs_shims();
|
|
9439
9656
|
var import_node_fs2 = require("fs");
|
|
9440
9657
|
var os8 = __toESM(require("os"), 1);
|
|
9441
|
-
var
|
|
9658
|
+
var path44 = __toESM(require("path"), 1);
|
|
9442
9659
|
function promptFourChoice(opts) {
|
|
9443
9660
|
const { stdin, stdout } = opts;
|
|
9444
9661
|
stdout("[k]eep mine / [t]ake theirs / [e]dit in $EDITOR / [a]bort: ");
|
|
@@ -9508,7 +9725,7 @@ async function promptThreeWayMerge(opts) {
|
|
|
9508
9725
|
case "a":
|
|
9509
9726
|
return { resolution: "aborted", body: local };
|
|
9510
9727
|
case "e": {
|
|
9511
|
-
const tmpFile =
|
|
9728
|
+
const tmpFile = path44.join(os8.tmpdir(), `cleargate-merge-${itemId}-${now()}.md`);
|
|
9512
9729
|
const markerContent = `<<<<<<< local
|
|
9513
9730
|
${local}
|
|
9514
9731
|
=======
|
|
@@ -9608,12 +9825,12 @@ init_config();
|
|
|
9608
9825
|
// src/lib/intake.ts
|
|
9609
9826
|
init_cjs_shims();
|
|
9610
9827
|
var fsPromises4 = __toESM(require("fs/promises"), 1);
|
|
9611
|
-
var
|
|
9828
|
+
var path46 = __toESM(require("path"), 1);
|
|
9612
9829
|
|
|
9613
9830
|
// src/lib/slug.ts
|
|
9614
9831
|
init_cjs_shims();
|
|
9615
9832
|
var fsPromises3 = __toESM(require("fs/promises"), 1);
|
|
9616
|
-
var
|
|
9833
|
+
var path45 = __toESM(require("path"), 1);
|
|
9617
9834
|
function slugify(title, max = 40) {
|
|
9618
9835
|
const normalized = title.normalize("NFKD").replace(new RegExp("\\p{M}", "gu"), "");
|
|
9619
9836
|
const lowered = normalized.toLowerCase();
|
|
@@ -9628,8 +9845,8 @@ function slugify(title, max = 40) {
|
|
|
9628
9845
|
var PROPOSAL_ID_RE = /^proposal_id:\s*"?PROP-(\d+)"?/m;
|
|
9629
9846
|
async function nextProposalId(projectRoot) {
|
|
9630
9847
|
const dirs = [
|
|
9631
|
-
|
|
9632
|
-
|
|
9848
|
+
path45.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
|
|
9849
|
+
path45.join(projectRoot, ".cleargate", "delivery", "archive")
|
|
9633
9850
|
];
|
|
9634
9851
|
let maxN = 0;
|
|
9635
9852
|
for (const dir of dirs) {
|
|
@@ -9641,7 +9858,7 @@ async function nextProposalId(projectRoot) {
|
|
|
9641
9858
|
}
|
|
9642
9859
|
for (const entry of entries) {
|
|
9643
9860
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
9644
|
-
const fullPath =
|
|
9861
|
+
const fullPath = path45.join(dir, entry.name);
|
|
9645
9862
|
try {
|
|
9646
9863
|
const raw = await fsPromises3.readFile(fullPath, "utf8");
|
|
9647
9864
|
const fmEnd = extractFrontmatterBlock(raw);
|
|
@@ -9659,8 +9876,8 @@ async function nextProposalId(projectRoot) {
|
|
|
9659
9876
|
}
|
|
9660
9877
|
async function findByRemoteId(projectRoot, remoteId) {
|
|
9661
9878
|
const dirs = [
|
|
9662
|
-
|
|
9663
|
-
|
|
9879
|
+
path45.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
|
|
9880
|
+
path45.join(projectRoot, ".cleargate", "delivery", "archive")
|
|
9664
9881
|
];
|
|
9665
9882
|
const escaped = remoteId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9666
9883
|
const re = new RegExp(`^remote_id:\\s*"?${escaped}"?\\s*$`, "m");
|
|
@@ -9673,7 +9890,7 @@ async function findByRemoteId(projectRoot, remoteId) {
|
|
|
9673
9890
|
}
|
|
9674
9891
|
for (const entry of entries) {
|
|
9675
9892
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
9676
|
-
const fullPath =
|
|
9893
|
+
const fullPath = path45.join(dir, entry.name);
|
|
9677
9894
|
try {
|
|
9678
9895
|
const raw = await fsPromises3.readFile(fullPath, "utf8");
|
|
9679
9896
|
const fm = extractFrontmatterBlock(raw);
|
|
@@ -9710,7 +9927,7 @@ async function runIntakeBranch(opts) {
|
|
|
9710
9927
|
labelFilter = "cleargate:proposal",
|
|
9711
9928
|
now = () => (/* @__PURE__ */ new Date()).toISOString()
|
|
9712
9929
|
} = opts;
|
|
9713
|
-
const pendingSyncDir =
|
|
9930
|
+
const pendingSyncDir = path46.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
9714
9931
|
let remoteItems = [];
|
|
9715
9932
|
try {
|
|
9716
9933
|
remoteItems = await mcp2.call(
|
|
@@ -9741,7 +9958,7 @@ async function runIntakeBranch(opts) {
|
|
|
9741
9958
|
const slug2 = slugify(item.title ?? "untitled");
|
|
9742
9959
|
const num2 = proposalId2.replace("PROP-", "");
|
|
9743
9960
|
const filename2 = `PROPOSAL-${num2}-remote-${slug2}.md`;
|
|
9744
|
-
const targetPath2 =
|
|
9961
|
+
const targetPath2 = path46.join(pendingSyncDir, filename2);
|
|
9745
9962
|
createdItems.push({
|
|
9746
9963
|
proposalId: proposalId2,
|
|
9747
9964
|
remoteId: item.remote_id,
|
|
@@ -9754,7 +9971,7 @@ async function runIntakeBranch(opts) {
|
|
|
9754
9971
|
const num = proposalId.replace("PROP-", "");
|
|
9755
9972
|
const slug = slugify(item.title ?? "untitled");
|
|
9756
9973
|
const filename = `PROPOSAL-${num}-remote-${slug}.md`;
|
|
9757
|
-
const targetPath =
|
|
9974
|
+
const targetPath = path46.join(pendingSyncDir, filename);
|
|
9758
9975
|
const nowTs = now();
|
|
9759
9976
|
const fm = {
|
|
9760
9977
|
proposal_id: proposalId,
|
|
@@ -9846,8 +10063,8 @@ path/to/new/file.ext - {Explanation of purpose}
|
|
|
9846
10063
|
}
|
|
9847
10064
|
async function hasAnyRemoteAuthored(projectRoot) {
|
|
9848
10065
|
const dirs = [
|
|
9849
|
-
|
|
9850
|
-
|
|
10066
|
+
path46.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
|
|
10067
|
+
path46.join(projectRoot, ".cleargate", "delivery", "archive")
|
|
9851
10068
|
];
|
|
9852
10069
|
for (const dir of dirs) {
|
|
9853
10070
|
let entries;
|
|
@@ -9858,7 +10075,7 @@ async function hasAnyRemoteAuthored(projectRoot) {
|
|
|
9858
10075
|
}
|
|
9859
10076
|
for (const entry of entries) {
|
|
9860
10077
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
9861
|
-
const fullPath =
|
|
10078
|
+
const fullPath = path46.join(dir, entry.name);
|
|
9862
10079
|
try {
|
|
9863
10080
|
const raw = await fsPromises4.readFile(fullPath, "utf8");
|
|
9864
10081
|
const fmEnd = raw.indexOf("\n---", 4);
|
|
@@ -9878,7 +10095,7 @@ async function hasAnyRemoteAuthored(projectRoot) {
|
|
|
9878
10095
|
init_cjs_shims();
|
|
9879
10096
|
var fs42 = __toESM(require("fs"), 1);
|
|
9880
10097
|
var fsPromises5 = __toESM(require("fs/promises"), 1);
|
|
9881
|
-
var
|
|
10098
|
+
var path47 = __toESM(require("path"), 1);
|
|
9882
10099
|
async function resolveActiveItems(projectRoot, localItems, nowFn = () => (/* @__PURE__ */ new Date()).toISOString()) {
|
|
9883
10100
|
const active = /* @__PURE__ */ new Set();
|
|
9884
10101
|
const now = Date.parse(nowFn());
|
|
@@ -9903,7 +10120,7 @@ async function resolveInSprintIds(projectRoot) {
|
|
|
9903
10120
|
const ids = /* @__PURE__ */ new Set();
|
|
9904
10121
|
try {
|
|
9905
10122
|
const sprintDir = resolveActiveSprintDir(projectRoot);
|
|
9906
|
-
const sprintId =
|
|
10123
|
+
const sprintId = path47.basename(sprintDir);
|
|
9907
10124
|
if (sprintId === "_off-sprint") return ids;
|
|
9908
10125
|
const sprintFile = await findSprintFile2(projectRoot, sprintId);
|
|
9909
10126
|
if (!sprintFile) return ids;
|
|
@@ -9918,14 +10135,14 @@ async function resolveInSprintIds(projectRoot) {
|
|
|
9918
10135
|
return ids;
|
|
9919
10136
|
}
|
|
9920
10137
|
async function findSprintFile2(projectRoot, sprintId) {
|
|
9921
|
-
const pendingSync =
|
|
9922
|
-
const archive =
|
|
10138
|
+
const pendingSync = path47.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
10139
|
+
const archive = path47.join(projectRoot, ".cleargate", "delivery", "archive");
|
|
9923
10140
|
for (const dir of [pendingSync, archive]) {
|
|
9924
10141
|
try {
|
|
9925
10142
|
const entries = fs42.readdirSync(dir, { withFileTypes: true });
|
|
9926
10143
|
for (const entry of entries) {
|
|
9927
10144
|
if (entry.isFile() && entry.name.startsWith(sprintId) && entry.name.endsWith(".md")) {
|
|
9928
|
-
return
|
|
10145
|
+
return path47.join(dir, entry.name);
|
|
9929
10146
|
}
|
|
9930
10147
|
}
|
|
9931
10148
|
} catch {
|
|
@@ -9937,12 +10154,12 @@ async function findSprintFile2(projectRoot, sprintId) {
|
|
|
9937
10154
|
// src/lib/comments-cache.ts
|
|
9938
10155
|
init_cjs_shims();
|
|
9939
10156
|
var fsPromises6 = __toESM(require("fs/promises"), 1);
|
|
9940
|
-
var
|
|
10157
|
+
var path48 = __toESM(require("path"), 1);
|
|
9941
10158
|
function cacheDir(projectRoot) {
|
|
9942
|
-
return
|
|
10159
|
+
return path48.join(projectRoot, ".cleargate", ".comments-cache");
|
|
9943
10160
|
}
|
|
9944
10161
|
function cachePath(projectRoot, remoteId) {
|
|
9945
|
-
return
|
|
10162
|
+
return path48.join(cacheDir(projectRoot), `${remoteId}.json`);
|
|
9946
10163
|
}
|
|
9947
10164
|
async function writeCommentCache(projectRoot, remoteId, comments) {
|
|
9948
10165
|
const dir = cacheDir(projectRoot);
|
|
@@ -9957,7 +10174,7 @@ async function writeCommentCache(projectRoot, remoteId, comments) {
|
|
|
9957
10174
|
// src/lib/wiki-comments-render.ts
|
|
9958
10175
|
init_cjs_shims();
|
|
9959
10176
|
var fsPromises7 = __toESM(require("fs/promises"), 1);
|
|
9960
|
-
var
|
|
10177
|
+
var path49 = __toESM(require("path"), 1);
|
|
9961
10178
|
var START = "<!-- cleargate:comments:start -->";
|
|
9962
10179
|
var END = "<!-- cleargate:comments:end -->";
|
|
9963
10180
|
function resolveBucket(fm) {
|
|
@@ -10002,7 +10219,7 @@ async function renderCommentsSection(opts) {
|
|
|
10002
10219
|
const bucket = resolveBucket(localItem.fm);
|
|
10003
10220
|
const primaryId = getPrimaryId(localItem.fm);
|
|
10004
10221
|
if (!bucket || !primaryId) return;
|
|
10005
|
-
const wikiPath =
|
|
10222
|
+
const wikiPath = path49.join(
|
|
10006
10223
|
projectRoot,
|
|
10007
10224
|
".cleargate",
|
|
10008
10225
|
"wiki",
|
|
@@ -10038,7 +10255,7 @@ async function renderCommentsSection(opts) {
|
|
|
10038
10255
|
await writeAtomic4(wikiPath, updated);
|
|
10039
10256
|
}
|
|
10040
10257
|
async function writeAtomic4(filePath, content) {
|
|
10041
|
-
await fsPromises7.mkdir(
|
|
10258
|
+
await fsPromises7.mkdir(path49.dirname(filePath), { recursive: true });
|
|
10042
10259
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
10043
10260
|
await fsPromises7.writeFile(tmpPath, content, "utf8");
|
|
10044
10261
|
await fsPromises7.rename(tmpPath, filePath);
|
|
@@ -10050,11 +10267,11 @@ async function syncCheckHandler(opts = {}) {
|
|
|
10050
10267
|
const env = opts.env ?? process.env;
|
|
10051
10268
|
const stdout = opts.stdout ?? ((s) => process.stdout.write(s));
|
|
10052
10269
|
const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
10053
|
-
const markerPath =
|
|
10270
|
+
const markerPath = path50.join(projectRoot, ".cleargate", ".sync-marker.json");
|
|
10054
10271
|
const updateMarker = async (nowIso2) => {
|
|
10055
10272
|
try {
|
|
10056
10273
|
const content = JSON.stringify({ last_check: nowIso2 });
|
|
10057
|
-
await fsPromises8.mkdir(
|
|
10274
|
+
await fsPromises8.mkdir(path50.dirname(markerPath), { recursive: true });
|
|
10058
10275
|
const tmpPath = `${markerPath}.tmp.${Date.now()}`;
|
|
10059
10276
|
await fsPromises8.writeFile(tmpPath, content, "utf8");
|
|
10060
10277
|
await fsPromises8.rename(tmpPath, markerPath);
|
|
@@ -10137,7 +10354,7 @@ async function syncHandler(opts = {}) {
|
|
|
10137
10354
|
const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
10138
10355
|
const identity = resolveIdentity(projectRoot);
|
|
10139
10356
|
const sprintRoot = resolveActiveSprintDir(projectRoot);
|
|
10140
|
-
const sprintId =
|
|
10357
|
+
const sprintId = path50.basename(sprintRoot);
|
|
10141
10358
|
let mcp2;
|
|
10142
10359
|
if (opts.mcp) {
|
|
10143
10360
|
mcp2 = opts.mcp;
|
|
@@ -10198,7 +10415,7 @@ async function syncHandler(opts = {}) {
|
|
|
10198
10415
|
exit(2);
|
|
10199
10416
|
return;
|
|
10200
10417
|
}
|
|
10201
|
-
const wikiMetaPath =
|
|
10418
|
+
const wikiMetaPath = path50.join(projectRoot, ".cleargate", "wiki", "meta.json");
|
|
10202
10419
|
let lastRemoteSync = "1970-01-01T00:00:00.000Z";
|
|
10203
10420
|
try {
|
|
10204
10421
|
const metaRaw = await fsPromises8.readFile(wikiMetaPath, "utf8");
|
|
@@ -10439,7 +10656,7 @@ async function syncHandler(opts = {}) {
|
|
|
10439
10656
|
};
|
|
10440
10657
|
await appendSyncLog(sprintRoot, entry);
|
|
10441
10658
|
}
|
|
10442
|
-
const conflictsFile =
|
|
10659
|
+
const conflictsFile = path50.join(projectRoot, ".cleargate", ".conflicts.json");
|
|
10443
10660
|
const conflictsContent = {
|
|
10444
10661
|
generated_at: nowFn(),
|
|
10445
10662
|
sprint_id: sprintId,
|
|
@@ -10447,7 +10664,7 @@ async function syncHandler(opts = {}) {
|
|
|
10447
10664
|
};
|
|
10448
10665
|
await writeAtomic5(conflictsFile, JSON.stringify(conflictsContent, null, 2) + "\n");
|
|
10449
10666
|
try {
|
|
10450
|
-
await fsPromises8.mkdir(
|
|
10667
|
+
await fsPromises8.mkdir(path50.dirname(wikiMetaPath), { recursive: true });
|
|
10451
10668
|
let meta = {};
|
|
10452
10669
|
try {
|
|
10453
10670
|
const raw = await fsPromises8.readFile(wikiMetaPath, "utf8");
|
|
@@ -10488,13 +10705,13 @@ async function applyPull(item, localPath, fm, actorEmail, nowFn) {
|
|
|
10488
10705
|
await writeAtomic5(localPath, newContent);
|
|
10489
10706
|
}
|
|
10490
10707
|
async function writeAtomic5(filePath, content) {
|
|
10491
|
-
await fsPromises8.mkdir(
|
|
10708
|
+
await fsPromises8.mkdir(path50.dirname(filePath), { recursive: true });
|
|
10492
10709
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
10493
10710
|
await fsPromises8.writeFile(tmpPath, content, "utf8");
|
|
10494
10711
|
await fsPromises8.rename(tmpPath, filePath);
|
|
10495
10712
|
}
|
|
10496
10713
|
async function scanLocalItems(projectRoot) {
|
|
10497
|
-
const pendingSync =
|
|
10714
|
+
const pendingSync = path50.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
10498
10715
|
const results = [];
|
|
10499
10716
|
let entries;
|
|
10500
10717
|
try {
|
|
@@ -10504,7 +10721,7 @@ async function scanLocalItems(projectRoot) {
|
|
|
10504
10721
|
}
|
|
10505
10722
|
for (const entry of entries) {
|
|
10506
10723
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
10507
|
-
const fullPath =
|
|
10724
|
+
const fullPath = path50.join(pendingSync, entry.name);
|
|
10508
10725
|
try {
|
|
10509
10726
|
const raw = await fsPromises8.readFile(fullPath, "utf8");
|
|
10510
10727
|
const { fm, body } = parseFrontmatter(raw);
|
|
@@ -10532,7 +10749,7 @@ init_config();
|
|
|
10532
10749
|
// src/lib/sync/work-items.ts
|
|
10533
10750
|
init_cjs_shims();
|
|
10534
10751
|
var fsPromises9 = __toESM(require("fs/promises"), 1);
|
|
10535
|
-
var
|
|
10752
|
+
var path51 = __toESM(require("path"), 1);
|
|
10536
10753
|
var import_node_crypto2 = require("crypto");
|
|
10537
10754
|
var BATCH_SIZE = 100;
|
|
10538
10755
|
var ATTRIBUTION_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -10580,8 +10797,8 @@ function getItemId2(fm) {
|
|
|
10580
10797
|
}
|
|
10581
10798
|
async function walkDeliveryDirs(projectRoot) {
|
|
10582
10799
|
const dirs = [
|
|
10583
|
-
|
|
10584
|
-
|
|
10800
|
+
path51.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
|
|
10801
|
+
path51.join(projectRoot, ".cleargate", "delivery", "archive")
|
|
10585
10802
|
];
|
|
10586
10803
|
const results = [];
|
|
10587
10804
|
for (const dir of dirs) {
|
|
@@ -10593,7 +10810,7 @@ async function walkDeliveryDirs(projectRoot) {
|
|
|
10593
10810
|
}
|
|
10594
10811
|
for (const entry of entries) {
|
|
10595
10812
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
10596
|
-
const fullPath =
|
|
10813
|
+
const fullPath = path51.join(dir, entry.name);
|
|
10597
10814
|
try {
|
|
10598
10815
|
const raw = await fsPromises9.readFile(fullPath, "utf8");
|
|
10599
10816
|
const { fm, body } = parseFrontmatter(raw);
|
|
@@ -10618,7 +10835,7 @@ async function walkDeliveryDirs(projectRoot) {
|
|
|
10618
10835
|
return results;
|
|
10619
10836
|
}
|
|
10620
10837
|
async function writeAtomic6(filePath, content) {
|
|
10621
|
-
await fsPromises9.mkdir(
|
|
10838
|
+
await fsPromises9.mkdir(path51.dirname(filePath), { recursive: true });
|
|
10622
10839
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
10623
10840
|
await fsPromises9.writeFile(tmpPath, content, "utf8");
|
|
10624
10841
|
await fsPromises9.rename(tmpPath, filePath);
|
|
@@ -10687,7 +10904,7 @@ async function syncWorkItems(opts) {
|
|
|
10687
10904
|
init_cjs_shims();
|
|
10688
10905
|
var fs43 = __toESM(require("fs"), 1);
|
|
10689
10906
|
var os9 = __toESM(require("os"), 1);
|
|
10690
|
-
var
|
|
10907
|
+
var path52 = __toESM(require("path"), 1);
|
|
10691
10908
|
var DEFAULT_BASE = "https://admin.cleargate.soula.ge/";
|
|
10692
10909
|
function adminUrl(urlPath, opts) {
|
|
10693
10910
|
const env = opts?.env ?? process.env;
|
|
@@ -10710,7 +10927,7 @@ function adminUrl(urlPath, opts) {
|
|
|
10710
10927
|
function readLocalConfig() {
|
|
10711
10928
|
const home = os9.homedir();
|
|
10712
10929
|
if (!home) return null;
|
|
10713
|
-
const configPath =
|
|
10930
|
+
const configPath = path52.join(home, ".cleargate", "config.json");
|
|
10714
10931
|
const raw = fs43.readFileSync(configPath, "utf8");
|
|
10715
10932
|
return JSON.parse(raw);
|
|
10716
10933
|
}
|
|
@@ -10826,7 +11043,7 @@ async function syncWorkItemsHandler(opts = {}) {
|
|
|
10826
11043
|
// src/commands/pull.ts
|
|
10827
11044
|
init_cjs_shims();
|
|
10828
11045
|
var fsPromises10 = __toESM(require("fs/promises"), 1);
|
|
10829
|
-
var
|
|
11046
|
+
var path53 = __toESM(require("path"), 1);
|
|
10830
11047
|
init_acquire();
|
|
10831
11048
|
init_config();
|
|
10832
11049
|
async function pullHandler(idOrRemoteId, opts = {}) {
|
|
@@ -10941,7 +11158,7 @@ async function pullHandler(idOrRemoteId, opts = {}) {
|
|
|
10941
11158
|
result: "ok"
|
|
10942
11159
|
};
|
|
10943
11160
|
await appendSyncLog(sprintRoot, entry);
|
|
10944
|
-
stdout(`pull: ${remoteId} applied to ${
|
|
11161
|
+
stdout(`pull: ${remoteId} applied to ${path53.relative(projectRoot, localPath)}
|
|
10945
11162
|
`);
|
|
10946
11163
|
if (opts.comments) {
|
|
10947
11164
|
const comments = await mcp2.call(
|
|
@@ -10964,7 +11181,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
|
|
|
10964
11181
|
if (/^[A-Z]+-\d+/.test(idOrRemoteId)) {
|
|
10965
11182
|
return idOrRemoteId;
|
|
10966
11183
|
}
|
|
10967
|
-
const pendingSync =
|
|
11184
|
+
const pendingSync = path53.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
10968
11185
|
let entries;
|
|
10969
11186
|
try {
|
|
10970
11187
|
entries = await fsPromises10.readdir(pendingSync, { withFileTypes: true });
|
|
@@ -10974,7 +11191,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
|
|
|
10974
11191
|
for (const entry of entries) {
|
|
10975
11192
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
10976
11193
|
try {
|
|
10977
|
-
const raw = await fsPromises10.readFile(
|
|
11194
|
+
const raw = await fsPromises10.readFile(path53.join(pendingSync, entry.name), "utf8");
|
|
10978
11195
|
const { fm } = parseFrontmatter(raw);
|
|
10979
11196
|
for (const key of ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id"]) {
|
|
10980
11197
|
if (fm[key] === idOrRemoteId && typeof fm["remote_id"] === "string") {
|
|
@@ -10987,7 +11204,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
|
|
|
10987
11204
|
return null;
|
|
10988
11205
|
}
|
|
10989
11206
|
async function findLocalFile(remoteId, projectRoot) {
|
|
10990
|
-
const pendingSync =
|
|
11207
|
+
const pendingSync = path53.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
10991
11208
|
let entries;
|
|
10992
11209
|
try {
|
|
10993
11210
|
entries = await fsPromises10.readdir(pendingSync, { withFileTypes: true });
|
|
@@ -10996,7 +11213,7 @@ async function findLocalFile(remoteId, projectRoot) {
|
|
|
10996
11213
|
}
|
|
10997
11214
|
for (const entry of entries) {
|
|
10998
11215
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
10999
|
-
const fullPath =
|
|
11216
|
+
const fullPath = path53.join(pendingSync, entry.name);
|
|
11000
11217
|
try {
|
|
11001
11218
|
const raw = await fsPromises10.readFile(fullPath, "utf8");
|
|
11002
11219
|
const { fm } = parseFrontmatter(raw);
|
|
@@ -11007,7 +11224,7 @@ async function findLocalFile(remoteId, projectRoot) {
|
|
|
11007
11224
|
return null;
|
|
11008
11225
|
}
|
|
11009
11226
|
async function writeAtomic7(filePath, content) {
|
|
11010
|
-
await fsPromises10.mkdir(
|
|
11227
|
+
await fsPromises10.mkdir(path53.dirname(filePath), { recursive: true });
|
|
11011
11228
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
11012
11229
|
await fsPromises10.writeFile(tmpPath, content, "utf8");
|
|
11013
11230
|
await fsPromises10.rename(tmpPath, filePath);
|
|
@@ -11023,7 +11240,7 @@ function getItemId3(fm) {
|
|
|
11023
11240
|
// src/commands/push.ts
|
|
11024
11241
|
init_cjs_shims();
|
|
11025
11242
|
var fsPromises11 = __toESM(require("fs/promises"), 1);
|
|
11026
|
-
var
|
|
11243
|
+
var path54 = __toESM(require("path"), 1);
|
|
11027
11244
|
init_acquire();
|
|
11028
11245
|
init_config();
|
|
11029
11246
|
async function pushHandler(fileOrId, opts = {}) {
|
|
@@ -11099,7 +11316,7 @@ async function pushHandler(fileOrId, opts = {}) {
|
|
|
11099
11316
|
}
|
|
11100
11317
|
async function handlePush(filePath, ctx) {
|
|
11101
11318
|
const { projectRoot, identity, sprintRoot, nowFn, resolveMcp, stdout, stderr, exit } = ctx;
|
|
11102
|
-
const resolvedPath =
|
|
11319
|
+
const resolvedPath = path54.isAbsolute(filePath) ? filePath : path54.resolve(projectRoot, filePath);
|
|
11103
11320
|
let rawContent;
|
|
11104
11321
|
try {
|
|
11105
11322
|
rawContent = await fsPromises11.readFile(resolvedPath, "utf8");
|
|
@@ -11225,8 +11442,8 @@ async function handleRevert(idOrRemoteId, ctx) {
|
|
|
11225
11442
|
void localPath;
|
|
11226
11443
|
}
|
|
11227
11444
|
async function resolveLocalItem(idOrRemoteId, projectRoot) {
|
|
11228
|
-
const pendingSync =
|
|
11229
|
-
const archive =
|
|
11445
|
+
const pendingSync = path54.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
11446
|
+
const archive = path54.join(projectRoot, ".cleargate", "delivery", "archive");
|
|
11230
11447
|
for (const dir of [pendingSync, archive]) {
|
|
11231
11448
|
let entries;
|
|
11232
11449
|
try {
|
|
@@ -11236,7 +11453,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
|
|
|
11236
11453
|
}
|
|
11237
11454
|
for (const entry of entries) {
|
|
11238
11455
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
11239
|
-
const fullPath =
|
|
11456
|
+
const fullPath = path54.join(dir, entry.name);
|
|
11240
11457
|
try {
|
|
11241
11458
|
const raw = await fsPromises11.readFile(fullPath, "utf8");
|
|
11242
11459
|
const { fm } = parseFrontmatter(raw);
|
|
@@ -11255,7 +11472,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
|
|
|
11255
11472
|
return null;
|
|
11256
11473
|
}
|
|
11257
11474
|
async function writeAtomic8(filePath, content) {
|
|
11258
|
-
await fsPromises11.mkdir(
|
|
11475
|
+
await fsPromises11.mkdir(path54.dirname(filePath), { recursive: true });
|
|
11259
11476
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
11260
11477
|
await fsPromises11.writeFile(tmpPath, content, "utf8");
|
|
11261
11478
|
await fsPromises11.rename(tmpPath, filePath);
|
|
@@ -11284,7 +11501,7 @@ function getItemType2(fm) {
|
|
|
11284
11501
|
// src/commands/conflicts.ts
|
|
11285
11502
|
init_cjs_shims();
|
|
11286
11503
|
var fsPromises12 = __toESM(require("fs/promises"), 1);
|
|
11287
|
-
var
|
|
11504
|
+
var path55 = __toESM(require("path"), 1);
|
|
11288
11505
|
init_acquire();
|
|
11289
11506
|
init_config();
|
|
11290
11507
|
var RESOLUTION_HINTS = {
|
|
@@ -11322,7 +11539,7 @@ async function conflictsHandler(opts = {}) {
|
|
|
11322
11539
|
}
|
|
11323
11540
|
}
|
|
11324
11541
|
}
|
|
11325
|
-
const conflictsFile =
|
|
11542
|
+
const conflictsFile = path55.join(projectRoot, ".cleargate", ".conflicts.json");
|
|
11326
11543
|
let data;
|
|
11327
11544
|
try {
|
|
11328
11545
|
const raw = await fsPromises12.readFile(conflictsFile, "utf8");
|
|
@@ -11411,7 +11628,7 @@ function formatEntry(entry) {
|
|
|
11411
11628
|
// src/commands/admin-login.ts
|
|
11412
11629
|
init_cjs_shims();
|
|
11413
11630
|
var fs44 = __toESM(require("fs"), 1);
|
|
11414
|
-
var
|
|
11631
|
+
var path56 = __toESM(require("path"), 1);
|
|
11415
11632
|
var os10 = __toESM(require("os"), 1);
|
|
11416
11633
|
var DEFAULT_MCP_URL = "http://localhost:3000";
|
|
11417
11634
|
function resolveMcpUrl(mcpUrlFlag, env) {
|
|
@@ -11420,10 +11637,10 @@ function resolveMcpUrl(mcpUrlFlag, env) {
|
|
|
11420
11637
|
function resolveAuthFilePath(opts) {
|
|
11421
11638
|
if (opts.authFilePath) return opts.authFilePath;
|
|
11422
11639
|
const homedirFn = opts.homedir ?? os10.homedir;
|
|
11423
|
-
return
|
|
11640
|
+
return path56.join(homedirFn(), ".cleargate", "admin-auth.json");
|
|
11424
11641
|
}
|
|
11425
11642
|
function writeAdminAuth(filePath, token) {
|
|
11426
|
-
const dir =
|
|
11643
|
+
const dir = path56.dirname(filePath);
|
|
11427
11644
|
fs44.mkdirSync(dir, { recursive: true });
|
|
11428
11645
|
const payload = JSON.stringify({ version: 1, token }, null, 2);
|
|
11429
11646
|
fs44.writeFileSync(filePath, payload, { encoding: "utf8", mode: 384 });
|
|
@@ -11538,7 +11755,7 @@ async function adminLoginHandler(opts = {}) {
|
|
|
11538
11755
|
// src/commands/hotfix.ts
|
|
11539
11756
|
init_cjs_shims();
|
|
11540
11757
|
var fs45 = __toESM(require("fs"), 1);
|
|
11541
|
-
var
|
|
11758
|
+
var path57 = __toESM(require("path"), 1);
|
|
11542
11759
|
function defaultExit4(code) {
|
|
11543
11760
|
return process.exit(code);
|
|
11544
11761
|
}
|
|
@@ -11562,8 +11779,8 @@ function maxHotfixId(pendingDir) {
|
|
|
11562
11779
|
return max;
|
|
11563
11780
|
}
|
|
11564
11781
|
function countActiveHotfixes(repoRoot) {
|
|
11565
|
-
const pendingDir =
|
|
11566
|
-
const archiveDir =
|
|
11782
|
+
const pendingDir = path57.join(repoRoot, ".cleargate", "delivery", "pending-sync");
|
|
11783
|
+
const archiveDir = path57.join(repoRoot, ".cleargate", "delivery", "archive");
|
|
11567
11784
|
const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
11568
11785
|
let count = 0;
|
|
11569
11786
|
let pendingEntries = [];
|
|
@@ -11582,7 +11799,7 @@ function countActiveHotfixes(repoRoot) {
|
|
|
11582
11799
|
for (const entry of archiveEntries) {
|
|
11583
11800
|
if (entry.startsWith("HOTFIX-") && entry.endsWith(".md")) {
|
|
11584
11801
|
try {
|
|
11585
|
-
const stat = fs45.statSync(
|
|
11802
|
+
const stat = fs45.statSync(path57.join(archiveDir, entry));
|
|
11586
11803
|
if (stat.mtimeMs >= sevenDaysAgo) count++;
|
|
11587
11804
|
} catch {
|
|
11588
11805
|
}
|
|
@@ -11591,7 +11808,7 @@ function countActiveHotfixes(repoRoot) {
|
|
|
11591
11808
|
return count;
|
|
11592
11809
|
}
|
|
11593
11810
|
function resolveTemplatePath(repoRoot) {
|
|
11594
|
-
return
|
|
11811
|
+
return path57.join(repoRoot, ".cleargate", "templates", "hotfix.md");
|
|
11595
11812
|
}
|
|
11596
11813
|
function hotfixNewHandler(opts, cli) {
|
|
11597
11814
|
const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
|
|
@@ -11610,7 +11827,7 @@ function hotfixNewHandler(opts, cli) {
|
|
|
11610
11827
|
);
|
|
11611
11828
|
return exitFn(1);
|
|
11612
11829
|
}
|
|
11613
|
-
const pendingDir =
|
|
11830
|
+
const pendingDir = path57.join(repoRoot, ".cleargate", "delivery", "pending-sync");
|
|
11614
11831
|
const maxId = maxHotfixId(pendingDir);
|
|
11615
11832
|
const nextId = maxId + 1;
|
|
11616
11833
|
const idStr = `HOTFIX-${String(nextId).padStart(3, "0")}`;
|
|
@@ -11625,7 +11842,7 @@ function hotfixNewHandler(opts, cli) {
|
|
|
11625
11842
|
const content = templateContent.replace(/\{ID\}/g, idStr).replace(/\{SLUG\}/g, opts.slug).replace(/\{ISO\}/g, now);
|
|
11626
11843
|
const fileSlug = opts.slug.replace(/-/g, "_");
|
|
11627
11844
|
const fileName = `${idStr}_${fileSlug}.md`;
|
|
11628
|
-
const outPath =
|
|
11845
|
+
const outPath = path57.join(pendingDir, fileName);
|
|
11629
11846
|
try {
|
|
11630
11847
|
fs45.mkdirSync(pendingDir, { recursive: true });
|
|
11631
11848
|
fs45.writeFileSync(outPath, content, "utf8");
|