opencode-swarm 7.141.2 → 7.142.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{config-doctor-weqs97sa.js → config-doctor-2a3qmp5p.js} +2 -2
- package/dist/cli/{core-zg7fqfsm.js → core-h9z49ant.js} +1 -1
- package/dist/cli/{curation-policy-j1fbc3ry.js → curation-policy-pkb2eeb1.js} +6 -6
- package/dist/cli/curator-drift-49p3jnte.js +1 -1
- package/dist/cli/{curator-llm-factory-8p86mgye.js → curator-llm-factory-9fr243kj.js} +29 -29
- package/dist/cli/{curator-v1tnrt93.js → curator-mtz194wy.js} +29 -29
- package/dist/cli/{evidence-summary-service-a4w0yc8h.js → evidence-summary-service-fgckng0a.js} +13 -11
- package/dist/cli/{gate-evidence-rt9034ft.js → gate-evidence-ppna7em4.js} +9 -5
- package/dist/cli/{guardrail-explain-8yrznk98.js → guardrail-explain-ejdvvnjz.js} +30 -30
- package/dist/cli/{guardrail-log-7hj4x9yt.js → guardrail-log-adjs25ye.js} +4 -4
- package/dist/cli/{hive-promoter-6zcnyh1j.js → hive-promoter-jejme31e.js} +29 -29
- package/dist/cli/{index-vts5e84g.js → index-0r4qs243.js} +31 -31
- package/dist/cli/index-2mb5y2w1.js +1372 -0
- package/dist/cli/{index-nse60anv.js → index-7c4bxgdh.js} +1 -1
- package/dist/cli/{index-qskz8j2z.js → index-82m5kwtd.js} +1 -1
- package/dist/cli/{index-6bp1jecx.js → index-9kf3mj08.js} +4 -4
- package/dist/cli/{index-szrcxvr7.js → index-9wmx9ca8.js} +6 -6
- package/dist/cli/{index-76651erq.js → index-ajfa2wmj.js} +9 -9
- package/dist/cli/{index-jpt07f2k.js → index-bb4pcn58.js} +2 -2
- package/dist/cli/{index-qa50yyeh.js → index-bkkxxwcd.js} +1 -1
- package/dist/cli/{index-c2hczjhp.js → index-erfnw81g.js} +3 -3
- package/dist/cli/{index-why8n7cr.js → index-gtkk5rx7.js} +137 -36
- package/dist/cli/{index-73sxchez.js → index-h7ye3bzp.js} +4127 -2558
- package/dist/cli/{index-hwxcdrv9.js → index-j02ez59y.js} +9 -9
- package/dist/cli/{index-h3vk67wp.js → index-k1xsjzm3.js} +3 -3
- package/dist/cli/{index-zbj3yrrd.js → index-k31en0ja.js} +3 -3
- package/dist/cli/{index-q4vaar2b.js → index-k92cagmt.js} +2 -2
- package/dist/cli/{index-p5y72gtj.js → index-kbshtwha.js} +3 -3
- package/dist/cli/{index-r6pdts5c.js → index-ktazgjqw.js} +2 -2
- package/dist/cli/{index-mxtt4x8r.js → index-myav90y6.js} +212 -10
- package/dist/cli/{index-kkn2jxda.js → index-rthq1a6w.js} +1 -1
- package/dist/cli/{index-9d4gck4e.js → index-s2rcz51a.js} +59 -35
- package/dist/cli/{index-y6k6x197.js → index-sdqtecsd.js} +1 -1
- package/dist/cli/{index-v250345n.js → index-tq5s07ta.js} +1 -1
- package/dist/cli/{index-zf5nkkdd.js → index-vefjxxmb.js} +1 -1
- package/dist/cli/{index-bxjhn3t3.js → index-vy11zjvh.js} +2 -2
- package/dist/cli/{index-kq5p3nm3.js → index-w7x7qxz2.js} +1 -1
- package/dist/cli/{index-mqqmant3.js → index-we279je2.js} +1 -1
- package/dist/cli/{index-xx0q37xb.js → index-xah70t2t.js} +1 -1
- package/dist/cli/{index-aqzvjhb7.js → index-xfhe29z3.js} +5 -5
- package/dist/cli/{index-f1hsrgw1.js → index-y9h2vqf6.js} +1 -1
- package/dist/cli/index.js +42 -29
- package/dist/cli/{knowledge-escalator-xjkbek46.js → knowledge-escalator-0b80ryka.js} +12 -12
- package/dist/cli/{knowledge-events-hsdx5prn.js → knowledge-events-8x2wt562.js} +10 -10
- package/dist/cli/{knowledge-link-x86ebng8.js → knowledge-link-fn5j3r4q.js} +5 -5
- package/dist/cli/{knowledge-store-vt059r81.js → knowledge-store-d0xj6wht.js} +6 -6
- package/dist/cli/{knowledge-validator-jr5694jb.js → knowledge-validator-ewfj679a.js} +8 -8
- package/dist/cli/{pending-delegations-7xsagjy5.js → pending-delegations-0hb97ps1.js} +4 -4
- package/dist/cli/{pr-subscriptions-r6cdsa3t.js → pr-subscriptions-b63t252j.js} +4 -4
- package/dist/cli/{runner-nm3baddf.js → runner-hrg7h2h4.js} +6 -6
- package/dist/cli/{scan-cursor-6nrkcfbr.js → scan-cursor-hfyz7zpw.js} +7 -7
- package/dist/cli/{schema-f6pt0zjy.js → schema-ney3c685.js} +1 -1
- package/dist/cli/{scope-persistence-jc0mtp7g.js → scope-persistence-dbfgs7gh.js} +6 -6
- package/dist/cli/{skill-generator-4vp33gjb.js → skill-generator-p651jex5.js} +14 -14
- package/dist/cli/{telemetry-zex3zv3v.js → telemetry-xyfb5vm8.js} +1 -1
- package/dist/cli/{worktree-collision-ownership-n41qw3n8.js → worktree-collision-ownership-ymdxetnn.js} +4 -4
- package/dist/cli/{worktree-isolation-a3hkz665.js → worktree-isolation-513vx61s.js} +29 -29
- package/dist/commands/close.d.ts +20 -2
- package/dist/commands/hive-quarantine.d.ts +23 -0
- package/dist/commands/registry.d.ts +9 -0
- package/dist/gate-evidence.d.ts +24 -1
- package/dist/hooks/hive-transaction.d.ts +41 -0
- package/dist/index.js +491 -478
- package/dist/knowledge/hive-quarantine.d.ts +156 -0
- package/dist/observability/catalog.d.ts +2 -2
- package/dist/plan/ledger.d.ts +31 -1
- package/dist/plan/manager.d.ts +1 -0
- package/dist/state.d.ts +1 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/workflow/close-terminal.d.ts +22 -0
- package/dist/workflow/coder-settlement.d.ts +0 -23
- package/dist/workflow/task-repair.d.ts +1 -0
- package/dist/workflow/task-terminal.d.ts +18 -23
- package/dist/workflow/workflow-wal-file.d.ts +20 -0
- package/dist/workflow/workflow-wal-schema.d.ts +67 -0
- package/dist/worktree/merge.d.ts +17 -0
- package/package.json +1 -1
- package/dist/cli/index-3d13jkzq.js +0 -623
|
@@ -6,16 +6,16 @@ import {
|
|
|
6
6
|
} from "./index-ae75rja9.js";
|
|
7
7
|
import {
|
|
8
8
|
resolveKnowledgeStoreDir
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-w7x7qxz2.js";
|
|
10
10
|
import {
|
|
11
11
|
atomicWriteFile
|
|
12
|
-
} from "./index-
|
|
13
|
-
import {
|
|
14
|
-
require_proper_lockfile
|
|
15
|
-
} from "./index-7g4c7s5r.js";
|
|
12
|
+
} from "./index-erfnw81g.js";
|
|
16
13
|
import {
|
|
17
14
|
readCachedParsedFile
|
|
18
15
|
} from "./index-ed5ykebp.js";
|
|
16
|
+
import {
|
|
17
|
+
require_proper_lockfile
|
|
18
|
+
} from "./index-7g4c7s5r.js";
|
|
19
19
|
import {
|
|
20
20
|
init_logger,
|
|
21
21
|
log
|
|
@@ -709,7 +709,7 @@ async function applyConfidenceFloorAction(directory, touched, options) {
|
|
|
709
709
|
const {
|
|
710
710
|
readAuthoritativeKnowledgeCounterRollups,
|
|
711
711
|
effectiveRetrievalOutcomes
|
|
712
|
-
} = await import("./knowledge-events-
|
|
712
|
+
} = await import("./knowledge-events-8x2wt562.js");
|
|
713
713
|
const rollups = await readAuthoritativeKnowledgeCounterRollups(directory);
|
|
714
714
|
const flagIds = new Set;
|
|
715
715
|
for (const e of atFloor) {
|
|
@@ -776,11 +776,11 @@ async function applyConfidenceFloorAction(directory, touched, options) {
|
|
|
776
776
|
});
|
|
777
777
|
}
|
|
778
778
|
if (action === "quarantine" && toQuarantine.length > 0) {
|
|
779
|
-
const { quarantineEntry } = await import("./knowledge-validator-
|
|
780
|
-
const { KnowledgeConfigSchema } = await import("./schema-
|
|
779
|
+
const { quarantineEntry } = await import("./knowledge-validator-ewfj679a.js");
|
|
780
|
+
const { KnowledgeConfigSchema } = await import("./schema-ney3c685.js");
|
|
781
781
|
let config;
|
|
782
782
|
try {
|
|
783
|
-
const { loadPluginConfigWithMeta } = await import("./index-
|
|
783
|
+
const { loadPluginConfigWithMeta } = await import("./index-kbshtwha.js");
|
|
784
784
|
const { config: loadedConfig } = loadPluginConfigWithMeta(directory);
|
|
785
785
|
config = KnowledgeConfigSchema.parse(loadedConfig.knowledge ?? {});
|
|
786
786
|
} catch {
|
|
@@ -2,18 +2,18 @@
|
|
|
2
2
|
import {
|
|
3
3
|
effectiveRetrievalOutcomes,
|
|
4
4
|
readAuthoritativeKnowledgeCounterRollups
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-ajfa2wmj.js";
|
|
6
6
|
import {
|
|
7
7
|
ALLOWED_SKILL_PATH_PREFIXES,
|
|
8
8
|
validateSkillPath
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-9kf3mj08.js";
|
|
10
10
|
import {
|
|
11
11
|
computeOutcomeSignal,
|
|
12
12
|
readKnowledge,
|
|
13
13
|
resolveHiveKnowledgePath,
|
|
14
14
|
resolveSwarmKnowledgePath,
|
|
15
15
|
transactKnowledge
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-j02ez59y.js";
|
|
17
17
|
import {
|
|
18
18
|
advisoryWarn,
|
|
19
19
|
init_warning_buffer
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
require_proper_lockfile
|
|
4
4
|
} from "./index-7g4c7s5r.js";
|
|
5
|
+
import {
|
|
6
|
+
emit
|
|
7
|
+
} from "./index-s2rcz51a.js";
|
|
5
8
|
import {
|
|
6
9
|
init_logger,
|
|
7
10
|
warn
|
|
8
11
|
} from "./index-zgwm4ryv.js";
|
|
9
|
-
import {
|
|
10
|
-
emit
|
|
11
|
-
} from "./index-9d4gck4e.js";
|
|
12
12
|
import {
|
|
13
13
|
__toESM
|
|
14
14
|
} from "./index-a76rekgs.js";
|
|
@@ -9,11 +9,11 @@ import {
|
|
|
9
9
|
} from "./index-y8552snf.js";
|
|
10
10
|
import {
|
|
11
11
|
atomicWriteFile
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-erfnw81g.js";
|
|
13
13
|
import {
|
|
14
14
|
assertProjectRoot,
|
|
15
15
|
withEvidenceLock
|
|
16
|
-
} from "./index-
|
|
16
|
+
} from "./index-k31en0ja.js";
|
|
17
17
|
import {
|
|
18
18
|
exports_external,
|
|
19
19
|
init_zod
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
_internals,
|
|
4
4
|
resolveWorktreeIsolationConfig
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-ktazgjqw.js";
|
|
6
6
|
import {
|
|
7
7
|
ApprovalEvidenceSchema,
|
|
8
8
|
BaseEvidenceSchema,
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
loadPluginConfig,
|
|
43
43
|
loadPluginConfigWithMeta,
|
|
44
44
|
loadPluginConfigWithMetaAsync
|
|
45
|
-
} from "./index-
|
|
45
|
+
} from "./index-sdqtecsd.js";
|
|
46
46
|
import"./index-4rhhvd1a.js";
|
|
47
47
|
import"./index-zgwm4ryv.js";
|
|
48
48
|
import {
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
TurboConfigSchema,
|
|
67
67
|
WorktreeIsolationConfigSchema,
|
|
68
68
|
resolveAutoReviewConfig
|
|
69
|
-
} from "./index-
|
|
69
|
+
} from "./index-we279je2.js";
|
|
70
70
|
import {
|
|
71
71
|
ALL_AGENT_NAMES,
|
|
72
72
|
ALL_SUBAGENT_NAMES,
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
init_loader,
|
|
4
4
|
loadPluginConfigWithMeta
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-sdqtecsd.js";
|
|
6
6
|
import {
|
|
7
7
|
init_schema
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-we279je2.js";
|
|
9
9
|
import {
|
|
10
10
|
DEFAULT_WORKTREE_ISOLATION_CONFIG,
|
|
11
11
|
init_constants
|
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
import {
|
|
3
3
|
assertProjectRoot,
|
|
4
4
|
withEvidenceLock
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-k31en0ja.js";
|
|
6
|
+
import {
|
|
7
|
+
emit
|
|
8
|
+
} from "./index-s2rcz51a.js";
|
|
6
9
|
import {
|
|
7
10
|
ExecutionProfileSchema,
|
|
8
11
|
PlanSchema,
|
|
9
12
|
TaskStatusSchema,
|
|
10
13
|
init_loader
|
|
11
|
-
} from "./index-
|
|
14
|
+
} from "./index-sdqtecsd.js";
|
|
12
15
|
import {
|
|
13
16
|
criticalWarn,
|
|
14
17
|
init_logger,
|
|
15
18
|
log
|
|
16
19
|
} from "./index-zgwm4ryv.js";
|
|
17
|
-
import {
|
|
18
|
-
emit
|
|
19
|
-
} from "./index-9d4gck4e.js";
|
|
20
20
|
|
|
21
21
|
// src/plan/utils.ts
|
|
22
22
|
import { createHash } from "crypto";
|
|
@@ -47,6 +47,28 @@ function normalizeExecutionProfileForHash(profile) {
|
|
|
47
47
|
|
|
48
48
|
// src/plan/ledger.ts
|
|
49
49
|
var LEDGER_SCHEMA_VERSION = "1.1.0";
|
|
50
|
+
function resolvePlanEpochIdentity(events, authoritativePlan) {
|
|
51
|
+
const planId = derivePlanId(authoritativePlan);
|
|
52
|
+
const planIdentityHash = derivePlanIdentityHash(authoritativePlan);
|
|
53
|
+
const payloadHash = computePlanHash(authoritativePlan);
|
|
54
|
+
const candidates = extractPlanEpochCandidates(events, planId);
|
|
55
|
+
const distinctCandidateKeys = new Set(candidates.map((candidate) => `${candidate.planEpoch}:${candidate.rootEventHash}`));
|
|
56
|
+
if (distinctCandidateKeys.size > 1) {
|
|
57
|
+
throw new Error(`Conflicting plan epoch metadata detected for ${planId}; refusing to continue.`);
|
|
58
|
+
}
|
|
59
|
+
if (candidates.length === 0) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
const existing = candidates[0];
|
|
63
|
+
return {
|
|
64
|
+
planId,
|
|
65
|
+
planIdentityHash,
|
|
66
|
+
planEpoch: existing.planEpoch,
|
|
67
|
+
rootEventHash: existing.rootEventHash,
|
|
68
|
+
payloadHash,
|
|
69
|
+
source: existing.source
|
|
70
|
+
};
|
|
71
|
+
}
|
|
50
72
|
var LEDGER_FILENAME = "plan-ledger.jsonl";
|
|
51
73
|
var LEDGER_LOCK_PATH = path.join(".swarm", LEDGER_FILENAME);
|
|
52
74
|
var PLAN_JSON_FILENAME = "plan.json";
|
|
@@ -63,6 +85,90 @@ function getLedgerPath(directory) {
|
|
|
63
85
|
function getPlanJsonPath(directory) {
|
|
64
86
|
return path.join(directory, ".swarm", PLAN_JSON_FILENAME);
|
|
65
87
|
}
|
|
88
|
+
function asRecord(value) {
|
|
89
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
function isSha256Hex(value) {
|
|
95
|
+
return /^[a-f0-9]{64}$/i.test(value);
|
|
96
|
+
}
|
|
97
|
+
function isUuid(value) {
|
|
98
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
99
|
+
}
|
|
100
|
+
function serializeLedgerEvent(event) {
|
|
101
|
+
return JSON.stringify(event);
|
|
102
|
+
}
|
|
103
|
+
function computeLedgerEventHash(event) {
|
|
104
|
+
return crypto.createHash("sha256").update(serializeLedgerEvent(event), "utf8").digest("hex");
|
|
105
|
+
}
|
|
106
|
+
function extractPlanEpochCandidates(events, expectedPlanId) {
|
|
107
|
+
if (events.length === 0) {
|
|
108
|
+
throw new Error("Plan ledger is empty; missing plan_created root.");
|
|
109
|
+
}
|
|
110
|
+
const rootEvent = events[0];
|
|
111
|
+
if (rootEvent.event_type !== "plan_created") {
|
|
112
|
+
throw new Error(`Plan ledger root must be plan_created; found ${rootEvent.event_type} at seq ${rootEvent.seq}.`);
|
|
113
|
+
}
|
|
114
|
+
if (rootEvent.plan_id !== expectedPlanId) {
|
|
115
|
+
throw new Error(`Plan ledger identity mismatch: expected ${expectedPlanId} but found ${rootEvent.plan_id}.`);
|
|
116
|
+
}
|
|
117
|
+
const rootEventHash = computeLedgerEventHash(rootEvent);
|
|
118
|
+
const candidates = [];
|
|
119
|
+
const rootPayload = asRecord(rootEvent.payload);
|
|
120
|
+
const rootPlanEpoch = rootPayload?.plan_epoch;
|
|
121
|
+
if (typeof rootPlanEpoch === "string" && rootPlanEpoch.length > 0) {
|
|
122
|
+
if (!isUuid(rootPlanEpoch)) {
|
|
123
|
+
throw new Error("Plan ledger root carries an invalid plan_epoch.");
|
|
124
|
+
}
|
|
125
|
+
candidates.push({
|
|
126
|
+
planEpoch: rootPlanEpoch,
|
|
127
|
+
rootEventHash,
|
|
128
|
+
source: "root"
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
for (const event of events) {
|
|
132
|
+
if (event.event_type !== "snapshot" || event.source !== "plan_epoch_adopted") {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (event.plan_id !== expectedPlanId) {
|
|
136
|
+
throw new Error(`Plan epoch adoption snapshot at seq ${event.seq} belongs to ${event.plan_id}, expected ${expectedPlanId}.`);
|
|
137
|
+
}
|
|
138
|
+
const payload = asRecord(event.payload);
|
|
139
|
+
const planEpoch = payload?.plan_epoch;
|
|
140
|
+
const rootHash = payload?.root_event_hash;
|
|
141
|
+
const embeddedPlan = PlanSchema.safeParse(payload?.plan);
|
|
142
|
+
if (!embeddedPlan.success) {
|
|
143
|
+
throw new Error(`Plan epoch adoption snapshot at seq ${event.seq} carries an invalid embedded plan.`);
|
|
144
|
+
}
|
|
145
|
+
const payloadHash = payload?.payload_hash;
|
|
146
|
+
if (typeof planEpoch !== "string" || !isUuid(planEpoch)) {
|
|
147
|
+
throw new Error(`Plan epoch adoption snapshot at seq ${event.seq} has an invalid plan_epoch.`);
|
|
148
|
+
}
|
|
149
|
+
if (typeof rootHash !== "string" || !isSha256Hex(rootHash)) {
|
|
150
|
+
throw new Error(`Plan epoch adoption snapshot at seq ${event.seq} has an invalid root_event_hash.`);
|
|
151
|
+
}
|
|
152
|
+
if (rootHash !== rootEventHash) {
|
|
153
|
+
throw new Error(`Plan epoch adoption snapshot at seq ${event.seq} does not match the canonical ledger root.`);
|
|
154
|
+
}
|
|
155
|
+
if (typeof payloadHash !== "string") {
|
|
156
|
+
throw new Error(`Plan epoch adoption snapshot at seq ${event.seq} is missing payload_hash.`);
|
|
157
|
+
}
|
|
158
|
+
if (derivePlanId(embeddedPlan.data) !== expectedPlanId) {
|
|
159
|
+
throw new Error(`Plan epoch adoption snapshot at seq ${event.seq} embeds a different plan identity.`);
|
|
160
|
+
}
|
|
161
|
+
if (computePlanHash(embeddedPlan.data) !== payloadHash) {
|
|
162
|
+
throw new Error(`Plan epoch adoption snapshot at seq ${event.seq} has a mismatched payload_hash.`);
|
|
163
|
+
}
|
|
164
|
+
candidates.push({
|
|
165
|
+
planEpoch,
|
|
166
|
+
rootEventHash: rootHash,
|
|
167
|
+
source: "plan_epoch_adopted"
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return candidates;
|
|
171
|
+
}
|
|
66
172
|
function writeFileFsyncedThenRename(tempPath, targetPath, data) {
|
|
67
173
|
const fd = fs.openSync(tempPath, "w");
|
|
68
174
|
try {
|
|
@@ -258,7 +364,10 @@ async function initLedger(directory, planId, initialPlanHash, initialPlan) {
|
|
|
258
364
|
}
|
|
259
365
|
} catch {}
|
|
260
366
|
}
|
|
261
|
-
const payload =
|
|
367
|
+
const payload = {
|
|
368
|
+
plan_epoch: crypto.randomUUID(),
|
|
369
|
+
...embeddedPlan ? { plan: embeddedPlan, payload_hash: planHashAfter } : {}
|
|
370
|
+
};
|
|
262
371
|
const event = {
|
|
263
372
|
seq: 1,
|
|
264
373
|
timestamp: new Date().toISOString(),
|
|
@@ -276,6 +385,95 @@ async function initLedger(directory, planId, initialPlanHash, initialPlan) {
|
|
|
276
385
|
`;
|
|
277
386
|
writeFileFsyncedThenRename(tempPath, ledgerPath, line);
|
|
278
387
|
}
|
|
388
|
+
async function readLedgerEventsForEpoch(directory) {
|
|
389
|
+
const integrity = await _internals.readLedgerEventsWithIntegrity(directory, {
|
|
390
|
+
failClosedOnReadError: true
|
|
391
|
+
});
|
|
392
|
+
if (integrity.truncated) {
|
|
393
|
+
throw new Error(`PLAN_LEDGER_TRUNCATED: ${getLedgerPath(directory)} has a malformed line; plan epoch identity cannot be resolved. Preserve this file and quarantine the corrupted suffix before retrying.`);
|
|
394
|
+
}
|
|
395
|
+
return integrity.events;
|
|
396
|
+
}
|
|
397
|
+
async function readPlanEpochIdentity(directory, authoritativePlan) {
|
|
398
|
+
assertProjectRoot(directory);
|
|
399
|
+
if (!await ledgerExists(directory)) {
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
const events = await readLedgerEventsForEpoch(directory);
|
|
403
|
+
if (events.length === 0) {
|
|
404
|
+
throw new Error("Plan ledger is empty; missing plan_created root.");
|
|
405
|
+
}
|
|
406
|
+
return resolvePlanEpochIdentity(events, authoritativePlan);
|
|
407
|
+
}
|
|
408
|
+
async function getOrAdoptPlanEpochUnderLock(directory, authoritativePlan) {
|
|
409
|
+
assertProjectRoot(directory);
|
|
410
|
+
const planId = derivePlanId(authoritativePlan);
|
|
411
|
+
const planIdentityHash = derivePlanIdentityHash(authoritativePlan);
|
|
412
|
+
const payloadHash = computePlanHash(authoritativePlan);
|
|
413
|
+
let lastStaleWriterError;
|
|
414
|
+
for (let attempt = 0;attempt < 4; attempt++) {
|
|
415
|
+
if (!await ledgerExists(directory)) {
|
|
416
|
+
try {
|
|
417
|
+
await initLedger(directory, planId, payloadHash, authoritativePlan);
|
|
418
|
+
} catch (error) {
|
|
419
|
+
if (!(error instanceof Error && error.message.includes("Ledger already initialized"))) {
|
|
420
|
+
throw error;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const events = await readLedgerEventsForEpoch(directory);
|
|
425
|
+
const existing = resolvePlanEpochIdentity(events, authoritativePlan);
|
|
426
|
+
if (existing) {
|
|
427
|
+
return existing;
|
|
428
|
+
}
|
|
429
|
+
if (events.length === 0) {
|
|
430
|
+
throw new Error("Plan ledger is empty; cannot adopt a plan epoch.");
|
|
431
|
+
}
|
|
432
|
+
const rootEvent = events[0];
|
|
433
|
+
const rootEventHash = computeLedgerEventHash(rootEvent);
|
|
434
|
+
const tail = events[events.length - 1];
|
|
435
|
+
const planEpoch = _internals.randomUUID();
|
|
436
|
+
const adoptionPayload = {
|
|
437
|
+
plan: authoritativePlan,
|
|
438
|
+
payload_hash: payloadHash,
|
|
439
|
+
plan_epoch: planEpoch,
|
|
440
|
+
root_event_hash: rootEventHash
|
|
441
|
+
};
|
|
442
|
+
try {
|
|
443
|
+
const appended = await _internals.appendLedgerEvent(directory, {
|
|
444
|
+
event_type: "snapshot",
|
|
445
|
+
source: "plan_epoch_adopted",
|
|
446
|
+
plan_id: planId,
|
|
447
|
+
payload: adoptionPayload
|
|
448
|
+
}, {
|
|
449
|
+
expectedSeq: tail.seq,
|
|
450
|
+
expectedLedgerHash: tail.plan_hash_after,
|
|
451
|
+
planHashAfter: payloadHash
|
|
452
|
+
});
|
|
453
|
+
const verifiedEvents = await readLedgerEventsForEpoch(directory);
|
|
454
|
+
const verified = verifiedEvents[verifiedEvents.length - 1];
|
|
455
|
+
const verifiedPayload = asRecord(verified?.payload);
|
|
456
|
+
if (!verified || verified.seq !== appended.seq || verified.event_type !== "snapshot" || verified.source !== "plan_epoch_adopted" || verified.plan_id !== planId || verifiedPayload?.plan_epoch !== planEpoch || verifiedPayload?.root_event_hash !== rootEventHash || verifiedPayload?.payload_hash !== payloadHash) {
|
|
457
|
+
throw new Error(`Plan epoch adoption read verification failed for ${planId}.`);
|
|
458
|
+
}
|
|
459
|
+
return {
|
|
460
|
+
planId,
|
|
461
|
+
planIdentityHash,
|
|
462
|
+
planEpoch,
|
|
463
|
+
rootEventHash,
|
|
464
|
+
payloadHash,
|
|
465
|
+
source: "plan_epoch_adopted"
|
|
466
|
+
};
|
|
467
|
+
} catch (error) {
|
|
468
|
+
if (error instanceof LedgerStaleWriterError) {
|
|
469
|
+
lastStaleWriterError = error;
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
throw error;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
throw new Error(`Unable to settle plan epoch for ${planId} after repeated stale-writer retries.`, { cause: lastStaleWriterError });
|
|
476
|
+
}
|
|
279
477
|
async function appendLedgerEvent(directory, eventInput, options) {
|
|
280
478
|
assertProjectRoot(directory);
|
|
281
479
|
return withEvidenceLock(directory, LEDGER_LOCK_PATH, "plan-ledger", "append-ledger-event", async () => {
|
|
@@ -627,7 +825,7 @@ function applyEventToPlan(plan, event) {
|
|
|
627
825
|
throw new Error(`applyEventToPlan: unhandled event type "${event.event_type}" at seq ${event.seq}`);
|
|
628
826
|
}
|
|
629
827
|
}
|
|
630
|
-
async function readLedgerEventsWithIntegrity(directory) {
|
|
828
|
+
async function readLedgerEventsWithIntegrity(directory, options) {
|
|
631
829
|
const ledgerPath = getLedgerPath(directory);
|
|
632
830
|
if (!fs.existsSync(ledgerPath)) {
|
|
633
831
|
return { events: [], truncated: false, badSuffix: null };
|
|
@@ -656,7 +854,10 @@ async function readLedgerEventsWithIntegrity(directory) {
|
|
|
656
854
|
}
|
|
657
855
|
events.sort((a, b) => a.seq - b.seq);
|
|
658
856
|
return { events, truncated, badSuffix };
|
|
659
|
-
} catch {
|
|
857
|
+
} catch (error) {
|
|
858
|
+
if (options?.failClosedOnReadError) {
|
|
859
|
+
throw new Error(`PLAN_LEDGER_UNREADABLE: ${ledgerPath} exists but could not be read (${error instanceof Error ? error.message : String(error)}); plan state cannot be resolved. This is NOT an absent ledger \u2014 preserve the file and check permissions/filesystem health before retrying.`);
|
|
860
|
+
}
|
|
660
861
|
return { events: [], truncated: false, badSuffix: null };
|
|
661
862
|
}
|
|
662
863
|
}
|
|
@@ -757,7 +958,8 @@ var _internals = {
|
|
|
757
958
|
getLedgerPath,
|
|
758
959
|
getPlanJsonPath,
|
|
759
960
|
writeFileFsyncedThenRename,
|
|
760
|
-
fsyncRecoveryDirectory
|
|
961
|
+
fsyncRecoveryDirectory,
|
|
962
|
+
randomUUID: () => crypto.randomUUID()
|
|
761
963
|
};
|
|
762
964
|
|
|
763
|
-
export { normalizeExecutionProfileForHash, derivePlanId, derivePlanIdentityHash, LedgerStaleWriterError, computePlanHash, computePlanStructureHash, computeCurrentPlanHash, ledgerExists, getLatestLedgerSeq, readLedgerEvents, initLedger, appendLedgerEvent, takeSnapshotWithRetry, takeSnapshotEvent, replaceTruncatedLedgerWithRecoveryRoot, replayFromLedger, replayFromLedgerWithStatus, readLedgerEventsWithIntegrity, loadLastApprovedPlan };
|
|
965
|
+
export { normalizeExecutionProfileForHash, derivePlanId, derivePlanIdentityHash, LedgerStaleWriterError, computePlanHash, computePlanStructureHash, computeCurrentPlanHash, ledgerExists, getLatestLedgerSeq, readLedgerEvents, initLedger, readPlanEpochIdentity, getOrAdoptPlanEpochUnderLock, appendLedgerEvent, takeSnapshotWithRetry, takeSnapshotEvent, replaceTruncatedLedgerWithRecoveryRoot, replayFromLedger, replayFromLedgerWithStatus, readLedgerEventsWithIntegrity, loadLastApprovedPlan };
|