@sema-agent/core 7.26.0 → 7.26.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 (29) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/core/permission-rule-provider.js +6 -1
  3. package/dist/core/permission-rule-store.d.ts +36 -0
  4. package/dist/core/permission-rule-store.js +119 -19
  5. package/dist/core/permission-rule-sync.js +14 -5
  6. package/dist/core/runner/prepare-inherited-gate.d.ts +1 -1
  7. package/dist/core/runner/prepare-inherited-gate.js +2 -1
  8. package/dist/core/runner/session-rule-policy.d.ts +1 -1
  9. package/dist/core/runner/session-rule-policy.js +6 -7
  10. package/dist/core/session-policy-store.d.ts +18 -0
  11. package/dist/core/session-policy-store.js +3 -0
  12. package/dist/core/store-contracts/permission-rule-write-contract.js +16 -3
  13. package/dist/core/store-contracts/read-back-shape-contract.d.ts +56 -0
  14. package/dist/core/store-contracts/read-back-shape-contract.js +78 -0
  15. package/dist/index.d.ts +4 -0
  16. package/dist/index.js +4 -0
  17. package/dist/stores/file/adoption/adopt.js +4 -10
  18. package/dist/stores/file/permission-rule-store.d.ts +5 -1
  19. package/dist/stores/file/permission-rule-store.js +5 -3
  20. package/dist/stores/file/session-policy-store.d.ts +32 -0
  21. package/dist/stores/file/session-policy-store.js +72 -50
  22. package/dist/tools/fs/shell-read-check.d.ts +58 -1
  23. package/dist/tools/fs/shell-read-check.js +47 -33
  24. package/dist/tools/fs/shell-read-establish.js +19 -8
  25. package/dist/tools/fs/shell-read-judge.d.ts +3 -0
  26. package/dist/tools/fs/shell-read-judge.js +3 -1
  27. package/package.json +1 -1
  28. package/test/export-surface.snapshot.json +51 -1
  29. package/wire-changes/core@7.26.1.json +605 -0
@@ -281,7 +281,9 @@ export function createShellReadEstablisher(env, readRoots) {
281
281
  return { paths: frontier, canonical: canonicalOfMatch };
282
282
  };
283
283
  const enumerateTraversal = async (rootCanonical, signal) => {
284
- const members = [];
284
+ const found = [];
285
+ const listedDirs = new Set();
286
+ let root;
285
287
  const stack = [{ dir: rootCanonical, spell: rootCanonical }];
286
288
  const visited = new Set([rootCanonical]);
287
289
  let dirsUsed = 0;
@@ -291,18 +293,23 @@ export function createShellReadEstablisher(env, readRoots) {
291
293
  return { unverifiable: `"${rootCanonical}" holds more than ${MAX_GLOB_DIRS} directories, too many to enumerate to verify what a recursive read would open` };
292
294
  const listed = await env.listDir(dir, signal);
293
295
  if (!listed.ok) {
296
+ if (dir === rootCanonical && listed.error.code === "not_directory")
297
+ root = "file";
294
298
  if (listed.error.code === "not_directory" || listed.error.code === "not_found")
295
299
  continue;
296
300
  return { unverifiable: `"${dir}" cannot be enumerated to verify what a recursive read would open (${listed.error.code})` };
297
301
  }
302
+ listedDirs.add(dir);
303
+ if (dir === rootCanonical)
304
+ root = "directory";
298
305
  for (const entry of listed.value) {
299
- if (members.length >= MAX_GLOB_MATCHES)
306
+ if (found.length >= MAX_GLOB_MATCHES)
300
307
  return { unverifiable: `"${rootCanonical}" holds more than ${MAX_GLOB_MATCHES} entries, too many to enumerate to verify what a recursive read would open` };
301
308
  const path = joinUnder(spell, entry.name);
302
309
  const canonicalPath = joinUnder(dir, entry.name);
303
310
  if (entry.kind === "symlink") {
304
311
  const canon = await env.canonicalPath(canonicalPath, signal);
305
- members.push({ path, ...(canon.ok ? { canonical: canon.value } : {}), symlink: true });
312
+ found.push({ path, ...(canon.ok ? { canonical: canon.value } : {}), symlink: true });
306
313
  if (canon.ok && !visited.has(canon.value)) {
307
314
  visited.add(canon.value);
308
315
  stack.push({ dir: canon.value, spell: path });
@@ -316,10 +323,11 @@ export function createShellReadEstablisher(env, readRoots) {
316
323
  }
317
324
  continue;
318
325
  }
319
- members.push({ path, canonical: canonicalPath, symlink: false });
326
+ found.push({ path, canonical: canonicalPath, symlink: false });
320
327
  }
321
328
  }
322
- return { members };
329
+ const members = found.map(({ path, canonical, symlink }) => ({ path, ...(canonical !== undefined ? { canonical } : {}), node: (symlink && canonical !== undefined && listedDirs.has(canonical) ? "directory" : "file") }));
330
+ return { ...(root !== undefined ? { root } : {}), members };
323
331
  };
324
332
  const canonicalReadOf = async (candidate, spelling, spellings, established, origin, canonicalKnown, signal) => {
325
333
  const real = canonicalKnown !== undefined ? { value: canonicalKnown, exact: true } : await resolve(spelling, signal);
@@ -338,16 +346,19 @@ export function createShellReadEstablisher(env, readRoots) {
338
346
  for (const candidate of judgedCandidatesOf(segment)) {
339
347
  const traversal = candidate.provenance === "traversal_root";
340
348
  const land = async (read, spellings, folded) => {
341
- out.push(read);
342
- if (!traversal || (read.established !== "canonical" && read.established !== "expansion") || read.target === undefined)
349
+ if (!traversal || (read.established !== "canonical" && read.established !== "expansion") || read.target === undefined) {
350
+ out.push(read);
343
351
  return;
352
+ }
344
353
  const walkedTree = await enumerateTraversal(read.target, signal);
345
354
  if ("unverifiable" in walkedTree) {
355
+ out.push(read);
346
356
  out.push({ candidate, established: "unestablishable", spellings, origin: folded, cause: walkedTree.unverifiable });
347
357
  return;
348
358
  }
359
+ out.push({ ...read, ...(walkedTree.root !== undefined ? { node: walkedTree.root } : {}) });
349
360
  for (const m of walkedTree.members)
350
- out.push(await canonicalReadOf(candidate, m.path, [m.path], "expansion", folded, m.canonical, signal));
361
+ out.push({ ...(await canonicalReadOf(candidate, m.path, [m.path], "expansion", folded, m.canonical, signal)), node: m.node });
351
362
  };
352
363
  for (const lexical of lexicalReadsOf(candidate, boundary)) {
353
364
  if (lexical.established !== "lexical") {
@@ -133,6 +133,9 @@ export interface EstablishedRead {
133
133
  readonly spellings: readonly string[];
134
134
  /** The pattern or traversal root an `expansion` came from, as folded. */
135
135
  readonly origin?: string;
136
+ /** What the environment said the target IS, where a read asked — only a traversal asks (it lists the root and
137
+ * every member it walks; a link's answer is its target's). Absent = nothing asked; a plain read never lists. */
138
+ readonly node?: "directory" | "file";
136
139
  /** Why the candidate could not be established. */
137
140
  readonly cause?: string;
138
141
  }
@@ -135,7 +135,9 @@ export function readRootGrantCandidateOf(judged, boundary) {
135
135
  return undefined;
136
136
  if (paths.some(hasWin32AliasedComponent))
137
137
  return undefined;
138
- const readsDirectory = new Set(outside.filter((f) => f.read.candidate.provenance === "traversal_root" || f.read.candidate.provenance === "cd_target").map((f) => f.read.target));
138
+ const readsDirectory = new Set(outside
139
+ .filter((f) => (f.read.candidate.provenance === "traversal_root" && f.read.node !== "file") || f.read.candidate.provenance === "cd_target")
140
+ .map((f) => f.read.target));
139
141
  const dirOf = (path) => (readsDirectory.has(path) ? path : parentDirLexically(path));
140
142
  let candidate = dirOf(paths[0]);
141
143
  for (const path of paths.slice(1)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.26.0",
3
+ "version": "7.26.1",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "_comment": "design/87 L3 — frozen public export surface of src/index.ts (name -> kind). DO NOT edit by hand to silence a red test. A removed/changed entry = a SemVer-BREAKING change; bump MAJOR and update this fixture in the SAME commit (design/87 §4.2 / §5.2). Regenerate via REGEN in test/export-surface.test.ts.",
3
3
  "_tierComment": "#435 v1 — machine-readable layering of the public surface: stable = demonstrated by README.md / src/examples; internal = an `Internal`-marked name or a runner/engine deep-subtree declaration (the model seam src/engine/llm is excluded — it is the BYOM contract, not an engine internal); advanced = a supported export the front door does not walk you through. THIS IS AN INITIAL HEURISTIC, derived mechanically and expected to be refined ticket by ticket: no human reviewed these 1700+ entries one by one, and nothing here claims otherwise. Known bias: a short or English-word export name (ok, err, Result, Usage) can match ordinary prose in README.md and land `stable` on a coincidence. Every export MUST carry a tier — a new export with no row fails the gate in export-surface.test.ts.",
4
- "count": 2424,
4
+ "count": 2449,
5
5
  "exports": {
6
6
  "A2ATaskState": "type",
7
7
  "A2ATaskStateReversal": "type",
@@ -225,6 +225,7 @@
225
225
  "CONSOLIDATION_SYSTEM_PROMPT": "variable",
226
226
  "CONTRACT_KIT_ENGINE_VERSION": "variable",
227
227
  "COORDINATOR_ROLE_PROMPT": "variable",
228
+ "CORRUPT_BODY_FORMS": "variable",
228
229
  "CROSS_SESSION_CLASSIFIER_RULE": "variable",
229
230
  "CROSS_SESSION_DIALOG_EXPIRY_DEFAULT": "variable",
230
231
  "CROSS_SESSION_DIALOG_EXPIRY_VALUES": "variable",
@@ -337,6 +338,7 @@
337
338
  "ControlPlaneCorruptError": "class",
338
339
  "ControlPlaneRebuildReceipt": "interface",
339
340
  "CoreCompatRange": "interface",
341
+ "CorruptBodyForm": "type",
340
342
  "CrossSessionCodecError": "class",
341
343
  "CrossSessionDialogExpiry": "type",
342
344
  "CrossSessionEnvelopeFields": "interface",
@@ -430,6 +432,7 @@
430
432
  "ErasureSelect": "type",
431
433
  "EscalationRecord": "interface",
432
434
  "EscalationTrigger": "type",
435
+ "EstablishedRead": "interface",
433
436
  "EventDedupe": "type",
434
437
  "EventDefaultPolicy": "type",
435
438
  "EvictPolicy": "type",
@@ -1094,11 +1097,15 @@
1094
1097
  "RUN_WORKFLOW_TOOL_NAME": "variable",
1095
1098
  "RawPrefixInputs": "interface",
1096
1099
  "RawRuleSyncState": "interface",
1100
+ "ReadBackShapeSubject": "interface",
1101
+ "ReadCandidate": "interface",
1097
1102
  "ReadDenyBuiltinConfig": "interface",
1098
1103
  "ReadDenyBuiltinRow": "interface",
1099
1104
  "ReadDenyBuiltinTier": "type",
1100
1105
  "ReadDenyEntry": "type",
1101
1106
  "ReadDenyMatcher": "interface",
1107
+ "ReadEstablishment": "type",
1108
+ "ReadFinding": "interface",
1102
1109
  "ReadOnlyCommandRow": "interface",
1103
1110
  "ReadOnlyFlagArity": "type",
1104
1111
  "ReadOnlyShellVerdict": "type",
@@ -1251,6 +1258,10 @@
1251
1258
  "SETTLEMENT_KINDS": "variable",
1252
1259
  "SHARED_MEMORY_LIST_PAGE_SIZE": "variable",
1253
1260
  "SHARED_MEMORY_READ_CAP_BYTES": "variable",
1261
+ "SHELL_READ_DECISION": "variable",
1262
+ "SHELL_READ_FINDINGS": "variable",
1263
+ "SHELL_READ_FINDING_RANK": "variable",
1264
+ "SHELL_READ_SEATS": "variable",
1254
1265
  "SHELL_WRAPPER_TABLE": "variable",
1255
1266
  "SKILL_TOOL_NAME": "variable",
1256
1267
  "STALE_RUNNING_REAP_ATTRIBUTION": "variable",
@@ -1340,6 +1351,17 @@
1340
1351
  "SharedMemoryStoreReader": "interface",
1341
1352
  "ShellCommandShape": "interface",
1342
1353
  "ShellGateDoctrine": "type",
1354
+ "ShellReadAdmission": "type",
1355
+ "ShellReadBoundary": "interface",
1356
+ "ShellReadDisposition": "type",
1357
+ "ShellReadFinding": "type",
1358
+ "ShellReadJudgeInput": "interface",
1359
+ "ShellReadJudgment": "interface",
1360
+ "ShellReadPlan": "interface",
1361
+ "ShellReadSeat": "type",
1362
+ "ShellReadSegment": "interface",
1363
+ "ShellReadStationSeat": "type",
1364
+ "ShellReadVerdict": "interface",
1343
1365
  "ShellRedirection": "interface",
1344
1366
  "ShellSegment": "interface",
1345
1367
  "ShellWord": "interface",
@@ -1369,6 +1391,7 @@
1369
1391
  "StopSource": "type",
1370
1392
  "StoreDurability": "type",
1371
1393
  "StoreFidelity": "type",
1394
+ "StoreReadBackShapeHooks": "interface",
1372
1395
  "StoredRules": "interface",
1373
1396
  "StoredSession": "class",
1374
1397
  "StoredSessionRules": "interface",
@@ -2040,6 +2063,7 @@
2040
2063
  "judgeParkedToolIdentity": "function",
2041
2064
  "judgePeerAdmission": "function",
2042
2065
  "judgePeerRecordFile": "function",
2066
+ "judgeShellRead": "function",
2043
2067
  "killProcessTree": "function",
2044
2068
  "languageFor": "function",
2045
2069
  "leafIdAfterEntry": "function",
@@ -2361,6 +2385,7 @@
2361
2385
  "splitWorkflowMeta": "function",
2362
2386
  "sqliteQuery": "function",
2363
2387
  "startWorkflow": "function",
2388
+ "storeReadBackShapeContract": "function",
2364
2389
  "stripEngineMetadata": "function",
2365
2390
  "stripFormatCharacters": "function",
2366
2391
  "stripRev": "function",
@@ -2651,6 +2676,7 @@
2651
2676
  "CONSOLIDATION_SYSTEM_PROMPT": "internal",
2652
2677
  "CONTRACT_KIT_ENGINE_VERSION": "advanced",
2653
2678
  "COORDINATOR_ROLE_PROMPT": "advanced",
2679
+ "CORRUPT_BODY_FORMS": "advanced",
2654
2680
  "CROSS_SESSION_CLASSIFIER_RULE": "advanced",
2655
2681
  "CROSS_SESSION_DIALOG_EXPIRY_DEFAULT": "advanced",
2656
2682
  "CROSS_SESSION_DIALOG_EXPIRY_VALUES": "advanced",
@@ -2763,6 +2789,7 @@
2763
2789
  "ControlPlaneCorruptError": "advanced",
2764
2790
  "ControlPlaneRebuildReceipt": "advanced",
2765
2791
  "CoreCompatRange": "advanced",
2792
+ "CorruptBodyForm": "advanced",
2766
2793
  "CrossSessionCodecError": "advanced",
2767
2794
  "CrossSessionDialogExpiry": "advanced",
2768
2795
  "CrossSessionEnvelopeFields": "advanced",
@@ -2856,6 +2883,7 @@
2856
2883
  "ErasureSelect": "advanced",
2857
2884
  "EscalationRecord": "advanced",
2858
2885
  "EscalationTrigger": "advanced",
2886
+ "EstablishedRead": "advanced",
2859
2887
  "EventDedupe": "advanced",
2860
2888
  "EventDefaultPolicy": "advanced",
2861
2889
  "EvictPolicy": "advanced",
@@ -3520,11 +3548,15 @@
3520
3548
  "RUN_WORKFLOW_TOOL_NAME": "stable",
3521
3549
  "RawPrefixInputs": "advanced",
3522
3550
  "RawRuleSyncState": "advanced",
3551
+ "ReadBackShapeSubject": "advanced",
3552
+ "ReadCandidate": "advanced",
3523
3553
  "ReadDenyBuiltinConfig": "advanced",
3524
3554
  "ReadDenyBuiltinRow": "advanced",
3525
3555
  "ReadDenyBuiltinTier": "advanced",
3526
3556
  "ReadDenyEntry": "advanced",
3527
3557
  "ReadDenyMatcher": "advanced",
3558
+ "ReadEstablishment": "advanced",
3559
+ "ReadFinding": "advanced",
3528
3560
  "ReadOnlyCommandRow": "advanced",
3529
3561
  "ReadOnlyFlagArity": "advanced",
3530
3562
  "ReadOnlyShellVerdict": "advanced",
@@ -3677,6 +3709,10 @@
3677
3709
  "SETTLEMENT_KINDS": "advanced",
3678
3710
  "SHARED_MEMORY_LIST_PAGE_SIZE": "advanced",
3679
3711
  "SHARED_MEMORY_READ_CAP_BYTES": "advanced",
3712
+ "SHELL_READ_DECISION": "advanced",
3713
+ "SHELL_READ_FINDINGS": "advanced",
3714
+ "SHELL_READ_FINDING_RANK": "advanced",
3715
+ "SHELL_READ_SEATS": "advanced",
3680
3716
  "SHELL_WRAPPER_TABLE": "advanced",
3681
3717
  "SKILL_TOOL_NAME": "internal",
3682
3718
  "STALE_RUNNING_REAP_ATTRIBUTION": "advanced",
@@ -3766,6 +3802,17 @@
3766
3802
  "SharedMemoryStoreReader": "advanced",
3767
3803
  "ShellCommandShape": "advanced",
3768
3804
  "ShellGateDoctrine": "advanced",
3805
+ "ShellReadAdmission": "advanced",
3806
+ "ShellReadBoundary": "advanced",
3807
+ "ShellReadDisposition": "advanced",
3808
+ "ShellReadFinding": "advanced",
3809
+ "ShellReadJudgeInput": "advanced",
3810
+ "ShellReadJudgment": "advanced",
3811
+ "ShellReadPlan": "advanced",
3812
+ "ShellReadSeat": "advanced",
3813
+ "ShellReadSegment": "advanced",
3814
+ "ShellReadStationSeat": "advanced",
3815
+ "ShellReadVerdict": "advanced",
3769
3816
  "ShellRedirection": "advanced",
3770
3817
  "ShellSegment": "advanced",
3771
3818
  "ShellWord": "advanced",
@@ -3795,6 +3842,7 @@
3795
3842
  "StopSource": "advanced",
3796
3843
  "StoreDurability": "advanced",
3797
3844
  "StoreFidelity": "advanced",
3845
+ "StoreReadBackShapeHooks": "advanced",
3798
3846
  "StoredRules": "advanced",
3799
3847
  "StoredSession": "stable",
3800
3848
  "StoredSessionRules": "advanced",
@@ -4466,6 +4514,7 @@
4466
4514
  "judgeParkedToolIdentity": "advanced",
4467
4515
  "judgePeerAdmission": "advanced",
4468
4516
  "judgePeerRecordFile": "advanced",
4517
+ "judgeShellRead": "advanced",
4469
4518
  "killProcessTree": "internal",
4470
4519
  "languageFor": "internal",
4471
4520
  "leafIdAfterEntry": "internal",
@@ -4787,6 +4836,7 @@
4787
4836
  "splitWorkflowMeta": "advanced",
4788
4837
  "sqliteQuery": "advanced",
4789
4838
  "startWorkflow": "advanced",
4839
+ "storeReadBackShapeContract": "advanced",
4790
4840
  "stripEngineMetadata": "advanced",
4791
4841
  "stripFormatCharacters": "advanced",
4792
4842
  "stripRev": "advanced",