nexus-agents 8.63.1 → 8.64.0

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.
@@ -11,7 +11,7 @@ import {
11
11
  NODE_ENGINE_RANGE,
12
12
  VERSION,
13
13
  isNodeVersionSupported
14
- } from "./chunk-ZJHPBJLQ.js";
14
+ } from "./chunk-SJGLXUWJ.js";
15
15
  import {
16
16
  claimGlobalRegistry
17
17
  } from "./chunk-TGYLZFU5.js";
@@ -1314,7 +1314,7 @@ async function runDoctorFix(result) {
1314
1314
  writeLine2("\u2500".repeat(40));
1315
1315
  let fixCount = 0;
1316
1316
  if (!result.dataDirectory.rootExists || result.dataDirectory.subdirectories.some((d) => !d.exists || !d.writable)) {
1317
- const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-GOITZLZI.js");
1317
+ const { initDataDirectories: initDataDirectories2, describeDataDirFix: describeDataDirFix2 } = await import("./setup-data-dir-TNH5NNCC.js");
1318
1318
  const outcome = describeDataDirFix2(initDataDirectories2());
1319
1319
  writeLine2(outcome.line);
1320
1320
  if (outcome.counted) fixCount++;
@@ -1416,4 +1416,4 @@ export {
1416
1416
  startStdioServer,
1417
1417
  closeServer
1418
1418
  };
1419
- //# sourceMappingURL=chunk-KM2Q6MWR.js.map
1419
+ //# sourceMappingURL=chunk-O4RBLWDG.js.map
@@ -25,10 +25,10 @@ import {
25
25
  toolSuccessStructured,
26
26
  withProgressHeartbeat,
27
27
  wrapToolWithTimeout
28
- } from "./chunk-J3WA3SHX.js";
28
+ } from "./chunk-WRC725P5.js";
29
29
  import {
30
30
  VERSION
31
- } from "./chunk-ZJHPBJLQ.js";
31
+ } from "./chunk-SJGLXUWJ.js";
32
32
  import {
33
33
  UNRESOLVED_MODEL_ID,
34
34
  assessPanelIndependence,
@@ -283,8 +283,57 @@ function reportPanelModelIndependence(modelIds, roleCount, phase, logger11) {
283
283
  }
284
284
 
285
285
  // src/audit/vote-record.ts
286
- import * as crypto from "node:crypto";
286
+ import * as crypto2 from "node:crypto";
287
287
  import { z as z2 } from "zod";
288
+
289
+ // src/audit/reasoning-commitment.ts
290
+ import * as crypto from "node:crypto";
291
+ var HEX_256_PATTERN = /^[0-9a-f]{64}$/;
292
+ function mintReasoningNonce() {
293
+ return crypto.randomBytes(32).toString("hex");
294
+ }
295
+ function computeReasoningDigest(reasoningNonce, reasoning) {
296
+ return crypto.createHash("sha256").update(reasoningNonce).update(reasoning).digest("hex");
297
+ }
298
+ var REASONING_DIGEST_TIERS = /* @__PURE__ */ new Set(["1.13"]);
299
+ function isReasoningDigestTier(version) {
300
+ return REASONING_DIGEST_TIERS.has(version);
301
+ }
302
+ function textTierShapeDefect(v) {
303
+ if (v.reasoningNonce !== void 0) {
304
+ return { key: "reasoningNonce", message: "reasoningNonce is a 1.13 key" };
305
+ }
306
+ if (v.reasoningDigest !== void 0) {
307
+ return { key: "reasoningDigest", message: "reasoningDigest is a 1.13 key" };
308
+ }
309
+ return null;
310
+ }
311
+ function digestTierShapeDefect(v) {
312
+ const hasText = v.reasoning !== void 0;
313
+ const hasNonce = v.reasoningNonce !== void 0;
314
+ const hasDigest = v.reasoningDigest !== void 0;
315
+ if (hasText && !hasNonce) {
316
+ return { key: "reasoningNonce", message: "reasoning without its reasoningNonce" };
317
+ }
318
+ if (hasNonce && !hasText) {
319
+ return { key: "reasoning", message: "reasoningNonce without the reasoning it opens" };
320
+ }
321
+ if (hasText && !hasDigest) {
322
+ return { key: "reasoningDigest", message: "reasoning without its reasoningDigest" };
323
+ }
324
+ if (hasDigest && !hasText) {
325
+ return {
326
+ key: "reasoning",
327
+ message: "a reasoning commitment with no opening (redaction is step 2, #6264)"
328
+ };
329
+ }
330
+ return null;
331
+ }
332
+ function reasoningCommitmentShapeDefect(digestTier, v) {
333
+ return digestTier ? digestTierShapeDefect(v) : textTierShapeDefect(v);
334
+ }
335
+
336
+ // src/audit/vote-record.ts
288
337
  var VoteRecordDecisionSchema = z2.enum(["approved", "rejected", "no_quorum"]);
289
338
  var VoteRecordOptionCoverageSchema = z2.object({
290
339
  /** Every approving voter, selecting or not — the tally's denominator. */
@@ -429,7 +478,39 @@ var VoterSummarySchema = z2.object({
429
478
  * misclassified (#6244). Rebuilt field-by-field on the `fallback` rule; the
430
479
  * `source` vocabulary is compile-checked against the live `RetriedFrom`.
431
480
  */
432
- retriedFrom: RetriedFromRecordSchema.optional()
481
+ retriedFrom: RetriedFromRecordSchema.optional(),
482
+ /**
483
+ * The per-entry salt of the reasoning commitment (#6263, schema 1.13;
484
+ * #5748 step 1, panel option A amended with a salt). 32 random bytes as
485
+ * lowercase hex, minted by `mintReasoningNonce` (reasoning-commitment.ts)
486
+ * once per entry.
487
+ *
488
+ * The nonce is the OPENING of the commitment, together with `reasoning`:
489
+ * on the digest tier the record hash folds ONLY `reasoningDigest`, and
490
+ * both text and nonce travel on the record outside the hash
491
+ * (`reasoningTruncated` stays hashed). The salt is the secret (#6274
492
+ * panel 1): hashed, it could not be dropped at redaction without
493
+ * breaking the hash and the #3927 signature; public, it would let
494
+ * `sha256(nonce ‖ guess)` confirm low-entropy reasoning once the text is
495
+ * gone. Outside the hash, a later step (#6264) drops text and nonce
496
+ * together while the original hash — and any signature over it — still
497
+ * verifies, and the 256-bit unknown salt keeps the digest opaque. The
498
+ * record-level refinement below holds the three together: on 1.13 text
499
+ * and nonce are present or absent TOGETHER and an entry with reasoning
500
+ * carries the digest; on every older tier it carries neither key (there
501
+ * they would be unhashed decoration).
502
+ */
503
+ reasoningNonce: z2.string().regex(HEX_256_PATTERN).optional(),
504
+ /**
505
+ * `sha256(reasoningNonce ‖ reasoning)` as lowercase hex (#6263, schema
506
+ * 1.13) — see `computeReasoningDigest` in reasoning-commitment.ts. The
507
+ * commitment to the text: {@link verifyVoteRecordSet} re-opens it
508
+ * whenever nonce and text are both present, so a text edited without
509
+ * re-committing is a `hash_mismatch` exactly as it was when the text
510
+ * itself was folded. A digest nobody re-opens would be a check that
511
+ * cannot fail.
512
+ */
513
+ reasoningDigest: z2.string().regex(HEX_256_PATTERN).optional()
433
514
  }).strict();
434
515
  function defineVoterKeys(keys) {
435
516
  return keys;
@@ -453,7 +534,25 @@ var VOTER_SUMMARY_KEYS = defineVoterKeys([
453
534
  // 1.12 (#6246): appended after `fallback`, present-only, so a 1.11 entry
454
535
  // projects byte-identically. Nested; `projectRetriedFrom` rebuilds it in
455
536
  // its own canonical order.
456
- "retriedFrom"
537
+ "retriedFrom",
538
+ // 1.13 (#6263): appended after `retriedFrom`, present-only. Only
539
+ // `reasoningDigest` is ever folded, and only on the digest tier, where
540
+ // `reasoning` above is NOT (`reasoningTruncated` stays folded on every
541
+ // tier); `reasoningNonce` is listed because every schema key must be (the
542
+ // `defineVoterKeys` constraint) but projects to absent on EVERY tier — it
543
+ // is the opening's salt, never hash-covered. `projectVoterField` keys the
544
+ // swap on the record version, so a 1.12 entry still projects
545
+ // byte-identically.
546
+ "reasoningNonce",
547
+ "reasoningDigest"
548
+ ]);
549
+ var REASONING_TIER_KEYS = /* @__PURE__ */ new Set([
550
+ "reasoningNonce",
551
+ "reasoningDigest"
552
+ ]);
553
+ var REASONING_OPENING_KEYS = /* @__PURE__ */ new Set([
554
+ "reasoning",
555
+ "reasoningNonce"
457
556
  ]);
458
557
  function noUnprojectedKeys(rest) {
459
558
  return rest;
@@ -476,7 +575,8 @@ function projectRetriedFrom(r) {
476
575
  ...errorTruncated !== void 0 ? { errorTruncated } : {}
477
576
  };
478
577
  }
479
- function projectVoterField(v, key) {
578
+ function projectVoterField(v, key, digestTier) {
579
+ if (digestTier ? REASONING_OPENING_KEYS.has(key) : REASONING_TIER_KEYS.has(key)) return void 0;
480
580
  if (key === "fallback") {
481
581
  return v.fallback === void 0 ? void 0 : projectSeatFallback(v.fallback);
482
582
  }
@@ -485,10 +585,10 @@ function projectVoterField(v, key) {
485
585
  }
486
586
  return v[key];
487
587
  }
488
- function projectVoterSummary(v) {
588
+ function projectVoterSummary(v, digestTier) {
489
589
  const out = {};
490
590
  for (const key of VOTER_SUMMARY_KEYS) {
491
- const value = projectVoterField(v, key);
591
+ const value = projectVoterField(v, key, digestTier);
492
592
  if (value !== void 0) out[key] = value;
493
593
  }
494
594
  return out;
@@ -525,7 +625,10 @@ var VoteRecordSchema = z2.object({
525
625
  * '1.2' adds the optional `ratifies` subject-binding field (#3927 item 1);
526
626
  * '1.10' adds the optional `ratifiesPr` PR-binding (#5130); '1.11' the
527
627
  * optional `errorPolicy` (#6211); '1.12' the per-voter `retriedFrom`
528
- * (#6246). Every tier is accepted — a 1.1 record
628
+ * (#6246); '1.13' the per-voter `reasoningNonce` + `reasoningDigest`
629
+ * and — the one tier that changes what an EXISTING key means to the
630
+ * hash — folds those instead of `reasoning` (#6263; the clip marker
631
+ * `reasoningTruncated` stays folded). Every tier is accepted — a 1.1 record
529
632
  * (no `ratifies`) verifies unchanged because each optional is folded into
530
633
  * the self-hash ONLY when present (see {@link computeVoteRecordHash}).
531
634
  * Tiers are labels, not ordered numbers: '1.10' follows '1.9' by
@@ -543,7 +646,8 @@ var VoteRecordSchema = z2.object({
543
646
  "1.9",
544
647
  "1.10",
545
648
  "1.11",
546
- "1.12"
649
+ "1.12",
650
+ "1.13"
547
651
  ]),
548
652
  /** Unique record id (also usable as a `ratificationVoteRef`). */
549
653
  id: z2.string().min(1),
@@ -678,7 +782,15 @@ var VoteRecordSchema = z2.object({
678
782
  previousHash: z2.string().length(64).optional(),
679
783
  /** SHA-256 over every field above EXCEPT `previousHash` (and except `hash`). */
680
784
  hash: z2.string().length(64)
681
- }).strict();
785
+ }).strict().superRefine((record, ctx) => {
786
+ const digestTier = isReasoningDigestTier(record.version);
787
+ for (const [i, v] of record.voters.entries()) {
788
+ const defect = reasoningCommitmentShapeDefect(digestTier, v);
789
+ if (defect !== null) {
790
+ ctx.addIssue({ code: "custom", path: ["voters", i, defect.key], message: defect.message });
791
+ }
792
+ }
793
+ });
682
794
  function foldOptionalFields(base, payload) {
683
795
  const withTally = payload.optionTally !== void 0 ? {
684
796
  ...base,
@@ -728,15 +840,21 @@ function computeVoteRecordHash(payload) {
728
840
  // entry ONLY when present, on the same rule as the record-level optional
729
841
  // fields: a pre-1.6 voter entry re-hashes byte-identical, so every
730
842
  // historical record still verifies, while editing or removing a stored
731
- // reasoning flips the hash.
732
- voters: payload.voters.map(projectVoterSummary),
843
+ // reasoning flips the hash. On the digest tier (#6263, schema 1.13) the
844
+ // entry folds `reasoningDigest` INSTEAD of the text, and the salt
845
+ // `reasoningNonce` stays outside the hash with the text (the clip marker
846
+ // stays folded); the text is bound by the digest, which
847
+ // `verifyVoteRecordSet` re-opens with the nonce.
848
+ voters: payload.voters.map(
849
+ (v) => projectVoterSummary(v, isReasoningDigestTier(payload.version))
850
+ ),
733
851
  correlationId: payload.correlationId ?? null
734
852
  };
735
853
  const canonical = JSON.stringify(foldOptionalFields(base, payload));
736
- return crypto.createHash("sha256").update(canonical).digest("hex");
854
+ return crypto2.createHash("sha256").update(canonical).digest("hex");
737
855
  }
738
856
  function hashProposal(proposal) {
739
- return crypto.createHash("sha256").update(proposal).digest("hex");
857
+ return crypto2.createHash("sha256").update(proposal).digest("hex");
740
858
  }
741
859
 
742
860
  // src/cli/voter-unverifiable.ts
@@ -6342,7 +6460,13 @@ function toVoterSummaries(votes) {
6342
6460
  }
6343
6461
  function reasoningFields(reasoning) {
6344
6462
  const { text, truncated } = clipForRecord(reasoning);
6345
- return { reasoning: text, ...truncated === true ? { reasoningTruncated: true } : {} };
6463
+ const reasoningNonce = mintReasoningNonce();
6464
+ return {
6465
+ reasoning: text,
6466
+ ...truncated === true ? { reasoningTruncated: true } : {},
6467
+ reasoningNonce,
6468
+ reasoningDigest: computeReasoningDigest(reasoningNonce, text)
6469
+ };
6346
6470
  }
6347
6471
  function recordDecisionFor(input) {
6348
6472
  return input.resolvedDecision ?? outcomeToDecision(input.result, input.votes, input.errorVoided ?? false);
@@ -6357,6 +6481,7 @@ function deriveOptionFields(votes, declaredOptions) {
6357
6481
  }
6358
6482
  function recordVersion(optionTally, optionCoverage, panelCoverage, voters, recordLevel) {
6359
6483
  const voterTier = voterTierOf(voters);
6484
+ if (voterTier === "1.13") return "1.13";
6360
6485
  if (voterTier === "1.12") return "1.12";
6361
6486
  if (recordLevel.errorPolicy !== void 0) return "1.11";
6362
6487
  if (recordLevel.ratifiesPr !== void 0) return "1.10";
@@ -6366,6 +6491,7 @@ function recordVersion(optionTally, optionCoverage, panelCoverage, voters, recor
6366
6491
  return optionTally !== void 0 ? "1.3" : "1.2";
6367
6492
  }
6368
6493
  function voterTierOf(voters) {
6494
+ if (voters.some((v) => v.reasoningDigest !== void 0)) return "1.13";
6369
6495
  if (voters.some((v) => v.retriedFrom !== void 0)) return "1.12";
6370
6496
  if (voters.some((v) => v.assignedCli !== void 0 || v.fallback !== void 0)) return "1.9";
6371
6497
  if (voters.some((v) => v.model !== void 0 || v.unverifiable === true)) return "1.8";
@@ -6945,7 +7071,7 @@ import {
6945
7071
  import { z as z11 } from "zod";
6946
7072
 
6947
7073
  // src/mcp/jobs/job-idempotency.ts
6948
- import { createHash as createHash2, randomUUID } from "node:crypto";
7074
+ import { createHash as createHash3, randomUUID } from "node:crypto";
6949
7075
  import { existsSync as existsSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
6950
7076
  import { z as z10 } from "zod";
6951
7077
  var logger7 = createLogger({ component: "job-idempotency" });
@@ -6963,7 +7089,7 @@ var IdempotencyIndexEntrySchema = z10.object({
6963
7089
  createdAt: z10.iso.datetime()
6964
7090
  });
6965
7091
  function sha256Hex(input) {
6966
- return createHash2("sha256").update(input).digest("hex");
7092
+ return createHash3("sha256").update(input).digest("hex");
6967
7093
  }
6968
7094
  function canonicalJsonStringify(value) {
6969
7095
  if (value === null || typeof value !== "object") return JSON.stringify(value);
@@ -8930,4 +9056,4 @@ export {
8930
9056
  CONSENSUS_VOTE_TOOL_SCHEMA,
8931
9057
  registerConsensusVoteTool
8932
9058
  };
8933
- //# sourceMappingURL=chunk-YHJO37S5.js.map
9059
+ //# sourceMappingURL=chunk-PCOVCRXL.js.map