wowbagger 0.1.0-alpha.13 → 0.1.0-alpha.17
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/CHANGELOG.md +249 -0
- package/README.md +27 -15
- package/docs/host-contract.md +7 -1
- package/docs/mutation-contract.md +114 -21
- package/docs/work-claim-contract.md +292 -67
- package/package.json +2 -2
- package/schemas/core-envelope.json +4 -3
- package/schemas/index.json +18 -0
- package/schemas/ledger-repair-proposal.json +170 -0
- package/schemas/ledger-repair-request.json +61 -0
- package/schemas/ledger-repair-response.json +90 -0
- package/skills/wowbagger/SKILL.md +134 -22
- package/src/claim-coordinator.js +17 -3
- package/src/claim-journal.js +125 -4
- package/src/claim-publication.js +122 -93
- package/src/claim-request.js +9 -0
- package/src/cli.js +127 -36
- package/src/git-autocommit.js +26 -21
- package/src/launch.js +2 -2
- package/src/ledger-repair.js +1170 -0
- package/src/mutation.js +15 -2
- package/src/reconciliation-classifier.js +117 -0
- package/src/version-drift.js +98 -0
package/src/cli.js
CHANGED
|
@@ -38,6 +38,14 @@ import {
|
|
|
38
38
|
import { readGitTreeFile, readGitTreeLedger } from './git-reconciliation.js';
|
|
39
39
|
import { finalizeFromRecoveryToken, withAutoCommit } from './git-autocommit.js';
|
|
40
40
|
import { loadLedger } from './ledger.js';
|
|
41
|
+
import {
|
|
42
|
+
finalizeNumberRepairCommit,
|
|
43
|
+
isNumberRepairRecoveryToken,
|
|
44
|
+
ledgerRepairInvalidRequest,
|
|
45
|
+
numberRepair,
|
|
46
|
+
numberRepairProposal,
|
|
47
|
+
} from './ledger-repair.js';
|
|
48
|
+
import { inspectVersionDrift } from './version-drift.js';
|
|
41
49
|
import {
|
|
42
50
|
assertReportOutputOutsideLedger,
|
|
43
51
|
buildReportModel,
|
|
@@ -93,6 +101,7 @@ const AUTO_COMMIT_COMMANDS = new Set([
|
|
|
93
101
|
'snooze',
|
|
94
102
|
'patch',
|
|
95
103
|
'publish-claimed',
|
|
104
|
+
'number-repair',
|
|
96
105
|
]);
|
|
97
106
|
// The report failures this command states. A code outside the set is an
|
|
98
107
|
// unexpected condition, never a classification the command can pass through.
|
|
@@ -130,6 +139,8 @@ const COMMAND_SUMMARIES = {
|
|
|
130
139
|
'claim-sync': 'Import committed adoption evidence into the local claim journal.',
|
|
131
140
|
'claim-adopt': 'Rule a committed out-of-protocol item revision legitimate.',
|
|
132
141
|
'mutation-finalize': 'Complete the Git commit an auto-commit mutation could not establish.',
|
|
142
|
+
'version-drift': 'Check installed skill and running core version compatibility.',
|
|
143
|
+
'number-repair': 'Apply a proposed duplicate-number repair to a ledger the mutation gate refuses.',
|
|
133
144
|
provision: 'Provision a Git-backed work-claim namespace.',
|
|
134
145
|
claim: 'Read and coordinate work claims for one ledger.',
|
|
135
146
|
'claim-verify': 'Reconcile the durable claim journal with ledger bytes and Git.',
|
|
@@ -157,6 +168,8 @@ const KNOWN_COMMANDS = new Set([
|
|
|
157
168
|
'claim-sync',
|
|
158
169
|
'claim-adopt',
|
|
159
170
|
'mutation-finalize',
|
|
171
|
+
'version-drift',
|
|
172
|
+
'number-repair',
|
|
160
173
|
]);
|
|
161
174
|
|
|
162
175
|
const CLAIM_SUBCOMMAND_SUMMARIES = {
|
|
@@ -191,6 +204,22 @@ export async function runCli(argumentsList, { scenario } = {}) {
|
|
|
191
204
|
return;
|
|
192
205
|
}
|
|
193
206
|
|
|
207
|
+
if (command === 'version-drift') {
|
|
208
|
+
const parsedOptions = parseContractOptions(command, argumentsList.slice(1));
|
|
209
|
+
if (parsedOptions.issues.length > 0) {
|
|
210
|
+
writeInvalidRequest(command, parsedOptions.issues);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
writeClaimEnvelope(await inspectVersionDrift({
|
|
214
|
+
skillPath: parsedOptions.options.skill
|
|
215
|
+
?? fileURLToPath(new URL('../skills/wowbagger/SKILL.md', import.meta.url)),
|
|
216
|
+
packagePath: fileURLToPath(new URL('../package.json', import.meta.url)),
|
|
217
|
+
runningDistribution: DISTRIBUTION_VERSION,
|
|
218
|
+
runningContractVersion: 5,
|
|
219
|
+
}));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
194
223
|
if (command === 'capabilities') {
|
|
195
224
|
const parsedOptions = parseContractOptions(command, argumentsList.slice(1));
|
|
196
225
|
if (parsedOptions.issues.length > 0) {
|
|
@@ -828,6 +857,13 @@ export async function runCli(argumentsList, { scenario } = {}) {
|
|
|
828
857
|
writeClaimInvalidRequest(command, parsedOptions.issues);
|
|
829
858
|
return;
|
|
830
859
|
}
|
|
860
|
+
if (isNumberRepairRecoveryToken(parsedOptions.options.recoveryToken)) {
|
|
861
|
+
writeClaimEnvelope(await finalizeNumberRepairCommit({
|
|
862
|
+
ledgerDirectory: parsedOptions.options.ledger,
|
|
863
|
+
token: parsedOptions.options.recoveryToken,
|
|
864
|
+
}));
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
831
867
|
writeClaimEnvelope(await finalizeFromRecoveryToken({
|
|
832
868
|
ledgerDirectory: parsedOptions.options.ledger,
|
|
833
869
|
token: parsedOptions.options.recoveryToken,
|
|
@@ -835,6 +871,47 @@ export async function runCli(argumentsList, { scenario } = {}) {
|
|
|
835
871
|
return;
|
|
836
872
|
}
|
|
837
873
|
|
|
874
|
+
// The proposal is request-free and read-only: the ledger is its whole input.
|
|
875
|
+
if (command === 'number-repair-proposal') {
|
|
876
|
+
const parsedOptions = parseContractOptions(command, argumentsList.slice(1));
|
|
877
|
+
if (parsedOptions.issues.length > 0) {
|
|
878
|
+
writeClaimEnvelope(ledgerRepairInvalidRequest(command, parsedOptions.issues));
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
writeClaimEnvelope(await numberRepairProposal(parsedOptions.options.ledger));
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (command === 'number-repair') {
|
|
886
|
+
const parsedOptions = parseContractOptions(command, argumentsList.slice(1));
|
|
887
|
+
if (parsedOptions.issues.length > 0) {
|
|
888
|
+
writeClaimEnvelope(ledgerRepairInvalidRequest(command, parsedOptions.issues));
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
let bytes;
|
|
892
|
+
try {
|
|
893
|
+
bytes = await requestSource(parsedOptions.options.input);
|
|
894
|
+
} catch {
|
|
895
|
+
writeClaimEnvelope(ledgerRepairInvalidRequest(command, [
|
|
896
|
+
issue('/input', 'invalid-value', 'Request input could not be read.'),
|
|
897
|
+
]));
|
|
898
|
+
return;
|
|
899
|
+
}
|
|
900
|
+
const parsedRequest = parseJsonRequest(bytes);
|
|
901
|
+
if (parsedRequest.issues.length > 0) {
|
|
902
|
+
writeClaimEnvelope(ledgerRepairInvalidRequest(command, parsedRequest.issues));
|
|
903
|
+
return;
|
|
904
|
+
}
|
|
905
|
+
// normalizeJsonValue rebuilds the tree into plain objects with every
|
|
906
|
+
// JsonNumber unwrapped, so the exact-member check cannot be slipped past
|
|
907
|
+
// with a `__proto__` member and the number witnesses compare as numbers.
|
|
908
|
+
writeClaimEnvelope(await numberRepair(normalizeJsonValue(parsedRequest.value), {
|
|
909
|
+
ledgerDirectory: parsedOptions.options.ledger,
|
|
910
|
+
autoCommit: parsedOptions.options.autoCommit === true,
|
|
911
|
+
}));
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
|
|
838
915
|
if (command === 'claim-adopt') {
|
|
839
916
|
const parsedOptions = parseContractOptions(command, argumentsList.slice(1));
|
|
840
917
|
if (parsedOptions.issues.length > 0) {
|
|
@@ -1315,28 +1392,31 @@ function parseContractOptions(command, argumentsList) {
|
|
|
1315
1392
|
const options = {};
|
|
1316
1393
|
const issues = [];
|
|
1317
1394
|
const seen = new Set();
|
|
1318
|
-
const valueFlags = command === '
|
|
1319
|
-
? new Map([['--
|
|
1320
|
-
: command === '
|
|
1321
|
-
? new Map([['--ledger', 'ledger'], ['--
|
|
1322
|
-
: command === '
|
|
1323
|
-
|
|
1324
|
-
|| command === '
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
? new Map([['--ledger', 'ledger']])
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1395
|
+
const valueFlags = command === 'version-drift'
|
|
1396
|
+
? new Map([['--skill', 'skill']])
|
|
1397
|
+
: command === 'inspect'
|
|
1398
|
+
? new Map([['--ledger', 'ledger'], ['--id', 'id'], ['--number', 'number'], ['--as-of', 'asOf']])
|
|
1399
|
+
: command === 'report'
|
|
1400
|
+
? new Map([['--ledger', 'ledger'], ['--as-of', 'asOf'], ['--out', 'out'], ['--view', 'view']])
|
|
1401
|
+
: command === 'create' || command === 'transition' || command === 'patch' || command === 'list'
|
|
1402
|
+
|| command === 'parent-migrate'
|
|
1403
|
+
|| command === 'snooze'
|
|
1404
|
+
|| command === 'extensions-provision'
|
|
1405
|
+
|| command === 'publish-claimed' || command === 'publication-read'
|
|
1406
|
+
|| command === 'claim-read' || command === 'claim-acquire' || command === 'claim-renew'
|
|
1407
|
+
|| command === 'claim-release' || command === 'claim-adopt'
|
|
1408
|
+
|| command === 'number-repair'
|
|
1409
|
+
? new Map([['--ledger', 'ledger'], ['--input', 'input']])
|
|
1410
|
+
: command === 'mutation-finalize'
|
|
1411
|
+
? new Map([['--ledger', 'ledger'], ['--recovery-token', 'recoveryToken']])
|
|
1412
|
+
: command === 'claim-merge-verify'
|
|
1413
|
+
? new Map([['--ledger', 'ledger'], ['--base', 'base'], ['--head', 'head']])
|
|
1414
|
+
: command === 'provision' || command === 'claim-capabilities' || command === 'claim-verify'
|
|
1415
|
+
|| command === 'claim-sync' || command === 'number-repair-proposal'
|
|
1416
|
+
? new Map([['--ledger', 'ledger']])
|
|
1417
|
+
: command === 'mint-id'
|
|
1418
|
+
? new Map([['--date', 'date']])
|
|
1419
|
+
: new Map();
|
|
1340
1420
|
// Bare flags carry no value. `--auto-commit` is accepted only on the
|
|
1341
1421
|
// commands whose Git finalization it folds in; `--workbench` only on the one
|
|
1342
1422
|
const bareFlags = AUTO_COMMIT_COMMANDS.has(command)
|
|
@@ -1346,13 +1426,15 @@ function parseContractOptions(command, argumentsList) {
|
|
|
1346
1426
|
: command === 'inspect'
|
|
1347
1427
|
? new Map([['--workbench', 'workbench']])
|
|
1348
1428
|
: new Map();
|
|
1349
|
-
const optionalFlags = command === '
|
|
1350
|
-
? new Set(['--
|
|
1351
|
-
: command === '
|
|
1352
|
-
? new Set(['--
|
|
1353
|
-
: command === '
|
|
1354
|
-
? new Set(['--
|
|
1355
|
-
:
|
|
1429
|
+
const optionalFlags = command === 'version-drift'
|
|
1430
|
+
? new Set(['--skill'])
|
|
1431
|
+
: command === 'mint-id'
|
|
1432
|
+
? new Set(['--date'])
|
|
1433
|
+
: command === 'report'
|
|
1434
|
+
? new Set(['--out', '--view'])
|
|
1435
|
+
: command === 'inspect'
|
|
1436
|
+
? new Set(['--id', '--number', '--as-of'])
|
|
1437
|
+
: new Set();
|
|
1356
1438
|
for (let index = 0; index < argumentsList.length; index += 1) {
|
|
1357
1439
|
const argument = argumentsList[index];
|
|
1358
1440
|
if (argument === '--json') {
|
|
@@ -1654,20 +1736,18 @@ async function runClaimCommand(claimCommand, argumentsList) {
|
|
|
1654
1736
|
}
|
|
1655
1737
|
try {
|
|
1656
1738
|
const envelope = await withClaimLock(storePath, async () => {
|
|
1657
|
-
let replayed;
|
|
1658
|
-
try {
|
|
1659
|
-
replayed = await replayClaimJournal(journalPath, namespace);
|
|
1660
|
-
} catch (error) {
|
|
1661
|
-
throw taggedFailure('CLAIM_STORE_UNREADABLE', error);
|
|
1662
|
-
}
|
|
1663
1739
|
// A claim lifecycle command classifies item reconciliation and refuses
|
|
1664
1740
|
// on it, so it must reason from the same writer evidence every other
|
|
1665
1741
|
// classifying surface uses; otherwise one command grants a claim on
|
|
1666
1742
|
// exactly the state another command refuses to write. It writes no item
|
|
1667
1743
|
// byte and no writer-attributed entry, so it reads the identity it
|
|
1668
|
-
// already answers to rather than creating one.
|
|
1744
|
+
// already answers to rather than creating one. Journal and identity are
|
|
1745
|
+
// both store state this command only reads, so neither reading failure
|
|
1746
|
+
// is anything but an unreadable store.
|
|
1747
|
+
let replayed;
|
|
1669
1748
|
let currentWorktreeId;
|
|
1670
1749
|
try {
|
|
1750
|
+
replayed = await replayClaimJournal(journalPath, namespace);
|
|
1671
1751
|
currentWorktreeId = await readWorktreeIdentity({
|
|
1672
1752
|
ledgerDirectory: parsedOptions.options.ledger,
|
|
1673
1753
|
gitCommonDir,
|
|
@@ -1890,6 +1970,17 @@ function usage(command) {
|
|
|
1890
1970
|
return 'Usage: wowbagger mutation-finalize --ledger <dir> --recovery-token <token> --json';
|
|
1891
1971
|
}
|
|
1892
1972
|
|
|
1973
|
+
if (command === 'version-drift') {
|
|
1974
|
+
return 'Usage: wowbagger version-drift [--skill <path>] --json';
|
|
1975
|
+
}
|
|
1976
|
+
if (command === 'number-repair-proposal') {
|
|
1977
|
+
return 'Usage: wowbagger number-repair-proposal --ledger <dir> --json';
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1980
|
+
if (command === 'number-repair') {
|
|
1981
|
+
return 'Usage: wowbagger number-repair --ledger <dir> --input <json-file|-> --json [--auto-commit]';
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1893
1984
|
if (command === 'claim') {
|
|
1894
1985
|
return 'Usage: wowbagger claim <read|acquire|renew|release|capabilities> [options]';
|
|
1895
1986
|
}
|
package/src/git-autocommit.js
CHANGED
|
@@ -119,17 +119,25 @@ async function finalize({
|
|
|
119
119
|
}) {
|
|
120
120
|
const { root, prefix } = placement;
|
|
121
121
|
const logPath = ledgerRelative(ledgerDirectory, claimReconcileLogPath(path.resolve(ledgerDirectory), namespace));
|
|
122
|
-
|
|
122
|
+
// Every mutation, create included, appends its own journal entries and
|
|
123
|
+
// rebuilds the derived reconciliation log, so every commit set carries that
|
|
124
|
+
// log alongside the item.
|
|
125
|
+
//
|
|
126
|
+
// Log dirt that predates the invocation is a separate question. A mutation on
|
|
127
|
+
// an existing item rebuilds residue its own prior claim operations left in
|
|
128
|
+
// this checkout; a create allocates a fresh identity and has no standing to
|
|
129
|
+
// absorb bytes that were already there, so it refuses instead.
|
|
130
|
+
const absorbsPriorLogDirt = command !== 'create';
|
|
123
131
|
|
|
124
132
|
// Preflight, before any Wowbagger write. Any staged path and every dirty
|
|
125
|
-
// ledger path except
|
|
126
|
-
//
|
|
133
|
+
// ledger path except an absorbable derived log refuse: a broad commit would
|
|
134
|
+
// otherwise take in foreign work.
|
|
127
135
|
const before = await inspectWorktree(root, prefix);
|
|
128
136
|
if (before.staged.length > 0) {
|
|
129
137
|
return shape.preflightFailed('staged-paths-present', { staged_paths: bounded(before.staged) });
|
|
130
138
|
}
|
|
131
139
|
const foreignDirtyBefore = before.dirtyLedger.filter((entry) => (
|
|
132
|
-
!(
|
|
140
|
+
!(absorbsPriorLogDirt && entry === logPath)
|
|
133
141
|
));
|
|
134
142
|
if (foreignDirtyBefore.length > 0) {
|
|
135
143
|
return shape.preflightFailed('ledger-not-clean', { dirty_paths: bounded(foreignDirtyBefore) });
|
|
@@ -165,13 +173,13 @@ async function finalize({
|
|
|
165
173
|
});
|
|
166
174
|
}
|
|
167
175
|
|
|
168
|
-
// Reconciliation rewrites the tracked log.
|
|
169
|
-
// that log
|
|
176
|
+
// Reconciliation rewrites the tracked log. Every command here will commit
|
|
177
|
+
// that log, so its own rewrite is never stray; anything else is.
|
|
170
178
|
const afterVerify = await inspectWorktree(root, prefix);
|
|
171
179
|
if (afterVerify.staged.length > 0) {
|
|
172
180
|
return shape.preflightFailed('staged-paths-present', { staged_paths: bounded(afterVerify.staged) });
|
|
173
181
|
}
|
|
174
|
-
const strayBefore = afterVerify.dirtyLedger.filter((entry) =>
|
|
182
|
+
const strayBefore = afterVerify.dirtyLedger.filter((entry) => entry !== logPath);
|
|
175
183
|
if (strayBefore.length > 0) {
|
|
176
184
|
return shape.preflightFailed('ledger-not-clean', { dirty_paths: bounded(strayBefore) });
|
|
177
185
|
}
|
|
@@ -210,10 +218,10 @@ async function finalize({
|
|
|
210
218
|
const itemChanged = await itemDiffersFromHead(root, prefix, published.path, published.revision);
|
|
211
219
|
const commitSet = [
|
|
212
220
|
...(itemChanged ? [published.path] : []),
|
|
213
|
-
|
|
221
|
+
logPath,
|
|
214
222
|
].sort(compareText);
|
|
215
223
|
const subject = commitSubject(command, published.number, published.id);
|
|
216
|
-
const witness =
|
|
224
|
+
const witness = shape.terminalWitness(outcome, published);
|
|
217
225
|
const context = {
|
|
218
226
|
command,
|
|
219
227
|
head,
|
|
@@ -232,7 +240,6 @@ async function finalize({
|
|
|
232
240
|
context,
|
|
233
241
|
commitSet,
|
|
234
242
|
digests,
|
|
235
|
-
journalOwned,
|
|
236
243
|
ledgerDirectory,
|
|
237
244
|
logPath,
|
|
238
245
|
ownArtifacts: shape.recoveryArtifactPaths(outcome),
|
|
@@ -287,7 +294,7 @@ async function finalize({
|
|
|
287
294
|
gitCommonDir,
|
|
288
295
|
namespace,
|
|
289
296
|
targetItemId: published.id,
|
|
290
|
-
writeLogWhenEmpty:
|
|
297
|
+
writeLogWhenEmpty: true,
|
|
291
298
|
});
|
|
292
299
|
const reconciliation = reconciliationFailureReason(reconciled, commit.commit, context.operationId, published.id);
|
|
293
300
|
if (reconciliation) {
|
|
@@ -305,7 +312,7 @@ async function finalize({
|
|
|
305
312
|
// Every check that must hold between publication and staging. Returning a
|
|
306
313
|
// reason here means the item is published and no Git write has happened yet.
|
|
307
314
|
async function prepareCommitSet({
|
|
308
|
-
context, commitSet, digests,
|
|
315
|
+
context, commitSet, digests, ledgerDirectory, logPath, ownArtifacts, prefix, root, witness,
|
|
309
316
|
}) {
|
|
310
317
|
let itemBytes;
|
|
311
318
|
try {
|
|
@@ -330,7 +337,6 @@ async function prepareCommitSet({
|
|
|
330
337
|
));
|
|
331
338
|
if (stray.length > 0) return { stage: 'prepare-commit-set', reason: 'tree-changed' };
|
|
332
339
|
|
|
333
|
-
if (!journalOwned) return null;
|
|
334
340
|
let logBytes;
|
|
335
341
|
try {
|
|
336
342
|
logBytes = await readFile(path.join(path.resolve(ledgerDirectory), logPath));
|
|
@@ -852,7 +858,6 @@ export async function finalizeFromRecoveryToken({ ledgerDirectory, token }) {
|
|
|
852
858
|
|
|
853
859
|
async function runFinalize({ gitCommonDir, ledgerDirectory, namespace, payload, placement }) {
|
|
854
860
|
const { root, prefix } = placement;
|
|
855
|
-
const journalOwned = payload.command !== 'create';
|
|
856
861
|
const logPath = ledgerRelative(ledgerDirectory, claimReconcileLogPath(path.resolve(ledgerDirectory), namespace));
|
|
857
862
|
const witness = payload.terminal_witness ?? null;
|
|
858
863
|
|
|
@@ -877,14 +882,15 @@ async function runFinalize({ gitCommonDir, ledgerDirectory, namespace, payload,
|
|
|
877
882
|
const itemChanged = await itemDiffersFromHead(root, prefix, derived.path, payload.published_revision);
|
|
878
883
|
commitSet = [
|
|
879
884
|
...(itemChanged ? [derived.path] : []),
|
|
880
|
-
|
|
885
|
+
logPath,
|
|
881
886
|
].sort(compareText);
|
|
882
887
|
} else {
|
|
883
888
|
commitSet = [...tokenPaths].sort(compareText);
|
|
884
889
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
890
|
+
// A token is only ever issued by the auto-commit path above, where every
|
|
891
|
+
// command owns its reconciliation log, so recovery accepts the same two
|
|
892
|
+
// shapes for every command.
|
|
893
|
+
const allowedCommitSets = [[logPath], [derived.path, logPath]];
|
|
888
894
|
const tokenMatchesMutation = allowedCommitSets.some((allowed) => sameSet(tokenPaths, allowed));
|
|
889
895
|
if (payload.item_path !== derived.path
|
|
890
896
|
|| !tokenMatchesMutation
|
|
@@ -910,7 +916,7 @@ async function runFinalize({ gitCommonDir, ledgerDirectory, namespace, payload,
|
|
|
910
916
|
}
|
|
911
917
|
|
|
912
918
|
const refusal = await finalizePreconditions({
|
|
913
|
-
commitSet, derived, digests, gitPaths,
|
|
919
|
+
commitSet, derived, digests, gitPaths, ledgerDirectory, logPath, payload, prefix, root, witness,
|
|
914
920
|
});
|
|
915
921
|
if (refusal) return finalizeRefused(refusal.reason, refusal.details);
|
|
916
922
|
|
|
@@ -952,7 +958,7 @@ async function runFinalize({ gitCommonDir, ledgerDirectory, namespace, payload,
|
|
|
952
958
|
}
|
|
953
959
|
|
|
954
960
|
async function finalizePreconditions({
|
|
955
|
-
commitSet, derived, digests, gitPaths,
|
|
961
|
+
commitSet, derived, digests, gitPaths, ledgerDirectory, logPath, payload, prefix, root, witness,
|
|
956
962
|
}) {
|
|
957
963
|
let itemBytes;
|
|
958
964
|
try {
|
|
@@ -973,7 +979,6 @@ async function finalizePreconditions({
|
|
|
973
979
|
}
|
|
974
980
|
const stray = observed.dirtyLedger.filter((entry) => !commitSet.includes(entry));
|
|
975
981
|
if (stray.length > 0) return { reason: 'ledger-not-clean', details: { dirty_paths: bounded(stray) } };
|
|
976
|
-
if (!journalOwned) return null;
|
|
977
982
|
let logBytes;
|
|
978
983
|
try {
|
|
979
984
|
logBytes = await readFile(path.join(path.resolve(ledgerDirectory), logPath));
|
package/src/launch.js
CHANGED
|
@@ -17,8 +17,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
17
17
|
|
|
18
18
|
// The engine floor the package declares. A host that resolves its own Node
|
|
19
19
|
// executable rather than reusing `process.execPath` must check it, because a
|
|
20
|
-
// Node
|
|
21
|
-
export const MINIMUM_NODE_MAJOR =
|
|
20
|
+
// Node 22 executable will fail somewhere inside the core rather than at launch.
|
|
21
|
+
export const MINIMUM_NODE_MAJOR = 24;
|
|
22
22
|
|
|
23
23
|
// The absolute path of the core script. It is resolved from this module's own
|
|
24
24
|
// URL, so it is correct for a global install, a local install, a workspace
|