cleargate 0.11.4 → 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/MANIFEST.json +2 -2
- package/dist/{chunk-Q3BTSXCK.js → chunk-WFNLCTY5.js} +90 -2
- package/dist/chunk-WFNLCTY5.js.map +1 -0
- package/dist/cli.cjs +184 -90
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +13 -5
- package/dist/cli.js.map +1 -1
- package/dist/templates/cleargate-planning/MANIFEST.json +2 -2
- package/dist/{whoami-W4U6DPVG.js → whoami-GQTFZHFQ.js} +2 -2
- package/package.json +1 -1
- package/templates/cleargate-planning/MANIFEST.json +2 -2
- package/dist/chunk-Q3BTSXCK.js.map +0 -1
- /package/dist/{whoami-W4U6DPVG.js.map → whoami-GQTFZHFQ.js.map} +0 -0
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
|
-
|
|
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.
|
|
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(
|
|
@@ -9618,7 +9712,7 @@ async function uninstallHandler(opts) {
|
|
|
9618
9712
|
// src/commands/sync.ts
|
|
9619
9713
|
init_cjs_shims();
|
|
9620
9714
|
var fsPromises8 = __toESM(require("fs/promises"), 1);
|
|
9621
|
-
var
|
|
9715
|
+
var path51 = __toESM(require("path"), 1);
|
|
9622
9716
|
|
|
9623
9717
|
// src/lib/sync-log.ts
|
|
9624
9718
|
init_cjs_shims();
|
|
@@ -9938,12 +10032,12 @@ init_config();
|
|
|
9938
10032
|
// src/lib/intake.ts
|
|
9939
10033
|
init_cjs_shims();
|
|
9940
10034
|
var fsPromises4 = __toESM(require("fs/promises"), 1);
|
|
9941
|
-
var
|
|
10035
|
+
var path47 = __toESM(require("path"), 1);
|
|
9942
10036
|
|
|
9943
10037
|
// src/lib/slug.ts
|
|
9944
10038
|
init_cjs_shims();
|
|
9945
10039
|
var fsPromises3 = __toESM(require("fs/promises"), 1);
|
|
9946
|
-
var
|
|
10040
|
+
var path46 = __toESM(require("path"), 1);
|
|
9947
10041
|
function slugify(title, max = 40) {
|
|
9948
10042
|
const normalized = title.normalize("NFKD").replace(new RegExp("\\p{M}", "gu"), "");
|
|
9949
10043
|
const lowered = normalized.toLowerCase();
|
|
@@ -9958,8 +10052,8 @@ function slugify(title, max = 40) {
|
|
|
9958
10052
|
var PROPOSAL_ID_RE = /^proposal_id:\s*"?PROP-(\d+)"?/m;
|
|
9959
10053
|
async function nextProposalId(projectRoot) {
|
|
9960
10054
|
const dirs = [
|
|
9961
|
-
|
|
9962
|
-
|
|
10055
|
+
path46.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
|
|
10056
|
+
path46.join(projectRoot, ".cleargate", "delivery", "archive")
|
|
9963
10057
|
];
|
|
9964
10058
|
let maxN = 0;
|
|
9965
10059
|
for (const dir of dirs) {
|
|
@@ -9971,7 +10065,7 @@ async function nextProposalId(projectRoot) {
|
|
|
9971
10065
|
}
|
|
9972
10066
|
for (const entry of entries) {
|
|
9973
10067
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
9974
|
-
const fullPath =
|
|
10068
|
+
const fullPath = path46.join(dir, entry.name);
|
|
9975
10069
|
try {
|
|
9976
10070
|
const raw = await fsPromises3.readFile(fullPath, "utf8");
|
|
9977
10071
|
const fmEnd = extractFrontmatterBlock(raw);
|
|
@@ -9989,8 +10083,8 @@ async function nextProposalId(projectRoot) {
|
|
|
9989
10083
|
}
|
|
9990
10084
|
async function findByRemoteId(projectRoot, remoteId) {
|
|
9991
10085
|
const dirs = [
|
|
9992
|
-
|
|
9993
|
-
|
|
10086
|
+
path46.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
|
|
10087
|
+
path46.join(projectRoot, ".cleargate", "delivery", "archive")
|
|
9994
10088
|
];
|
|
9995
10089
|
const escaped = remoteId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9996
10090
|
const re = new RegExp(`^remote_id:\\s*"?${escaped}"?\\s*$`, "m");
|
|
@@ -10003,7 +10097,7 @@ async function findByRemoteId(projectRoot, remoteId) {
|
|
|
10003
10097
|
}
|
|
10004
10098
|
for (const entry of entries) {
|
|
10005
10099
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
10006
|
-
const fullPath =
|
|
10100
|
+
const fullPath = path46.join(dir, entry.name);
|
|
10007
10101
|
try {
|
|
10008
10102
|
const raw = await fsPromises3.readFile(fullPath, "utf8");
|
|
10009
10103
|
const fm = extractFrontmatterBlock(raw);
|
|
@@ -10040,7 +10134,7 @@ async function runIntakeBranch(opts) {
|
|
|
10040
10134
|
labelFilter = "cleargate:proposal",
|
|
10041
10135
|
now = () => (/* @__PURE__ */ new Date()).toISOString()
|
|
10042
10136
|
} = opts;
|
|
10043
|
-
const pendingSyncDir =
|
|
10137
|
+
const pendingSyncDir = path47.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
10044
10138
|
let remoteItems = [];
|
|
10045
10139
|
try {
|
|
10046
10140
|
remoteItems = await mcp2.call(
|
|
@@ -10071,7 +10165,7 @@ async function runIntakeBranch(opts) {
|
|
|
10071
10165
|
const slug2 = slugify(item.title ?? "untitled");
|
|
10072
10166
|
const num2 = proposalId2.replace("PROP-", "");
|
|
10073
10167
|
const filename2 = `PROPOSAL-${num2}-remote-${slug2}.md`;
|
|
10074
|
-
const targetPath2 =
|
|
10168
|
+
const targetPath2 = path47.join(pendingSyncDir, filename2);
|
|
10075
10169
|
createdItems.push({
|
|
10076
10170
|
proposalId: proposalId2,
|
|
10077
10171
|
remoteId: item.remote_id,
|
|
@@ -10084,7 +10178,7 @@ async function runIntakeBranch(opts) {
|
|
|
10084
10178
|
const num = proposalId.replace("PROP-", "");
|
|
10085
10179
|
const slug = slugify(item.title ?? "untitled");
|
|
10086
10180
|
const filename = `PROPOSAL-${num}-remote-${slug}.md`;
|
|
10087
|
-
const targetPath =
|
|
10181
|
+
const targetPath = path47.join(pendingSyncDir, filename);
|
|
10088
10182
|
const nowTs = now();
|
|
10089
10183
|
const fm = {
|
|
10090
10184
|
proposal_id: proposalId,
|
|
@@ -10176,8 +10270,8 @@ path/to/new/file.ext - {Explanation of purpose}
|
|
|
10176
10270
|
}
|
|
10177
10271
|
async function hasAnyRemoteAuthored(projectRoot) {
|
|
10178
10272
|
const dirs = [
|
|
10179
|
-
|
|
10180
|
-
|
|
10273
|
+
path47.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
|
|
10274
|
+
path47.join(projectRoot, ".cleargate", "delivery", "archive")
|
|
10181
10275
|
];
|
|
10182
10276
|
for (const dir of dirs) {
|
|
10183
10277
|
let entries;
|
|
@@ -10188,7 +10282,7 @@ async function hasAnyRemoteAuthored(projectRoot) {
|
|
|
10188
10282
|
}
|
|
10189
10283
|
for (const entry of entries) {
|
|
10190
10284
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
10191
|
-
const fullPath =
|
|
10285
|
+
const fullPath = path47.join(dir, entry.name);
|
|
10192
10286
|
try {
|
|
10193
10287
|
const raw = await fsPromises4.readFile(fullPath, "utf8");
|
|
10194
10288
|
const fmEnd = raw.indexOf("\n---", 4);
|
|
@@ -10206,9 +10300,9 @@ async function hasAnyRemoteAuthored(projectRoot) {
|
|
|
10206
10300
|
|
|
10207
10301
|
// src/lib/active-criteria.ts
|
|
10208
10302
|
init_cjs_shims();
|
|
10209
|
-
var
|
|
10303
|
+
var fs43 = __toESM(require("fs"), 1);
|
|
10210
10304
|
var fsPromises5 = __toESM(require("fs/promises"), 1);
|
|
10211
|
-
var
|
|
10305
|
+
var path48 = __toESM(require("path"), 1);
|
|
10212
10306
|
async function resolveActiveItems(projectRoot, localItems, nowFn = () => (/* @__PURE__ */ new Date()).toISOString()) {
|
|
10213
10307
|
const active = /* @__PURE__ */ new Set();
|
|
10214
10308
|
const now = Date.parse(nowFn());
|
|
@@ -10233,7 +10327,7 @@ async function resolveInSprintIds(projectRoot) {
|
|
|
10233
10327
|
const ids = /* @__PURE__ */ new Set();
|
|
10234
10328
|
try {
|
|
10235
10329
|
const sprintDir = resolveActiveSprintDir(projectRoot);
|
|
10236
|
-
const sprintId =
|
|
10330
|
+
const sprintId = path48.basename(sprintDir);
|
|
10237
10331
|
if (sprintId === "_off-sprint") return ids;
|
|
10238
10332
|
const sprintFile = await findSprintFile2(projectRoot, sprintId);
|
|
10239
10333
|
if (!sprintFile) return ids;
|
|
@@ -10248,14 +10342,14 @@ async function resolveInSprintIds(projectRoot) {
|
|
|
10248
10342
|
return ids;
|
|
10249
10343
|
}
|
|
10250
10344
|
async function findSprintFile2(projectRoot, sprintId) {
|
|
10251
|
-
const pendingSync =
|
|
10252
|
-
const archive =
|
|
10345
|
+
const pendingSync = path48.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
10346
|
+
const archive = path48.join(projectRoot, ".cleargate", "delivery", "archive");
|
|
10253
10347
|
for (const dir of [pendingSync, archive]) {
|
|
10254
10348
|
try {
|
|
10255
|
-
const entries =
|
|
10349
|
+
const entries = fs43.readdirSync(dir, { withFileTypes: true });
|
|
10256
10350
|
for (const entry of entries) {
|
|
10257
10351
|
if (entry.isFile() && entry.name.startsWith(sprintId) && entry.name.endsWith(".md")) {
|
|
10258
|
-
return
|
|
10352
|
+
return path48.join(dir, entry.name);
|
|
10259
10353
|
}
|
|
10260
10354
|
}
|
|
10261
10355
|
} catch {
|
|
@@ -10267,12 +10361,12 @@ async function findSprintFile2(projectRoot, sprintId) {
|
|
|
10267
10361
|
// src/lib/comments-cache.ts
|
|
10268
10362
|
init_cjs_shims();
|
|
10269
10363
|
var fsPromises6 = __toESM(require("fs/promises"), 1);
|
|
10270
|
-
var
|
|
10364
|
+
var path49 = __toESM(require("path"), 1);
|
|
10271
10365
|
function cacheDir(projectRoot) {
|
|
10272
|
-
return
|
|
10366
|
+
return path49.join(projectRoot, ".cleargate", ".comments-cache");
|
|
10273
10367
|
}
|
|
10274
10368
|
function cachePath(projectRoot, remoteId) {
|
|
10275
|
-
return
|
|
10369
|
+
return path49.join(cacheDir(projectRoot), `${remoteId}.json`);
|
|
10276
10370
|
}
|
|
10277
10371
|
async function writeCommentCache(projectRoot, remoteId, comments) {
|
|
10278
10372
|
const dir = cacheDir(projectRoot);
|
|
@@ -10287,7 +10381,7 @@ async function writeCommentCache(projectRoot, remoteId, comments) {
|
|
|
10287
10381
|
// src/lib/wiki-comments-render.ts
|
|
10288
10382
|
init_cjs_shims();
|
|
10289
10383
|
var fsPromises7 = __toESM(require("fs/promises"), 1);
|
|
10290
|
-
var
|
|
10384
|
+
var path50 = __toESM(require("path"), 1);
|
|
10291
10385
|
var START = "<!-- cleargate:comments:start -->";
|
|
10292
10386
|
var END = "<!-- cleargate:comments:end -->";
|
|
10293
10387
|
function resolveBucket(fm) {
|
|
@@ -10332,7 +10426,7 @@ async function renderCommentsSection(opts) {
|
|
|
10332
10426
|
const bucket = resolveBucket(localItem.fm);
|
|
10333
10427
|
const primaryId = getPrimaryId(localItem.fm);
|
|
10334
10428
|
if (!bucket || !primaryId) return;
|
|
10335
|
-
const wikiPath =
|
|
10429
|
+
const wikiPath = path50.join(
|
|
10336
10430
|
projectRoot,
|
|
10337
10431
|
".cleargate",
|
|
10338
10432
|
"wiki",
|
|
@@ -10368,7 +10462,7 @@ async function renderCommentsSection(opts) {
|
|
|
10368
10462
|
await writeAtomic4(wikiPath, updated);
|
|
10369
10463
|
}
|
|
10370
10464
|
async function writeAtomic4(filePath, content) {
|
|
10371
|
-
await fsPromises7.mkdir(
|
|
10465
|
+
await fsPromises7.mkdir(path50.dirname(filePath), { recursive: true });
|
|
10372
10466
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
10373
10467
|
await fsPromises7.writeFile(tmpPath, content, "utf8");
|
|
10374
10468
|
await fsPromises7.rename(tmpPath, filePath);
|
|
@@ -10380,11 +10474,11 @@ async function syncCheckHandler(opts = {}) {
|
|
|
10380
10474
|
const env = opts.env ?? process.env;
|
|
10381
10475
|
const stdout = opts.stdout ?? ((s) => process.stdout.write(s));
|
|
10382
10476
|
const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
10383
|
-
const markerPath =
|
|
10477
|
+
const markerPath = path51.join(projectRoot, ".cleargate", ".sync-marker.json");
|
|
10384
10478
|
const updateMarker = async (nowIso2) => {
|
|
10385
10479
|
try {
|
|
10386
10480
|
const content = JSON.stringify({ last_check: nowIso2 });
|
|
10387
|
-
await fsPromises8.mkdir(
|
|
10481
|
+
await fsPromises8.mkdir(path51.dirname(markerPath), { recursive: true });
|
|
10388
10482
|
const tmpPath = `${markerPath}.tmp.${Date.now()}`;
|
|
10389
10483
|
await fsPromises8.writeFile(tmpPath, content, "utf8");
|
|
10390
10484
|
await fsPromises8.rename(tmpPath, markerPath);
|
|
@@ -10467,7 +10561,7 @@ async function syncHandler(opts = {}) {
|
|
|
10467
10561
|
const nowFn = opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString());
|
|
10468
10562
|
const identity = resolveIdentity(projectRoot);
|
|
10469
10563
|
const sprintRoot = resolveActiveSprintDir(projectRoot);
|
|
10470
|
-
const sprintId =
|
|
10564
|
+
const sprintId = path51.basename(sprintRoot);
|
|
10471
10565
|
let mcp2;
|
|
10472
10566
|
if (opts.mcp) {
|
|
10473
10567
|
mcp2 = opts.mcp;
|
|
@@ -10528,7 +10622,7 @@ async function syncHandler(opts = {}) {
|
|
|
10528
10622
|
exit(2);
|
|
10529
10623
|
return;
|
|
10530
10624
|
}
|
|
10531
|
-
const wikiMetaPath =
|
|
10625
|
+
const wikiMetaPath = path51.join(projectRoot, ".cleargate", "wiki", "meta.json");
|
|
10532
10626
|
let lastRemoteSync = "1970-01-01T00:00:00.000Z";
|
|
10533
10627
|
try {
|
|
10534
10628
|
const metaRaw = await fsPromises8.readFile(wikiMetaPath, "utf8");
|
|
@@ -10769,7 +10863,7 @@ async function syncHandler(opts = {}) {
|
|
|
10769
10863
|
};
|
|
10770
10864
|
await appendSyncLog(sprintRoot, entry);
|
|
10771
10865
|
}
|
|
10772
|
-
const conflictsFile =
|
|
10866
|
+
const conflictsFile = path51.join(projectRoot, ".cleargate", ".conflicts.json");
|
|
10773
10867
|
const conflictsContent = {
|
|
10774
10868
|
generated_at: nowFn(),
|
|
10775
10869
|
sprint_id: sprintId,
|
|
@@ -10777,7 +10871,7 @@ async function syncHandler(opts = {}) {
|
|
|
10777
10871
|
};
|
|
10778
10872
|
await writeAtomic5(conflictsFile, JSON.stringify(conflictsContent, null, 2) + "\n");
|
|
10779
10873
|
try {
|
|
10780
|
-
await fsPromises8.mkdir(
|
|
10874
|
+
await fsPromises8.mkdir(path51.dirname(wikiMetaPath), { recursive: true });
|
|
10781
10875
|
let meta = {};
|
|
10782
10876
|
try {
|
|
10783
10877
|
const raw = await fsPromises8.readFile(wikiMetaPath, "utf8");
|
|
@@ -10818,13 +10912,13 @@ async function applyPull(item, localPath, fm, actorEmail, nowFn) {
|
|
|
10818
10912
|
await writeAtomic5(localPath, newContent);
|
|
10819
10913
|
}
|
|
10820
10914
|
async function writeAtomic5(filePath, content) {
|
|
10821
|
-
await fsPromises8.mkdir(
|
|
10915
|
+
await fsPromises8.mkdir(path51.dirname(filePath), { recursive: true });
|
|
10822
10916
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
10823
10917
|
await fsPromises8.writeFile(tmpPath, content, "utf8");
|
|
10824
10918
|
await fsPromises8.rename(tmpPath, filePath);
|
|
10825
10919
|
}
|
|
10826
10920
|
async function scanLocalItems(projectRoot) {
|
|
10827
|
-
const pendingSync =
|
|
10921
|
+
const pendingSync = path51.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
10828
10922
|
const results = [];
|
|
10829
10923
|
let entries;
|
|
10830
10924
|
try {
|
|
@@ -10834,7 +10928,7 @@ async function scanLocalItems(projectRoot) {
|
|
|
10834
10928
|
}
|
|
10835
10929
|
for (const entry of entries) {
|
|
10836
10930
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
10837
|
-
const fullPath =
|
|
10931
|
+
const fullPath = path51.join(pendingSync, entry.name);
|
|
10838
10932
|
try {
|
|
10839
10933
|
const raw = await fsPromises8.readFile(fullPath, "utf8");
|
|
10840
10934
|
const { fm, body } = parseFrontmatter(raw);
|
|
@@ -10862,7 +10956,7 @@ init_config();
|
|
|
10862
10956
|
// src/lib/sync/work-items.ts
|
|
10863
10957
|
init_cjs_shims();
|
|
10864
10958
|
var fsPromises9 = __toESM(require("fs/promises"), 1);
|
|
10865
|
-
var
|
|
10959
|
+
var path52 = __toESM(require("path"), 1);
|
|
10866
10960
|
var import_node_crypto2 = require("crypto");
|
|
10867
10961
|
var BATCH_SIZE = 100;
|
|
10868
10962
|
var ATTRIBUTION_FIELDS = /* @__PURE__ */ new Set([
|
|
@@ -10910,8 +11004,8 @@ function getItemId2(fm) {
|
|
|
10910
11004
|
}
|
|
10911
11005
|
async function walkDeliveryDirs(projectRoot) {
|
|
10912
11006
|
const dirs = [
|
|
10913
|
-
|
|
10914
|
-
|
|
11007
|
+
path52.join(projectRoot, ".cleargate", "delivery", "pending-sync"),
|
|
11008
|
+
path52.join(projectRoot, ".cleargate", "delivery", "archive")
|
|
10915
11009
|
];
|
|
10916
11010
|
const results = [];
|
|
10917
11011
|
for (const dir of dirs) {
|
|
@@ -10923,7 +11017,7 @@ async function walkDeliveryDirs(projectRoot) {
|
|
|
10923
11017
|
}
|
|
10924
11018
|
for (const entry of entries) {
|
|
10925
11019
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
10926
|
-
const fullPath =
|
|
11020
|
+
const fullPath = path52.join(dir, entry.name);
|
|
10927
11021
|
try {
|
|
10928
11022
|
const raw = await fsPromises9.readFile(fullPath, "utf8");
|
|
10929
11023
|
const { fm, body } = parseFrontmatter(raw);
|
|
@@ -10948,7 +11042,7 @@ async function walkDeliveryDirs(projectRoot) {
|
|
|
10948
11042
|
return results;
|
|
10949
11043
|
}
|
|
10950
11044
|
async function writeAtomic6(filePath, content) {
|
|
10951
|
-
await fsPromises9.mkdir(
|
|
11045
|
+
await fsPromises9.mkdir(path52.dirname(filePath), { recursive: true });
|
|
10952
11046
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
10953
11047
|
await fsPromises9.writeFile(tmpPath, content, "utf8");
|
|
10954
11048
|
await fsPromises9.rename(tmpPath, filePath);
|
|
@@ -11015,9 +11109,9 @@ async function syncWorkItems(opts) {
|
|
|
11015
11109
|
|
|
11016
11110
|
// src/lib/admin-url.ts
|
|
11017
11111
|
init_cjs_shims();
|
|
11018
|
-
var
|
|
11019
|
-
var
|
|
11020
|
-
var
|
|
11112
|
+
var fs44 = __toESM(require("fs"), 1);
|
|
11113
|
+
var os10 = __toESM(require("os"), 1);
|
|
11114
|
+
var path53 = __toESM(require("path"), 1);
|
|
11021
11115
|
var DEFAULT_BASE = "https://admin.cleargate.soula.ge/";
|
|
11022
11116
|
function adminUrl(urlPath, opts) {
|
|
11023
11117
|
const env = opts?.env ?? process.env;
|
|
@@ -11038,10 +11132,10 @@ function adminUrl(urlPath, opts) {
|
|
|
11038
11132
|
return base;
|
|
11039
11133
|
}
|
|
11040
11134
|
function readLocalConfig() {
|
|
11041
|
-
const home =
|
|
11135
|
+
const home = os10.homedir();
|
|
11042
11136
|
if (!home) return null;
|
|
11043
|
-
const configPath =
|
|
11044
|
-
const raw =
|
|
11137
|
+
const configPath = path53.join(home, ".cleargate", "config.json");
|
|
11138
|
+
const raw = fs44.readFileSync(configPath, "utf8");
|
|
11045
11139
|
return JSON.parse(raw);
|
|
11046
11140
|
}
|
|
11047
11141
|
|
|
@@ -11156,7 +11250,7 @@ async function syncWorkItemsHandler(opts = {}) {
|
|
|
11156
11250
|
// src/commands/pull.ts
|
|
11157
11251
|
init_cjs_shims();
|
|
11158
11252
|
var fsPromises10 = __toESM(require("fs/promises"), 1);
|
|
11159
|
-
var
|
|
11253
|
+
var path54 = __toESM(require("path"), 1);
|
|
11160
11254
|
init_acquire();
|
|
11161
11255
|
init_config();
|
|
11162
11256
|
async function pullHandler(idOrRemoteId, opts = {}) {
|
|
@@ -11271,7 +11365,7 @@ async function pullHandler(idOrRemoteId, opts = {}) {
|
|
|
11271
11365
|
result: "ok"
|
|
11272
11366
|
};
|
|
11273
11367
|
await appendSyncLog(sprintRoot, entry);
|
|
11274
|
-
stdout(`pull: ${remoteId} applied to ${
|
|
11368
|
+
stdout(`pull: ${remoteId} applied to ${path54.relative(projectRoot, localPath)}
|
|
11275
11369
|
`);
|
|
11276
11370
|
if (opts.comments) {
|
|
11277
11371
|
const comments = await mcp2.call(
|
|
@@ -11294,7 +11388,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
|
|
|
11294
11388
|
if (/^[A-Z]+-\d+/.test(idOrRemoteId)) {
|
|
11295
11389
|
return idOrRemoteId;
|
|
11296
11390
|
}
|
|
11297
|
-
const pendingSync =
|
|
11391
|
+
const pendingSync = path54.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
11298
11392
|
let entries;
|
|
11299
11393
|
try {
|
|
11300
11394
|
entries = await fsPromises10.readdir(pendingSync, { withFileTypes: true });
|
|
@@ -11304,7 +11398,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
|
|
|
11304
11398
|
for (const entry of entries) {
|
|
11305
11399
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
11306
11400
|
try {
|
|
11307
|
-
const raw = await fsPromises10.readFile(
|
|
11401
|
+
const raw = await fsPromises10.readFile(path54.join(pendingSync, entry.name), "utf8");
|
|
11308
11402
|
const { fm } = parseFrontmatter(raw);
|
|
11309
11403
|
for (const key of ["story_id", "epic_id", "proposal_id", "cr_id", "bug_id"]) {
|
|
11310
11404
|
if (fm[key] === idOrRemoteId && typeof fm["remote_id"] === "string") {
|
|
@@ -11317,7 +11411,7 @@ async function resolveRemoteId(idOrRemoteId, projectRoot) {
|
|
|
11317
11411
|
return null;
|
|
11318
11412
|
}
|
|
11319
11413
|
async function findLocalFile(remoteId, projectRoot) {
|
|
11320
|
-
const pendingSync =
|
|
11414
|
+
const pendingSync = path54.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
11321
11415
|
let entries;
|
|
11322
11416
|
try {
|
|
11323
11417
|
entries = await fsPromises10.readdir(pendingSync, { withFileTypes: true });
|
|
@@ -11326,7 +11420,7 @@ async function findLocalFile(remoteId, projectRoot) {
|
|
|
11326
11420
|
}
|
|
11327
11421
|
for (const entry of entries) {
|
|
11328
11422
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
11329
|
-
const fullPath =
|
|
11423
|
+
const fullPath = path54.join(pendingSync, entry.name);
|
|
11330
11424
|
try {
|
|
11331
11425
|
const raw = await fsPromises10.readFile(fullPath, "utf8");
|
|
11332
11426
|
const { fm } = parseFrontmatter(raw);
|
|
@@ -11337,7 +11431,7 @@ async function findLocalFile(remoteId, projectRoot) {
|
|
|
11337
11431
|
return null;
|
|
11338
11432
|
}
|
|
11339
11433
|
async function writeAtomic7(filePath, content) {
|
|
11340
|
-
await fsPromises10.mkdir(
|
|
11434
|
+
await fsPromises10.mkdir(path54.dirname(filePath), { recursive: true });
|
|
11341
11435
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
11342
11436
|
await fsPromises10.writeFile(tmpPath, content, "utf8");
|
|
11343
11437
|
await fsPromises10.rename(tmpPath, filePath);
|
|
@@ -11353,7 +11447,7 @@ function getItemId3(fm) {
|
|
|
11353
11447
|
// src/commands/push.ts
|
|
11354
11448
|
init_cjs_shims();
|
|
11355
11449
|
var fsPromises11 = __toESM(require("fs/promises"), 1);
|
|
11356
|
-
var
|
|
11450
|
+
var path55 = __toESM(require("path"), 1);
|
|
11357
11451
|
init_acquire();
|
|
11358
11452
|
init_config();
|
|
11359
11453
|
async function pushHandler(fileOrId, opts = {}) {
|
|
@@ -11429,7 +11523,7 @@ async function pushHandler(fileOrId, opts = {}) {
|
|
|
11429
11523
|
}
|
|
11430
11524
|
async function handlePush(filePath, ctx) {
|
|
11431
11525
|
const { projectRoot, identity, sprintRoot, nowFn, resolveMcp, stdout, stderr, exit } = ctx;
|
|
11432
|
-
const resolvedPath =
|
|
11526
|
+
const resolvedPath = path55.isAbsolute(filePath) ? filePath : path55.resolve(projectRoot, filePath);
|
|
11433
11527
|
let rawContent;
|
|
11434
11528
|
try {
|
|
11435
11529
|
rawContent = await fsPromises11.readFile(resolvedPath, "utf8");
|
|
@@ -11555,8 +11649,8 @@ async function handleRevert(idOrRemoteId, ctx) {
|
|
|
11555
11649
|
void localPath;
|
|
11556
11650
|
}
|
|
11557
11651
|
async function resolveLocalItem(idOrRemoteId, projectRoot) {
|
|
11558
|
-
const pendingSync =
|
|
11559
|
-
const archive =
|
|
11652
|
+
const pendingSync = path55.join(projectRoot, ".cleargate", "delivery", "pending-sync");
|
|
11653
|
+
const archive = path55.join(projectRoot, ".cleargate", "delivery", "archive");
|
|
11560
11654
|
for (const dir of [pendingSync, archive]) {
|
|
11561
11655
|
let entries;
|
|
11562
11656
|
try {
|
|
@@ -11566,7 +11660,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
|
|
|
11566
11660
|
}
|
|
11567
11661
|
for (const entry of entries) {
|
|
11568
11662
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
11569
|
-
const fullPath =
|
|
11663
|
+
const fullPath = path55.join(dir, entry.name);
|
|
11570
11664
|
try {
|
|
11571
11665
|
const raw = await fsPromises11.readFile(fullPath, "utf8");
|
|
11572
11666
|
const { fm } = parseFrontmatter(raw);
|
|
@@ -11585,7 +11679,7 @@ async function resolveLocalItem(idOrRemoteId, projectRoot) {
|
|
|
11585
11679
|
return null;
|
|
11586
11680
|
}
|
|
11587
11681
|
async function writeAtomic8(filePath, content) {
|
|
11588
|
-
await fsPromises11.mkdir(
|
|
11682
|
+
await fsPromises11.mkdir(path55.dirname(filePath), { recursive: true });
|
|
11589
11683
|
const tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
11590
11684
|
await fsPromises11.writeFile(tmpPath, content, "utf8");
|
|
11591
11685
|
await fsPromises11.rename(tmpPath, filePath);
|
|
@@ -11614,7 +11708,7 @@ function getItemType2(fm) {
|
|
|
11614
11708
|
// src/commands/conflicts.ts
|
|
11615
11709
|
init_cjs_shims();
|
|
11616
11710
|
var fsPromises12 = __toESM(require("fs/promises"), 1);
|
|
11617
|
-
var
|
|
11711
|
+
var path56 = __toESM(require("path"), 1);
|
|
11618
11712
|
init_acquire();
|
|
11619
11713
|
init_config();
|
|
11620
11714
|
var RESOLUTION_HINTS = {
|
|
@@ -11652,7 +11746,7 @@ async function conflictsHandler(opts = {}) {
|
|
|
11652
11746
|
}
|
|
11653
11747
|
}
|
|
11654
11748
|
}
|
|
11655
|
-
const conflictsFile =
|
|
11749
|
+
const conflictsFile = path56.join(projectRoot, ".cleargate", ".conflicts.json");
|
|
11656
11750
|
let data;
|
|
11657
11751
|
try {
|
|
11658
11752
|
const raw = await fsPromises12.readFile(conflictsFile, "utf8");
|
|
@@ -11740,24 +11834,24 @@ function formatEntry(entry) {
|
|
|
11740
11834
|
|
|
11741
11835
|
// src/commands/admin-login.ts
|
|
11742
11836
|
init_cjs_shims();
|
|
11743
|
-
var
|
|
11744
|
-
var
|
|
11745
|
-
var
|
|
11837
|
+
var fs45 = __toESM(require("fs"), 1);
|
|
11838
|
+
var path57 = __toESM(require("path"), 1);
|
|
11839
|
+
var os11 = __toESM(require("os"), 1);
|
|
11746
11840
|
var DEFAULT_MCP_URL = "http://localhost:3000";
|
|
11747
11841
|
function resolveMcpUrl(mcpUrlFlag, env) {
|
|
11748
11842
|
return (mcpUrlFlag ?? (env ?? process.env)["CLEARGATE_MCP_URL"] ?? DEFAULT_MCP_URL).replace(/\/$/, "");
|
|
11749
11843
|
}
|
|
11750
11844
|
function resolveAuthFilePath(opts) {
|
|
11751
11845
|
if (opts.authFilePath) return opts.authFilePath;
|
|
11752
|
-
const homedirFn = opts.homedir ??
|
|
11753
|
-
return
|
|
11846
|
+
const homedirFn = opts.homedir ?? os11.homedir;
|
|
11847
|
+
return path57.join(homedirFn(), ".cleargate", "admin-auth.json");
|
|
11754
11848
|
}
|
|
11755
11849
|
function writeAdminAuth(filePath, token) {
|
|
11756
|
-
const dir =
|
|
11757
|
-
|
|
11850
|
+
const dir = path57.dirname(filePath);
|
|
11851
|
+
fs45.mkdirSync(dir, { recursive: true });
|
|
11758
11852
|
const payload = JSON.stringify({ version: 1, token }, null, 2);
|
|
11759
|
-
|
|
11760
|
-
|
|
11853
|
+
fs45.writeFileSync(filePath, payload, { encoding: "utf8", mode: 384 });
|
|
11854
|
+
fs45.chmodSync(filePath, 384);
|
|
11761
11855
|
}
|
|
11762
11856
|
async function adminLoginHandler(opts = {}) {
|
|
11763
11857
|
const fetchFn = opts.fetch ?? globalThis.fetch;
|
|
@@ -11867,8 +11961,8 @@ async function adminLoginHandler(opts = {}) {
|
|
|
11867
11961
|
|
|
11868
11962
|
// src/commands/hotfix.ts
|
|
11869
11963
|
init_cjs_shims();
|
|
11870
|
-
var
|
|
11871
|
-
var
|
|
11964
|
+
var fs46 = __toESM(require("fs"), 1);
|
|
11965
|
+
var path58 = __toESM(require("path"), 1);
|
|
11872
11966
|
function defaultExit4(code) {
|
|
11873
11967
|
return process.exit(code);
|
|
11874
11968
|
}
|
|
@@ -11878,7 +11972,7 @@ function maxHotfixId(pendingDir) {
|
|
|
11878
11972
|
let max = 0;
|
|
11879
11973
|
let entries;
|
|
11880
11974
|
try {
|
|
11881
|
-
entries =
|
|
11975
|
+
entries = fs46.readdirSync(pendingDir);
|
|
11882
11976
|
} catch {
|
|
11883
11977
|
return 0;
|
|
11884
11978
|
}
|
|
@@ -11892,13 +11986,13 @@ function maxHotfixId(pendingDir) {
|
|
|
11892
11986
|
return max;
|
|
11893
11987
|
}
|
|
11894
11988
|
function countActiveHotfixes(repoRoot) {
|
|
11895
|
-
const pendingDir =
|
|
11896
|
-
const archiveDir =
|
|
11989
|
+
const pendingDir = path58.join(repoRoot, ".cleargate", "delivery", "pending-sync");
|
|
11990
|
+
const archiveDir = path58.join(repoRoot, ".cleargate", "delivery", "archive");
|
|
11897
11991
|
const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1e3;
|
|
11898
11992
|
let count = 0;
|
|
11899
11993
|
let pendingEntries = [];
|
|
11900
11994
|
try {
|
|
11901
|
-
pendingEntries =
|
|
11995
|
+
pendingEntries = fs46.readdirSync(pendingDir);
|
|
11902
11996
|
} catch {
|
|
11903
11997
|
}
|
|
11904
11998
|
for (const entry of pendingEntries) {
|
|
@@ -11906,13 +12000,13 @@ function countActiveHotfixes(repoRoot) {
|
|
|
11906
12000
|
}
|
|
11907
12001
|
let archiveEntries = [];
|
|
11908
12002
|
try {
|
|
11909
|
-
archiveEntries =
|
|
12003
|
+
archiveEntries = fs46.readdirSync(archiveDir);
|
|
11910
12004
|
} catch {
|
|
11911
12005
|
}
|
|
11912
12006
|
for (const entry of archiveEntries) {
|
|
11913
12007
|
if (entry.startsWith("HOTFIX-") && entry.endsWith(".md")) {
|
|
11914
12008
|
try {
|
|
11915
|
-
const stat =
|
|
12009
|
+
const stat = fs46.statSync(path58.join(archiveDir, entry));
|
|
11916
12010
|
if (stat.mtimeMs >= sevenDaysAgo) count++;
|
|
11917
12011
|
} catch {
|
|
11918
12012
|
}
|
|
@@ -11921,7 +12015,7 @@ function countActiveHotfixes(repoRoot) {
|
|
|
11921
12015
|
return count;
|
|
11922
12016
|
}
|
|
11923
12017
|
function resolveTemplatePath(repoRoot) {
|
|
11924
|
-
return
|
|
12018
|
+
return path58.join(repoRoot, ".cleargate", "templates", "hotfix.md");
|
|
11925
12019
|
}
|
|
11926
12020
|
function hotfixNewHandler(opts, cli) {
|
|
11927
12021
|
const stdoutFn = cli?.stdout ?? ((s) => process.stdout.write(s + "\n"));
|
|
@@ -11940,14 +12034,14 @@ function hotfixNewHandler(opts, cli) {
|
|
|
11940
12034
|
);
|
|
11941
12035
|
return exitFn(1);
|
|
11942
12036
|
}
|
|
11943
|
-
const pendingDir =
|
|
12037
|
+
const pendingDir = path58.join(repoRoot, ".cleargate", "delivery", "pending-sync");
|
|
11944
12038
|
const maxId = maxHotfixId(pendingDir);
|
|
11945
12039
|
const nextId = maxId + 1;
|
|
11946
12040
|
const idStr = `HOTFIX-${String(nextId).padStart(3, "0")}`;
|
|
11947
12041
|
const templatePath = resolveTemplatePath(repoRoot);
|
|
11948
12042
|
let templateContent;
|
|
11949
12043
|
try {
|
|
11950
|
-
templateContent =
|
|
12044
|
+
templateContent = fs46.readFileSync(templatePath, "utf8");
|
|
11951
12045
|
} catch {
|
|
11952
12046
|
stderrFn(`[cleargate hotfix new] template not found: ${templatePath}`);
|
|
11953
12047
|
return exitFn(2);
|
|
@@ -11955,10 +12049,10 @@ function hotfixNewHandler(opts, cli) {
|
|
|
11955
12049
|
const content = templateContent.replace(/\{ID\}/g, idStr).replace(/\{SLUG\}/g, opts.slug).replace(/\{ISO\}/g, now);
|
|
11956
12050
|
const fileSlug = opts.slug.replace(/-/g, "_");
|
|
11957
12051
|
const fileName = `${idStr}_${fileSlug}.md`;
|
|
11958
|
-
const outPath =
|
|
12052
|
+
const outPath = path58.join(pendingDir, fileName);
|
|
11959
12053
|
try {
|
|
11960
|
-
|
|
11961
|
-
|
|
12054
|
+
fs46.mkdirSync(pendingDir, { recursive: true });
|
|
12055
|
+
fs46.writeFileSync(outPath, content, "utf8");
|
|
11962
12056
|
} catch (err) {
|
|
11963
12057
|
const msg = err instanceof Error ? err.message : String(err);
|
|
11964
12058
|
stderrFn(`[cleargate hotfix new] write failed: ${msg}`);
|