@rpamis/comet 0.4.0-beta.7 → 0.4.0-beta.9
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/LICENSE +21 -21
- package/README.md +3 -3
- package/assets/manifest.json +1 -1
- package/assets/skills/comet/reference/comet-yaml-fields.md +2 -2
- package/assets/skills/comet/scripts/comet-entry-runtime.mjs +118 -6
- package/assets/skills/comet/scripts/comet-hook-router.mjs +244 -26
- package/assets/skills/comet/scripts/comet-runtime.mjs +221 -104
- package/assets/skills/comet-archive/SKILL.md +29 -20
- package/assets/skills/comet-native/SKILL.md +23 -15
- package/assets/skills/comet-native/reference/artifacts.md +19 -4
- package/assets/skills/comet-native/reference/commands.md +8 -2
- package/assets/skills/comet-native/reference/recovery.md +1 -1
- package/assets/skills/comet-native/scripts/comet-native-runtime.mjs +1136 -471
- package/assets/skills-zh/comet/reference/comet-yaml-fields.md +2 -2
- package/assets/skills-zh/comet-archive/SKILL.md +29 -20
- package/assets/skills-zh/comet-native/SKILL.md +23 -15
- package/assets/skills-zh/comet-native/reference/artifacts.md +20 -5
- package/assets/skills-zh/comet-native/reference/commands.md +8 -2
- package/assets/skills-zh/comet-native/reference/recovery.md +1 -1
- package/dist/app/commands/init.d.ts.map +1 -1
- package/dist/app/commands/init.js +3 -6
- package/dist/app/commands/init.js.map +1 -1
- package/dist/domains/bundle/bundle-platform.d.ts.map +1 -1
- package/dist/domains/bundle/bundle-platform.js +1 -1
- package/dist/domains/bundle/bundle-platform.js.map +1 -1
- package/dist/domains/comet-classic/classic-guard.d.ts.map +1 -1
- package/dist/domains/comet-classic/classic-guard.js +3 -2
- package/dist/domains/comet-classic/classic-guard.js.map +1 -1
- package/dist/domains/comet-entry/current-selection.d.ts.map +1 -1
- package/dist/domains/comet-entry/current-selection.js +6 -8
- package/dist/domains/comet-entry/current-selection.js.map +1 -1
- package/dist/domains/comet-entry/project-status.d.ts.map +1 -1
- package/dist/domains/comet-entry/project-status.js +5 -1
- package/dist/domains/comet-entry/project-status.js.map +1 -1
- package/dist/domains/comet-native/native-archive-transaction.d.ts.map +1 -1
- package/dist/domains/comet-native/native-archive-transaction.js +5 -6
- package/dist/domains/comet-native/native-archive-transaction.js.map +1 -1
- package/dist/domains/comet-native/native-atomic-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-atomic-file.js +11 -7
- package/dist/domains/comet-native/native-atomic-file.js.map +1 -1
- package/dist/domains/comet-native/native-bounded-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-bounded-file.js +11 -7
- package/dist/domains/comet-native/native-bounded-file.js.map +1 -1
- package/dist/domains/comet-native/native-build-evidence.js +2 -2
- package/dist/domains/comet-native/native-build-evidence.js.map +1 -1
- package/dist/domains/comet-native/native-change.d.ts +4 -2
- package/dist/domains/comet-native/native-change.d.ts.map +1 -1
- package/dist/domains/comet-native/native-change.js +18 -4
- package/dist/domains/comet-native/native-change.js.map +1 -1
- package/dist/domains/comet-native/native-check-receipt-storage.d.ts.map +1 -1
- package/dist/domains/comet-native/native-check-receipt-storage.js +11 -7
- package/dist/domains/comet-native/native-check-receipt-storage.js.map +1 -1
- package/dist/domains/comet-native/native-check-receipt.d.ts.map +1 -1
- package/dist/domains/comet-native/native-check-receipt.js +16 -11
- package/dist/domains/comet-native/native-check-receipt.js.map +1 -1
- package/dist/domains/comet-native/native-cli.d.ts.map +1 -1
- package/dist/domains/comet-native/native-cli.js +120 -16
- package/dist/domains/comet-native/native-cli.js.map +1 -1
- package/dist/domains/comet-native/native-config.d.ts +5 -1
- package/dist/domains/comet-native/native-config.d.ts.map +1 -1
- package/dist/domains/comet-native/native-config.js +78 -0
- package/dist/domains/comet-native/native-config.js.map +1 -1
- package/dist/domains/comet-native/native-continuation.d.ts +2 -1
- package/dist/domains/comet-native/native-continuation.d.ts.map +1 -1
- package/dist/domains/comet-native/native-continuation.js +13 -5
- package/dist/domains/comet-native/native-continuation.js.map +1 -1
- package/dist/domains/comet-native/native-diagnostics.d.ts +7 -3
- package/dist/domains/comet-native/native-diagnostics.d.ts.map +1 -1
- package/dist/domains/comet-native/native-diagnostics.js +19 -9
- package/dist/domains/comet-native/native-diagnostics.js.map +1 -1
- package/dist/domains/comet-native/native-evidence-retention.d.ts.map +1 -1
- package/dist/domains/comet-native/native-evidence-retention.js +5 -3
- package/dist/domains/comet-native/native-evidence-retention.js.map +1 -1
- package/dist/domains/comet-native/native-evidence-storage.d.ts.map +1 -1
- package/dist/domains/comet-native/native-evidence-storage.js +11 -7
- package/dist/domains/comet-native/native-evidence-storage.js.map +1 -1
- package/dist/domains/comet-native/native-file-identity.d.ts +3 -0
- package/dist/domains/comet-native/native-file-identity.d.ts.map +1 -0
- package/dist/domains/comet-native/native-file-identity.js +2 -0
- package/dist/domains/comet-native/native-file-identity.js.map +1 -0
- package/dist/domains/comet-native/native-findings.d.ts.map +1 -1
- package/dist/domains/comet-native/native-findings.js +19 -1
- package/dist/domains/comet-native/native-findings.js.map +1 -1
- package/dist/domains/comet-native/native-guards.d.ts +2 -1
- package/dist/domains/comet-native/native-guards.d.ts.map +1 -1
- package/dist/domains/comet-native/native-guards.js +14 -0
- package/dist/domains/comet-native/native-guards.js.map +1 -1
- package/dist/domains/comet-native/native-lock.d.ts.map +1 -1
- package/dist/domains/comet-native/native-lock.js +30 -35
- package/dist/domains/comet-native/native-lock.js.map +1 -1
- package/dist/domains/comet-native/native-protected-file.d.ts.map +1 -1
- package/dist/domains/comet-native/native-protected-file.js +9 -8
- package/dist/domains/comet-native/native-protected-file.js.map +1 -1
- package/dist/domains/comet-native/native-root-move.d.ts.map +1 -1
- package/dist/domains/comet-native/native-root-move.js +2 -0
- package/dist/domains/comet-native/native-root-move.js.map +1 -1
- package/dist/domains/comet-native/native-run-store.d.ts.map +1 -1
- package/dist/domains/comet-native/native-run-store.js +9 -8
- package/dist/domains/comet-native/native-run-store.js.map +1 -1
- package/dist/domains/comet-native/native-snapshot.d.ts +5 -1
- package/dist/domains/comet-native/native-snapshot.d.ts.map +1 -1
- package/dist/domains/comet-native/native-snapshot.js +225 -5
- package/dist/domains/comet-native/native-snapshot.js.map +1 -1
- package/dist/domains/comet-native/native-transitions.d.ts +2 -1
- package/dist/domains/comet-native/native-transitions.d.ts.map +1 -1
- package/dist/domains/comet-native/native-transitions.js +34 -11
- package/dist/domains/comet-native/native-transitions.js.map +1 -1
- package/dist/domains/comet-native/native-types.d.ts +16 -0
- package/dist/domains/comet-native/native-types.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-runtime.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-runtime.js +5 -3
- package/dist/domains/comet-native/native-verification-runtime.js.map +1 -1
- package/dist/domains/comet-native/native-verification-scope.d.ts +2 -1
- package/dist/domains/comet-native/native-verification-scope.d.ts.map +1 -1
- package/dist/domains/comet-native/native-verification-scope.js +6 -1
- package/dist/domains/comet-native/native-verification-scope.js.map +1 -1
- package/dist/domains/dashboard/native-collector.d.ts.map +1 -1
- package/dist/domains/dashboard/native-collector.js +4 -1
- package/dist/domains/dashboard/native-collector.js.map +1 -1
- package/dist/domains/dashboard/web/index.html +14 -14
- package/dist/domains/skill/platform-install.d.ts.map +1 -1
- package/dist/domains/skill/platform-install.js +9 -0
- package/dist/domains/skill/platform-install.js.map +1 -1
- package/dist/domains/skill/project-instructions.d.ts.map +1 -1
- package/dist/domains/skill/project-instructions.js +4 -2
- package/dist/domains/skill/project-instructions.js.map +1 -1
- package/dist/domains/workflow-contract/project-config.d.ts +1 -1
- package/dist/domains/workflow-contract/project-config.d.ts.map +1 -1
- package/dist/domains/workflow-contract/project-config.js +24 -2
- package/dist/domains/workflow-contract/project-config.js.map +1 -1
- package/dist/platform/fs/file-identity.d.ts +9 -0
- package/dist/platform/fs/file-identity.d.ts.map +1 -0
- package/dist/platform/fs/file-identity.js +21 -0
- package/dist/platform/fs/file-identity.js.map +1 -0
- package/dist/platform/fs/file-system.d.ts.map +1 -1
- package/dist/platform/fs/file-system.js +13 -9
- package/dist/platform/fs/file-system.js.map +1 -1
- package/dist/platform/fs/race-safe-read.d.ts +47 -0
- package/dist/platform/fs/race-safe-read.d.ts.map +1 -0
- package/dist/platform/fs/race-safe-read.js +132 -0
- package/dist/platform/fs/race-safe-read.js.map +1 -0
- package/eval/README.md +1 -1
- package/eval/local/tasks/comet-native-clarification-depth/environment/Dockerfile +27 -0
- package/eval/local/tasks/comet-native-clarification-depth/environment/test_wordcount.py +25 -0
- package/eval/local/tasks/comet-native-clarification-depth/environment/wordcount.py +36 -0
- package/eval/local/tasks/comet-native-clarification-depth/instruction.md +17 -0
- package/eval/local/tasks/comet-native-clarification-depth/task.toml +47 -0
- package/eval/local/tasks/comet-native-clarification-depth/validation/test_native_clarification_depth.py +618 -0
- package/eval/local/tasks/comet-native-clarification-modes/validation/test_native_clarification_modes.py +1 -1
- package/eval/local/tasks/index.yaml +6 -0
- package/eval/local/tests/conftest.py +146 -2
- package/eval/local/tests/scaffold/test_conftest_helpers.py +188 -1
- package/eval/local/tests/scaffold/test_tasks.py +440 -8
- package/eval/local/tests/scaffold/test_utils.py +114 -1
- package/eval/local/tests/tasks/test_tasks.py +2 -0
- package/eval/pyproject.toml +4 -4
- package/eval/scaffold/python/aligned_comparison.py +1 -0
- package/eval/scaffold/python/tasks.py +2 -0
- package/eval/scaffold/shell/docker.sh +1 -1
- package/eval/scaffold/shell/run-claude-loop.sh +25 -2
- package/package.json +8 -1
|
@@ -6927,14 +6927,14 @@ var require_parser = __commonJS({
|
|
|
6927
6927
|
case "scalar":
|
|
6928
6928
|
case "single-quoted-scalar":
|
|
6929
6929
|
case "double-quoted-scalar": {
|
|
6930
|
-
const
|
|
6930
|
+
const fs24 = this.flowScalar(this.type);
|
|
6931
6931
|
if (atNextItem || it.value) {
|
|
6932
|
-
map.items.push({ start, key:
|
|
6932
|
+
map.items.push({ start, key: fs24, sep: [] });
|
|
6933
6933
|
this.onKeyLine = true;
|
|
6934
6934
|
} else if (it.sep) {
|
|
6935
|
-
this.stack.push(
|
|
6935
|
+
this.stack.push(fs24);
|
|
6936
6936
|
} else {
|
|
6937
|
-
Object.assign(it, { key:
|
|
6937
|
+
Object.assign(it, { key: fs24, sep: [] });
|
|
6938
6938
|
this.onKeyLine = true;
|
|
6939
6939
|
}
|
|
6940
6940
|
return;
|
|
@@ -7062,13 +7062,13 @@ var require_parser = __commonJS({
|
|
|
7062
7062
|
case "scalar":
|
|
7063
7063
|
case "single-quoted-scalar":
|
|
7064
7064
|
case "double-quoted-scalar": {
|
|
7065
|
-
const
|
|
7065
|
+
const fs24 = this.flowScalar(this.type);
|
|
7066
7066
|
if (!it || it.value)
|
|
7067
|
-
fc.items.push({ start: [], key:
|
|
7067
|
+
fc.items.push({ start: [], key: fs24, sep: [] });
|
|
7068
7068
|
else if (it.sep)
|
|
7069
|
-
this.stack.push(
|
|
7069
|
+
this.stack.push(fs24);
|
|
7070
7070
|
else
|
|
7071
|
-
Object.assign(it, { key:
|
|
7071
|
+
Object.assign(it, { key: fs24, sep: [] });
|
|
7072
7072
|
return;
|
|
7073
7073
|
}
|
|
7074
7074
|
case "flow-map-end":
|
|
@@ -7546,7 +7546,7 @@ import { pathToFileURL } from "url";
|
|
|
7546
7546
|
// domains/comet-classic/classic-archive.ts
|
|
7547
7547
|
import { createHash as createHash3 } from "crypto";
|
|
7548
7548
|
import { spawnSync } from "child_process";
|
|
7549
|
-
import { promises as
|
|
7549
|
+
import { promises as fs15 } from "fs";
|
|
7550
7550
|
import path15 from "path";
|
|
7551
7551
|
|
|
7552
7552
|
// domains/comet-classic/classic-paths.ts
|
|
@@ -9531,13 +9531,133 @@ function applyClassicTransition(current, event, options = {}) {
|
|
|
9531
9531
|
}
|
|
9532
9532
|
|
|
9533
9533
|
// domains/comet-classic/classic-current-change.ts
|
|
9534
|
-
import { promises as
|
|
9534
|
+
import { promises as fs14 } from "fs";
|
|
9535
9535
|
import path14 from "path";
|
|
9536
9536
|
|
|
9537
9537
|
// domains/comet-entry/current-selection.ts
|
|
9538
9538
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
9539
|
-
import { promises as
|
|
9539
|
+
import { promises as fs12 } from "fs";
|
|
9540
9540
|
import path12 from "path";
|
|
9541
|
+
|
|
9542
|
+
// platform/fs/race-safe-read.ts
|
|
9543
|
+
import { constants as fsConstants, promises as fs11 } from "fs";
|
|
9544
|
+
|
|
9545
|
+
// platform/fs/file-identity.ts
|
|
9546
|
+
function hasPlatformIdentity(value) {
|
|
9547
|
+
return value !== 0 && value !== 0n && value !== "0";
|
|
9548
|
+
}
|
|
9549
|
+
function hasComparableFileObject(left, right) {
|
|
9550
|
+
return hasPlatformIdentity(left.dev) && hasPlatformIdentity(right.dev) && hasPlatformIdentity(left.ino) && hasPlatformIdentity(right.ino);
|
|
9551
|
+
}
|
|
9552
|
+
function sameFileObject(left, right) {
|
|
9553
|
+
const comparableDevice = hasPlatformIdentity(left.dev) && hasPlatformIdentity(right.dev);
|
|
9554
|
+
if (comparableDevice && left.dev !== right.dev) return false;
|
|
9555
|
+
const comparableInode = hasPlatformIdentity(left.ino) && hasPlatformIdentity(right.ino);
|
|
9556
|
+
if (comparableInode && left.ino !== right.ino) return false;
|
|
9557
|
+
if (comparableDevice && comparableInode) return true;
|
|
9558
|
+
return left.birthtime === right.birthtime;
|
|
9559
|
+
}
|
|
9560
|
+
|
|
9561
|
+
// platform/fs/race-safe-read.ts
|
|
9562
|
+
var RaceSafeReadError = class extends Error {
|
|
9563
|
+
reason;
|
|
9564
|
+
constructor(reason, message, options) {
|
|
9565
|
+
super(message, options);
|
|
9566
|
+
this.name = "RaceSafeReadError";
|
|
9567
|
+
this.reason = reason;
|
|
9568
|
+
}
|
|
9569
|
+
};
|
|
9570
|
+
function birthtimeOf(stat) {
|
|
9571
|
+
return "birthtimeNs" in stat && typeof stat.birthtimeNs === "bigint" ? stat.birthtimeNs : stat.birthtimeMs;
|
|
9572
|
+
}
|
|
9573
|
+
function ctimeOf(stat) {
|
|
9574
|
+
return "ctimeNs" in stat && typeof stat.ctimeNs === "bigint" ? stat.ctimeNs : stat.ctimeMs;
|
|
9575
|
+
}
|
|
9576
|
+
function identityOf(stat) {
|
|
9577
|
+
return { dev: stat.dev, ino: stat.ino, birthtime: birthtimeOf(stat) };
|
|
9578
|
+
}
|
|
9579
|
+
function sameStatIdentity(left, right) {
|
|
9580
|
+
const leftObject = identityOf(left);
|
|
9581
|
+
const rightObject = identityOf(right);
|
|
9582
|
+
if (hasComparableFileObject(leftObject, rightObject)) {
|
|
9583
|
+
return sameFileObject(leftObject, rightObject);
|
|
9584
|
+
}
|
|
9585
|
+
return sameFileObject(leftObject, rightObject) && birthtimeOf(left) === birthtimeOf(right) && ctimeOf(left) === ctimeOf(right) && left.size === right.size;
|
|
9586
|
+
}
|
|
9587
|
+
async function readFileRaceSafe(file, maxBytes, options = {}) {
|
|
9588
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1) {
|
|
9589
|
+
throw new Error("race-safe read byte limit must be a positive integer");
|
|
9590
|
+
}
|
|
9591
|
+
const label = options.label ?? "file";
|
|
9592
|
+
const bigint = options.bigint === true;
|
|
9593
|
+
const before = await fs11.lstat(file, { bigint });
|
|
9594
|
+
if (!before.isFile() || before.isSymbolicLink()) {
|
|
9595
|
+
throw new RaceSafeReadError("not-regular-file", `${label} must be a regular file`);
|
|
9596
|
+
}
|
|
9597
|
+
if (BigInt(before.size) > BigInt(maxBytes)) {
|
|
9598
|
+
throw new RaceSafeReadError("too-large", `${label} exceeds ${maxBytes} bytes`);
|
|
9599
|
+
}
|
|
9600
|
+
const beforeRealPath = await fs11.realpath(file);
|
|
9601
|
+
await options.verify?.("pre-open", { realPath: beforeRealPath, identity: identityOf(before) });
|
|
9602
|
+
const flags = process.platform === "win32" ? fsConstants.O_RDONLY : fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_NONBLOCK;
|
|
9603
|
+
let handle;
|
|
9604
|
+
try {
|
|
9605
|
+
handle = await fs11.open(file, flags);
|
|
9606
|
+
} catch (error) {
|
|
9607
|
+
if (error.code === "ELOOP") {
|
|
9608
|
+
throw new RaceSafeReadError("not-regular-file", `${label} must be a regular file`, {
|
|
9609
|
+
cause: error
|
|
9610
|
+
});
|
|
9611
|
+
}
|
|
9612
|
+
throw error;
|
|
9613
|
+
}
|
|
9614
|
+
try {
|
|
9615
|
+
const [opened, pathAfterOpen, realPathAfterOpen] = await Promise.all([
|
|
9616
|
+
handle.stat({ bigint }),
|
|
9617
|
+
fs11.lstat(file, { bigint }),
|
|
9618
|
+
fs11.realpath(file)
|
|
9619
|
+
]);
|
|
9620
|
+
if (!opened.isFile() || !pathAfterOpen.isFile() || pathAfterOpen.isSymbolicLink() || realPathAfterOpen !== beforeRealPath || !sameStatIdentity(before, opened) || !sameStatIdentity(before, pathAfterOpen)) {
|
|
9621
|
+
throw new RaceSafeReadError("changed", `${label} changed while opening`);
|
|
9622
|
+
}
|
|
9623
|
+
await options.verify?.("post-open", {
|
|
9624
|
+
realPath: realPathAfterOpen,
|
|
9625
|
+
identity: identityOf(opened)
|
|
9626
|
+
});
|
|
9627
|
+
await options.hooks?.afterOpen?.();
|
|
9628
|
+
const chunks = [];
|
|
9629
|
+
let total = 0;
|
|
9630
|
+
const buffer = Buffer.allocUnsafe(Math.min(64 * 1024, maxBytes + 1));
|
|
9631
|
+
for (; ; ) {
|
|
9632
|
+
const remaining = maxBytes + 1 - total;
|
|
9633
|
+
const { bytesRead } = await handle.read(buffer, 0, Math.min(buffer.length, remaining), null);
|
|
9634
|
+
if (bytesRead === 0) break;
|
|
9635
|
+
total += bytesRead;
|
|
9636
|
+
if (total > maxBytes) {
|
|
9637
|
+
throw new RaceSafeReadError("too-large", `${label} exceeds ${maxBytes} bytes`);
|
|
9638
|
+
}
|
|
9639
|
+
chunks.push(Buffer.from(buffer.subarray(0, bytesRead)));
|
|
9640
|
+
}
|
|
9641
|
+
await options.hooks?.beforeFinalCheck?.();
|
|
9642
|
+
const [afterHandle, afterPath, afterRealPath] = await Promise.all([
|
|
9643
|
+
handle.stat({ bigint }),
|
|
9644
|
+
fs11.lstat(file, { bigint }),
|
|
9645
|
+
fs11.realpath(file)
|
|
9646
|
+
]);
|
|
9647
|
+
if (!afterPath.isFile() || afterPath.isSymbolicLink() || afterRealPath !== beforeRealPath || !sameStatIdentity(before, afterHandle) || !sameStatIdentity(before, afterPath)) {
|
|
9648
|
+
throw new RaceSafeReadError("changed", `${label} changed while reading`);
|
|
9649
|
+
}
|
|
9650
|
+
await options.verify?.("post-read", {
|
|
9651
|
+
realPath: afterRealPath,
|
|
9652
|
+
identity: identityOf(afterHandle)
|
|
9653
|
+
});
|
|
9654
|
+
return { bytes: Buffer.concat(chunks, total), stat: afterHandle, realPath: afterRealPath };
|
|
9655
|
+
} finally {
|
|
9656
|
+
await handle.close();
|
|
9657
|
+
}
|
|
9658
|
+
}
|
|
9659
|
+
|
|
9660
|
+
// domains/comet-entry/current-selection.ts
|
|
9541
9661
|
var COMET_CURRENT_SELECTION_SCHEMA = "comet.selection.v2";
|
|
9542
9662
|
var COMET_CURRENT_SELECTION_MAX_BYTES = 16 * 1024;
|
|
9543
9663
|
function cometCurrentSelectionFile(projectRoot2) {
|
|
@@ -9599,16 +9719,11 @@ function parseSelection(source) {
|
|
|
9599
9719
|
async function readCometCurrentSelection(projectRoot2) {
|
|
9600
9720
|
let source;
|
|
9601
9721
|
try {
|
|
9602
|
-
const
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
}
|
|
9606
|
-
|
|
9607
|
-
throw new Error(
|
|
9608
|
-
`current change selection exceeds ${COMET_CURRENT_SELECTION_MAX_BYTES} bytes`
|
|
9609
|
-
);
|
|
9610
|
-
}
|
|
9611
|
-
source = await fs11.readFile(cometCurrentSelectionFile(projectRoot2), "utf8");
|
|
9722
|
+
const file = cometCurrentSelectionFile(projectRoot2);
|
|
9723
|
+
const { bytes } = await readFileRaceSafe(file, COMET_CURRENT_SELECTION_MAX_BYTES, {
|
|
9724
|
+
label: "current change selection"
|
|
9725
|
+
});
|
|
9726
|
+
source = bytes.toString("utf8");
|
|
9612
9727
|
} catch (error) {
|
|
9613
9728
|
if (error.code === "ENOENT") return { status: "missing" };
|
|
9614
9729
|
throw new Error(
|
|
@@ -9624,18 +9739,18 @@ async function writeCometCurrentSelection(projectRoot2, selection) {
|
|
|
9624
9739
|
if (parsed.legacy) throw new Error("cannot write a legacy current change selection");
|
|
9625
9740
|
const file = cometCurrentSelectionFile(projectRoot2);
|
|
9626
9741
|
const temporary = `${file}.${randomUUID6()}.tmp`;
|
|
9627
|
-
await
|
|
9742
|
+
await fs12.mkdir(path12.dirname(file), { recursive: true });
|
|
9628
9743
|
try {
|
|
9629
|
-
await
|
|
9744
|
+
await fs12.writeFile(temporary, `${JSON.stringify(parsed.selection, null, 2)}
|
|
9630
9745
|
`, "utf8");
|
|
9631
|
-
await
|
|
9746
|
+
await fs12.rename(temporary, file);
|
|
9632
9747
|
} catch (error) {
|
|
9633
|
-
await
|
|
9748
|
+
await fs12.rm(temporary, { force: true });
|
|
9634
9749
|
throw error;
|
|
9635
9750
|
}
|
|
9636
9751
|
}
|
|
9637
9752
|
async function clearCometCurrentSelection(projectRoot2) {
|
|
9638
|
-
await
|
|
9753
|
+
await fs12.rm(cometCurrentSelectionFile(projectRoot2), { force: true });
|
|
9639
9754
|
}
|
|
9640
9755
|
async function clearCometCurrentSelectionIf(projectRoot2, workflow, change) {
|
|
9641
9756
|
const current = await readCometCurrentSelection(projectRoot2);
|
|
@@ -9650,7 +9765,7 @@ async function clearCometCurrentSelectionIf(projectRoot2, workflow, change) {
|
|
|
9650
9765
|
var import_yaml3 = __toESM(require_dist(), 1);
|
|
9651
9766
|
import { execFileSync } from "child_process";
|
|
9652
9767
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
9653
|
-
import { promises as
|
|
9768
|
+
import { promises as fs13 } from "fs";
|
|
9654
9769
|
import path13 from "path";
|
|
9655
9770
|
function liveGitBranch(cwd) {
|
|
9656
9771
|
try {
|
|
@@ -9692,7 +9807,7 @@ function evaluateBranchBinding(input) {
|
|
|
9692
9807
|
}
|
|
9693
9808
|
async function resolveBranchBinding(changeDir, options) {
|
|
9694
9809
|
const file = path13.join(changeDir, ".comet.yaml");
|
|
9695
|
-
const document = (0, import_yaml3.parseDocument)(await
|
|
9810
|
+
const document = (0, import_yaml3.parseDocument)(await fs13.readFile(file, "utf8"), { uniqueKeys: false });
|
|
9696
9811
|
if (document.errors.length > 0) {
|
|
9697
9812
|
throw new Error(`Invalid .comet.yaml: ${document.errors[0].message}`);
|
|
9698
9813
|
}
|
|
@@ -9711,14 +9826,14 @@ async function resolveBranchBinding(changeDir, options) {
|
|
|
9711
9826
|
}
|
|
9712
9827
|
async function healBoundBranch(changeDir, branch) {
|
|
9713
9828
|
const file = path13.join(changeDir, ".comet.yaml");
|
|
9714
|
-
const document = (0, import_yaml3.parseDocument)(await
|
|
9829
|
+
const document = (0, import_yaml3.parseDocument)(await fs13.readFile(file, "utf8"), { uniqueKeys: false });
|
|
9715
9830
|
document.set("bound_branch", branch);
|
|
9716
9831
|
const temporary = `${file}.${randomUUID7()}.tmp`;
|
|
9717
9832
|
try {
|
|
9718
|
-
await
|
|
9719
|
-
await
|
|
9833
|
+
await fs13.writeFile(temporary, document.toString(), "utf8");
|
|
9834
|
+
await fs13.rename(temporary, file);
|
|
9720
9835
|
} catch (error) {
|
|
9721
|
-
await
|
|
9836
|
+
await fs13.rm(temporary, { force: true });
|
|
9722
9837
|
throw error;
|
|
9723
9838
|
}
|
|
9724
9839
|
}
|
|
@@ -9744,7 +9859,7 @@ async function validateActiveChange(projectRoot2, changeName) {
|
|
|
9744
9859
|
assertOpenSpecChangeName(changeName);
|
|
9745
9860
|
const changeDir = changeDirectory(projectRoot2, changeName);
|
|
9746
9861
|
try {
|
|
9747
|
-
await
|
|
9862
|
+
await fs14.access(path14.join(changeDir, ".comet.yaml"));
|
|
9748
9863
|
} catch (error) {
|
|
9749
9864
|
if (error.code === "ENOENT") {
|
|
9750
9865
|
throw new Error(
|
|
@@ -9882,7 +9997,7 @@ var ArchiveOutput = class {
|
|
|
9882
9997
|
};
|
|
9883
9998
|
async function exists2(file) {
|
|
9884
9999
|
try {
|
|
9885
|
-
await
|
|
10000
|
+
await fs15.access(file);
|
|
9886
10001
|
return true;
|
|
9887
10002
|
} catch (error) {
|
|
9888
10003
|
if (error.code === "ENOENT") return false;
|
|
@@ -9936,10 +10051,10 @@ async function findArchiveDir(change, preferred) {
|
|
|
9936
10051
|
if (await exists2(preferred)) return preferred;
|
|
9937
10052
|
const archiveRoot = "openspec/changes/archive";
|
|
9938
10053
|
if (!await exists2(archiveRoot)) return null;
|
|
9939
|
-
for (const entry2 of (await
|
|
10054
|
+
for (const entry2 of (await fs15.readdir(archiveRoot)).sort()) {
|
|
9940
10055
|
if (!entry2.endsWith(`-${change}`)) continue;
|
|
9941
10056
|
const candidate = `${archiveRoot}/${entry2}`;
|
|
9942
|
-
if ((await
|
|
10057
|
+
if ((await fs15.stat(candidate)).isDirectory()) return candidate;
|
|
9943
10058
|
}
|
|
9944
10059
|
return null;
|
|
9945
10060
|
}
|
|
@@ -9969,9 +10084,9 @@ async function annotateFrontmatter(output, file, archiveName, extraFields, dryRu
|
|
|
9969
10084
|
output.stepsTotal += 1;
|
|
9970
10085
|
return;
|
|
9971
10086
|
}
|
|
9972
|
-
const original = await
|
|
10087
|
+
const original = await fs15.readFile(file, "utf8");
|
|
9973
10088
|
const updated = annotatedMarkdown(original, archiveName, extraFields);
|
|
9974
|
-
await
|
|
10089
|
+
await fs15.writeFile(file, updated);
|
|
9975
10090
|
output.stderr.push(green(` [OK] Annotated: ${file}`));
|
|
9976
10091
|
output.stepsOk += 1;
|
|
9977
10092
|
output.stepsTotal += 1;
|
|
@@ -9980,10 +10095,10 @@ async function verifyMainSpecsClean() {
|
|
|
9980
10095
|
const specsRoot = "openspec/specs";
|
|
9981
10096
|
if (!await exists2(specsRoot)) return;
|
|
9982
10097
|
let found = false;
|
|
9983
|
-
for (const entry2 of await
|
|
10098
|
+
for (const entry2 of await fs15.readdir(specsRoot)) {
|
|
9984
10099
|
const specFile = `${specsRoot}/${entry2}/spec.md`;
|
|
9985
10100
|
if (!await exists2(specFile)) continue;
|
|
9986
|
-
const matches = (await
|
|
10101
|
+
const matches = (await fs15.readFile(specFile, "utf8")).split(/\r?\n/u).map((line, index) => ({ line, number: index + 1 })).filter((item) => /^## (ADDED|MODIFIED|REMOVED|RENAMED) Requirements$/u.test(item.line));
|
|
9987
10102
|
if (matches.length > 0) {
|
|
9988
10103
|
found = true;
|
|
9989
10104
|
process.stderr.write(
|
|
@@ -10238,7 +10353,7 @@ var classicArchiveCommand = async (args) => {
|
|
|
10238
10353
|
var import_yaml6 = __toESM(require_dist(), 1);
|
|
10239
10354
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10240
10355
|
import { createHash as createHash4 } from "crypto";
|
|
10241
|
-
import { existsSync, promises as
|
|
10356
|
+
import { existsSync, promises as fs19, readFileSync } from "fs";
|
|
10242
10357
|
import path19 from "path";
|
|
10243
10358
|
|
|
10244
10359
|
// domains/comet-classic/classic-command-checks.ts
|
|
@@ -10420,7 +10535,7 @@ async function inspectClassicChange(changeDir, name) {
|
|
|
10420
10535
|
|
|
10421
10536
|
// domains/comet-classic/classic-validate-command.ts
|
|
10422
10537
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
10423
|
-
import { promises as
|
|
10538
|
+
import { promises as fs16 } from "fs";
|
|
10424
10539
|
import path17 from "path";
|
|
10425
10540
|
var GREEN2 = "\x1B[32m";
|
|
10426
10541
|
var RED2 = "\x1B[31m";
|
|
@@ -10471,7 +10586,7 @@ function color(code, message) {
|
|
|
10471
10586
|
}
|
|
10472
10587
|
async function exists3(file) {
|
|
10473
10588
|
try {
|
|
10474
|
-
await
|
|
10589
|
+
await fs16.access(file);
|
|
10475
10590
|
return true;
|
|
10476
10591
|
} catch (error) {
|
|
10477
10592
|
if (error.code === "ENOENT") return false;
|
|
@@ -10506,7 +10621,7 @@ var classicValidateCommand = async (args) => {
|
|
|
10506
10621
|
};
|
|
10507
10622
|
let source;
|
|
10508
10623
|
try {
|
|
10509
|
-
source = await
|
|
10624
|
+
source = await fs16.readFile(yamlFile, "utf8");
|
|
10510
10625
|
} catch (error) {
|
|
10511
10626
|
if (error.code === "ENOENT") {
|
|
10512
10627
|
fail3(".comet.yaml does not exist");
|
|
@@ -10580,23 +10695,23 @@ var classicValidateCommand = async (args) => {
|
|
|
10580
10695
|
// domains/comet-classic/classic-project-config.ts
|
|
10581
10696
|
var import_yaml5 = __toESM(require_dist(), 1);
|
|
10582
10697
|
import os from "os";
|
|
10583
|
-
import { promises as
|
|
10698
|
+
import { promises as fs18 } from "fs";
|
|
10584
10699
|
import path18 from "path";
|
|
10585
10700
|
|
|
10586
10701
|
// platform/fs/file-system.ts
|
|
10587
|
-
import { promises as
|
|
10702
|
+
import { promises as fs17 } from "fs";
|
|
10588
10703
|
async function fileExists3(filePath) {
|
|
10589
10704
|
try {
|
|
10590
|
-
await
|
|
10705
|
+
await fs17.access(filePath);
|
|
10591
10706
|
return true;
|
|
10592
10707
|
} catch (error) {
|
|
10593
|
-
if (
|
|
10708
|
+
if (isMissingPathError(error)) return false;
|
|
10594
10709
|
throw error;
|
|
10595
10710
|
}
|
|
10596
10711
|
}
|
|
10597
10712
|
async function readDir(dirPath) {
|
|
10598
10713
|
try {
|
|
10599
|
-
return await
|
|
10714
|
+
return await fs17.readdir(dirPath);
|
|
10600
10715
|
} catch (error) {
|
|
10601
10716
|
const code = error?.code;
|
|
10602
10717
|
if (code === "ENOENT" || code === "ENOTDIR") {
|
|
@@ -10605,8 +10720,9 @@ async function readDir(dirPath) {
|
|
|
10605
10720
|
throw error;
|
|
10606
10721
|
}
|
|
10607
10722
|
}
|
|
10608
|
-
function
|
|
10609
|
-
|
|
10723
|
+
function isMissingPathError(error) {
|
|
10724
|
+
const code = error?.code;
|
|
10725
|
+
return code === "ENOENT" || code === "ENOTDIR";
|
|
10610
10726
|
}
|
|
10611
10727
|
|
|
10612
10728
|
// domains/comet-classic/classic-project-config.ts
|
|
@@ -10627,7 +10743,7 @@ function configCandidates(options = {}) {
|
|
|
10627
10743
|
async function readClassicConfigValue(field2, options = {}) {
|
|
10628
10744
|
for (const candidate of configCandidates(options)) {
|
|
10629
10745
|
if (!await fileExists3(candidate.file)) continue;
|
|
10630
|
-
const document = (0, import_yaml5.parseDocument)(await
|
|
10746
|
+
const document = (0, import_yaml5.parseDocument)(await fs18.readFile(candidate.file, "utf8"), {
|
|
10631
10747
|
uniqueKeys: false
|
|
10632
10748
|
});
|
|
10633
10749
|
const root = document.toJS();
|
|
@@ -10705,7 +10821,7 @@ var GuardOutput = class {
|
|
|
10705
10821
|
};
|
|
10706
10822
|
async function exists4(file) {
|
|
10707
10823
|
try {
|
|
10708
|
-
await
|
|
10824
|
+
await fs19.access(file);
|
|
10709
10825
|
return true;
|
|
10710
10826
|
} catch (error) {
|
|
10711
10827
|
if (error.code === "ENOENT") return false;
|
|
@@ -10714,7 +10830,7 @@ async function exists4(file) {
|
|
|
10714
10830
|
}
|
|
10715
10831
|
async function nonempty(file) {
|
|
10716
10832
|
try {
|
|
10717
|
-
return (await
|
|
10833
|
+
return (await fs19.stat(file)).size > 0;
|
|
10718
10834
|
} catch (error) {
|
|
10719
10835
|
if (error.code === "ENOENT") return false;
|
|
10720
10836
|
throw error;
|
|
@@ -10729,7 +10845,7 @@ async function resolveChangeDir(name) {
|
|
|
10729
10845
|
}
|
|
10730
10846
|
async function readField(changeDir, field2) {
|
|
10731
10847
|
const file = path19.join(changeDir, ".comet.yaml");
|
|
10732
|
-
const document = (0, import_yaml6.parseDocument)(await
|
|
10848
|
+
const document = (0, import_yaml6.parseDocument)(await fs19.readFile(file, "utf8"), { uniqueKeys: false });
|
|
10733
10849
|
if (document.errors.length > 0) {
|
|
10734
10850
|
throw new GuardFailure(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
|
|
10735
10851
|
}
|
|
@@ -10770,7 +10886,7 @@ function countEnglishWords(source) {
|
|
|
10770
10886
|
}
|
|
10771
10887
|
async function documentLanguageMatchesConfigured(changeDir, file) {
|
|
10772
10888
|
const language = await configuredLanguage(changeDir);
|
|
10773
|
-
const source = stripFencedCodeBlocks(await
|
|
10889
|
+
const source = stripFencedCodeBlocks(await fs19.readFile(file, "utf8"));
|
|
10774
10890
|
const cjk = countCjkChars(source);
|
|
10775
10891
|
const englishWords = countEnglishWords(source);
|
|
10776
10892
|
if (language === "zh-CN" && cjk < 20 && englishWords >= 20) {
|
|
@@ -10794,7 +10910,7 @@ async function handoffSourceFiles(changeDir) {
|
|
|
10794
10910
|
const files = [`${changeDir}/proposal.md`, `${changeDir}/design.md`, `${changeDir}/tasks.md`];
|
|
10795
10911
|
const specs = `${changeDir}/specs`;
|
|
10796
10912
|
if (await exists4(specs)) {
|
|
10797
|
-
for (const entry2 of (await
|
|
10913
|
+
for (const entry2 of (await fs19.readdir(specs)).sort()) {
|
|
10798
10914
|
const spec = `${specs}/${entry2}/spec.md`;
|
|
10799
10915
|
if (await exists4(spec)) files.push(spec);
|
|
10800
10916
|
}
|
|
@@ -10886,7 +11002,7 @@ var INFERRED_COMMAND_SOURCES = [
|
|
|
10886
11002
|
async function removedProjectCommandField(field2) {
|
|
10887
11003
|
const config = path19.join(".comet", "config.yaml");
|
|
10888
11004
|
if (!await exists4(config)) return false;
|
|
10889
|
-
const document = (0, import_yaml6.parseDocument)(await
|
|
11005
|
+
const document = (0, import_yaml6.parseDocument)(await fs19.readFile(config, "utf8"));
|
|
10890
11006
|
if (document.errors.length > 0) {
|
|
10891
11007
|
throw new Error(
|
|
10892
11008
|
`.comet/config.yaml is invalid YAML (${document.errors[0].message}); cannot check for removed "${field2}" field. Fix the config and retry.`
|
|
@@ -10974,7 +11090,7 @@ async function tasksAllDone(changeDir) {
|
|
|
10974
11090
|
Next: restore or create tasks.md for this change before leaving build.`
|
|
10975
11091
|
);
|
|
10976
11092
|
}
|
|
10977
|
-
const source = await
|
|
11093
|
+
const source = await fs19.readFile(tasks, "utf8");
|
|
10978
11094
|
if (!/- \[x\]/u.test(source)) {
|
|
10979
11095
|
return fail(
|
|
10980
11096
|
"tasks.md has no completed tasks.\nNext: complete implementation tasks and mark them with '- [x]'."
|
|
@@ -10993,7 +11109,7 @@ Next: complete or explicitly remove unfinished tasks, then mark tasks.md with '-
|
|
|
10993
11109
|
async function tasksHasAny(changeDir) {
|
|
10994
11110
|
const tasks = path19.join(changeDir, "tasks.md");
|
|
10995
11111
|
if (!await exists4(tasks)) return false;
|
|
10996
|
-
return /- \[/u.test(await
|
|
11112
|
+
return /- \[/u.test(await fs19.readFile(tasks, "utf8"));
|
|
10997
11113
|
}
|
|
10998
11114
|
async function planTasksAllDone(changeDir) {
|
|
10999
11115
|
const plan = await readField(changeDir, "plan");
|
|
@@ -11004,7 +11120,7 @@ async function planTasksAllDone(changeDir) {
|
|
|
11004
11120
|
Next: restore the Superpowers plan file or update .comet.yaml plan before leaving build.`
|
|
11005
11121
|
);
|
|
11006
11122
|
}
|
|
11007
|
-
const source = await
|
|
11123
|
+
const source = await fs19.readFile(plan, "utf8");
|
|
11008
11124
|
const unfinished = source.split(/\r?\n/u).map((line, index) => ({ line, number: index + 1 })).filter((entry2) => /^\s*- \[ \]/u.test(entry2.line));
|
|
11009
11125
|
if (unfinished.length > 0) {
|
|
11010
11126
|
return fail(
|
|
@@ -11118,7 +11234,7 @@ async function archivedIsTrue(changeDir) {
|
|
|
11118
11234
|
return await readField(changeDir, "archived") === "true";
|
|
11119
11235
|
}
|
|
11120
11236
|
async function designDocFrontmatterHas(designDoc, field2, expected) {
|
|
11121
|
-
const source = (await
|
|
11237
|
+
const source = (await fs19.readFile(designDoc, "utf8")).replace(/^\uFEFF/u, "");
|
|
11122
11238
|
let inFrontmatter = false;
|
|
11123
11239
|
for (const line of source.split(/\r?\n/u)) {
|
|
11124
11240
|
if (!inFrontmatter) {
|
|
@@ -11183,7 +11299,8 @@ async function designHandoffMarkdownTraceable(changeDir) {
|
|
|
11183
11299
|
const markdown = `${context.replace(/\.json$/u, "")}.md`;
|
|
11184
11300
|
if (!await nonempty(markdown))
|
|
11185
11301
|
return fail(`design handoff markdown is missing or empty: ${markdown}`);
|
|
11186
|
-
const source = await
|
|
11302
|
+
const source = await fs19.readFile(markdown, "utf8");
|
|
11303
|
+
const lines = new Set(source.split(/\r?\n/u));
|
|
11187
11304
|
const problems = [];
|
|
11188
11305
|
if (!/^Generated-by: comet-handoff\.sh$/mu.test(source)) {
|
|
11189
11306
|
problems.push("handoff markdown is missing Generated-by marker");
|
|
@@ -11193,10 +11310,10 @@ async function designHandoffMarkdownTraceable(changeDir) {
|
|
|
11193
11310
|
}
|
|
11194
11311
|
for (const file of await handoffSourceFiles(changeDir)) {
|
|
11195
11312
|
if (!await exists4(file)) continue;
|
|
11196
|
-
if (!
|
|
11313
|
+
if (!lines.has(`- Source: ${file}`)) {
|
|
11197
11314
|
problems.push(`handoff markdown is missing source reference: ${file}`);
|
|
11198
11315
|
}
|
|
11199
|
-
if (!
|
|
11316
|
+
if (!lines.has(`- SHA256: ${hashFile(file)}`)) {
|
|
11200
11317
|
problems.push(`handoff markdown is missing current sha256 for: ${file}`);
|
|
11201
11318
|
}
|
|
11202
11319
|
}
|
|
@@ -11210,7 +11327,7 @@ async function betaSpecJsonStructurallyValid(changeDir) {
|
|
|
11210
11327
|
const context = await readField(changeDir, "handoff_context");
|
|
11211
11328
|
if (!context || context === "null") return fail("handoff_context is missing from .comet.yaml");
|
|
11212
11329
|
if (!await nonempty(context)) return fail(`spec-context.json is missing or empty: ${context}`);
|
|
11213
|
-
const source = await
|
|
11330
|
+
const source = await fs19.readFile(context, "utf8");
|
|
11214
11331
|
const problems = [];
|
|
11215
11332
|
let parsed;
|
|
11216
11333
|
try {
|
|
@@ -11510,7 +11627,7 @@ Valid phases: open, design, build, verify, archive`
|
|
|
11510
11627
|
// domains/comet-classic/classic-handoff.ts
|
|
11511
11628
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
11512
11629
|
import { createHash as createHash5 } from "crypto";
|
|
11513
|
-
import { promises as
|
|
11630
|
+
import { promises as fs20, readFileSync as readFileSync2 } from "fs";
|
|
11514
11631
|
import path20 from "path";
|
|
11515
11632
|
var GREEN4 = "\x1B[32m";
|
|
11516
11633
|
var RED4 = "\x1B[31m";
|
|
@@ -11545,7 +11662,7 @@ var HandoffOutput = class {
|
|
|
11545
11662
|
};
|
|
11546
11663
|
async function exists5(file) {
|
|
11547
11664
|
try {
|
|
11548
|
-
await
|
|
11665
|
+
await fs20.access(file);
|
|
11549
11666
|
return true;
|
|
11550
11667
|
} catch (error) {
|
|
11551
11668
|
if (error.code === "ENOENT") return false;
|
|
@@ -11554,7 +11671,7 @@ async function exists5(file) {
|
|
|
11554
11671
|
}
|
|
11555
11672
|
async function nonempty2(file) {
|
|
11556
11673
|
try {
|
|
11557
|
-
return (await
|
|
11674
|
+
return (await fs20.stat(file)).size > 0;
|
|
11558
11675
|
} catch (error) {
|
|
11559
11676
|
if (error.code === "ENOENT") return false;
|
|
11560
11677
|
throw error;
|
|
@@ -11583,7 +11700,7 @@ async function handoffSourceFiles2(changeDir) {
|
|
|
11583
11700
|
const files = [`${changeDir}/proposal.md`, `${changeDir}/design.md`, `${changeDir}/tasks.md`];
|
|
11584
11701
|
const specs = `${changeDir}/specs`;
|
|
11585
11702
|
if (await exists5(specs)) {
|
|
11586
|
-
for (const entry2 of (await
|
|
11703
|
+
for (const entry2 of (await fs20.readdir(specs)).sort()) {
|
|
11587
11704
|
const spec = `${specs}/${entry2}/spec.md`;
|
|
11588
11705
|
if (await exists5(spec)) files.push(spec);
|
|
11589
11706
|
}
|
|
@@ -11631,7 +11748,7 @@ async function writeMarkdownContext(changeDir, change, mode, contextHash, output
|
|
|
11631
11748
|
];
|
|
11632
11749
|
for (const file of await handoffSourceFiles2(changeDir)) {
|
|
11633
11750
|
if (!await exists5(file)) continue;
|
|
11634
|
-
const content = await
|
|
11751
|
+
const content = await fs20.readFile(file, "utf8");
|
|
11635
11752
|
const total = lineCount(content);
|
|
11636
11753
|
lines.push(
|
|
11637
11754
|
`## ${file}`,
|
|
@@ -11656,7 +11773,7 @@ async function writeMarkdownContext(changeDir, change, mode, contextHash, output
|
|
|
11656
11773
|
}
|
|
11657
11774
|
lines.push("");
|
|
11658
11775
|
}
|
|
11659
|
-
await
|
|
11776
|
+
await fs20.writeFile(output, lines.join("\n"));
|
|
11660
11777
|
}
|
|
11661
11778
|
async function writeJsonContext(changeDir, change, mode, contextHash, output) {
|
|
11662
11779
|
const entries = [];
|
|
@@ -11679,7 +11796,7 @@ async function writeJsonContext(changeDir, change, mode, contextHash, output) {
|
|
|
11679
11796
|
"}",
|
|
11680
11797
|
""
|
|
11681
11798
|
].join("\n");
|
|
11682
|
-
await
|
|
11799
|
+
await fs20.writeFile(output, document);
|
|
11683
11800
|
}
|
|
11684
11801
|
async function writeSpecProjectionForFile(file, content) {
|
|
11685
11802
|
return [
|
|
@@ -11719,11 +11836,11 @@ async function writeSpecMarkdownContext(changeDir, change, contextHash, output)
|
|
|
11719
11836
|
const specs = `${changeDir}/specs`;
|
|
11720
11837
|
let projected = false;
|
|
11721
11838
|
if (await exists5(specs)) {
|
|
11722
|
-
for (const entry2 of (await
|
|
11839
|
+
for (const entry2 of (await fs20.readdir(specs)).sort()) {
|
|
11723
11840
|
const spec = `${specs}/${entry2}/spec.md`;
|
|
11724
11841
|
if (!await exists5(spec)) continue;
|
|
11725
11842
|
projected = true;
|
|
11726
|
-
lines.push(...await writeSpecProjectionForFile(spec, await
|
|
11843
|
+
lines.push(...await writeSpecProjectionForFile(spec, await fs20.readFile(spec, "utf8")));
|
|
11727
11844
|
}
|
|
11728
11845
|
}
|
|
11729
11846
|
if (!projected) {
|
|
@@ -11732,7 +11849,7 @@ async function writeSpecMarkdownContext(changeDir, change, contextHash, output)
|
|
|
11732
11849
|
lines.push(
|
|
11733
11850
|
"Full source files remain canonical. If a required heading or scenario is missing here, regenerate the handoff or read the source spec directly. Supporting files (proposal, design, tasks) are referenced by hash only."
|
|
11734
11851
|
);
|
|
11735
|
-
await
|
|
11852
|
+
await fs20.writeFile(output, lines.join("\n"));
|
|
11736
11853
|
}
|
|
11737
11854
|
async function writeSpecJsonContext(changeDir, change, contextHash, output) {
|
|
11738
11855
|
const entries = [];
|
|
@@ -11741,7 +11858,7 @@ async function writeSpecJsonContext(changeDir, change, contextHash, output) {
|
|
|
11741
11858
|
const role = /\/specs\/[^/]+\/spec\.md$/u.test(file) ? "spec" : "supporting";
|
|
11742
11859
|
entries.push({ path: file, sha256: hashFile2(file), role });
|
|
11743
11860
|
}
|
|
11744
|
-
await
|
|
11861
|
+
await fs20.writeFile(
|
|
11745
11862
|
output,
|
|
11746
11863
|
`${JSON.stringify(
|
|
11747
11864
|
{
|
|
@@ -11761,7 +11878,7 @@ async function writeSpecJsonContext(changeDir, change, contextHash, output) {
|
|
|
11761
11878
|
}
|
|
11762
11879
|
async function readField2(changeDir, field2) {
|
|
11763
11880
|
const file = path20.join(changeDir, ".comet.yaml");
|
|
11764
|
-
const document = (0, import_yaml7.parseDocument)(await
|
|
11881
|
+
const document = (0, import_yaml7.parseDocument)(await fs20.readFile(file, "utf8"), { uniqueKeys: false });
|
|
11765
11882
|
if (document.errors.length > 0) {
|
|
11766
11883
|
throw new HandoffFailure(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
|
|
11767
11884
|
}
|
|
@@ -11795,7 +11912,7 @@ async function completedHandoffIsCurrent(changeDir, run, contextHash, contextJso
|
|
|
11795
11912
|
readCheckpoint(changeDir, run.checkpointRef)
|
|
11796
11913
|
]);
|
|
11797
11914
|
if (!await exists5(contextJson) || !await exists5(contextMd)) return false;
|
|
11798
|
-
if (context !== await
|
|
11915
|
+
if (context !== await fs20.readFile(contextMd, "utf8")) return false;
|
|
11799
11916
|
if (artifacts.handoff_context !== contextJson || artifacts.handoff_markdown !== contextMd) {
|
|
11800
11917
|
return false;
|
|
11801
11918
|
}
|
|
@@ -11918,7 +12035,7 @@ var classicHandoffCommand = async (args) => {
|
|
|
11918
12035
|
run: pendingRun,
|
|
11919
12036
|
unknownKeys: (await readClassicState(changeDir)).unknownKeys
|
|
11920
12037
|
});
|
|
11921
|
-
await
|
|
12038
|
+
await fs20.mkdir(handoffDir, { recursive: true });
|
|
11922
12039
|
if (handoffMode === "beta") {
|
|
11923
12040
|
await writeSpecMarkdownContext(changeDir, change, contextHash, contextMd);
|
|
11924
12041
|
await writeSpecJsonContext(changeDir, change, contextHash, contextJson);
|
|
@@ -11926,7 +12043,7 @@ var classicHandoffCommand = async (args) => {
|
|
|
11926
12043
|
await writeMarkdownContext(changeDir, change, handoffMode, contextHash, contextMd);
|
|
11927
12044
|
await writeJsonContext(changeDir, change, handoffMode, contextHash, contextJson);
|
|
11928
12045
|
}
|
|
11929
|
-
const context = await
|
|
12046
|
+
const context = await fs20.readFile(contextMd, "utf8");
|
|
11930
12047
|
await writeContext(changeDir, pendingRun.contextRef, context);
|
|
11931
12048
|
const artifacts = {
|
|
11932
12049
|
...await readArtifacts(changeDir, pendingRun.artifactsRef),
|
|
@@ -11983,7 +12100,7 @@ var classicHandoffCommand = async (args) => {
|
|
|
11983
12100
|
};
|
|
11984
12101
|
|
|
11985
12102
|
// domains/comet-classic/classic-hook-guard.ts
|
|
11986
|
-
import { existsSync as existsSync2, promises as
|
|
12103
|
+
import { existsSync as existsSync2, promises as fs21, readFileSync as readFileSync3 } from "fs";
|
|
11987
12104
|
import path21 from "path";
|
|
11988
12105
|
function result(exitCode, message) {
|
|
11989
12106
|
return { exitCode, stderr: message + "\n" };
|
|
@@ -12028,7 +12145,7 @@ async function physicalPathForPossiblyMissingTarget(target) {
|
|
|
12028
12145
|
let cursor = resolved;
|
|
12029
12146
|
while (cursor && cursor !== root) {
|
|
12030
12147
|
try {
|
|
12031
|
-
const physicalBase = await
|
|
12148
|
+
const physicalBase = await fs21.realpath(cursor);
|
|
12032
12149
|
return path21.join(physicalBase, ...missingSegments.reverse());
|
|
12033
12150
|
} catch (error) {
|
|
12034
12151
|
const code = error.code;
|
|
@@ -12038,7 +12155,7 @@ async function physicalPathForPossiblyMissingTarget(target) {
|
|
|
12038
12155
|
}
|
|
12039
12156
|
}
|
|
12040
12157
|
try {
|
|
12041
|
-
const physicalRoot = await
|
|
12158
|
+
const physicalRoot = await fs21.realpath(root);
|
|
12042
12159
|
return path21.join(physicalRoot, ...missingSegments.reverse());
|
|
12043
12160
|
} catch {
|
|
12044
12161
|
return null;
|
|
@@ -12051,7 +12168,7 @@ async function projectRelative(target, projectRoot2) {
|
|
|
12051
12168
|
if (rootRelative !== null) return rootRelative;
|
|
12052
12169
|
try {
|
|
12053
12170
|
const physicalCandidate = await physicalPathForPossiblyMissingTarget(rawCandidate);
|
|
12054
|
-
const physicalRoot = await
|
|
12171
|
+
const physicalRoot = await fs21.realpath(projectRoot2);
|
|
12055
12172
|
if (physicalCandidate) {
|
|
12056
12173
|
const physicalRootRelative = relativeToProjectRoot(physicalCandidate, physicalRoot);
|
|
12057
12174
|
if (physicalRootRelative !== null) return physicalRootRelative;
|
|
@@ -12091,7 +12208,7 @@ async function activeChanges(projectRoot2) {
|
|
|
12091
12208
|
const changesDir = path21.join(projectRoot2, "openspec", "changes");
|
|
12092
12209
|
const governingChanges = [];
|
|
12093
12210
|
if (!existsSync2(changesDir)) return governingChanges;
|
|
12094
|
-
for (const entry2 of (await
|
|
12211
|
+
for (const entry2 of (await fs21.readdir(changesDir, { withFileTypes: true })).sort(
|
|
12095
12212
|
(left, right) => left.name.localeCompare(right.name)
|
|
12096
12213
|
)) {
|
|
12097
12214
|
if (!entry2.isDirectory() || entry2.name === "archive") continue;
|
|
@@ -12876,7 +12993,7 @@ var classicIntentCommand = async (args, _options) => {
|
|
|
12876
12993
|
|
|
12877
12994
|
// domains/comet-classic/classic-resume-probe.ts
|
|
12878
12995
|
import path22 from "path";
|
|
12879
|
-
import { promises as
|
|
12996
|
+
import { promises as fs22 } from "fs";
|
|
12880
12997
|
import { spawn } from "child_process";
|
|
12881
12998
|
var COMET_RESUME_PROBE_SCHEMA_VERSION = "comet.resume_probe.v1";
|
|
12882
12999
|
function isRecord3(value) {
|
|
@@ -12919,7 +13036,7 @@ function result3(action, change, confidence, reason, evidence = []) {
|
|
|
12919
13036
|
}
|
|
12920
13037
|
async function readIfExists(filePath) {
|
|
12921
13038
|
if (!await fileExists3(filePath)) return "";
|
|
12922
|
-
return
|
|
13039
|
+
return fs22.readFile(filePath, "utf8");
|
|
12923
13040
|
}
|
|
12924
13041
|
async function changeSearchText(changeDir, classic) {
|
|
12925
13042
|
const files = ["proposal.md", "design.md", "tasks.md"];
|
|
@@ -12999,7 +13116,7 @@ async function discoverActiveChanges(projectRoot2) {
|
|
|
12999
13116
|
for (const entry2 of entries) {
|
|
13000
13117
|
if (entry2 === "archive") continue;
|
|
13001
13118
|
const changeDir = path22.join(changesDir, entry2);
|
|
13002
|
-
const stat = await
|
|
13119
|
+
const stat = await fs22.stat(changeDir).catch(() => null);
|
|
13003
13120
|
if (!stat?.isDirectory()) continue;
|
|
13004
13121
|
const hasCometState = await fileExists3(path22.join(changeDir, ".comet.yaml"));
|
|
13005
13122
|
if (!hasCometState) {
|
|
@@ -13304,7 +13421,7 @@ var classicResumeProbeCommand = async (args) => {
|
|
|
13304
13421
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
13305
13422
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
13306
13423
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
13307
|
-
import { existsSync as existsSync3, promises as
|
|
13424
|
+
import { existsSync as existsSync3, promises as fs23 } from "fs";
|
|
13308
13425
|
import path23 from "path";
|
|
13309
13426
|
init_state();
|
|
13310
13427
|
var GREEN5 = "\x1B[32m";
|
|
@@ -13419,7 +13536,7 @@ function validateRelativePath(value, field2) {
|
|
|
13419
13536
|
}
|
|
13420
13537
|
async function exists6(file) {
|
|
13421
13538
|
try {
|
|
13422
|
-
await
|
|
13539
|
+
await fs23.access(file);
|
|
13423
13540
|
return true;
|
|
13424
13541
|
} catch (error) {
|
|
13425
13542
|
if (error.code === "ENOENT") return false;
|
|
@@ -13428,7 +13545,7 @@ async function exists6(file) {
|
|
|
13428
13545
|
}
|
|
13429
13546
|
async function nonempty3(file) {
|
|
13430
13547
|
try {
|
|
13431
|
-
return (await
|
|
13548
|
+
return (await fs23.stat(file)).size > 0;
|
|
13432
13549
|
} catch (error) {
|
|
13433
13550
|
if (error.code === "ENOENT") return false;
|
|
13434
13551
|
throw error;
|
|
@@ -13440,7 +13557,7 @@ async function changeDirectory2(name) {
|
|
|
13440
13557
|
async function readDocument2(file) {
|
|
13441
13558
|
let source;
|
|
13442
13559
|
try {
|
|
13443
|
-
source = await
|
|
13560
|
+
source = await fs23.readFile(file, "utf8");
|
|
13444
13561
|
} catch (error) {
|
|
13445
13562
|
if (error.code === "ENOENT") {
|
|
13446
13563
|
fail2(
|
|
@@ -13454,13 +13571,13 @@ async function readDocument2(file) {
|
|
|
13454
13571
|
return document;
|
|
13455
13572
|
}
|
|
13456
13573
|
async function atomicWrite2(file, content) {
|
|
13457
|
-
await
|
|
13574
|
+
await fs23.mkdir(path23.dirname(file), { recursive: true });
|
|
13458
13575
|
const temporary = `${file}.${randomUUID8()}.tmp`;
|
|
13459
13576
|
try {
|
|
13460
|
-
await
|
|
13461
|
-
await
|
|
13577
|
+
await fs23.writeFile(temporary, content, "utf8");
|
|
13578
|
+
await fs23.rename(temporary, file);
|
|
13462
13579
|
} catch (error) {
|
|
13463
|
-
await
|
|
13580
|
+
await fs23.rm(temporary, { force: true });
|
|
13464
13581
|
throw error;
|
|
13465
13582
|
}
|
|
13466
13583
|
}
|
|
@@ -13734,7 +13851,7 @@ async function init(output, name, workflow) {
|
|
|
13734
13851
|
validateEnum(workflow, PROFILES);
|
|
13735
13852
|
const { file, label, directory } = await stateFile(name);
|
|
13736
13853
|
if (await exists6(file)) fail2(`ERROR: .comet.yaml already exists at ${label}/.comet.yaml`);
|
|
13737
|
-
await
|
|
13854
|
+
await fs23.mkdir(directory, { recursive: true });
|
|
13738
13855
|
const preset = workflow !== "full";
|
|
13739
13856
|
const reviewMode = preset ? "off" : await reviewModeDefault();
|
|
13740
13857
|
const document = new import_yaml8.Document({
|
|
@@ -13964,7 +14081,7 @@ async function taskCheckoff(output, taskFile, taskText) {
|
|
|
13964
14081
|
if (!taskText) fail2("ERROR: Task text cannot be empty");
|
|
13965
14082
|
const file = path23.resolve(taskFile);
|
|
13966
14083
|
if (!await exists6(file)) fail2(`ERROR: Task file not found: ${taskFile}`);
|
|
13967
|
-
const lines = (await
|
|
14084
|
+
const lines = (await fs23.readFile(file, "utf8")).split(/\r?\n/u);
|
|
13968
14085
|
const matches = lines.filter(
|
|
13969
14086
|
(line) => [`- [ ] ${taskText}`, `- [x] ${taskText}`, `- [X] ${taskText}`].includes(line)
|
|
13970
14087
|
);
|
|
@@ -14140,14 +14257,14 @@ async function recoverBuild(output, name, directory, workflow) {
|
|
|
14140
14257
|
);
|
|
14141
14258
|
return;
|
|
14142
14259
|
}
|
|
14143
|
-
const lines = (await
|
|
14260
|
+
const lines = (await fs23.readFile(tasks, "utf8")).split(/\r?\n/u);
|
|
14144
14261
|
const total = lines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
|
|
14145
14262
|
const done = lines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
|
|
14146
14263
|
const pending = total - done;
|
|
14147
14264
|
let planTotal = 0;
|
|
14148
14265
|
let planDone = 0;
|
|
14149
14266
|
if (plan && plan !== "null" && await exists6(path23.resolve(plan))) {
|
|
14150
|
-
const planLines = (await
|
|
14267
|
+
const planLines = (await fs23.readFile(path23.resolve(plan), "utf8")).split(/\r?\n/u);
|
|
14151
14268
|
planTotal = planLines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
|
|
14152
14269
|
planDone = planLines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
|
|
14153
14270
|
}
|
|
@@ -14279,18 +14396,18 @@ async function scale(output, name) {
|
|
|
14279
14396
|
const { file, directory, label } = await stateFile(name);
|
|
14280
14397
|
if (!await exists6(file)) fail2(`ERROR: .comet.yaml not found at ${label}/.comet.yaml`);
|
|
14281
14398
|
const tasksFile = path23.join(directory, "tasks.md");
|
|
14282
|
-
const taskCount = await exists6(tasksFile) ? (await
|
|
14399
|
+
const taskCount = await exists6(tasksFile) ? (await fs23.readFile(tasksFile, "utf8")).split(/\r?\n/u).filter((line) => /^- \[/u.test(line)).length : 0;
|
|
14283
14400
|
const specs = path23.join(directory, "specs");
|
|
14284
14401
|
let deltaSpecs = 0;
|
|
14285
14402
|
if (await exists6(specs)) {
|
|
14286
|
-
for (const entry2 of await
|
|
14403
|
+
for (const entry2 of await fs23.readdir(specs)) {
|
|
14287
14404
|
if (await exists6(path23.join(specs, entry2, "spec.md"))) deltaSpecs += 1;
|
|
14288
14405
|
}
|
|
14289
14406
|
}
|
|
14290
14407
|
const plan = await readField3(name, "plan");
|
|
14291
14408
|
let baseRef = "";
|
|
14292
14409
|
if (plan && plan !== "null" && await exists6(path23.resolve(plan))) {
|
|
14293
|
-
const match = (await
|
|
14410
|
+
const match = (await fs23.readFile(path23.resolve(plan), "utf8")).match(/^base-ref:\s*(.+)$/mu);
|
|
14294
14411
|
baseRef = match?.[1].trim() ?? "";
|
|
14295
14412
|
}
|
|
14296
14413
|
if (!baseRef) baseRef = await readField3(name, "base_ref");
|