@rpamis/comet 0.4.0-beta.8 → 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/README.md +1 -1
- 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 +95 -4
- package/assets/skills/comet/scripts/comet-hook-router.mjs +224 -35
- package/assets/skills/comet/scripts/comet-runtime.mjs +218 -102
- 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 +1052 -458
- 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/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-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.d.ts.map +1 -1
- package/dist/domains/comet-native/native-check-receipt.js +5 -3
- 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-file-identity.d.ts +2 -8
- package/dist/domains/comet-native/native-file-identity.d.ts.map +1 -1
- package/dist/domains/comet-native/native-file-identity.js +1 -20
- package/dist/domains/comet-native/native-file-identity.js.map +1 -1
- 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 +24 -32
- package/dist/domains/comet-native/native-lock.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-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 +218 -2
- 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/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/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 +1 -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,7 @@ 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");
|
|
11187
11303
|
const lines = new Set(source.split(/\r?\n/u));
|
|
11188
11304
|
const problems = [];
|
|
11189
11305
|
if (!/^Generated-by: comet-handoff\.sh$/mu.test(source)) {
|
|
@@ -11211,7 +11327,7 @@ async function betaSpecJsonStructurallyValid(changeDir) {
|
|
|
11211
11327
|
const context = await readField(changeDir, "handoff_context");
|
|
11212
11328
|
if (!context || context === "null") return fail("handoff_context is missing from .comet.yaml");
|
|
11213
11329
|
if (!await nonempty(context)) return fail(`spec-context.json is missing or empty: ${context}`);
|
|
11214
|
-
const source = await
|
|
11330
|
+
const source = await fs19.readFile(context, "utf8");
|
|
11215
11331
|
const problems = [];
|
|
11216
11332
|
let parsed;
|
|
11217
11333
|
try {
|
|
@@ -11511,7 +11627,7 @@ Valid phases: open, design, build, verify, archive`
|
|
|
11511
11627
|
// domains/comet-classic/classic-handoff.ts
|
|
11512
11628
|
var import_yaml7 = __toESM(require_dist(), 1);
|
|
11513
11629
|
import { createHash as createHash5 } from "crypto";
|
|
11514
|
-
import { promises as
|
|
11630
|
+
import { promises as fs20, readFileSync as readFileSync2 } from "fs";
|
|
11515
11631
|
import path20 from "path";
|
|
11516
11632
|
var GREEN4 = "\x1B[32m";
|
|
11517
11633
|
var RED4 = "\x1B[31m";
|
|
@@ -11546,7 +11662,7 @@ var HandoffOutput = class {
|
|
|
11546
11662
|
};
|
|
11547
11663
|
async function exists5(file) {
|
|
11548
11664
|
try {
|
|
11549
|
-
await
|
|
11665
|
+
await fs20.access(file);
|
|
11550
11666
|
return true;
|
|
11551
11667
|
} catch (error) {
|
|
11552
11668
|
if (error.code === "ENOENT") return false;
|
|
@@ -11555,7 +11671,7 @@ async function exists5(file) {
|
|
|
11555
11671
|
}
|
|
11556
11672
|
async function nonempty2(file) {
|
|
11557
11673
|
try {
|
|
11558
|
-
return (await
|
|
11674
|
+
return (await fs20.stat(file)).size > 0;
|
|
11559
11675
|
} catch (error) {
|
|
11560
11676
|
if (error.code === "ENOENT") return false;
|
|
11561
11677
|
throw error;
|
|
@@ -11584,7 +11700,7 @@ async function handoffSourceFiles2(changeDir) {
|
|
|
11584
11700
|
const files = [`${changeDir}/proposal.md`, `${changeDir}/design.md`, `${changeDir}/tasks.md`];
|
|
11585
11701
|
const specs = `${changeDir}/specs`;
|
|
11586
11702
|
if (await exists5(specs)) {
|
|
11587
|
-
for (const entry2 of (await
|
|
11703
|
+
for (const entry2 of (await fs20.readdir(specs)).sort()) {
|
|
11588
11704
|
const spec = `${specs}/${entry2}/spec.md`;
|
|
11589
11705
|
if (await exists5(spec)) files.push(spec);
|
|
11590
11706
|
}
|
|
@@ -11632,7 +11748,7 @@ async function writeMarkdownContext(changeDir, change, mode, contextHash, output
|
|
|
11632
11748
|
];
|
|
11633
11749
|
for (const file of await handoffSourceFiles2(changeDir)) {
|
|
11634
11750
|
if (!await exists5(file)) continue;
|
|
11635
|
-
const content = await
|
|
11751
|
+
const content = await fs20.readFile(file, "utf8");
|
|
11636
11752
|
const total = lineCount(content);
|
|
11637
11753
|
lines.push(
|
|
11638
11754
|
`## ${file}`,
|
|
@@ -11657,7 +11773,7 @@ async function writeMarkdownContext(changeDir, change, mode, contextHash, output
|
|
|
11657
11773
|
}
|
|
11658
11774
|
lines.push("");
|
|
11659
11775
|
}
|
|
11660
|
-
await
|
|
11776
|
+
await fs20.writeFile(output, lines.join("\n"));
|
|
11661
11777
|
}
|
|
11662
11778
|
async function writeJsonContext(changeDir, change, mode, contextHash, output) {
|
|
11663
11779
|
const entries = [];
|
|
@@ -11680,7 +11796,7 @@ async function writeJsonContext(changeDir, change, mode, contextHash, output) {
|
|
|
11680
11796
|
"}",
|
|
11681
11797
|
""
|
|
11682
11798
|
].join("\n");
|
|
11683
|
-
await
|
|
11799
|
+
await fs20.writeFile(output, document);
|
|
11684
11800
|
}
|
|
11685
11801
|
async function writeSpecProjectionForFile(file, content) {
|
|
11686
11802
|
return [
|
|
@@ -11720,11 +11836,11 @@ async function writeSpecMarkdownContext(changeDir, change, contextHash, output)
|
|
|
11720
11836
|
const specs = `${changeDir}/specs`;
|
|
11721
11837
|
let projected = false;
|
|
11722
11838
|
if (await exists5(specs)) {
|
|
11723
|
-
for (const entry2 of (await
|
|
11839
|
+
for (const entry2 of (await fs20.readdir(specs)).sort()) {
|
|
11724
11840
|
const spec = `${specs}/${entry2}/spec.md`;
|
|
11725
11841
|
if (!await exists5(spec)) continue;
|
|
11726
11842
|
projected = true;
|
|
11727
|
-
lines.push(...await writeSpecProjectionForFile(spec, await
|
|
11843
|
+
lines.push(...await writeSpecProjectionForFile(spec, await fs20.readFile(spec, "utf8")));
|
|
11728
11844
|
}
|
|
11729
11845
|
}
|
|
11730
11846
|
if (!projected) {
|
|
@@ -11733,7 +11849,7 @@ async function writeSpecMarkdownContext(changeDir, change, contextHash, output)
|
|
|
11733
11849
|
lines.push(
|
|
11734
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."
|
|
11735
11851
|
);
|
|
11736
|
-
await
|
|
11852
|
+
await fs20.writeFile(output, lines.join("\n"));
|
|
11737
11853
|
}
|
|
11738
11854
|
async function writeSpecJsonContext(changeDir, change, contextHash, output) {
|
|
11739
11855
|
const entries = [];
|
|
@@ -11742,7 +11858,7 @@ async function writeSpecJsonContext(changeDir, change, contextHash, output) {
|
|
|
11742
11858
|
const role = /\/specs\/[^/]+\/spec\.md$/u.test(file) ? "spec" : "supporting";
|
|
11743
11859
|
entries.push({ path: file, sha256: hashFile2(file), role });
|
|
11744
11860
|
}
|
|
11745
|
-
await
|
|
11861
|
+
await fs20.writeFile(
|
|
11746
11862
|
output,
|
|
11747
11863
|
`${JSON.stringify(
|
|
11748
11864
|
{
|
|
@@ -11762,7 +11878,7 @@ async function writeSpecJsonContext(changeDir, change, contextHash, output) {
|
|
|
11762
11878
|
}
|
|
11763
11879
|
async function readField2(changeDir, field2) {
|
|
11764
11880
|
const file = path20.join(changeDir, ".comet.yaml");
|
|
11765
|
-
const document = (0, import_yaml7.parseDocument)(await
|
|
11881
|
+
const document = (0, import_yaml7.parseDocument)(await fs20.readFile(file, "utf8"), { uniqueKeys: false });
|
|
11766
11882
|
if (document.errors.length > 0) {
|
|
11767
11883
|
throw new HandoffFailure(`ERROR: Invalid .comet.yaml: ${document.errors[0].message}`);
|
|
11768
11884
|
}
|
|
@@ -11796,7 +11912,7 @@ async function completedHandoffIsCurrent(changeDir, run, contextHash, contextJso
|
|
|
11796
11912
|
readCheckpoint(changeDir, run.checkpointRef)
|
|
11797
11913
|
]);
|
|
11798
11914
|
if (!await exists5(contextJson) || !await exists5(contextMd)) return false;
|
|
11799
|
-
if (context !== await
|
|
11915
|
+
if (context !== await fs20.readFile(contextMd, "utf8")) return false;
|
|
11800
11916
|
if (artifacts.handoff_context !== contextJson || artifacts.handoff_markdown !== contextMd) {
|
|
11801
11917
|
return false;
|
|
11802
11918
|
}
|
|
@@ -11919,7 +12035,7 @@ var classicHandoffCommand = async (args) => {
|
|
|
11919
12035
|
run: pendingRun,
|
|
11920
12036
|
unknownKeys: (await readClassicState(changeDir)).unknownKeys
|
|
11921
12037
|
});
|
|
11922
|
-
await
|
|
12038
|
+
await fs20.mkdir(handoffDir, { recursive: true });
|
|
11923
12039
|
if (handoffMode === "beta") {
|
|
11924
12040
|
await writeSpecMarkdownContext(changeDir, change, contextHash, contextMd);
|
|
11925
12041
|
await writeSpecJsonContext(changeDir, change, contextHash, contextJson);
|
|
@@ -11927,7 +12043,7 @@ var classicHandoffCommand = async (args) => {
|
|
|
11927
12043
|
await writeMarkdownContext(changeDir, change, handoffMode, contextHash, contextMd);
|
|
11928
12044
|
await writeJsonContext(changeDir, change, handoffMode, contextHash, contextJson);
|
|
11929
12045
|
}
|
|
11930
|
-
const context = await
|
|
12046
|
+
const context = await fs20.readFile(contextMd, "utf8");
|
|
11931
12047
|
await writeContext(changeDir, pendingRun.contextRef, context);
|
|
11932
12048
|
const artifacts = {
|
|
11933
12049
|
...await readArtifacts(changeDir, pendingRun.artifactsRef),
|
|
@@ -11984,7 +12100,7 @@ var classicHandoffCommand = async (args) => {
|
|
|
11984
12100
|
};
|
|
11985
12101
|
|
|
11986
12102
|
// domains/comet-classic/classic-hook-guard.ts
|
|
11987
|
-
import { existsSync as existsSync2, promises as
|
|
12103
|
+
import { existsSync as existsSync2, promises as fs21, readFileSync as readFileSync3 } from "fs";
|
|
11988
12104
|
import path21 from "path";
|
|
11989
12105
|
function result(exitCode, message) {
|
|
11990
12106
|
return { exitCode, stderr: message + "\n" };
|
|
@@ -12029,7 +12145,7 @@ async function physicalPathForPossiblyMissingTarget(target) {
|
|
|
12029
12145
|
let cursor = resolved;
|
|
12030
12146
|
while (cursor && cursor !== root) {
|
|
12031
12147
|
try {
|
|
12032
|
-
const physicalBase = await
|
|
12148
|
+
const physicalBase = await fs21.realpath(cursor);
|
|
12033
12149
|
return path21.join(physicalBase, ...missingSegments.reverse());
|
|
12034
12150
|
} catch (error) {
|
|
12035
12151
|
const code = error.code;
|
|
@@ -12039,7 +12155,7 @@ async function physicalPathForPossiblyMissingTarget(target) {
|
|
|
12039
12155
|
}
|
|
12040
12156
|
}
|
|
12041
12157
|
try {
|
|
12042
|
-
const physicalRoot = await
|
|
12158
|
+
const physicalRoot = await fs21.realpath(root);
|
|
12043
12159
|
return path21.join(physicalRoot, ...missingSegments.reverse());
|
|
12044
12160
|
} catch {
|
|
12045
12161
|
return null;
|
|
@@ -12052,7 +12168,7 @@ async function projectRelative(target, projectRoot2) {
|
|
|
12052
12168
|
if (rootRelative !== null) return rootRelative;
|
|
12053
12169
|
try {
|
|
12054
12170
|
const physicalCandidate = await physicalPathForPossiblyMissingTarget(rawCandidate);
|
|
12055
|
-
const physicalRoot = await
|
|
12171
|
+
const physicalRoot = await fs21.realpath(projectRoot2);
|
|
12056
12172
|
if (physicalCandidate) {
|
|
12057
12173
|
const physicalRootRelative = relativeToProjectRoot(physicalCandidate, physicalRoot);
|
|
12058
12174
|
if (physicalRootRelative !== null) return physicalRootRelative;
|
|
@@ -12092,7 +12208,7 @@ async function activeChanges(projectRoot2) {
|
|
|
12092
12208
|
const changesDir = path21.join(projectRoot2, "openspec", "changes");
|
|
12093
12209
|
const governingChanges = [];
|
|
12094
12210
|
if (!existsSync2(changesDir)) return governingChanges;
|
|
12095
|
-
for (const entry2 of (await
|
|
12211
|
+
for (const entry2 of (await fs21.readdir(changesDir, { withFileTypes: true })).sort(
|
|
12096
12212
|
(left, right) => left.name.localeCompare(right.name)
|
|
12097
12213
|
)) {
|
|
12098
12214
|
if (!entry2.isDirectory() || entry2.name === "archive") continue;
|
|
@@ -12877,7 +12993,7 @@ var classicIntentCommand = async (args, _options) => {
|
|
|
12877
12993
|
|
|
12878
12994
|
// domains/comet-classic/classic-resume-probe.ts
|
|
12879
12995
|
import path22 from "path";
|
|
12880
|
-
import { promises as
|
|
12996
|
+
import { promises as fs22 } from "fs";
|
|
12881
12997
|
import { spawn } from "child_process";
|
|
12882
12998
|
var COMET_RESUME_PROBE_SCHEMA_VERSION = "comet.resume_probe.v1";
|
|
12883
12999
|
function isRecord3(value) {
|
|
@@ -12920,7 +13036,7 @@ function result3(action, change, confidence, reason, evidence = []) {
|
|
|
12920
13036
|
}
|
|
12921
13037
|
async function readIfExists(filePath) {
|
|
12922
13038
|
if (!await fileExists3(filePath)) return "";
|
|
12923
|
-
return
|
|
13039
|
+
return fs22.readFile(filePath, "utf8");
|
|
12924
13040
|
}
|
|
12925
13041
|
async function changeSearchText(changeDir, classic) {
|
|
12926
13042
|
const files = ["proposal.md", "design.md", "tasks.md"];
|
|
@@ -13000,7 +13116,7 @@ async function discoverActiveChanges(projectRoot2) {
|
|
|
13000
13116
|
for (const entry2 of entries) {
|
|
13001
13117
|
if (entry2 === "archive") continue;
|
|
13002
13118
|
const changeDir = path22.join(changesDir, entry2);
|
|
13003
|
-
const stat = await
|
|
13119
|
+
const stat = await fs22.stat(changeDir).catch(() => null);
|
|
13004
13120
|
if (!stat?.isDirectory()) continue;
|
|
13005
13121
|
const hasCometState = await fileExists3(path22.join(changeDir, ".comet.yaml"));
|
|
13006
13122
|
if (!hasCometState) {
|
|
@@ -13305,7 +13421,7 @@ var classicResumeProbeCommand = async (args) => {
|
|
|
13305
13421
|
var import_yaml8 = __toESM(require_dist(), 1);
|
|
13306
13422
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
13307
13423
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
13308
|
-
import { existsSync as existsSync3, promises as
|
|
13424
|
+
import { existsSync as existsSync3, promises as fs23 } from "fs";
|
|
13309
13425
|
import path23 from "path";
|
|
13310
13426
|
init_state();
|
|
13311
13427
|
var GREEN5 = "\x1B[32m";
|
|
@@ -13420,7 +13536,7 @@ function validateRelativePath(value, field2) {
|
|
|
13420
13536
|
}
|
|
13421
13537
|
async function exists6(file) {
|
|
13422
13538
|
try {
|
|
13423
|
-
await
|
|
13539
|
+
await fs23.access(file);
|
|
13424
13540
|
return true;
|
|
13425
13541
|
} catch (error) {
|
|
13426
13542
|
if (error.code === "ENOENT") return false;
|
|
@@ -13429,7 +13545,7 @@ async function exists6(file) {
|
|
|
13429
13545
|
}
|
|
13430
13546
|
async function nonempty3(file) {
|
|
13431
13547
|
try {
|
|
13432
|
-
return (await
|
|
13548
|
+
return (await fs23.stat(file)).size > 0;
|
|
13433
13549
|
} catch (error) {
|
|
13434
13550
|
if (error.code === "ENOENT") return false;
|
|
13435
13551
|
throw error;
|
|
@@ -13441,7 +13557,7 @@ async function changeDirectory2(name) {
|
|
|
13441
13557
|
async function readDocument2(file) {
|
|
13442
13558
|
let source;
|
|
13443
13559
|
try {
|
|
13444
|
-
source = await
|
|
13560
|
+
source = await fs23.readFile(file, "utf8");
|
|
13445
13561
|
} catch (error) {
|
|
13446
13562
|
if (error.code === "ENOENT") {
|
|
13447
13563
|
fail2(
|
|
@@ -13455,13 +13571,13 @@ async function readDocument2(file) {
|
|
|
13455
13571
|
return document;
|
|
13456
13572
|
}
|
|
13457
13573
|
async function atomicWrite2(file, content) {
|
|
13458
|
-
await
|
|
13574
|
+
await fs23.mkdir(path23.dirname(file), { recursive: true });
|
|
13459
13575
|
const temporary = `${file}.${randomUUID8()}.tmp`;
|
|
13460
13576
|
try {
|
|
13461
|
-
await
|
|
13462
|
-
await
|
|
13577
|
+
await fs23.writeFile(temporary, content, "utf8");
|
|
13578
|
+
await fs23.rename(temporary, file);
|
|
13463
13579
|
} catch (error) {
|
|
13464
|
-
await
|
|
13580
|
+
await fs23.rm(temporary, { force: true });
|
|
13465
13581
|
throw error;
|
|
13466
13582
|
}
|
|
13467
13583
|
}
|
|
@@ -13735,7 +13851,7 @@ async function init(output, name, workflow) {
|
|
|
13735
13851
|
validateEnum(workflow, PROFILES);
|
|
13736
13852
|
const { file, label, directory } = await stateFile(name);
|
|
13737
13853
|
if (await exists6(file)) fail2(`ERROR: .comet.yaml already exists at ${label}/.comet.yaml`);
|
|
13738
|
-
await
|
|
13854
|
+
await fs23.mkdir(directory, { recursive: true });
|
|
13739
13855
|
const preset = workflow !== "full";
|
|
13740
13856
|
const reviewMode = preset ? "off" : await reviewModeDefault();
|
|
13741
13857
|
const document = new import_yaml8.Document({
|
|
@@ -13965,7 +14081,7 @@ async function taskCheckoff(output, taskFile, taskText) {
|
|
|
13965
14081
|
if (!taskText) fail2("ERROR: Task text cannot be empty");
|
|
13966
14082
|
const file = path23.resolve(taskFile);
|
|
13967
14083
|
if (!await exists6(file)) fail2(`ERROR: Task file not found: ${taskFile}`);
|
|
13968
|
-
const lines = (await
|
|
14084
|
+
const lines = (await fs23.readFile(file, "utf8")).split(/\r?\n/u);
|
|
13969
14085
|
const matches = lines.filter(
|
|
13970
14086
|
(line) => [`- [ ] ${taskText}`, `- [x] ${taskText}`, `- [X] ${taskText}`].includes(line)
|
|
13971
14087
|
);
|
|
@@ -14141,14 +14257,14 @@ async function recoverBuild(output, name, directory, workflow) {
|
|
|
14141
14257
|
);
|
|
14142
14258
|
return;
|
|
14143
14259
|
}
|
|
14144
|
-
const lines = (await
|
|
14260
|
+
const lines = (await fs23.readFile(tasks, "utf8")).split(/\r?\n/u);
|
|
14145
14261
|
const total = lines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
|
|
14146
14262
|
const done = lines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
|
|
14147
14263
|
const pending = total - done;
|
|
14148
14264
|
let planTotal = 0;
|
|
14149
14265
|
let planDone = 0;
|
|
14150
14266
|
if (plan && plan !== "null" && await exists6(path23.resolve(plan))) {
|
|
14151
|
-
const planLines = (await
|
|
14267
|
+
const planLines = (await fs23.readFile(path23.resolve(plan), "utf8")).split(/\r?\n/u);
|
|
14152
14268
|
planTotal = planLines.filter((line) => /^\s*- \[[ xX]\] /u.test(line)).length;
|
|
14153
14269
|
planDone = planLines.filter((line) => /^\s*- \[[xX]\] /u.test(line)).length;
|
|
14154
14270
|
}
|
|
@@ -14280,18 +14396,18 @@ async function scale(output, name) {
|
|
|
14280
14396
|
const { file, directory, label } = await stateFile(name);
|
|
14281
14397
|
if (!await exists6(file)) fail2(`ERROR: .comet.yaml not found at ${label}/.comet.yaml`);
|
|
14282
14398
|
const tasksFile = path23.join(directory, "tasks.md");
|
|
14283
|
-
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;
|
|
14284
14400
|
const specs = path23.join(directory, "specs");
|
|
14285
14401
|
let deltaSpecs = 0;
|
|
14286
14402
|
if (await exists6(specs)) {
|
|
14287
|
-
for (const entry2 of await
|
|
14403
|
+
for (const entry2 of await fs23.readdir(specs)) {
|
|
14288
14404
|
if (await exists6(path23.join(specs, entry2, "spec.md"))) deltaSpecs += 1;
|
|
14289
14405
|
}
|
|
14290
14406
|
}
|
|
14291
14407
|
const plan = await readField3(name, "plan");
|
|
14292
14408
|
let baseRef = "";
|
|
14293
14409
|
if (plan && plan !== "null" && await exists6(path23.resolve(plan))) {
|
|
14294
|
-
const match = (await
|
|
14410
|
+
const match = (await fs23.readFile(path23.resolve(plan), "utf8")).match(/^base-ref:\s*(.+)$/mu);
|
|
14295
14411
|
baseRef = match?.[1].trim() ?? "";
|
|
14296
14412
|
}
|
|
14297
14413
|
if (!baseRef) baseRef = await readField3(name, "base_ref");
|