cleargate 0.12.0 → 0.13.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/dist/MANIFEST.json +13 -13
- package/dist/{chunk-HZPJ5QX4.js → chunk-EG6YGT2O.js} +315 -33
- package/dist/chunk-EG6YGT2O.js.map +1 -0
- package/dist/cli.cjs +612 -289
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +73 -37
- package/dist/cli.js.map +1 -1
- package/dist/lib/lifecycle-reconcile.cjs +318 -34
- package/dist/lib/lifecycle-reconcile.cjs.map +1 -1
- package/dist/lib/lifecycle-reconcile.d.cts +55 -4
- package/dist/lib/lifecycle-reconcile.d.ts +55 -4
- package/dist/lib/lifecycle-reconcile.js +7 -3
- package/dist/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +1 -1
- package/dist/templates/cleargate-planning/.claude/agents/developer.md +8 -4
- package/dist/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +2 -0
- package/dist/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +73 -0
- package/dist/templates/cleargate-planning/.cleargate/templates/Bug.md +1 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/CR.md +1 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/epic.md +1 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/hotfix.md +1 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/initiative.md +1 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/sprint_report.md +1 -1
- package/dist/templates/cleargate-planning/.cleargate/templates/story.md +1 -1
- package/dist/templates/cleargate-planning/CLAUDE.md +2 -0
- package/dist/templates/cleargate-planning/MANIFEST.json +13 -13
- package/package.json +8 -9
- package/templates/cleargate-planning/.claude/agents/cleargate-wiki-lint.md +1 -1
- package/templates/cleargate-planning/.claude/agents/developer.md +8 -4
- package/templates/cleargate-planning/.claude/hooks/pre-commit-surface-gate.sh +2 -0
- package/templates/cleargate-planning/.cleargate/scripts/close_sprint.mjs +73 -0
- package/templates/cleargate-planning/.cleargate/templates/Bug.md +1 -1
- package/templates/cleargate-planning/.cleargate/templates/CR.md +1 -1
- package/templates/cleargate-planning/.cleargate/templates/epic.md +1 -1
- package/templates/cleargate-planning/.cleargate/templates/hotfix.md +1 -1
- package/templates/cleargate-planning/.cleargate/templates/initiative.md +1 -1
- package/templates/cleargate-planning/.cleargate/templates/sprint_report.md +1 -1
- package/templates/cleargate-planning/.cleargate/templates/story.md +1 -1
- package/templates/cleargate-planning/CLAUDE.md +2 -0
- package/templates/cleargate-planning/MANIFEST.json +13 -13
- package/dist/chunk-HZPJ5QX4.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
checkVerbMismatch,
|
|
4
4
|
parseFrontmatter,
|
|
5
5
|
reconcileDecomposition,
|
|
6
|
-
reconcileLifecycle
|
|
7
|
-
|
|
6
|
+
reconcileLifecycle,
|
|
7
|
+
walkActiveParents
|
|
8
|
+
} from "./chunk-EG6YGT2O.js";
|
|
8
9
|
import {
|
|
9
10
|
AcquireError,
|
|
10
11
|
acquireAccessToken,
|
|
@@ -22,7 +23,7 @@ import { Command } from "commander";
|
|
|
22
23
|
// package.json
|
|
23
24
|
var package_default = {
|
|
24
25
|
name: "cleargate",
|
|
25
|
-
version: "0.
|
|
26
|
+
version: "0.13.0",
|
|
26
27
|
private: false,
|
|
27
28
|
type: "module",
|
|
28
29
|
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.",
|
|
@@ -69,12 +70,11 @@ var package_default = {
|
|
|
69
70
|
build: "tsup",
|
|
70
71
|
dev: "tsup --watch",
|
|
71
72
|
typecheck: "tsc --noEmit",
|
|
72
|
-
test: "tsx --test --test-reporter=spec 'test/**/*.node.test.ts'",
|
|
73
|
-
"test:file": "tsx --test --test-reporter=spec",
|
|
74
|
-
"test:
|
|
75
|
-
"test:
|
|
76
|
-
"
|
|
77
|
-
"test:node:file": "tsx --test --test-reporter=spec"
|
|
73
|
+
test: "tsx --test --test-concurrency=1 --experimental-test-module-mocks --test-reporter=spec 'test/**/*.node.test.ts' '!test/fixtures/**'",
|
|
74
|
+
"test:file": "tsx --test --test-concurrency=1 --experimental-test-module-mocks --test-reporter=spec",
|
|
75
|
+
"test:node": "tsx --test --test-concurrency=1 --experimental-test-module-mocks --test-reporter=spec 'test/**/*.node.test.ts' '!test/fixtures/**'",
|
|
76
|
+
"test:node:file": "tsx --test --test-concurrency=1 --experimental-test-module-mocks --test-reporter=spec",
|
|
77
|
+
"check:no-vitest": `node -e "const r=require('child_process').execSync('grep -rE \\"\\\\b(vitest|vi\\\\.fn|vi\\\\.mock|vi\\\\.spyOn|vi\\\\.stubGlobal|vi\\\\.useFakeTimers|vi\\\\.useRealTimers|vi\\\\.advanceTimersByTime|vi\\\\.hoisted)\\\\b\\" --include=\\"*.ts\\" --include=\\"*.js\\" --include=\\"*.mjs\\" --exclude-dir=test/fixtures . 2>/dev/null || true', {encoding:'utf8'}); if(r.trim()){console.error('vitest residue detected:\\\\n'+r); process.exit(1)} console.log('no vitest residue')"`
|
|
78
78
|
},
|
|
79
79
|
dependencies: {
|
|
80
80
|
"@napi-rs/keyring": "^1.2.0",
|
|
@@ -89,10 +89,10 @@ var package_default = {
|
|
|
89
89
|
"@types/js-yaml": "^4.0.9",
|
|
90
90
|
"@types/node": "^24.0.0",
|
|
91
91
|
"@types/pg": "^8.11.10",
|
|
92
|
+
"ts-morph": "28.0.0",
|
|
92
93
|
tsup: "^8",
|
|
93
94
|
tsx: "^4.21.0",
|
|
94
|
-
typescript: "^5.8.0"
|
|
95
|
-
vitest: "^2.1.0"
|
|
95
|
+
typescript: "^5.8.0"
|
|
96
96
|
}
|
|
97
97
|
};
|
|
98
98
|
|
|
@@ -6463,22 +6463,50 @@ function reconcileLifecycleCliHandler(opts, cli) {
|
|
|
6463
6463
|
});
|
|
6464
6464
|
if (result.drift.length === 0) {
|
|
6465
6465
|
stdoutFn(`lifecycle: clean (${result.clean} artifacts reconciled)`);
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6466
|
+
} else {
|
|
6467
|
+
stderrFn(`lifecycle: DRIFT detected (${result.drift.length} unreconciled artifacts):`);
|
|
6468
|
+
for (const item of result.drift) {
|
|
6469
|
+
stderrFn(
|
|
6470
|
+
` DRIFT: ${item.id} status=${item.actual_status ?? "missing"} in ${item.in_archive ? "archive" : "pending-sync"}, expected ${item.expected_status} (commit ${item.commit_shas[0] ?? "unknown"})`
|
|
6471
|
+
);
|
|
6472
|
+
stderrFn(
|
|
6473
|
+
` Remediation: git mv .cleargate/delivery/pending-sync/${item.file_path?.replace("pending-sync/", "") ?? item.id + "_*.md"} .cleargate/delivery/archive/ && update status: ${item.expected_status}`
|
|
6474
|
+
);
|
|
6475
|
+
}
|
|
6476
|
+
if (!opts.parents) {
|
|
6477
|
+
return exitFn(1);
|
|
6478
|
+
}
|
|
6476
6479
|
}
|
|
6477
|
-
return exitFn(1);
|
|
6478
6480
|
} catch (err) {
|
|
6479
6481
|
stderrFn(`lifecycle reconciliation error: ${err instanceof Error ? err.message : String(err)}`);
|
|
6480
|
-
|
|
6482
|
+
if (!opts.parents) {
|
|
6483
|
+
return exitFn(1);
|
|
6484
|
+
}
|
|
6485
|
+
}
|
|
6486
|
+
if (opts.parents) {
|
|
6487
|
+
const archiveRoot = path31.join(deliveryRoot, "archive");
|
|
6488
|
+
walkActiveParents({ deliveryRoot, archiveRoot }).then((results) => {
|
|
6489
|
+
stdoutFn("Parent rollup audit (--parents):");
|
|
6490
|
+
for (const r of results) {
|
|
6491
|
+
if (r.verdict === "auto-flip") {
|
|
6492
|
+
stdoutFn(
|
|
6493
|
+
` ${r.parent_id} \u2713 proposed: Completed (${r.terminal_children.length}/${r.terminal_children.length} children Completed)`
|
|
6494
|
+
);
|
|
6495
|
+
} else if (r.verdict === "halt-partial" || r.verdict === "halt-zero-children") {
|
|
6496
|
+
stdoutFn(` ${r.parent_id} \u2717 ${r.verdict}: ${r.halt_reason ?? "no details"}`);
|
|
6497
|
+
} else if (r.verdict === "no-op") {
|
|
6498
|
+
} else {
|
|
6499
|
+
stdoutFn(` ${r.parent_id} ~ ${r.verdict}`);
|
|
6500
|
+
}
|
|
6501
|
+
}
|
|
6502
|
+
exitFn(0);
|
|
6503
|
+
}).catch((err) => {
|
|
6504
|
+
stderrFn(`--parents audit error: ${err instanceof Error ? err.message : String(err)}`);
|
|
6505
|
+
exitFn(0);
|
|
6506
|
+
});
|
|
6507
|
+
return;
|
|
6481
6508
|
}
|
|
6509
|
+
return exitFn(0);
|
|
6482
6510
|
}
|
|
6483
6511
|
function parseFileFrontmatter(raw) {
|
|
6484
6512
|
const lines = raw.split("\n");
|
|
@@ -10346,6 +10374,7 @@ function getItemId3(fm) {
|
|
|
10346
10374
|
}
|
|
10347
10375
|
|
|
10348
10376
|
// src/commands/push.ts
|
|
10377
|
+
import * as fs40 from "fs";
|
|
10349
10378
|
import * as fsPromises11 from "fs/promises";
|
|
10350
10379
|
import * as path49 from "path";
|
|
10351
10380
|
async function pushHandler(fileOrId, opts = {}) {
|
|
@@ -10355,6 +10384,13 @@ async function pushHandler(fileOrId, opts = {}) {
|
|
|
10355
10384
|
const stderr = opts.stderr ?? ((s) => process.stderr.write(s));
|
|
10356
10385
|
const exit = opts.exit ?? ((c) => process.exit(c));
|
|
10357
10386
|
const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
10387
|
+
const migrationLockPath = path49.join(projectRoot, ".cleargate", ".migration-lock");
|
|
10388
|
+
if (fs40.existsSync(migrationLockPath)) {
|
|
10389
|
+
stderr(`Error: CR-067 migration in progress (.migration-lock held); retry in 30s
|
|
10390
|
+
`);
|
|
10391
|
+
exit(75);
|
|
10392
|
+
return;
|
|
10393
|
+
}
|
|
10358
10394
|
const identity = resolveIdentity(projectRoot);
|
|
10359
10395
|
const sprintRoot = resolveActiveSprintDir(projectRoot);
|
|
10360
10396
|
async function resolveMcp() {
|
|
@@ -10750,7 +10786,7 @@ function formatEntry(entry) {
|
|
|
10750
10786
|
}
|
|
10751
10787
|
|
|
10752
10788
|
// src/commands/admin-login.ts
|
|
10753
|
-
import * as
|
|
10789
|
+
import * as fs41 from "fs";
|
|
10754
10790
|
import * as path51 from "path";
|
|
10755
10791
|
import * as os7 from "os";
|
|
10756
10792
|
var DEFAULT_MCP_URL = "http://localhost:3000";
|
|
@@ -10764,10 +10800,10 @@ function resolveAuthFilePath(opts) {
|
|
|
10764
10800
|
}
|
|
10765
10801
|
function writeAdminAuth(filePath, token) {
|
|
10766
10802
|
const dir = path51.dirname(filePath);
|
|
10767
|
-
|
|
10803
|
+
fs41.mkdirSync(dir, { recursive: true });
|
|
10768
10804
|
const payload = JSON.stringify({ version: 1, token }, null, 2);
|
|
10769
|
-
|
|
10770
|
-
|
|
10805
|
+
fs41.writeFileSync(filePath, payload, { encoding: "utf8", mode: 384 });
|
|
10806
|
+
fs41.chmodSync(filePath, 384);
|
|
10771
10807
|
}
|
|
10772
10808
|
async function adminLoginHandler(opts = {}) {
|
|
10773
10809
|
const fetchFn = opts.fetch ?? globalThis.fetch;
|
|
@@ -10876,7 +10912,7 @@ async function adminLoginHandler(opts = {}) {
|
|
|
10876
10912
|
}
|
|
10877
10913
|
|
|
10878
10914
|
// src/commands/hotfix.ts
|
|
10879
|
-
import * as
|
|
10915
|
+
import * as fs42 from "fs";
|
|
10880
10916
|
import * as path52 from "path";
|
|
10881
10917
|
function defaultExit4(code) {
|
|
10882
10918
|
return process.exit(code);
|
|
@@ -10887,7 +10923,7 @@ function maxHotfixId(pendingDir) {
|
|
|
10887
10923
|
let max = 0;
|
|
10888
10924
|
let entries;
|
|
10889
10925
|
try {
|
|
10890
|
-
entries =
|
|
10926
|
+
entries = fs42.readdirSync(pendingDir);
|
|
10891
10927
|
} catch {
|
|
10892
10928
|
return 0;
|
|
10893
10929
|
}
|
|
@@ -10907,7 +10943,7 @@ function countActiveHotfixes(repoRoot) {
|
|
|
10907
10943
|
let count = 0;
|
|
10908
10944
|
let pendingEntries = [];
|
|
10909
10945
|
try {
|
|
10910
|
-
pendingEntries =
|
|
10946
|
+
pendingEntries = fs42.readdirSync(pendingDir);
|
|
10911
10947
|
} catch {
|
|
10912
10948
|
}
|
|
10913
10949
|
for (const entry of pendingEntries) {
|
|
@@ -10915,13 +10951,13 @@ function countActiveHotfixes(repoRoot) {
|
|
|
10915
10951
|
}
|
|
10916
10952
|
let archiveEntries = [];
|
|
10917
10953
|
try {
|
|
10918
|
-
archiveEntries =
|
|
10954
|
+
archiveEntries = fs42.readdirSync(archiveDir);
|
|
10919
10955
|
} catch {
|
|
10920
10956
|
}
|
|
10921
10957
|
for (const entry of archiveEntries) {
|
|
10922
10958
|
if (entry.startsWith("HOTFIX-") && entry.endsWith(".md")) {
|
|
10923
10959
|
try {
|
|
10924
|
-
const stat =
|
|
10960
|
+
const stat = fs42.statSync(path52.join(archiveDir, entry));
|
|
10925
10961
|
if (stat.mtimeMs >= sevenDaysAgo) count++;
|
|
10926
10962
|
} catch {
|
|
10927
10963
|
}
|
|
@@ -10956,7 +10992,7 @@ function hotfixNewHandler(opts, cli) {
|
|
|
10956
10992
|
const templatePath = resolveTemplatePath(repoRoot);
|
|
10957
10993
|
let templateContent;
|
|
10958
10994
|
try {
|
|
10959
|
-
templateContent =
|
|
10995
|
+
templateContent = fs42.readFileSync(templatePath, "utf8");
|
|
10960
10996
|
} catch {
|
|
10961
10997
|
stderrFn(`[cleargate hotfix new] template not found: ${templatePath}`);
|
|
10962
10998
|
return exitFn(2);
|
|
@@ -10966,8 +11002,8 @@ function hotfixNewHandler(opts, cli) {
|
|
|
10966
11002
|
const fileName = `${idStr}_${fileSlug}.md`;
|
|
10967
11003
|
const outPath = path52.join(pendingDir, fileName);
|
|
10968
11004
|
try {
|
|
10969
|
-
|
|
10970
|
-
|
|
11005
|
+
fs42.mkdirSync(pendingDir, { recursive: true });
|
|
11006
|
+
fs42.writeFileSync(outPath, content, "utf8");
|
|
10971
11007
|
} catch (err) {
|
|
10972
11008
|
const msg = err instanceof Error ? err.message : String(err);
|
|
10973
11009
|
stderrFn(`[cleargate hotfix new] write failed: ${msg}`);
|
|
@@ -11394,8 +11430,8 @@ sprint.command("close <sprint-id>").description("close a sprint \u2014 validates
|
|
|
11394
11430
|
}
|
|
11395
11431
|
sprintCloseHandler(handlerOpts);
|
|
11396
11432
|
});
|
|
11397
|
-
sprint.command("reconcile-lifecycle <sprint-id>").description("CR-017: check lifecycle status of artifacts referenced in this sprint's commits (exits 1 on drift)").option("--since <iso-date>", "start of git log range (default: sprint start_date or 90 days ago)").option("--until <iso-date>", "end of git log range (default: now)").action((sprintId, opts) => {
|
|
11398
|
-
reconcileLifecycleCliHandler({ sprintId, since: opts.since, until: opts.until });
|
|
11433
|
+
sprint.command("reconcile-lifecycle <sprint-id>").description("CR-017: check lifecycle status of artifacts referenced in this sprint's commits (exits 1 on drift)").option("--since <iso-date>", "start of git log range (default: sprint start_date or 90 days ago)").option("--until <iso-date>", "end of git log range (default: now)").option("--parents", "audit parent (Epic/Sprint) rollup statuses; read-only (CR-066)").action((sprintId, opts) => {
|
|
11434
|
+
reconcileLifecycleCliHandler({ sprintId, since: opts.since, until: opts.until, parents: opts.parents });
|
|
11399
11435
|
});
|
|
11400
11436
|
sprint.command("archive <sprint-id>").description("archive a completed sprint \u2014 move pending-sync files, clear .active, merge + delete sprint branch").option("--dry-run", "print the archive plan without making any changes").option("--allow-wiki-lint-debt", "CR-022 M5: waive wiki-lint findings during archive (mirrors --allow-drift pattern)").action(async (sprintId, opts) => {
|
|
11401
11437
|
const handlerOpts = { sprintId };
|