gentle-pi 2.1.1 → 2.1.2
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/lib/native-review-cli.ts
CHANGED
|
@@ -480,6 +480,7 @@ export interface NativeReviewAuthorityEntry {
|
|
|
480
480
|
status: NativeReviewAuthorityEntryStatus;
|
|
481
481
|
state?: string;
|
|
482
482
|
revision?: string;
|
|
483
|
+
snapshotIdentity?: string;
|
|
483
484
|
chainIdentity?: string;
|
|
484
485
|
recovery?: NativeReviewRecovery;
|
|
485
486
|
problems: readonly string[];
|
|
@@ -748,6 +749,7 @@ function exactObject(value: unknown, required: readonly string[], optional: read
|
|
|
748
749
|
}
|
|
749
750
|
function requiredString(value: unknown): string { if (typeof value !== "string" || value.length === 0) throw new Error("expected string"); return value; }
|
|
750
751
|
function stringValue(value: unknown): string { if (typeof value !== "string") throw new Error("expected string"); return value; }
|
|
752
|
+
function sha256Identity(value: unknown): string { const parsed = requiredString(value); if (!/^sha256:[0-9a-f]{64}$/.test(parsed)) throw new Error("expected canonical SHA-256 identity"); return parsed; }
|
|
751
753
|
function booleanValue(value: unknown): boolean { if (typeof value !== "boolean") throw new Error("expected boolean"); return value; }
|
|
752
754
|
function nonNegativeInteger(value: unknown): number { if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error("expected safe non-negative integer"); return value; }
|
|
753
755
|
function positiveInteger(value: unknown): number { if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) throw new Error("expected safe positive integer"); return value; }
|
|
@@ -957,7 +959,7 @@ function decodeNativeReviewRecovery(value: unknown): NativeReviewRecovery {
|
|
|
957
959
|
};
|
|
958
960
|
}
|
|
959
961
|
function decodeNativeReviewStatusEntry(value: unknown): NativeReviewAuthorityEntry {
|
|
960
|
-
const entry = exactObject(value, ["version", "path", "status", "problems"], ["lineage_id", "state", "revision", "chain_identity", "recovery"]);
|
|
962
|
+
const entry = exactObject(value, ["version", "path", "status", "problems"], ["lineage_id", "state", "revision", "snapshot_identity", "chain_identity", "recovery"]);
|
|
961
963
|
return {
|
|
962
964
|
version: enumString(entry.version, Object.values(NATIVE_REVIEW_AUTHORITY_ENTRY_VERSION)) as NativeReviewAuthorityEntryVersion,
|
|
963
965
|
...(entry.lineage_id === undefined ? {} : { lineageId: requiredString(entry.lineage_id) }),
|
|
@@ -965,6 +967,7 @@ function decodeNativeReviewStatusEntry(value: unknown): NativeReviewAuthorityEnt
|
|
|
965
967
|
status: enumString(entry.status, Object.values(NATIVE_REVIEW_AUTHORITY_ENTRY_STATUS)) as NativeReviewAuthorityEntryStatus,
|
|
966
968
|
...(entry.state === undefined ? {} : { state: requiredString(entry.state) }),
|
|
967
969
|
...(entry.revision === undefined ? {} : { revision: requiredString(entry.revision) }),
|
|
970
|
+
...(entry.snapshot_identity === undefined ? {} : { snapshotIdentity: sha256Identity(entry.snapshot_identity) }),
|
|
968
971
|
...(entry.chain_identity === undefined ? {} : { chainIdentity: requiredString(entry.chain_identity) }),
|
|
969
972
|
...(entry.recovery === undefined ? {} : { recovery: decodeNativeReviewRecovery(entry.recovery) }),
|
|
970
973
|
problems: stringArray(entry.problems),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gentle-pi",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.2",
|
|
4
4
|
"description": "Turn Pi into el Gentleman: a senior-architect development harness with SDD/OpenSpec, subagents, strict TDD evidence, review guardrails, and skill discovery.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -505,6 +505,7 @@ export const NATIVE_REVIEW_RECOVERY_DISPOSITION = {
|
|
|
505
505
|
|
|
506
506
|
|
|
507
507
|
|
|
508
|
+
|
|
508
509
|
|
|
509
510
|
|
|
510
511
|
export const NATIVE_START_ACTION = { CREATED: "created", RESUMED: "resumed", REUSE_RECEIPT: "reuse-receipt", BLOCKED_SCOPE_ACTION: "blocked-scope-action" } ;
|
|
@@ -749,6 +750,7 @@ function exactObject(value , required , optional
|
|
|
749
750
|
}
|
|
750
751
|
function requiredString(value ) { if (typeof value !== "string" || value.length === 0) throw new Error("expected string"); return value; }
|
|
751
752
|
function stringValue(value ) { if (typeof value !== "string") throw new Error("expected string"); return value; }
|
|
753
|
+
function sha256Identity(value ) { const parsed = requiredString(value); if (!/^sha256:[0-9a-f]{64}$/.test(parsed)) throw new Error("expected canonical SHA-256 identity"); return parsed; }
|
|
752
754
|
function booleanValue(value ) { if (typeof value !== "boolean") throw new Error("expected boolean"); return value; }
|
|
753
755
|
function nonNegativeInteger(value ) { if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error("expected safe non-negative integer"); return value; }
|
|
754
756
|
function positiveInteger(value ) { if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) throw new Error("expected safe positive integer"); return value; }
|
|
@@ -958,7 +960,7 @@ function decodeNativeReviewRecovery(value ) {
|
|
|
958
960
|
};
|
|
959
961
|
}
|
|
960
962
|
function decodeNativeReviewStatusEntry(value ) {
|
|
961
|
-
const entry = exactObject(value, ["version", "path", "status", "problems"], ["lineage_id", "state", "revision", "chain_identity", "recovery"]);
|
|
963
|
+
const entry = exactObject(value, ["version", "path", "status", "problems"], ["lineage_id", "state", "revision", "snapshot_identity", "chain_identity", "recovery"]);
|
|
962
964
|
return {
|
|
963
965
|
version: enumString(entry.version, Object.values(NATIVE_REVIEW_AUTHORITY_ENTRY_VERSION)) ,
|
|
964
966
|
...(entry.lineage_id === undefined ? {} : { lineageId: requiredString(entry.lineage_id) }),
|
|
@@ -966,6 +968,7 @@ function decodeNativeReviewStatusEntry(value )
|
|
|
966
968
|
status: enumString(entry.status, Object.values(NATIVE_REVIEW_AUTHORITY_ENTRY_STATUS)) ,
|
|
967
969
|
...(entry.state === undefined ? {} : { state: requiredString(entry.state) }),
|
|
968
970
|
...(entry.revision === undefined ? {} : { revision: requiredString(entry.revision) }),
|
|
971
|
+
...(entry.snapshot_identity === undefined ? {} : { snapshotIdentity: sha256Identity(entry.snapshot_identity) }),
|
|
969
972
|
...(entry.chain_identity === undefined ? {} : { chainIdentity: requiredString(entry.chain_identity) }),
|
|
970
973
|
...(entry.recovery === undefined ? {} : { recovery: decodeNativeReviewRecovery(entry.recovery) }),
|
|
971
974
|
problems: stringArray(entry.problems),
|
|
@@ -668,6 +668,33 @@ test("native review status uses the anticipated v2.1.5 contract, preserves Windo
|
|
|
668
668
|
}
|
|
669
669
|
});
|
|
670
670
|
|
|
671
|
+
test("native review status decodes and retains the v2.2.2 compact snapshot identity", async () => {
|
|
672
|
+
const snapshotIdentity = "sha256:0586c3d40c3acf3db92214ddaf07afe44ad862518b48d608ae4157377ab2f3cc";
|
|
673
|
+
const entry = {
|
|
674
|
+
version: "compact-v2",
|
|
675
|
+
lineage_id: "issue-136-v2-1-2-final",
|
|
676
|
+
path: "C:\\repo with spaces\\.git\\gentle-ai\\review-transactions\\v2\\issue-136-v2-1-2-final",
|
|
677
|
+
status: "active",
|
|
678
|
+
state: "reviewing",
|
|
679
|
+
revision: "sha256:8103efb360d10d1717a4d22e38c8b75074f99680ed6a5eb3ab40e0ed9fb69931",
|
|
680
|
+
snapshot_identity: snapshotIdentity,
|
|
681
|
+
problems: [],
|
|
682
|
+
};
|
|
683
|
+
const status = { ...JSON.parse(REVIEW_STATUS.stdout), status: "active", entries: [entry] };
|
|
684
|
+
const queue = queuedAdapter([{ stdout: "gentle-ai 2.2.2\n" }, { stdout: JSON.stringify(status) }]);
|
|
685
|
+
const decoded = await new NativeReviewCliV213(queue.adapter).reviewStatus({ cwd: "C:\\repo with spaces" });
|
|
686
|
+
assert.equal(decoded.entries[0]?.snapshotIdentity, snapshotIdentity);
|
|
687
|
+
|
|
688
|
+
const malformed = queuedAdapter([{ stdout: "gentle-ai 2.2.2\n" }, { stdout: JSON.stringify({ ...status, entries: [{ ...entry, snapshot_identity: snapshotIdentity.slice("sha256:".length) }] }) }]);
|
|
689
|
+
await assert.rejects(
|
|
690
|
+
() => new NativeReviewCliV213(malformed.adapter).reviewStatus({ cwd: "C:\\repo with spaces" }),
|
|
691
|
+
(error: unknown) => error instanceof NativeReviewCliError
|
|
692
|
+
&& error.code === NATIVE_REVIEW_ERROR_CODE.SCHEMA_INCOMPATIBLE
|
|
693
|
+
&& error.operation === "review/status"
|
|
694
|
+
&& error.mutationOutcome === "none",
|
|
695
|
+
);
|
|
696
|
+
});
|
|
697
|
+
|
|
671
698
|
test("native review status decodes 2.1.8 released lock residue and keeps unknown lock statuses fail-closed", async () => {
|
|
672
699
|
// gentle-ai 2.1.8 leaves review-transactions/v2/LOCK behind after ORDINARY
|
|
673
700
|
// successful operations and reports it as {"status":"released"} without
|
|
@@ -1137,9 +1137,9 @@ test("pi-pretty wrapper uses real package path resolution for pnpm symlink insta
|
|
|
1137
1137
|
assert.match(wrapper, /quietToolsEnabled/);
|
|
1138
1138
|
});
|
|
1139
1139
|
|
|
1140
|
-
test("v2.1.
|
|
1140
|
+
test("v2.1.2 release package and runtime stop before publication", () => {
|
|
1141
1141
|
const packageJson = readPackageJson();
|
|
1142
|
-
assert.equal(packageJson.version, "2.1.
|
|
1142
|
+
assert.equal(packageJson.version, "2.1.2", "the release manifest must remain explicitly pinned to v2.1.2");
|
|
1143
1143
|
assert.equal(
|
|
1144
1144
|
packageJson.scripts?.test,
|
|
1145
1145
|
"node --experimental-strip-types --test tests/*.test.ts && pnpm run test:harness",
|