@sema-agent/core 7.4.0 → 7.5.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.
Files changed (115) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/agents/cascade.d.ts +2 -1
  3. package/dist/agents/peer-notices.d.ts +11 -1
  4. package/dist/agents/peer-session-drain.js +2 -0
  5. package/dist/agents/verify.d.ts +2 -1
  6. package/dist/core/ask-origin.d.ts +130 -0
  7. package/dist/core/ask-origin.js +35 -0
  8. package/dist/core/auto-mode-arming.d.ts +40 -1
  9. package/dist/core/auto-mode-arming.js +51 -3
  10. package/dist/core/auto-mode.d.ts +87 -10
  11. package/dist/core/auto-mode.js +34 -6
  12. package/dist/core/checkpoint-store.d.ts +41 -6
  13. package/dist/core/checkpoint-store.js +8 -0
  14. package/dist/core/hooks.d.ts +63 -19
  15. package/dist/core/hooks.js +37 -16
  16. package/dist/core/mcp.d.ts +47 -55
  17. package/dist/core/mcp.js +89 -31
  18. package/dist/core/park-selfcheck.js +3 -0
  19. package/dist/core/permission-rule-consent.d.ts +2 -11
  20. package/dist/core/permission-rule-consent.js +13 -62
  21. package/dist/core/permission-rule-org.d.ts +70 -54
  22. package/dist/core/permission-rule-org.js +47 -61
  23. package/dist/core/permission-rule-provider.d.ts +162 -0
  24. package/dist/core/permission-rule-provider.js +148 -0
  25. package/dist/core/permission-rule-session.d.ts +23 -19
  26. package/dist/core/permission-rule-session.js +5 -5
  27. package/dist/core/permission-rule-store.d.ts +46 -21
  28. package/dist/core/permission-rule-store.js +13 -6
  29. package/dist/core/permission-rule-sync.d.ts +2 -1
  30. package/dist/core/permission-rule-sync.js +11 -0
  31. package/dist/core/runner/assemble-result.d.ts +3 -2
  32. package/dist/core/runner/checkpoint-scope.d.ts +32 -0
  33. package/dist/core/runner/checkpoint-scope.js +4 -0
  34. package/dist/core/runner/contracts.d.ts +1878 -0
  35. package/dist/core/runner/contracts.js +1 -0
  36. package/dist/core/runner/denial-limit-arms.d.ts +57 -31
  37. package/dist/core/runner/denial-limit-arms.js +42 -17
  38. package/dist/core/runner/derived-route-fallback.d.ts +34 -0
  39. package/dist/core/runner/derived-route-fallback.js +16 -0
  40. package/dist/core/runner/prepare-acquire-reconcile.d.ts +1 -1
  41. package/dist/core/runner/prepare-announce-once.d.ts +83 -0
  42. package/dist/core/runner/prepare-announce-once.js +105 -0
  43. package/dist/core/runner/prepare-caps-and-workflow.d.ts +170 -0
  44. package/dist/core/runner/prepare-caps-and-workflow.js +255 -0
  45. package/dist/core/runner/prepare-config-doors.d.ts +2 -10
  46. package/dist/core/runner/prepare-defer-classify.d.ts +86 -0
  47. package/dist/core/runner/prepare-defer-classify.js +107 -0
  48. package/dist/core/runner/prepare-delegation-surface.d.ts +104 -0
  49. package/dist/core/runner/prepare-delegation-surface.js +144 -0
  50. package/dist/core/runner/prepare-execution-env.d.ts +54 -0
  51. package/dist/core/runner/prepare-execution-env.js +86 -0
  52. package/dist/core/runner/prepare-file-history.d.ts +95 -0
  53. package/dist/core/runner/prepare-file-history.js +383 -0
  54. package/dist/core/runner/prepare-hands-readface.d.ts +6 -8
  55. package/dist/core/runner/prepare-hands-readface.js +3 -3
  56. package/dist/core/runner/prepare-inherited-gate.d.ts +268 -0
  57. package/dist/core/runner/prepare-inherited-gate.js +266 -0
  58. package/dist/core/runner/prepare-listings.d.ts +77 -0
  59. package/dist/core/runner/prepare-listings.js +76 -0
  60. package/dist/core/runner/prepare-lsp.d.ts +55 -0
  61. package/dist/core/runner/prepare-lsp.js +27 -0
  62. package/dist/core/runner/prepare-memory.d.ts +1 -1
  63. package/dist/core/runner/prepare-offload-wrappers.d.ts +62 -0
  64. package/dist/core/runner/prepare-offload-wrappers.js +45 -0
  65. package/dist/core/runner/prepare-permission-rules.d.ts +132 -0
  66. package/dist/core/runner/prepare-permission-rules.js +140 -0
  67. package/dist/core/runner/prepare-project-context.d.ts +131 -0
  68. package/dist/core/runner/prepare-project-context.js +150 -0
  69. package/dist/core/runner/prepare-prompt-inputs.d.ts +138 -0
  70. package/dist/core/runner/prepare-prompt-inputs.js +141 -0
  71. package/dist/core/runner/prepare-protocol-tools.d.ts +91 -0
  72. package/dist/core/runner/prepare-protocol-tools.js +182 -0
  73. package/dist/core/runner/prepare-question-face.d.ts +119 -0
  74. package/dist/core/runner/prepare-question-face.js +83 -0
  75. package/dist/core/runner/prepare-run-refs.d.ts +89 -0
  76. package/dist/core/runner/prepare-run-refs.js +39 -0
  77. package/dist/core/runner/prepare-safety-scan.d.ts +3 -2
  78. package/dist/core/runner/prepare-task.d.ts +11 -1815
  79. package/dist/core/runner/prepare-task.js +138 -2542
  80. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +111 -0
  81. package/dist/core/runner/prepare-tool-disclosure-mount.js +219 -0
  82. package/dist/core/runner/prepare-wiring-manifest.d.ts +184 -0
  83. package/dist/core/runner/prepare-wiring-manifest.js +240 -0
  84. package/dist/core/runner/prepare-workspace-restore.d.ts +1 -27
  85. package/dist/core/runner/prepare-workspace-restore.js +1 -22
  86. package/dist/core/runner/rollback-stack.d.ts +32 -0
  87. package/dist/core/runner/rollback-stack.js +30 -0
  88. package/dist/core/runner/runtask.d.ts +11 -2
  89. package/dist/core/runner/runtask.js +27 -9
  90. package/dist/core/runner/workspace-path.d.ts +33 -0
  91. package/dist/core/runner/workspace-path.js +22 -0
  92. package/dist/core/sensitive-path-policy.d.ts +16 -0
  93. package/dist/core/sensitive-path-policy.js +1 -1
  94. package/dist/core/tool-policy.d.ts +57 -9
  95. package/dist/core/tool-policy.js +11 -0
  96. package/dist/core/types.d.ts +63 -51
  97. package/dist/core/wiring-manifest.d.ts +40 -3
  98. package/dist/core/wiring-manifest.js +4 -3
  99. package/dist/core/write-protect.d.ts +13 -2
  100. package/dist/core/write-protect.js +58 -29
  101. package/dist/engine/harness/types.d.ts +38 -16
  102. package/dist/engine/harness/types.js +25 -1
  103. package/dist/engine/session/session.d.ts +3 -11
  104. package/dist/index.d.ts +10 -6
  105. package/dist/index.js +9 -5
  106. package/dist/internal/harness.d.ts +1 -0
  107. package/dist/stores/file/adoption/adopt.d.ts +1 -1
  108. package/dist/stores/file/adoption/marker.d.ts +1 -1
  109. package/dist/stores/file/permission-rule-adopt.js +4 -3
  110. package/dist/stores/file/permission-rule-store.d.ts +65 -25
  111. package/dist/stores/file/permission-rule-store.js +215 -37
  112. package/dist/stores/file/task-list-store.d.ts +1 -1
  113. package/dist/tools/fs/read-face.d.ts +1 -1
  114. package/package.json +8 -2
  115. package/test/export-surface.snapshot.json +76 -28
@@ -1,10 +1,32 @@
1
- import { closeSync, constants as FS, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
1
+ import { closeSync, constants as FS, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { PERMISSION_RULE_WRITER, applySyncJoin, applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, foldDelta, } from "../../core/permission-rule-store.js";
5
5
  import { canonicalize } from "../../core/canonical-json.js";
6
6
  import { BootLock } from "./fs-atomic.js";
7
7
  import { assertAdoptionBootGate } from "./adoption/marker.js";
8
+ function isRuleFile(v) {
9
+ const p = v;
10
+ return typeof p === "object" && p !== null && p.schemaVersion === 3 && Array.isArray(p.rules) && Array.isArray(p.tombstones) && typeof p.rev === "number" && (p.quarantined === undefined || Array.isArray(p.quarantined));
11
+ }
12
+ function isLegacyRuleFile(v) {
13
+ const p = v;
14
+ return typeof p === "object" && p !== null && (p.schemaVersion === 1 || p.schemaVersion === 2) && Array.isArray(p.rules) && Array.isArray(p.tombstones) && typeof p.rev === "number";
15
+ }
16
+ function isOrgStateFile(v) {
17
+ const p = v;
18
+ return typeof p === "object" && p !== null && p.schemaVersion === 1 && typeof p.state === "object" && p.state !== null;
19
+ }
20
+ function schemaVersionWord(v) {
21
+ return typeof v === "object" && v !== null ? v.schemaVersion : undefined;
22
+ }
23
+ function jsonForm(v) {
24
+ return JSON.parse(JSON.stringify(v));
25
+ }
26
+ export const ORG_STATE_FILE = "org.json";
27
+ export const SCHEMA3_MARKER_FILE = ".rule-schema-3";
28
+ export class OrgRevisionRefusal extends Error {
29
+ }
8
30
  const LOCAL_OWNER_FILE = "local-owner.json";
9
31
  const ADOPTION_FILE = "PERMISSION-RULES-ADOPTION.json";
10
32
  export function readRuleAdoptionFile(dir) {
@@ -92,7 +114,7 @@ function assertSafeDir(dir) {
92
114
  `refusing to use it — anyone who can write here can grant themselves permissions`);
93
115
  }
94
116
  }
95
- class FilePermissionRuleStore {
117
+ class FileDurableRulePartition {
96
118
  dir;
97
119
  file;
98
120
  acquireWriteLock;
@@ -134,12 +156,11 @@ class FilePermissionRuleStore {
134
156
  this.disclose(why);
135
157
  return { unreadable: why };
136
158
  }
137
- if ((parsed?.schemaVersion !== 1 && parsed?.schemaVersion !== 2) ||
138
- !Array.isArray(parsed.rules) ||
139
- !Array.isArray(parsed.tombstones) ||
140
- typeof parsed.rev !== "number" ||
141
- (parsed.quarantined !== undefined && !Array.isArray(parsed.quarantined))) {
142
- const why = `${this.file} does not carry a readable rule-file shape; refusing the whole file and loading zero rules`;
159
+ if (!isRuleFile(parsed)) {
160
+ const sv = schemaVersionWord(parsed);
161
+ const why = sv === 1 || sv === 2
162
+ ? `${this.file} is a schema ${String(sv)} bucket that was not migrated to schema 3 (written by an older engine after this directory was migrated?); refusing the whole file and loading zero rules`
163
+ : `${this.file} does not carry a readable rule-file shape; refusing the whole file and loading zero rules`;
143
164
  this.disclose(why);
144
165
  return { unreadable: why };
145
166
  }
@@ -175,6 +196,8 @@ class FilePermissionRuleStore {
175
196
  }
176
197
  async list() {
177
198
  const r = this.read();
199
+ if ("unreadable" in r)
200
+ throw new Error(r.unreadable);
178
201
  if (!("file" in r))
179
202
  return { ...EMPTY_READ };
180
203
  const screened = this.screenDurableRows(r.file);
@@ -189,34 +212,13 @@ class FilePermissionRuleStore {
189
212
  const r = this.read();
190
213
  return "file" in r ? this.screenDurableRows(r.file).quarantined : [];
191
214
  }
192
- async readOrgState() {
193
- const r = this.read();
194
- return "file" in r ? r.file.org : undefined;
195
- }
196
- async installOrgState(state) {
197
- this.acquireWriteLock();
198
- await this.serialize(() => {
199
- const cur = this.current();
200
- if (cur.org !== undefined && state.revisionHighWater < cur.org.revisionHighWater) {
201
- throw new Error(`refusing to lower the org revision high-water mark (${cur.org.revisionHighWater} → ${state.revisionHighWater}) — an interleaved install must re-read and re-compare`);
202
- }
203
- if (cur.org !== undefined &&
204
- state.snapshot.revision === cur.org.snapshot.revision &&
205
- canonicalize(state.snapshot.rules) !== canonicalize(cur.org.snapshot.rules)) {
206
- throw new Error(`refusing to replace org revision ${state.snapshot.revision} with DIFFERENT policy content under the same revision — content changes must bump the revision`);
207
- }
208
- if (!this.writeAndVerify({ ...cur, schemaVersion: 2, org: state })) {
209
- throw new Error("the permission-rule store did not survive its own write; the org snapshot was not installed");
210
- }
211
- });
212
- }
213
215
  current() {
214
216
  const r = this.read();
215
217
  if ("unreadable" in r) {
216
218
  throw new Error(`refusing to write the permission-rule store while it cannot be read: ${r.unreadable}`);
217
219
  }
218
220
  if ("absent" in r) {
219
- return { schemaVersion: 1, actor: `file-${randomBytes(6).toString("hex")}`, counter: 0, rev: 0, rules: [], tombstones: [] };
221
+ return { schemaVersion: 3, actor: `file-${randomBytes(6).toString("hex")}`, counter: 0, rev: 0, rules: [], tombstones: [] };
220
222
  }
221
223
  return {
222
224
  schemaVersion: r.file.schemaVersion,
@@ -226,7 +228,6 @@ class FilePermissionRuleStore {
226
228
  rules: r.file.rules,
227
229
  tombstones: r.file.tombstones,
228
230
  ...(r.file.sync !== undefined ? { sync: r.file.sync } : {}),
229
- ...(r.file.org !== undefined ? { org: r.file.org } : {}),
230
231
  ...(r.file.quarantined !== undefined ? { quarantined: r.file.quarantined } : {}),
231
232
  };
232
233
  }
@@ -284,7 +285,6 @@ class FilePermissionRuleStore {
284
285
  }, delta, Date.now());
285
286
  const landed = {
286
287
  ...cur,
287
- schemaVersion: 2,
288
288
  rev: cur.rev + 1,
289
289
  rules: next.rules,
290
290
  tombstones: next.tombstones,
@@ -309,15 +309,105 @@ class FilePermissionRuleStore {
309
309
  }),
310
310
  };
311
311
  }
312
- export class FilePermissionRuleStoreProvider {
312
+ export class FileDurableRulePartitionProvider {
313
313
  dir;
314
314
  onError;
315
315
  lock;
316
+ orgPersistence;
316
317
  constructor(dir, onError, opts) {
317
318
  this.dir = dir;
318
319
  this.onError = onError;
319
320
  if (opts?.dataRoot !== undefined)
320
- assertAdoptionBootGate(opts.dataRoot, "FilePermissionRuleStoreProvider");
321
+ assertAdoptionBootGate(opts.dataRoot, "FileDurableRulePartitionProvider");
322
+ this.migrateLegacyBuckets();
323
+ }
324
+ migrateLegacyBuckets() {
325
+ if (!existsSync(this.dir))
326
+ return;
327
+ if (existsSync(join(this.dir, SCHEMA3_MARKER_FILE)))
328
+ return;
329
+ try {
330
+ assertSafeDir(this.dir);
331
+ }
332
+ catch (err) {
333
+ this.onError?.(`legacy scan skipped: ${err.message}`);
334
+ return;
335
+ }
336
+ const held = this.lock !== undefined;
337
+ try {
338
+ this.acquireWriteLock();
339
+ }
340
+ catch (err) {
341
+ this.onError?.(`rule-file schema migration deferred (the directory will be scanned again by the next construction that can take its writer lock): ${err.message}`);
342
+ return;
343
+ }
344
+ let complete = true;
345
+ try {
346
+ let names;
347
+ try {
348
+ names = readdirSync(this.dir);
349
+ }
350
+ catch (err) {
351
+ this.onError?.(`rule-file schema migration deferred (the directory could not be listed): ${err.message}`);
352
+ return;
353
+ }
354
+ const candidates = names.filter((name) => name === LOCAL_OWNER_FILE || /^[0-9a-f]{64}\.json$/.test(name)).sort();
355
+ const legacy = [];
356
+ for (const name of candidates) {
357
+ const read = readLegacyBucket(join(this.dir, name));
358
+ if (read !== undefined)
359
+ legacy.push({ name, file: read });
360
+ }
361
+ if (legacy.length === 0) {
362
+ this.writeSchema3Marker();
363
+ return;
364
+ }
365
+ const orgHome = this.fileOrgPersistence();
366
+ for (const { name, file } of legacy) {
367
+ const { org, schemaVersion: _legacyVersion, checksum: _legacyChecksum, ...rest } = file;
368
+ if (org !== undefined) {
369
+ try {
370
+ orgHome.installOrgStateSync(org);
371
+ }
372
+ catch (err) {
373
+ if (err instanceof OrgRevisionRefusal) {
374
+ this.onError?.(`the org block of ${name} was not folded into ${ORG_STATE_FILE}: ${err.message}`);
375
+ }
376
+ else {
377
+ complete = false;
378
+ this.onError?.(`legacy bucket ${name} left untouched: its org block could not be installed into ${ORG_STATE_FILE} (${err.message}); the migration will retry on the next construction`);
379
+ continue;
380
+ }
381
+ }
382
+ }
383
+ const next = { ...rest, schemaVersion: 3 };
384
+ atomicPublish(this.dir, join(this.dir, name), JSON.stringify({ ...next, checksum: checksumOf(next) }, null, 2));
385
+ this.onError?.(`migrated ${name} to rule-file schema 3${org !== undefined ? ` (its org block moved to ${ORG_STATE_FILE})` : ""}`);
386
+ }
387
+ if (complete)
388
+ this.writeSchema3Marker();
389
+ }
390
+ finally {
391
+ if (!held) {
392
+ this.lock?.release();
393
+ this.lock = undefined;
394
+ }
395
+ }
396
+ }
397
+ writeSchema3Marker() {
398
+ try {
399
+ atomicPublish(this.dir, join(this.dir, SCHEMA3_MARKER_FILE), JSON.stringify({ schemaVersion: 3 }));
400
+ }
401
+ catch (err) {
402
+ this.onError?.(`could not write ${SCHEMA3_MARKER_FILE}: ${err.message}; the legacy scan will run again next construction`);
403
+ }
404
+ }
405
+ orgStatePersistence() {
406
+ return this.fileOrgPersistence();
407
+ }
408
+ fileOrgPersistence() {
409
+ this.orgPersistence ??= new FileOrgRuleStatePersistence(this.dir, this.acquireWriteLock, this.onError);
410
+ return this.orgPersistence;
321
411
  }
322
412
  acquireWriteLock = () => {
323
413
  if (this.lock !== undefined)
@@ -338,11 +428,11 @@ export class FilePermissionRuleStoreProvider {
338
428
  return this.readOnlySourceView(principalRuleFileName(principal), principalRuleFileName(rec.toPrincipal), "adopted" in adoption || adoption.marker.phase >= 4);
339
429
  }
340
430
  }
341
- return new FilePermissionRuleStore(this.dir, join(this.dir, principalRuleFileName(principal)), this.acquireWriteLock, this.onError);
431
+ return new FileDurableRulePartition(this.dir, join(this.dir, principalRuleFileName(principal)), this.acquireWriteLock, this.onError);
342
432
  }
343
433
  readOnlySourceView(sourceName, targetName, flipped) {
344
434
  const pick = flipped ? targetName : existsSync(join(this.dir, sourceName)) ? sourceName : targetName;
345
- return readOnlyRuleStoreView(new FilePermissionRuleStore(this.dir, join(this.dir, pick), this.acquireWriteLock, this.onError));
435
+ return readOnlyRuleStoreView(new FileDurableRulePartition(this.dir, join(this.dir, pick), this.acquireWriteLock, this.onError));
346
436
  }
347
437
  forLocalOwner() {
348
438
  const adoption = readRuleAdoptionFile(this.dir);
@@ -352,13 +442,101 @@ export class FilePermissionRuleStoreProvider {
352
442
  return this.readOnlySourceView(LOCAL_OWNER_FILE, principalRuleFileName(rec.toPrincipal), "adopted" in adoption || adoption.marker.phase >= 4);
353
443
  }
354
444
  }
355
- return new FilePermissionRuleStore(this.dir, join(this.dir, LOCAL_OWNER_FILE), this.acquireWriteLock, this.onError);
445
+ return new FileDurableRulePartition(this.dir, join(this.dir, LOCAL_OWNER_FILE), this.acquireWriteLock, this.onError);
356
446
  }
357
447
  dispose() {
358
448
  this.lock?.release();
359
449
  this.lock = undefined;
360
450
  }
361
451
  }
452
+ function readLegacyBucket(file) {
453
+ let raw;
454
+ try {
455
+ const st = lstatSync(file);
456
+ if (st.isSymbolicLink() || !st.isFile())
457
+ return undefined;
458
+ raw = readFileSync(file, "utf8");
459
+ }
460
+ catch {
461
+ return undefined;
462
+ }
463
+ let parsed;
464
+ try {
465
+ parsed = JSON.parse(raw);
466
+ }
467
+ catch {
468
+ return undefined;
469
+ }
470
+ if (!isLegacyRuleFile(parsed))
471
+ return undefined;
472
+ const { checksum, ...body } = parsed;
473
+ return checksum === checksumOf(body) ? parsed : undefined;
474
+ }
475
+ class FileOrgRuleStatePersistence {
476
+ dir;
477
+ acquireWriteLock;
478
+ onError;
479
+ file;
480
+ writeChain = Promise.resolve();
481
+ constructor(dir, acquireWriteLock, onError) {
482
+ this.dir = dir;
483
+ this.acquireWriteLock = acquireWriteLock;
484
+ this.onError = onError;
485
+ this.file = join(dir, ORG_STATE_FILE);
486
+ }
487
+ readSync() {
488
+ let raw;
489
+ try {
490
+ assertSafeDir(this.dir);
491
+ const st = lstatSync(this.file);
492
+ if (st.isSymbolicLink() || !st.isFile())
493
+ throw new Error(`${this.file} is a symlink or not a regular file; refusing to load the org state from it`);
494
+ raw = readFileSync(this.file, "utf8");
495
+ }
496
+ catch (err) {
497
+ if (err?.code === "ENOENT")
498
+ return undefined;
499
+ throw err;
500
+ }
501
+ const parsed = JSON.parse(raw);
502
+ if (!isOrgStateFile(parsed))
503
+ throw new Error(`${this.file} does not carry a readable org-state shape; refusing it whole`);
504
+ const { checksum, ...body } = parsed;
505
+ if (checksum !== checksumOf(body))
506
+ throw new Error(`${this.file} failed its integrity check; refusing it whole`);
507
+ return parsed.state;
508
+ }
509
+ async readOrgState() {
510
+ return this.readSync();
511
+ }
512
+ installOrgStateSync(state) {
513
+ this.acquireWriteLock();
514
+ assertSafeDir(this.dir);
515
+ state = jsonForm(state);
516
+ const cur = this.readSync();
517
+ if (cur !== undefined && state.revisionHighWater < cur.revisionHighWater) {
518
+ throw new OrgRevisionRefusal(`refusing to lower the org revision high-water mark (${cur.revisionHighWater} → ${state.revisionHighWater}) — an interleaved install must re-read and re-compare`);
519
+ }
520
+ if (cur !== undefined && state.snapshot.revision === cur.snapshot.revision && canonicalize(state.snapshot.rules) !== canonicalize(cur.snapshot.rules)) {
521
+ throw new OrgRevisionRefusal(`refusing to replace org revision ${state.snapshot.revision} with DIFFERENT policy content under the same revision — content changes must bump the revision`);
522
+ }
523
+ if (cur !== undefined && state.snapshot.revision === cur.snapshot.revision && state.snapshot.fetchedAtMs <= cur.snapshot.fetchedAtMs)
524
+ return;
525
+ const body = { schemaVersion: 1, state };
526
+ atomicPublish(this.dir, this.file, JSON.stringify({ ...body, checksum: checksumOf(body) }, null, 2));
527
+ const after = this.readSync();
528
+ if (after === undefined || canonicalize(after) !== canonicalize(state)) {
529
+ const why = "the org state file did not survive its own write; the org snapshot was not installed";
530
+ this.onError?.(why);
531
+ throw new Error(why);
532
+ }
533
+ }
534
+ async installOrgState(state) {
535
+ const run = this.writeChain.then(() => this.installOrgStateSync(state), () => this.installOrgStateSync(state));
536
+ this.writeChain = run.then(() => undefined, () => undefined);
537
+ await run;
538
+ }
539
+ }
362
540
  function readOnlyRuleStoreView(store) {
363
541
  return {
364
542
  list: () => store.list(),
@@ -4,7 +4,7 @@ export declare function createFileTaskListStore(root: string, opts?: {
4
4
  * The DATA ROOT whose adoption marker gates construction (design/183 I6). Most of the file family
5
5
  * takes the data root and derives `join(root, "<family>")` itself; this factory is one of the TWO
6
6
  * faces that instead take a caller-chosen directory (the other being
7
- * `FilePermissionRuleStoreProvider`, which takes a rule bucket) — here, the document's own
7
+ * `FileDurableRulePartitionProvider`, which takes a rule bucket) — here, the document's own
8
8
  * directory. So when a deployment hands in a SUBDIRECTORY the I6 check would look for the marker
9
9
  * inside that subdirectory, find nothing, and pass unconditionally: a gate that is always open
10
10
  * (backlog #136⑦). Supply the data root here and the gate reads the anchor the root-taking faces
@@ -19,7 +19,7 @@ export interface ReadFaceInputs {
19
19
  /** The verifier read-only mount (`handsReadOnly` / toolkit `readOnly`): its containment is a
20
20
  * LOAD-BEARING wall (bash_readonly is genuinely confined by it) — never openable. */
21
21
  readOnlyMount: boolean;
22
- /** Org governance declared (RunnerDeps.permissionRuleOrg in place): default roots; the task layer
22
+ /** Org governance declared (`RunnerDeps.permissionRuleStore.partitions.org === true`): default roots; the task layer
23
23
  * may not open (D-2 — tighten-only under governance; the deps layer, being the deployment's own
24
24
  * declaration, still may). */
25
25
  orgGoverned: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.4.0",
3
+ "version": "7.5.1",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -58,6 +58,7 @@
58
58
  "prepare": "npm run build",
59
59
  "prepublishOnly": "npm run build && npm run test",
60
60
  "gate:blackbox": "node scripts/run-blackbox-gate.mjs",
61
+ "gate:repro": "node scripts/run-repro-gate.mjs",
61
62
  "gate:ledger": "node scripts/verify-hardening-ledger.mjs",
62
63
  "gate:compensation": "node scripts/verify-compensation-registry.mjs",
63
64
  "gate:message-branching": "node scripts/verify-no-message-branching.mjs",
@@ -71,7 +72,12 @@
71
72
  "gate:debts:rc": "node scripts/verify-debts.mjs --rc-gate",
72
73
  "gate:error-surface": "node scripts/verify-error-surface.mjs",
73
74
  "gate:criteria": "node scripts/criteria-lint.mjs",
74
- "gate:reminder-literal": "node scripts/verify-reminder-literal.mjs"
75
+ "gate:reminder-literal": "node scripts/verify-reminder-literal.mjs",
76
+ "gate:wire": "node scripts/wire-changes.mjs",
77
+ "gate:layering": "node scripts/verify-layering.mjs",
78
+ "gate:phase-api": "node scripts/verify-phase-api.mjs",
79
+ "gate:agent-returns": "node scripts/verify-agent-returns.mjs",
80
+ "gate:all": "node scripts/gate-all.mjs"
75
81
  },
76
82
  "dependencies": {
77
83
  "@modelcontextprotocol/sdk": "1.30.0",