cleargate 0.11.1 → 0.11.4
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 +29 -0
- package/dist/MANIFEST.json +5 -5
- package/dist/cli.cjs +118 -5
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +117 -5
- package/dist/cli.js.map +1 -1
- package/dist/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +6 -1
- package/dist/templates/cleargate-planning/.claude/hooks/token-ledger.sh +162 -45
- package/dist/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +7 -1
- package/dist/templates/cleargate-planning/MANIFEST.json +5 -5
- package/package.json +1 -1
- package/templates/cleargate-planning/.claude/hooks/pending-task-sentinel.sh +6 -1
- package/templates/cleargate-planning/.claude/hooks/token-ledger.sh +162 -45
- package/templates/cleargate-planning/.cleargate/scripts/write_dispatch.sh +7 -1
- package/templates/cleargate-planning/MANIFEST.json +5 -5
package/dist/cli.js
CHANGED
|
@@ -21,7 +21,7 @@ import { Command } from "commander";
|
|
|
21
21
|
// package.json
|
|
22
22
|
var package_default = {
|
|
23
23
|
name: "cleargate",
|
|
24
|
-
version: "0.11.
|
|
24
|
+
version: "0.11.4",
|
|
25
25
|
private: false,
|
|
26
26
|
type: "module",
|
|
27
27
|
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.",
|
|
@@ -2430,6 +2430,61 @@ function resolveScaffoldRoot(opts) {
|
|
|
2430
2430
|
};
|
|
2431
2431
|
}
|
|
2432
2432
|
|
|
2433
|
+
// src/lib/session-load-delta.ts
|
|
2434
|
+
function canonicalize(value) {
|
|
2435
|
+
if (value === null || typeof value !== "object") {
|
|
2436
|
+
return JSON.stringify(value);
|
|
2437
|
+
}
|
|
2438
|
+
if (Array.isArray(value)) {
|
|
2439
|
+
return "[" + value.map(canonicalize).join(",") + "]";
|
|
2440
|
+
}
|
|
2441
|
+
const obj = value;
|
|
2442
|
+
const sortedKeys = Object.keys(obj).sort();
|
|
2443
|
+
const pairs = sortedKeys.map((k) => JSON.stringify(k) + ":" + canonicalize(obj[k]));
|
|
2444
|
+
return "{" + pairs.join(",") + "}";
|
|
2445
|
+
}
|
|
2446
|
+
var HOOK_EVENTS = ["PreToolUse", "PostToolUse", "SessionStart", "SubagentStop"];
|
|
2447
|
+
function extractSettingsHooksBlock(settings) {
|
|
2448
|
+
const hooks = settings["hooks"] ?? {};
|
|
2449
|
+
const extracted = {};
|
|
2450
|
+
for (const event of HOOK_EVENTS) {
|
|
2451
|
+
if (Object.prototype.hasOwnProperty.call(hooks, event)) {
|
|
2452
|
+
extracted[event] = hooks[event];
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
return extracted;
|
|
2456
|
+
}
|
|
2457
|
+
function extractMcpCleargateEntry(mcp2) {
|
|
2458
|
+
const servers = mcp2["mcpServers"] ?? {};
|
|
2459
|
+
return servers["cleargate"] ?? null;
|
|
2460
|
+
}
|
|
2461
|
+
function extractSessionLoadDelta(filePath, oldContent, newContent) {
|
|
2462
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
2463
|
+
if (normalized === ".claude/settings.json") {
|
|
2464
|
+
try {
|
|
2465
|
+
const oldSettings = JSON.parse(oldContent);
|
|
2466
|
+
const newSettings = JSON.parse(newContent);
|
|
2467
|
+
const oldHooks = extractSettingsHooksBlock(oldSettings);
|
|
2468
|
+
const newHooks = extractSettingsHooksBlock(newSettings);
|
|
2469
|
+
return canonicalize(oldHooks) !== canonicalize(newHooks);
|
|
2470
|
+
} catch {
|
|
2471
|
+
return true;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
if (normalized === ".mcp.json") {
|
|
2475
|
+
try {
|
|
2476
|
+
const oldMcp = JSON.parse(oldContent);
|
|
2477
|
+
const newMcp = JSON.parse(newContent);
|
|
2478
|
+
const oldEntry = extractMcpCleargateEntry(oldMcp);
|
|
2479
|
+
const newEntry = extractMcpCleargateEntry(newMcp);
|
|
2480
|
+
return canonicalize(oldEntry) !== canonicalize(newEntry);
|
|
2481
|
+
} catch {
|
|
2482
|
+
return true;
|
|
2483
|
+
}
|
|
2484
|
+
}
|
|
2485
|
+
return true;
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2433
2488
|
// src/commands/init.ts
|
|
2434
2489
|
var HOOK_ADDITION = {
|
|
2435
2490
|
hooks: {
|
|
@@ -2605,10 +2660,17 @@ async function initHandler(opts = {}) {
|
|
|
2605
2660
|
}
|
|
2606
2661
|
}
|
|
2607
2662
|
const mergedSettings = mergeSettings(existingSettings, HOOK_ADDITION);
|
|
2663
|
+
const mergedSettingsContent = JSON.stringify(mergedSettings, null, 2) + "\n";
|
|
2664
|
+
const existingSettingsContent = existingSettings !== null ? JSON.stringify(existingSettings, null, 2) + "\n" : "{}";
|
|
2608
2665
|
fs15.mkdirSync(path15.dirname(settingsPath), { recursive: true });
|
|
2609
|
-
writeAtomic(settingsPath,
|
|
2610
|
-
|
|
2666
|
+
writeAtomic(settingsPath, mergedSettingsContent);
|
|
2667
|
+
if (extractSessionLoadDelta(".claude/settings.json", existingSettingsContent, mergedSettingsContent)) {
|
|
2668
|
+
stdout(`[cleargate init] Updated .claude/settings.json: merged PostToolUse hook \u2014 restart Claude Code if already open.
|
|
2611
2669
|
`);
|
|
2670
|
+
} else {
|
|
2671
|
+
stdout(`[cleargate init] .claude/settings.json unchanged (hooks block already current)
|
|
2672
|
+
`);
|
|
2673
|
+
}
|
|
2612
2674
|
const claudeMdPath = path15.join(cwd, "CLAUDE.md");
|
|
2613
2675
|
const claudeMdSrcPath = path15.join(payloadDir, "CLAUDE.md");
|
|
2614
2676
|
let claudeMdBlock;
|
|
@@ -7775,7 +7837,16 @@ function removeClearGateHooks(settings) {
|
|
|
7775
7837
|
// src/lib/merge-ui.ts
|
|
7776
7838
|
import { createPatch } from "diff";
|
|
7777
7839
|
function renderInlineDiff(ours, theirs, filePath) {
|
|
7778
|
-
|
|
7840
|
+
const patch = createPatch(filePath, ours, theirs, "installed", "upstream");
|
|
7841
|
+
const hasHunkLines = patch.split("\n").filter((l) => l.startsWith("+") || l.startsWith("-")).filter((l) => !l.startsWith("+++") && !l.startsWith("---")).length > 0;
|
|
7842
|
+
if (!hasHunkLines) {
|
|
7843
|
+
const ourBytes = Buffer.byteLength(ours, "utf-8");
|
|
7844
|
+
const theirBytes = Buffer.byteLength(theirs, "utf-8");
|
|
7845
|
+
const byteNote = ourBytes !== theirBytes ? `${Math.abs(theirBytes - ourBytes)} bytes changed` : "same byte count";
|
|
7846
|
+
return patch + `(whitespace/EOL-only differences \u2014 ${byteNote})
|
|
7847
|
+
`;
|
|
7848
|
+
}
|
|
7849
|
+
return patch;
|
|
7779
7850
|
}
|
|
7780
7851
|
async function promptMergeChoice(opts) {
|
|
7781
7852
|
const { path: filePath, state: state2, ours, theirs } = opts;
|
|
@@ -7845,6 +7916,9 @@ async function writeAtomic2(filePath, content) {
|
|
|
7845
7916
|
const tmpPath = filePath + ".tmp." + Date.now();
|
|
7846
7917
|
await fsp.writeFile(tmpPath, content, "utf-8");
|
|
7847
7918
|
await fsp.rename(tmpPath, filePath);
|
|
7919
|
+
if (filePath.endsWith(".sh")) {
|
|
7920
|
+
await fsp.chmod(filePath, 493);
|
|
7921
|
+
}
|
|
7848
7922
|
}
|
|
7849
7923
|
async function updateSnapshotEntry(projectRoot, filePath, newSha) {
|
|
7850
7924
|
const snapshotPath = path36.join(projectRoot, ".cleargate", ".install-manifest.json");
|
|
@@ -8067,7 +8141,15 @@ async function upgradeHandler(flags, cli) {
|
|
|
8067
8141
|
let count = 0;
|
|
8068
8142
|
for (const item of workItems) {
|
|
8069
8143
|
const state2 = classify(item.entry.sha256, item.installSha, item.currentSha, item.entry.tier);
|
|
8070
|
-
|
|
8144
|
+
const projectedPostSha = item.entry.sha256;
|
|
8145
|
+
const projectedPostState = classify(
|
|
8146
|
+
item.entry.sha256,
|
|
8147
|
+
item.entry.sha256,
|
|
8148
|
+
projectedPostSha,
|
|
8149
|
+
item.entry.tier
|
|
8150
|
+
);
|
|
8151
|
+
const stateLabel = state2 !== projectedPostState ? `state=${state2} \u2192 ${projectedPostState}` : `state=${state2}`;
|
|
8152
|
+
stdout(`[dry-run] ${item.entry.path} action=${item.action} ${stateLabel}`);
|
|
8071
8153
|
count++;
|
|
8072
8154
|
}
|
|
8073
8155
|
stdout(`[dry-run] ${count} files planned. No changes made.`);
|
|
@@ -8075,8 +8157,19 @@ async function upgradeHandler(flags, cli) {
|
|
|
8075
8157
|
}
|
|
8076
8158
|
const packageRoot = cli?.packageRoot ?? cwd;
|
|
8077
8159
|
const driftMap = {};
|
|
8160
|
+
const SESSION_LOAD_PATHS = /* @__PURE__ */ new Set([".claude/settings.json", ".mcp.json"]);
|
|
8161
|
+
const sessionRestartFiles = [];
|
|
8078
8162
|
for (const item of workItems) {
|
|
8079
8163
|
const { entry, currentSha, installSha, action } = item;
|
|
8164
|
+
let preMutationContent = null;
|
|
8165
|
+
if (SESSION_LOAD_PATHS.has(entry.path)) {
|
|
8166
|
+
const targetPath = path36.join(cwd, entry.path);
|
|
8167
|
+
try {
|
|
8168
|
+
preMutationContent = await fsp.readFile(targetPath, "utf-8");
|
|
8169
|
+
} catch {
|
|
8170
|
+
preMutationContent = "";
|
|
8171
|
+
}
|
|
8172
|
+
}
|
|
8080
8173
|
switch (action) {
|
|
8081
8174
|
case "skip": {
|
|
8082
8175
|
stdout(`[skip] ${entry.path} policy=${entry.overwrite_policy}`);
|
|
@@ -8107,9 +8200,28 @@ async function upgradeHandler(flags, cli) {
|
|
|
8107
8200
|
current_sha: postSha,
|
|
8108
8201
|
package_sha: entry.sha256
|
|
8109
8202
|
};
|
|
8203
|
+
if (SESSION_LOAD_PATHS.has(entry.path) && preMutationContent !== null) {
|
|
8204
|
+
const targetPath = path36.join(cwd, entry.path);
|
|
8205
|
+
let postMutationContent;
|
|
8206
|
+
try {
|
|
8207
|
+
postMutationContent = await fsp.readFile(targetPath, "utf-8");
|
|
8208
|
+
} catch {
|
|
8209
|
+
postMutationContent = "";
|
|
8210
|
+
}
|
|
8211
|
+
if (extractSessionLoadDelta(entry.path, preMutationContent, postMutationContent)) {
|
|
8212
|
+
sessionRestartFiles.push(entry.path);
|
|
8213
|
+
}
|
|
8214
|
+
}
|
|
8110
8215
|
}
|
|
8111
8216
|
await writeDriftState(cwd, driftMap, { lastRefreshed: now.toISOString() });
|
|
8112
8217
|
stdout("[upgrade] complete.");
|
|
8218
|
+
if (sessionRestartFiles.length > 0) {
|
|
8219
|
+
stdout("");
|
|
8220
|
+
stdout(`\u26A0 Restart Claude Code in this repo to load the new ${sessionRestartFiles.length === 1 ? "config" : "configs"}:`);
|
|
8221
|
+
for (const f of sessionRestartFiles) {
|
|
8222
|
+
stdout(` ${f} (loaded once at session start)`);
|
|
8223
|
+
}
|
|
8224
|
+
}
|
|
8113
8225
|
}
|
|
8114
8226
|
|
|
8115
8227
|
// src/commands/uninstall.ts
|