cleargate 0.11.3 → 0.11.5

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/cli.cjs CHANGED
@@ -114,6 +114,40 @@ function requireMcpUrl(cfg) {
114
114
  }
115
115
  return cfg.mcpUrl;
116
116
  }
117
+ function saveConfig(updates, opts = {}) {
118
+ const home = os.homedir();
119
+ if (!home) {
120
+ throw new Error("Cannot determine home directory.");
121
+ }
122
+ const configPath = opts.configPath ?? path2.join(home, ".cleargate", "config.json");
123
+ const dir = path2.dirname(configPath);
124
+ let existing = {};
125
+ try {
126
+ const raw = fs2.readFileSync(configPath, "utf8");
127
+ const parsed = JSON.parse(raw);
128
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
129
+ existing = parsed;
130
+ }
131
+ } catch (err) {
132
+ if (!(err instanceof Error && "code" in err && err.code === "ENOENT")) {
133
+ }
134
+ }
135
+ const merged = { ...existing };
136
+ for (const [k, v] of Object.entries(updates)) {
137
+ if (v !== void 0) merged[k] = v;
138
+ }
139
+ fs2.mkdirSync(dir, { recursive: true, mode: 448 });
140
+ try {
141
+ fs2.chmodSync(dir, 448);
142
+ } catch {
143
+ }
144
+ const tmpPath = path2.join(dir, ".config.json.tmp");
145
+ const json = JSON.stringify(merged, null, 2) + "\n";
146
+ fs2.writeFileSync(tmpPath, json, { mode: 384 });
147
+ fs2.chmodSync(tmpPath, 384);
148
+ fs2.renameSync(tmpPath, configPath);
149
+ fs2.chmodSync(configPath, 384);
150
+ }
117
151
  var fs2, os, path2, import_zod, ConfigSchema;
118
152
  var init_config = __esm({
119
153
  "src/config.ts"() {
@@ -383,6 +417,41 @@ var init_membership = __esm({
383
417
  });
384
418
 
385
419
  // src/auth/acquire.ts
420
+ function defaultDiskCachePath(env = process.env) {
421
+ const override = env["CLEARGATE_DISK_CACHE_PATH"];
422
+ if (override === "off") return null;
423
+ if (typeof override === "string" && override.length > 0) return override;
424
+ const home = os9.homedir();
425
+ if (!home) return null;
426
+ return path45.join(home, ".cleargate", "access-token.json");
427
+ }
428
+ function readDiskCache(filePath) {
429
+ try {
430
+ const raw = fs42.readFileSync(filePath, "utf8");
431
+ const parsed = JSON.parse(raw);
432
+ if (parsed !== null && typeof parsed === "object" && parsed.version === 1 && typeof parsed.entries === "object" && parsed.entries !== null) {
433
+ return parsed;
434
+ }
435
+ } catch {
436
+ }
437
+ return { version: 1, entries: {} };
438
+ }
439
+ function writeDiskCache(filePath, data) {
440
+ const dir = path45.dirname(filePath);
441
+ try {
442
+ fs42.mkdirSync(dir, { recursive: true, mode: 448 });
443
+ try {
444
+ fs42.chmodSync(dir, 448);
445
+ } catch {
446
+ }
447
+ const tmpPath = path45.join(dir, ".access-token.json.tmp");
448
+ fs42.writeFileSync(tmpPath, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
449
+ fs42.chmodSync(tmpPath, 384);
450
+ fs42.renameSync(tmpPath, filePath);
451
+ fs42.chmodSync(filePath, 384);
452
+ } catch {
453
+ }
454
+ }
386
455
  function decodeJwtPayload2(token) {
387
456
  try {
388
457
  const parts = token.split(".");
@@ -408,6 +477,15 @@ async function acquireAccessToken(opts) {
408
477
  return cached.accessToken;
409
478
  }
410
479
  }
480
+ const diskCachePath = opts.diskCachePath === void 0 ? defaultDiskCachePath() : opts.diskCachePath;
481
+ if (!opts.forceRefresh && diskCachePath) {
482
+ const file = readDiskCache(diskCachePath);
483
+ const entry = file.entries[cacheKey];
484
+ if (entry && nowFn() < entry.expiresAtMs) {
485
+ CACHE.set(cacheKey, entry);
486
+ return entry.accessToken;
487
+ }
488
+ }
411
489
  const store = await (opts.createStore ?? createTokenStore)();
412
490
  const stored = await store.load(opts.profile);
413
491
  if (!stored) {
@@ -456,15 +534,24 @@ async function acquireAccessToken(opts) {
456
534
  const exp = payload?.exp;
457
535
  if (typeof exp === "number" && Number.isFinite(exp)) {
458
536
  const expiresAtMs = (exp - 60) * 1e3;
459
- CACHE.set(cacheKey, { accessToken, expiresAtMs });
537
+ const entry = { accessToken, expiresAtMs };
538
+ CACHE.set(cacheKey, entry);
539
+ if (diskCachePath) {
540
+ const file = readDiskCache(diskCachePath);
541
+ file.entries[cacheKey] = entry;
542
+ writeDiskCache(diskCachePath, file);
543
+ }
460
544
  }
461
545
  return accessToken;
462
546
  }
463
- var CACHE, AcquireError;
547
+ var fs42, os9, path45, CACHE, AcquireError;
464
548
  var init_acquire = __esm({
465
549
  "src/auth/acquire.ts"() {
466
550
  "use strict";
467
551
  init_cjs_shims();
552
+ fs42 = __toESM(require("fs"), 1);
553
+ os9 = __toESM(require("os"), 1);
554
+ path45 = __toESM(require("path"), 1);
468
555
  init_factory();
469
556
  CACHE = /* @__PURE__ */ new Map();
470
557
  AcquireError = class extends Error {
@@ -696,7 +783,7 @@ var import_commander = require("commander");
696
783
  // package.json
697
784
  var package_default = {
698
785
  name: "cleargate",
699
- version: "0.11.3",
786
+ version: "0.11.5",
700
787
  private: false,
701
788
  type: "module",
702
789
  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.",
@@ -1314,7 +1401,8 @@ async function joinHandler(opts) {
1314
1401
  if (UUID_V4_RE.test(opts.inviteUrl)) {
1315
1402
  token = opts.inviteUrl;
1316
1403
  const cfg = loadConfig({
1317
- flags: { profile: opts.profile, mcpUrl: opts.mcpUrlFlag }
1404
+ flags: { profile: opts.profile, mcpUrl: opts.mcpUrlFlag },
1405
+ ...opts.configPath !== void 0 ? { configPath: opts.configPath } : {}
1318
1406
  });
1319
1407
  if (!cfg.mcpUrl) {
1320
1408
  stderr(
@@ -1651,9 +1739,15 @@ async function joinHandler(opts) {
1651
1739
  try {
1652
1740
  const store = await (opts.createStore ?? createTokenStore)();
1653
1741
  await store.save(opts.profile, refreshToken);
1742
+ saveConfig(
1743
+ { mcpUrl: baseUrl },
1744
+ opts.configPath !== void 0 ? { configPath: opts.configPath } : {}
1745
+ );
1654
1746
  stdout(`joined project '${projectName}' as '${hostname3()}'
1655
1747
  `);
1656
1748
  stdout(`refresh token saved to ${store.backend}.
1749
+ `);
1750
+ stdout(`mcp_url ${baseUrl} saved to ~/.cleargate/config.json.
1657
1751
  `);
1658
1752
  } catch (err) {
1659
1753
  stderr(
@@ -3176,6 +3270,62 @@ function resolveScaffoldRoot(opts) {
3176
3270
  };
3177
3271
  }
3178
3272
 
3273
+ // src/lib/session-load-delta.ts
3274
+ init_cjs_shims();
3275
+ function canonicalize(value) {
3276
+ if (value === null || typeof value !== "object") {
3277
+ return JSON.stringify(value);
3278
+ }
3279
+ if (Array.isArray(value)) {
3280
+ return "[" + value.map(canonicalize).join(",") + "]";
3281
+ }
3282
+ const obj = value;
3283
+ const sortedKeys = Object.keys(obj).sort();
3284
+ const pairs = sortedKeys.map((k) => JSON.stringify(k) + ":" + canonicalize(obj[k]));
3285
+ return "{" + pairs.join(",") + "}";
3286
+ }
3287
+ var HOOK_EVENTS = ["PreToolUse", "PostToolUse", "SessionStart", "SubagentStop"];
3288
+ function extractSettingsHooksBlock(settings) {
3289
+ const hooks = settings["hooks"] ?? {};
3290
+ const extracted = {};
3291
+ for (const event of HOOK_EVENTS) {
3292
+ if (Object.prototype.hasOwnProperty.call(hooks, event)) {
3293
+ extracted[event] = hooks[event];
3294
+ }
3295
+ }
3296
+ return extracted;
3297
+ }
3298
+ function extractMcpCleargateEntry(mcp2) {
3299
+ const servers = mcp2["mcpServers"] ?? {};
3300
+ return servers["cleargate"] ?? null;
3301
+ }
3302
+ function extractSessionLoadDelta(filePath, oldContent, newContent) {
3303
+ const normalized = filePath.replace(/\\/g, "/");
3304
+ if (normalized === ".claude/settings.json") {
3305
+ try {
3306
+ const oldSettings = JSON.parse(oldContent);
3307
+ const newSettings = JSON.parse(newContent);
3308
+ const oldHooks = extractSettingsHooksBlock(oldSettings);
3309
+ const newHooks = extractSettingsHooksBlock(newSettings);
3310
+ return canonicalize(oldHooks) !== canonicalize(newHooks);
3311
+ } catch {
3312
+ return true;
3313
+ }
3314
+ }
3315
+ if (normalized === ".mcp.json") {
3316
+ try {
3317
+ const oldMcp = JSON.parse(oldContent);
3318
+ const newMcp = JSON.parse(newContent);
3319
+ const oldEntry = extractMcpCleargateEntry(oldMcp);
3320
+ const newEntry = extractMcpCleargateEntry(newMcp);
3321
+ return canonicalize(oldEntry) !== canonicalize(newEntry);
3322
+ } catch {
3323
+ return true;
3324
+ }
3325
+ }
3326
+ return true;
3327
+ }
3328
+
3179
3329
  // src/commands/init.ts
3180
3330
  var HOOK_ADDITION = {
3181
3331
  hooks: {
@@ -3351,10 +3501,17 @@ async function initHandler(opts = {}) {
3351
3501
  }
3352
3502
  }
3353
3503
  const mergedSettings = mergeSettings(existingSettings, HOOK_ADDITION);
3504
+ const mergedSettingsContent = JSON.stringify(mergedSettings, null, 2) + "\n";
3505
+ const existingSettingsContent = existingSettings !== null ? JSON.stringify(existingSettings, null, 2) + "\n" : "{}";
3354
3506
  fs17.mkdirSync(path18.dirname(settingsPath), { recursive: true });
3355
- writeAtomic(settingsPath, JSON.stringify(mergedSettings, null, 2) + "\n");
3356
- stdout(`[cleargate init] Updated .claude/settings.json: merged PostToolUse hook \u2014 restart Claude Code if already open.
3507
+ writeAtomic(settingsPath, mergedSettingsContent);
3508
+ if (extractSessionLoadDelta(".claude/settings.json", existingSettingsContent, mergedSettingsContent)) {
3509
+ stdout(`[cleargate init] Updated .claude/settings.json: merged PostToolUse hook \u2014 restart Claude Code if already open.
3510
+ `);
3511
+ } else {
3512
+ stdout(`[cleargate init] .claude/settings.json unchanged (hooks block already current)
3357
3513
  `);
3514
+ }
3358
3515
  const claudeMdPath = path18.join(cwd, "CLAUDE.md");
3359
3516
  const claudeMdSrcPath = path18.join(payloadDir, "CLAUDE.md");
3360
3517
  let claudeMdBlock;
@@ -8863,7 +9020,16 @@ function removeClearGateHooks(settings) {
8863
9020
  init_cjs_shims();
8864
9021
  var import_diff = require("diff");
8865
9022
  function renderInlineDiff(ours, theirs, filePath) {
8866
- return (0, import_diff.createPatch)(filePath, ours, theirs, "installed", "upstream");
9023
+ const patch = (0, import_diff.createPatch)(filePath, ours, theirs, "installed", "upstream");
9024
+ const hasHunkLines = patch.split("\n").filter((l) => l.startsWith("+") || l.startsWith("-")).filter((l) => !l.startsWith("+++") && !l.startsWith("---")).length > 0;
9025
+ if (!hasHunkLines) {
9026
+ const ourBytes = Buffer.byteLength(ours, "utf-8");
9027
+ const theirBytes = Buffer.byteLength(theirs, "utf-8");
9028
+ const byteNote = ourBytes !== theirBytes ? `${Math.abs(theirBytes - ourBytes)} bytes changed` : "same byte count";
9029
+ return patch + `(whitespace/EOL-only differences \u2014 ${byteNote})
9030
+ `;
9031
+ }
9032
+ return patch;
8867
9033
  }
8868
9034
  async function promptMergeChoice(opts) {
8869
9035
  const { path: filePath, state: state2, ours, theirs } = opts;
@@ -9159,7 +9325,15 @@ async function upgradeHandler(flags, cli) {
9159
9325
  let count = 0;
9160
9326
  for (const item of workItems) {
9161
9327
  const state2 = classify(item.entry.sha256, item.installSha, item.currentSha, item.entry.tier);
9162
- stdout(`[dry-run] ${item.entry.path} action=${item.action} state=${state2}`);
9328
+ const projectedPostSha = item.entry.sha256;
9329
+ const projectedPostState = classify(
9330
+ item.entry.sha256,
9331
+ item.entry.sha256,
9332
+ projectedPostSha,
9333
+ item.entry.tier
9334
+ );
9335
+ const stateLabel = state2 !== projectedPostState ? `state=${state2} \u2192 ${projectedPostState}` : `state=${state2}`;
9336
+ stdout(`[dry-run] ${item.entry.path} action=${item.action} ${stateLabel}`);
9163
9337
  count++;
9164
9338
  }
9165
9339
  stdout(`[dry-run] ${count} files planned. No changes made.`);
@@ -9171,6 +9345,15 @@ async function upgradeHandler(flags, cli) {
9171
9345
  const sessionRestartFiles = [];
9172
9346
  for (const item of workItems) {
9173
9347
  const { entry, currentSha, installSha, action } = item;
9348
+ let preMutationContent = null;
9349
+ if (SESSION_LOAD_PATHS.has(entry.path)) {
9350
+ const targetPath = path41.join(cwd, entry.path);
9351
+ try {
9352
+ preMutationContent = await fsp.readFile(targetPath, "utf-8");
9353
+ } catch {
9354
+ preMutationContent = "";
9355
+ }
9356
+ }
9174
9357
  switch (action) {
9175
9358
  case "skip": {
9176
9359
  stdout(`[skip] ${entry.path} policy=${entry.overwrite_policy}`);
@@ -9201,8 +9384,17 @@ async function upgradeHandler(flags, cli) {
9201
9384
  current_sha: postSha,
9202
9385
  package_sha: entry.sha256
9203
9386
  };
9204
- if (SESSION_LOAD_PATHS.has(entry.path) && postSha !== currentSha) {
9205
- sessionRestartFiles.push(entry.path);
9387
+ if (SESSION_LOAD_PATHS.has(entry.path) && preMutationContent !== null) {
9388
+ const targetPath = path41.join(cwd, entry.path);
9389
+ let postMutationContent;
9390
+ try {
9391
+ postMutationContent = await fsp.readFile(targetPath, "utf-8");
9392
+ } catch {
9393
+ postMutationContent = "";
9394
+ }
9395
+ if (extractSessionLoadDelta(entry.path, preMutationContent, postMutationContent)) {
9396
+ sessionRestartFiles.push(entry.path);
9397
+ }
9206
9398
  }
9207
9399
  }
9208
9400
  await writeDriftState(cwd, driftMap, { lastRefreshed: now.toISOString() });
@@ -9520,7 +9712,7 @@ async function uninstallHandler(opts) {
9520
9712
  // src/commands/sync.ts
9521
9713
  init_cjs_shims();
9522
9714
  var fsPromises8 = __toESM(require("fs/promises"), 1);
9523
- var path50 = __toESM(require("path"), 1);
9715
+ var path51 = __toESM(require("path"), 1);
9524
9716
 
9525
9717
  // src/lib/sync-log.ts
9526
9718
  init_cjs_shims();
@@ -9840,12 +10032,12 @@ init_config();
9840
10032
  // src/lib/intake.ts
9841
10033
  init_cjs_shims();
9842
10034
  var fsPromises4 = __toESM(require("fs/promises"), 1);
9843
- var path46 = __toESM(require("path"), 1);
10035
+ var path47 = __toESM(require("path"), 1);
9844
10036
 
9845
10037
  // src/lib/slug.ts
9846
10038
  init_cjs_shims();
9847
10039
  var fsPromises3 = __toESM(require("fs/promises"), 1);
9848
- var path45 = __toESM(require("path"), 1);
10040
+ var path46 = __toESM(require("path"), 1);
9849
10041
  function slugify(title, max = 40) {
9850
10042
  const normalized = title.normalize("NFKD").replace(new RegExp("\\p{M}", "gu"), "");
9851
10043
  const lowered = normalized.toLowerCase();
@@ -9860,8 +10052,8 @@ function slugify(title, max = 40) {
9860
10052
  var PROPOSAL_ID_RE = /^proposal_id:\s*"?PROP-(\d+)"?/m;
9861
10053
  async function nextProposalId(projectRoot) {
9862
10054
  const dirs = [
9863
- path45.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
9864
- path45.join(projectRoot, ".cleargate", "delivery", "archive")
10055
+ path46.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
10056
+ path46.join(projectRoot, ".cleargate", "delivery", "archive")
9865
10057
  ];
9866
10058
  let maxN = 0;
9867
10059
  for (const dir of dirs) {
@@ -9873,7 +10065,7 @@ async function nextProposalId(projectRoot) {
9873
10065
  }
9874
10066
  for (const entry of entries) {
9875
10067
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
9876
- const fullPath = path45.join(dir, entry.name);
10068
+ const fullPath = path46.join(dir, entry.name);
9877
10069
  try {
9878
10070
  const raw = await fsPromises3.readFile(fullPath, "utf8");
9879
10071
  const fmEnd = extractFrontmatterBlock(raw);
@@ -9891,8 +10083,8 @@ async function nextProposalId(projectRoot) {
9891
10083
  }
9892
10084
  async function findByRemoteId(projectRoot, remoteId) {
9893
10085
  const dirs = [
9894
- path45.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
9895
- path45.join(projectRoot, ".cleargate", "delivery", "archive")
10086
+ path46.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
10087
+ path46.join(projectRoot, ".cleargate", "delivery", "archive")
9896
10088
  ];
9897
10089
  const escaped = remoteId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
9898
10090
  const re = new RegExp(`^remote_id:\\s*"?${escaped}"?\\s*$`, "m");
@@ -9905,7 +10097,7 @@ async function findByRemoteId(projectRoot, remoteId) {
9905
10097
  }
9906
10098
  for (const entry of entries) {
9907
10099
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
9908
- const fullPath = path45.join(dir, entry.name);
10100
+ const fullPath = path46.join(dir, entry.name);
9909
10101
  try {
9910
10102
  const raw = await fsPromises3.readFile(fullPath, "utf8");
9911
10103
  const fm = extractFrontmatterBlock(raw);
@@ -9942,7 +10134,7 @@ async function runIntakeBranch(opts) {
9942
10134
  labelFilter = "cleargate:proposal",
9943
10135
  now = () => (/* @__PURE__ */ new Date()).toISOString()
9944
10136
  } = opts;
9945
- const pendingSyncDir = path46.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10137
+ const pendingSyncDir = path47.join(projectRoot, ".cleargate", "delivery", "pending-sync");
9946
10138
  let remoteItems = [];
9947
10139
  try {
9948
10140
  remoteItems = await mcp2.call(
@@ -9973,7 +10165,7 @@ async function runIntakeBranch(opts) {
9973
10165
  const slug2 = slugify(item.title ?? "untitled");
9974
10166
  const num2 = proposalId2.replace("PROP-", "");
9975
10167
  const filename2 = `PROPOSAL-${num2}-remote-${slug2}.md`;
9976
- const targetPath2 = path46.join(pendingSyncDir, filename2);
10168
+ const targetPath2 = path47.join(pendingSyncDir, filename2);
9977
10169
  createdItems.push({
9978
10170
  proposalId: proposalId2,
9979
10171
  remoteId: item.remote_id,
@@ -9986,7 +10178,7 @@ async function runIntakeBranch(opts) {
9986
10178
  const num = proposalId.replace("PROP-", "");
9987
10179
  const slug = slugify(item.title ?? "untitled");
9988
10180
  const filename = `PROPOSAL-${num}-remote-${slug}.md`;
9989
- const targetPath = path46.join(pendingSyncDir, filename);
10181
+ const targetPath = path47.join(pendingSyncDir, filename);
9990
10182
  const nowTs = now();
9991
10183
  const fm = {
9992
10184
  proposal_id: proposalId,
@@ -10078,8 +10270,8 @@ path/to/new/file.ext - {Explanation of purpose}
10078
10270
  }
10079
10271
  async function hasAnyRemoteAuthored(projectRoot) {
10080
10272
  const dirs = [
10081
- path46.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
10082
- path46.join(projectRoot, ".cleargate", "delivery", "archive")
10273
+ path47.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
10274
+ path47.join(projectRoot, ".cleargate", "delivery", "archive")
10083
10275
  ];
10084
10276
  for (const dir of dirs) {
10085
10277
  let entries;
@@ -10090,7 +10282,7 @@ async function hasAnyRemoteAuthored(projectRoot) {
10090
10282
  }
10091
10283
  for (const entry of entries) {
10092
10284
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
10093
- const fullPath = path46.join(dir, entry.name);
10285
+ const fullPath = path47.join(dir, entry.name);
10094
10286
  try {
10095
10287
  const raw = await fsPromises4.readFile(fullPath, "utf8");
10096
10288
  const fmEnd = raw.indexOf("\n---", 4);
@@ -10108,9 +10300,9 @@ async function hasAnyRemoteAuthored(projectRoot) {
10108
10300
 
10109
10301
  // src/lib/active-criteria.ts
10110
10302
  init_cjs_shims();
10111
- var fs42 = __toESM(require("fs"), 1);
10303
+ var fs43 = __toESM(require("fs"), 1);
10112
10304
  var fsPromises5 = __toESM(require("fs/promises"), 1);
10113
- var path47 = __toESM(require("path"), 1);
10305
+ var path48 = __toESM(require("path"), 1);
10114
10306
  async function resolveActiveItems(projectRoot, localItems, nowFn = () => (/* @__PURE__ */ new Date()).toISOString()) {
10115
10307
  const active = /* @__PURE__ */ new Set();
10116
10308
  const now = Date.parse(nowFn());
@@ -10135,7 +10327,7 @@ async function resolveInSprintIds(projectRoot) {
10135
10327
  const ids = /* @__PURE__ */ new Set();
10136
10328
  try {
10137
10329
  const sprintDir = resolveActiveSprintDir(projectRoot);
10138
- const sprintId = path47.basename(sprintDir);
10330
+ const sprintId = path48.basename(sprintDir);
10139
10331
  if (sprintId === "_off-sprint") return ids;
10140
10332
  const sprintFile = await findSprintFile2(projectRoot, sprintId);
10141
10333
  if (!sprintFile) return ids;
@@ -10150,14 +10342,14 @@ async function resolveInSprintIds(projectRoot) {
10150
10342
  return ids;
10151
10343
  }
10152
10344
  async function findSprintFile2(projectRoot, sprintId) {
10153
- const pendingSync = path47.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10154
- const archive = path47.join(projectRoot, ".cleargate", "delivery", "archive");
10345
+ const pendingSync = path48.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10346
+ const archive = path48.join(projectRoot, ".cleargate", "delivery", "archive");
10155
10347
  for (const dir of [pendingSync, archive]) {
10156
10348
  try {
10157
- const entries = fs42.readdirSync(dir, { withFileTypes: true });
10349
+ const entries = fs43.readdirSync(dir, { withFileTypes: true });
10158
10350
  for (const entry of entries) {
10159
10351
  if (entry.isFile() && entry.name.startsWith(sprintId) && entry.name.endsWith(".md")) {
10160
- return path47.join(dir, entry.name);
10352
+ return path48.join(dir, entry.name);
10161
10353
  }
10162
10354
  }
10163
10355
  } catch {
@@ -10169,12 +10361,12 @@ async function findSprintFile2(projectRoot, sprintId) {
10169
10361
  // src/lib/comments-cache.ts
10170
10362
  init_cjs_shims();
10171
10363
  var fsPromises6 = __toESM(require("fs/promises"), 1);
10172
- var path48 = __toESM(require("path"), 1);
10364
+ var path49 = __toESM(require("path"), 1);
10173
10365
  function cacheDir(projectRoot) {
10174
- return path48.join(projectRoot, ".cleargate", ".comments-cache");
10366
+ return path49.join(projectRoot, ".cleargate", ".comments-cache");
10175
10367
  }
10176
10368
  function cachePath(projectRoot, remoteId) {
10177
- return path48.join(cacheDir(projectRoot), `${remoteId}.json`);
10369
+ return path49.join(cacheDir(projectRoot), `${remoteId}.json`);
10178
10370
  }
10179
10371
  async function writeCommentCache(projectRoot, remoteId, comments) {
10180
10372
  const dir = cacheDir(projectRoot);
@@ -10189,7 +10381,7 @@ async function writeCommentCache(projectRoot, remoteId, comments) {
10189
10381
  // src/lib/wiki-comments-render.ts
10190
10382
  init_cjs_shims();
10191
10383
  var fsPromises7 = __toESM(require("fs/promises"), 1);
10192
- var path49 = __toESM(require("path"), 1);
10384
+ var path50 = __toESM(require("path"), 1);
10193
10385
  var START = "<!-- cleargate:comments:start -->";
10194
10386
  var END = "<!-- cleargate:comments:end -->";
10195
10387
  function resolveBucket(fm) {
@@ -10234,7 +10426,7 @@ async function renderCommentsSection(opts) {
10234
10426
  const bucket = resolveBucket(localItem.fm);
10235
10427
  const primaryId = getPrimaryId(localItem.fm);
10236
10428
  if (!bucket || !primaryId) return;
10237
- const wikiPath = path49.join(
10429
+ const wikiPath = path50.join(
10238
10430
  projectRoot,
10239
10431
  ".cleargate",
10240
10432
  "wiki",
@@ -10270,7 +10462,7 @@ async function renderCommentsSection(opts) {
10270
10462
  await writeAtomic4(wikiPath, updated);
10271
10463
  }
10272
10464
  async function writeAtomic4(filePath, content) {
10273
- await fsPromises7.mkdir(path49.dirname(filePath), { recursive: true });
10465
+ await fsPromises7.mkdir(path50.dirname(filePath), { recursive: true });
10274
10466
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
10275
10467
  await fsPromises7.writeFile(tmpPath, content, "utf8");
10276
10468
  await fsPromises7.rename(tmpPath, filePath);
@@ -10282,11 +10474,11 @@ async function syncCheckHandler(opts = {}) {
10282
10474
  const env = opts.env ?? process.env;
10283
10475
  const stdout = opts.stdout ?? ((s) => process.stdout.write(s));
10284
10476
  const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
10285
- const markerPath = path50.join(projectRoot, ".cleargate", ".sync-marker.json");
10477
+ const markerPath = path51.join(projectRoot, ".cleargate", ".sync-marker.json");
10286
10478
  const updateMarker = async (nowIso2) => {
10287
10479
  try {
10288
10480
  const content = JSON.stringify({ last_check: nowIso2 });
10289
- await fsPromises8.mkdir(path50.dirname(markerPath), { recursive: true });
10481
+ await fsPromises8.mkdir(path51.dirname(markerPath), { recursive: true });
10290
10482
  const tmpPath = `${markerPath}.tmp.${Date.now()}`;
10291
10483
  await fsPromises8.writeFile(tmpPath, content, "utf8");
10292
10484
  await fsPromises8.rename(tmpPath, markerPath);
@@ -10369,7 +10561,7 @@ async function syncHandler(opts = {}) {
10369
10561
  const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
10370
10562
  const identity = resolveIdentity(projectRoot);
10371
10563
  const sprintRoot = resolveActiveSprintDir(projectRoot);
10372
- const sprintId = path50.basename(sprintRoot);
10564
+ const sprintId = path51.basename(sprintRoot);
10373
10565
  let mcp2;
10374
10566
  if (opts.mcp) {
10375
10567
  mcp2 = opts.mcp;
@@ -10430,7 +10622,7 @@ async function syncHandler(opts = {}) {
10430
10622
  exit(2);
10431
10623
  return;
10432
10624
  }
10433
- const wikiMetaPath = path50.join(projectRoot, ".cleargate", "wiki", "meta.json");
10625
+ const wikiMetaPath = path51.join(projectRoot, ".cleargate", "wiki", "meta.json");
10434
10626
  let lastRemoteSync = "1970-01-01T00:00:00.000Z";
10435
10627
  try {
10436
10628
  const metaRaw = await fsPromises8.readFile(wikiMetaPath, "utf8");
@@ -10671,7 +10863,7 @@ async function syncHandler(opts = {}) {
10671
10863
  };
10672
10864
  await appendSyncLog(sprintRoot, entry);
10673
10865
  }
10674
- const conflictsFile = path50.join(projectRoot, ".cleargate", ".conflicts.json");
10866
+ const conflictsFile = path51.join(projectRoot, ".cleargate", ".conflicts.json");
10675
10867
  const conflictsContent = {
10676
10868
  generated_at: nowFn(),
10677
10869
  sprint_id: sprintId,
@@ -10679,7 +10871,7 @@ async function syncHandler(opts = {}) {
10679
10871
  };
10680
10872
  await writeAtomic5(conflictsFile, JSON.stringify(conflictsContent, null, 2) + "\n");
10681
10873
  try {
10682
- await fsPromises8.mkdir(path50.dirname(wikiMetaPath), { recursive: true });
10874
+ await fsPromises8.mkdir(path51.dirname(wikiMetaPath), { recursive: true });
10683
10875
  let meta = {};
10684
10876
  try {
10685
10877
  const raw = await fsPromises8.readFile(wikiMetaPath, "utf8");
@@ -10720,13 +10912,13 @@ async function applyPull(item, localPath, fm, actorEmail, nowFn) {
10720
10912
  await writeAtomic5(localPath, newContent);
10721
10913
  }
10722
10914
  async function writeAtomic5(filePath, content) {
10723
- await fsPromises8.mkdir(path50.dirname(filePath), { recursive: true });
10915
+ await fsPromises8.mkdir(path51.dirname(filePath), { recursive: true });
10724
10916
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
10725
10917
  await fsPromises8.writeFile(tmpPath, content, "utf8");
10726
10918
  await fsPromises8.rename(tmpPath, filePath);
10727
10919
  }
10728
10920
  async function scanLocalItems(projectRoot) {
10729
- const pendingSync = path50.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10921
+ const pendingSync = path51.join(projectRoot, ".cleargate", "delivery", "pending-sync");
10730
10922
  const results = [];
10731
10923
  let entries;
10732
10924
  try {
@@ -10736,7 +10928,7 @@ async function scanLocalItems(projectRoot) {
10736
10928
  }
10737
10929
  for (const entry of entries) {
10738
10930
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
10739
- const fullPath = path50.join(pendingSync, entry.name);
10931
+ const fullPath = path51.join(pendingSync, entry.name);
10740
10932
  try {
10741
10933
  const raw = await fsPromises8.readFile(fullPath, "utf8");
10742
10934
  const { fm, body } = parseFrontmatter(raw);
@@ -10764,7 +10956,7 @@ init_config();
10764
10956
  // src/lib/sync/work-items.ts
10765
10957
  init_cjs_shims();
10766
10958
  var fsPromises9 = __toESM(require("fs/promises"), 1);
10767
- var path51 = __toESM(require("path"), 1);
10959
+ var path52 = __toESM(require("path"), 1);
10768
10960
  var import_node_crypto2 = require("crypto");
10769
10961
  var BATCH_SIZE = 100;
10770
10962
  var ATTRIBUTION_FIELDS = /* @__PURE__ */ new Set([
@@ -10812,8 +11004,8 @@ function getItemId2(fm) {
10812
11004
  }
10813
11005
  async function walkDeliveryDirs(projectRoot) {
10814
11006
  const dirs = [
10815
- path51.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
10816
- path51.join(projectRoot, ".cleargate", "delivery", "archive")
11007
+ path52.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
11008
+ path52.join(projectRoot, ".cleargate", "delivery", "archive")
10817
11009
  ];
10818
11010
  const results = [];
10819
11011
  for (const dir of dirs) {
@@ -10825,7 +11017,7 @@ async function walkDeliveryDirs(projectRoot) {
10825
11017
  }
10826
11018
  for (const entry of entries) {
10827
11019
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
10828
- const fullPath = path51.join(dir, entry.name);
11020
+ const fullPath = path52.join(dir, entry.name);
10829
11021
  try {
10830
11022
  const raw = await fsPromises9.readFile(fullPath, "utf8");
10831
11023
  const { fm, body } = parseFrontmatter(raw);
@@ -10850,7 +11042,7 @@ async function walkDeliveryDirs(projectRoot) {
10850
11042
  return results;
10851
11043
  }
10852
11044
  async function writeAtomic6(filePath, content) {
10853
- await fsPromises9.mkdir(path51.dirname(filePath), { recursive: true });
11045
+ await fsPromises9.mkdir(path52.dirname(filePath), { recursive: true });
10854
11046
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
10855
11047
  await fsPromises9.writeFile(tmpPath, content, "utf8");
10856
11048
  await fsPromises9.rename(tmpPath, filePath);
@@ -10917,9 +11109,9 @@ async function syncWorkItems(opts) {
10917
11109
 
10918
11110
  // src/lib/admin-url.ts
10919
11111
  init_cjs_shims();
10920
- var fs43 = __toESM(require("fs"), 1);
10921
- var os9 = __toESM(require("os"), 1);
10922
- var path52 = __toESM(require("path"), 1);
11112
+ var fs44 = __toESM(require("fs"), 1);
11113
+ var os10 = __toESM(require("os"), 1);
11114
+ var path53 = __toESM(require("path"), 1);
10923
11115
  var DEFAULT_BASE = "https://admin.cleargate.soula.ge/";
10924
11116
  function adminUrl(urlPath, opts) {
10925
11117
  const env = opts?.env ?? process.env;
@@ -10940,10 +11132,10 @@ function adminUrl(urlPath, opts) {
10940
11132
  return base;
10941
11133
  }
10942
11134
  function readLocalConfig() {
10943
- const home = os9.homedir();
11135
+ const home = os10.homedir();
10944
11136
  if (!home) return null;
10945
- const configPath = path52.join(home, ".cleargate", "config.json");
10946
- const raw = fs43.readFileSync(configPath, "utf8");
11137
+ const configPath = path53.join(home, ".cleargate", "config.json");
11138
+ const raw = fs44.readFileSync(configPath, "utf8");
10947
11139
  return JSON.parse(raw);
10948
11140
  }
10949
11141
 
@@ -11058,7 +11250,7 @@ async function syncWorkItemsHandler(opts = {}) {
11058
11250
  // src/commands/pull.ts
11059
11251
  init_cjs_shims();
11060
11252
  var fsPromises10 = __toESM(require("fs/promises"), 1);
11061
- var path53 = __toESM(require("path"), 1);
11253
+ var path54 = __toESM(require("path"), 1);
11062
11254
  init_acquire();
11063
11255
  init_config();
11064
11256
  async function pullHandler(idOrRemoteId, opts = {}) {
@@ -11173,7 +11365,7 @@ async function pullHandler(idOrRemoteId, opts = {}) {
11173
11365
  result: "ok"
11174
11366
  };
11175
11367
  await appendSyncLog(sprintRoot, entry);
11176
- stdout(`pull: ${remoteId} applied to ${path53.relative(projectRoot, localPath)}
11368
+ stdout(`pull: ${remoteId} applied to ${path54.relative(projectRoot, localPath)}
11177
11369
  `);
11178
11370
  if (opts.comments) {
11179
11371
  const comments = await mcp2.call(
@@ -11196,7 +11388,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
11196
11388
  if (/^[A-Z]+-\d+/.test(idOrRemoteId)) {
11197
11389
  return idOrRemoteId;
11198
11390
  }
11199
- const pendingSync = path53.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11391
+ const pendingSync = path54.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11200
11392
  let entries;
11201
11393
  try {
11202
11394
  entries = await fsPromises10.readdir(pendingSync, { withFileTypes: true });
@@ -11206,7 +11398,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
11206
11398
  for (const entry of entries) {
11207
11399
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
11208
11400
  try {
11209
- const raw = await fsPromises10.readFile(path53.join(pendingSync, entry.name), "utf8");
11401
+ const raw = await fsPromises10.readFile(path54.join(pendingSync, entry.name), "utf8");
11210
11402
  const { fm } = parseFrontmatter(raw);
11211
11403
  for (const key of ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id"]) {
11212
11404
  if (fm[key] === idOrRemoteId && typeof fm["remote_id"] === "string") {
@@ -11219,7 +11411,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
11219
11411
  return null;
11220
11412
  }
11221
11413
  async function findLocalFile(remoteId, projectRoot) {
11222
- const pendingSync = path53.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11414
+ const pendingSync = path54.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11223
11415
  let entries;
11224
11416
  try {
11225
11417
  entries = await fsPromises10.readdir(pendingSync, { withFileTypes: true });
@@ -11228,7 +11420,7 @@ async function findLocalFile(remoteId, projectRoot) {
11228
11420
  }
11229
11421
  for (const entry of entries) {
11230
11422
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
11231
- const fullPath = path53.join(pendingSync, entry.name);
11423
+ const fullPath = path54.join(pendingSync, entry.name);
11232
11424
  try {
11233
11425
  const raw = await fsPromises10.readFile(fullPath, "utf8");
11234
11426
  const { fm } = parseFrontmatter(raw);
@@ -11239,7 +11431,7 @@ async function findLocalFile(remoteId, projectRoot) {
11239
11431
  return null;
11240
11432
  }
11241
11433
  async function writeAtomic7(filePath, content) {
11242
- await fsPromises10.mkdir(path53.dirname(filePath), { recursive: true });
11434
+ await fsPromises10.mkdir(path54.dirname(filePath), { recursive: true });
11243
11435
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
11244
11436
  await fsPromises10.writeFile(tmpPath, content, "utf8");
11245
11437
  await fsPromises10.rename(tmpPath, filePath);
@@ -11255,7 +11447,7 @@ function getItemId3(fm) {
11255
11447
  // src/commands/push.ts
11256
11448
  init_cjs_shims();
11257
11449
  var fsPromises11 = __toESM(require("fs/promises"), 1);
11258
- var path54 = __toESM(require("path"), 1);
11450
+ var path55 = __toESM(require("path"), 1);
11259
11451
  init_acquire();
11260
11452
  init_config();
11261
11453
  async function pushHandler(fileOrId, opts = {}) {
@@ -11331,7 +11523,7 @@ async function pushHandler(fileOrId, opts = {}) {
11331
11523
  }
11332
11524
  async function handlePush(filePath, ctx) {
11333
11525
  const { projectRoot, identity, sprintRoot, nowFn, resolveMcp, stdout, stderr, exit } = ctx;
11334
- const resolvedPath = path54.isAbsolute(filePath) ? filePath : path54.resolve(projectRoot, filePath);
11526
+ const resolvedPath = path55.isAbsolute(filePath) ? filePath : path55.resolve(projectRoot, filePath);
11335
11527
  let rawContent;
11336
11528
  try {
11337
11529
  rawContent = await fsPromises11.readFile(resolvedPath, "utf8");
@@ -11457,8 +11649,8 @@ async function handleRevert(idOrRemoteId, ctx) {
11457
11649
  void localPath;
11458
11650
  }
11459
11651
  async function resolveLocalItem(idOrRemoteId, projectRoot) {
11460
- const pendingSync = path54.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11461
- const archive = path54.join(projectRoot, ".cleargate", "delivery", "archive");
11652
+ const pendingSync = path55.join(projectRoot, ".cleargate", "delivery", "pending-sync");
11653
+ const archive = path55.join(projectRoot, ".cleargate", "delivery", "archive");
11462
11654
  for (const dir of [pendingSync, archive]) {
11463
11655
  let entries;
11464
11656
  try {
@@ -11468,7 +11660,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
11468
11660
  }
11469
11661
  for (const entry of entries) {
11470
11662
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
11471
- const fullPath = path54.join(dir, entry.name);
11663
+ const fullPath = path55.join(dir, entry.name);
11472
11664
  try {
11473
11665
  const raw = await fsPromises11.readFile(fullPath, "utf8");
11474
11666
  const { fm } = parseFrontmatter(raw);
@@ -11487,7 +11679,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
11487
11679
  return null;
11488
11680
  }
11489
11681
  async function writeAtomic8(filePath, content) {
11490
- await fsPromises11.mkdir(path54.dirname(filePath), { recursive: true });
11682
+ await fsPromises11.mkdir(path55.dirname(filePath), { recursive: true });
11491
11683
  const tmpPath = `${filePath}.tmp.${Date.now()}`;
11492
11684
  await fsPromises11.writeFile(tmpPath, content, "utf8");
11493
11685
  await fsPromises11.rename(tmpPath, filePath);
@@ -11516,7 +11708,7 @@ function getItemType2(fm) {
11516
11708
  // src/commands/conflicts.ts
11517
11709
  init_cjs_shims();
11518
11710
  var fsPromises12 = __toESM(require("fs/promises"), 1);
11519
- var path55 = __toESM(require("path"), 1);
11711
+ var path56 = __toESM(require("path"), 1);
11520
11712
  init_acquire();
11521
11713
  init_config();
11522
11714
  var RESOLUTION_HINTS = {
@@ -11554,7 +11746,7 @@ async function conflictsHandler(opts = {}) {
11554
11746
  }
11555
11747
  }
11556
11748
  }
11557
- const conflictsFile = path55.join(projectRoot, ".cleargate", ".conflicts.json");
11749
+ const conflictsFile = path56.join(projectRoot, ".cleargate", ".conflicts.json");
11558
11750
  let data;
11559
11751
  try {
11560
11752
  const raw = await fsPromises12.readFile(conflictsFile, "utf8");
@@ -11642,24 +11834,24 @@ function formatEntry(entry) {
11642
11834
 
11643
11835
  // src/commands/admin-login.ts
11644
11836
  init_cjs_shims();
11645
- var fs44 = __toESM(require("fs"), 1);
11646
- var path56 = __toESM(require("path"), 1);
11647
- var os10 = __toESM(require("os"), 1);
11837
+ var fs45 = __toESM(require("fs"), 1);
11838
+ var path57 = __toESM(require("path"), 1);
11839
+ var os11 = __toESM(require("os"), 1);
11648
11840
  var DEFAULT_MCP_URL = "http://localhost:3000";
11649
11841
  function resolveMcpUrl(mcpUrlFlag, env) {
11650
11842
  return (mcpUrlFlag ?? (env ?? process.env)["CLEARGATE_MCP_URL"] ?? DEFAULT_MCP_URL).replace(/\/$/, "");
11651
11843
  }
11652
11844
  function resolveAuthFilePath(opts) {
11653
11845
  if (opts.authFilePath) return opts.authFilePath;
11654
- const homedirFn = opts.homedir ?? os10.homedir;
11655
- return path56.join(homedirFn(), ".cleargate", "admin-auth.json");
11846
+ const homedirFn = opts.homedir ?? os11.homedir;
11847
+ return path57.join(homedirFn(), ".cleargate", "admin-auth.json");
11656
11848
  }
11657
11849
  function writeAdminAuth(filePath, token) {
11658
- const dir = path56.dirname(filePath);
11659
- fs44.mkdirSync(dir, { recursive: true });
11850
+ const dir = path57.dirname(filePath);
11851
+ fs45.mkdirSync(dir, { recursive: true });
11660
11852
  const payload = JSON.stringify({ version: 1, token }, null, 2);
11661
- fs44.writeFileSync(filePath, payload, { encoding: "utf8", mode: 384 });
11662
- fs44.chmodSync(filePath, 384);
11853
+ fs45.writeFileSync(filePath, payload, { encoding: "utf8", mode: 384 });
11854
+ fs45.chmodSync(filePath, 384);
11663
11855
  }
11664
11856
  async function adminLoginHandler(opts = {}) {
11665
11857
  const fetchFn = opts.fetch ?? globalThis.fetch;
@@ -11769,8 +11961,8 @@ async function adminLoginHandler(opts = {}) {
11769
11961
 
11770
11962
  // src/commands/hotfix.ts
11771
11963
  init_cjs_shims();
11772
- var fs45 = __toESM(require("fs"), 1);
11773
- var path57 = __toESM(require("path"), 1);
11964
+ var fs46 = __toESM(require("fs"), 1);
11965
+ var path58 = __toESM(require("path"), 1);
11774
11966
  function defaultExit4(code) {
11775
11967
  return process.exit(code);
11776
11968
  }
@@ -11780,7 +11972,7 @@ function maxHotfixId(pendingDir) {
11780
11972
  let max = 0;
11781
11973
  let entries;
11782
11974
  try {
11783
- entries = fs45.readdirSync(pendingDir);
11975
+ entries = fs46.readdirSync(pendingDir);
11784
11976
  } catch {
11785
11977
  return 0;
11786
11978
  }
@@ -11794,13 +11986,13 @@ function maxHotfixId(pendingDir) {
11794
11986
  return max;
11795
11987
  }
11796
11988
  function countActiveHotfixes(repoRoot) {
11797
- const pendingDir = path57.join(repoRoot, ".cleargate", "delivery", "pending-sync");
11798
- const archiveDir = path57.join(repoRoot, ".cleargate", "delivery", "archive");
11989
+ const pendingDir = path58.join(repoRoot, ".cleargate", "delivery", "pending-sync");
11990
+ const archiveDir = path58.join(repoRoot, ".cleargate", "delivery", "archive");
11799
11991
  const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
11800
11992
  let count = 0;
11801
11993
  let pendingEntries = [];
11802
11994
  try {
11803
- pendingEntries = fs45.readdirSync(pendingDir);
11995
+ pendingEntries = fs46.readdirSync(pendingDir);
11804
11996
  } catch {
11805
11997
  }
11806
11998
  for (const entry of pendingEntries) {
@@ -11808,13 +12000,13 @@ function countActiveHotfixes(repoRoot) {
11808
12000
  }
11809
12001
  let archiveEntries = [];
11810
12002
  try {
11811
- archiveEntries = fs45.readdirSync(archiveDir);
12003
+ archiveEntries = fs46.readdirSync(archiveDir);
11812
12004
  } catch {
11813
12005
  }
11814
12006
  for (const entry of archiveEntries) {
11815
12007
  if (entry.startsWith("HOTFIX-") && entry.endsWith(".md")) {
11816
12008
  try {
11817
- const stat = fs45.statSync(path57.join(archiveDir, entry));
12009
+ const stat = fs46.statSync(path58.join(archiveDir, entry));
11818
12010
  if (stat.mtimeMs >= sevenDaysAgo) count++;
11819
12011
  } catch {
11820
12012
  }
@@ -11823,7 +12015,7 @@ function countActiveHotfixes(repoRoot) {
11823
12015
  return count;
11824
12016
  }
11825
12017
  function resolveTemplatePath(repoRoot) {
11826
- return path57.join(repoRoot, ".cleargate", "templates", "hotfix.md");
12018
+ return path58.join(repoRoot, ".cleargate", "templates", "hotfix.md");
11827
12019
  }
11828
12020
  function hotfixNewHandler(opts, cli) {
11829
12021
  const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
@@ -11842,14 +12034,14 @@ function hotfixNewHandler(opts, cli) {
11842
12034
  );
11843
12035
  return exitFn(1);
11844
12036
  }
11845
- const pendingDir = path57.join(repoRoot, ".cleargate", "delivery", "pending-sync");
12037
+ const pendingDir = path58.join(repoRoot, ".cleargate", "delivery", "pending-sync");
11846
12038
  const maxId = maxHotfixId(pendingDir);
11847
12039
  const nextId = maxId + 1;
11848
12040
  const idStr = `HOTFIX-${String(nextId).padStart(3, "0")}`;
11849
12041
  const templatePath = resolveTemplatePath(repoRoot);
11850
12042
  let templateContent;
11851
12043
  try {
11852
- templateContent = fs45.readFileSync(templatePath, "utf8");
12044
+ templateContent = fs46.readFileSync(templatePath, "utf8");
11853
12045
  } catch {
11854
12046
  stderrFn(`[cleargate hotfix new] template not found: ${templatePath}`);
11855
12047
  return exitFn(2);
@@ -11857,10 +12049,10 @@ function hotfixNewHandler(opts, cli) {
11857
12049
  const content = templateContent.replace(/\{ID\}/g, idStr).replace(/\{SLUG\}/g, opts.slug).replace(/\{ISO\}/g, now);
11858
12050
  const fileSlug = opts.slug.replace(/-/g, "_");
11859
12051
  const fileName = `${idStr}_${fileSlug}.md`;
11860
- const outPath = path57.join(pendingDir, fileName);
12052
+ const outPath = path58.join(pendingDir, fileName);
11861
12053
  try {
11862
- fs45.mkdirSync(pendingDir, { recursive: true });
11863
- fs45.writeFileSync(outPath, content, "utf8");
12054
+ fs46.mkdirSync(pendingDir, { recursive: true });
12055
+ fs46.writeFileSync(outPath, content, "utf8");
11864
12056
  } catch (err) {
11865
12057
  const msg = err instanceof Error ? err.message : String(err);
11866
12058
  stderrFn(`[cleargate hotfix new] write failed: ${msg}`);