@sema-agent/core 7.38.0 → 7.38.2

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.
@@ -1,3 +1,4 @@
1
+ import { type HomeViewSource } from "./read-deny-home.js";
1
2
  import type { AssertAllKeysHandled } from "../../core/ask-origin.js";
2
3
  import type { ExecutionEnv } from "../../internal/harness-types.js";
3
4
  import { protectivePathTargetOf, type ToolCallLike } from "../../core/tool-registry.js";
@@ -449,6 +450,7 @@ export type RootsSeat = readonly string[] | (() => readonly string[] | undefined
449
450
  */
450
451
  export declare function resolveKey(env: ExecutionEnv, rootCanonical: string, path: string, signal?: AbortSignal, baseCwd?: string, additionalRoots?: RootsSeat, exactFileReadExemption?: (canonicalKey: string) => boolean, readDeny?: {
451
452
  readonly face?: "write";
453
+ readonly homeViews?: HomeViewSource;
452
454
  matchTarget(canonicalKey: string, lexicalView?: string, opts?: {
453
455
  readonly aliasResolved?: boolean;
454
456
  }): {
@@ -469,7 +469,7 @@ export async function resolveKey(env, rootCanonical, path, signal, baseCwd, addi
469
469
  const judged = { aliasResolved: canon.aliasResolved === true };
470
470
  let hit = readDeny.matchTarget(key, lexicalViewOf(path, baseCwd ?? rootCanonical), judged);
471
471
  if (hit === null) {
472
- const homeView = await homeViewsOf(env, signal).of(key);
472
+ const homeView = await homeViewsOf(env, readDeny, signal).of(key);
473
473
  if (homeView !== undefined)
474
474
  hit = readDeny.matchTarget(key, homeView, judged);
475
475
  }
@@ -1,4 +1,5 @@
1
1
  import type { ExecutionEnv } from "../../internal/harness-types.js";
2
+ import { type HomeViewsCarrier } from "./read-deny-home.js";
2
3
  /** The JS scanner's own output ceiling, in bytes of emitted content rows. Pinned to the
3
4
  * ripgrep leg's figure ({@link MAX_EXEC_OUTPUT_BYTES}, the exec pipe's rolling-tail bound) so the two
4
5
  * legs cannot disagree about how much one search may return; see the collection site in {@link jsGrep}
@@ -130,7 +131,7 @@ export declare function walk(env: ExecutionEnv, root: string, start: string, ign
130
131
  matchPath(path: string): {
131
132
  pattern: string;
132
133
  } | null;
133
- }): Promise<WalkResult>;
134
+ } & HomeViewsCarrier): Promise<WalkResult>;
134
135
  /** The JS-leg withholding disclosure: an empty result must stay distinguishable from
135
136
  * searched-and-empty, so this note rides EVERY output shape when something was pruned. Distinct from
136
137
  * {@link walkCaveat}: pruning is deliberate withholding, not incompleteness.
@@ -157,8 +158,8 @@ export interface ReadDenyWithheld {
157
158
  count?: number;
158
159
  patterns?: readonly string[];
159
160
  }
160
- /** The deny judge seam every search leg shares (structural subset of ReadDenyMatcher). */
161
- export interface ReadDenyJudge {
161
+ /** The deny judge seam every search leg shares (structural subset of ReadDenyMatcher), with its placement's home views. */
162
+ export interface ReadDenyJudge extends HomeViewsCarrier {
162
163
  matchPath(path: string): {
163
164
  pattern: string;
164
165
  } | null;
@@ -228,7 +228,7 @@ export async function walk(env, root, start, ignore, signal, deny) {
228
228
  let aborted = false;
229
229
  let denyPruned = 0;
230
230
  const denyPatterns = [];
231
- const views = deny !== undefined ? homeViewsOf(env, signal) : undefined;
231
+ const views = deny !== undefined ? homeViewsOf(env, deny, signal) : undefined;
232
232
  const denyHit = async (path, leaf) => {
233
233
  let hit = deny?.matchPath(path);
234
234
  if (!hit && views !== undefined) {
@@ -1156,7 +1156,7 @@ function rgRecordAbsolute(base) {
1156
1156
  return (p) => (base === undefined || family === undefined || isAbsoluteForFamily(family, p) ? p : joinForFamily(family, base, p.replace(/^\.[\\/]/, "")));
1157
1157
  }
1158
1158
  async function rgOutputDenyTripwireAt(env, stdout, mode, deny, opts, signal) {
1159
- const views = homeViewsOf(env, signal);
1159
+ const views = homeViewsOf(env, deny, signal);
1160
1160
  const absolute = rgRecordAbsolute(opts.base);
1161
1161
  const placed = new Map();
1162
1162
  for (const record of parseRgRecords(stdout, mode, opts.dropIncompleteTail === true)) {
@@ -1343,7 +1343,7 @@ export async function runGrepDetailed(env, root, p, signal, deny) {
1343
1343
  return false;
1344
1344
  if (deny.unexcludableUnder(scope))
1345
1345
  return true;
1346
- const view = await homeViewsOf(env, signal).of(scope);
1346
+ const view = await homeViewsOf(env, deny, signal).of(scope);
1347
1347
  return view !== undefined && deny.unexcludableUnder(view);
1348
1348
  };
1349
1349
  if (!(await unexcludableUnder()) && (await detectRipgrep(env)))
@@ -20,6 +20,7 @@
20
20
  import type { ExecutionEnv } from "../../internal/harness-types.js";
21
21
  import { violationDetails } from "./safety.js";
22
22
  import { type ShellReadPlan } from "./shell-read-plan.js";
23
+ import { type HomeViewSource } from "./read-deny-home.js";
23
24
  import { type EstablishedRead, type ShellReadBoundary, type ShellReadDisposition, type ShellReadFinding, type ShellReadSeat } from "./shell-read-judge.js";
24
25
  import type { ReadRootGrantCandidate } from "../../core/tool-spec.js";
25
26
  import type { ToolCallLike } from "../../core/tool-registry.js";
@@ -145,6 +146,9 @@ export interface ShellReadStationOptions {
145
146
  /** `true` ⇔ every root `boundaryOf` returns is already a canonical identity (the Runner's): the station never
146
147
  * re-resolves one, so a root swapped for a link after it was declared or granted cannot bring in the link's target. */
147
148
  readonly rootsCanonical?: boolean;
149
+ /** The home views of the placement the boundary's deny seats were compiled at (read-deny-home.ts) — the Runner's. Absent,
150
+ * the declared home alone. */
151
+ readonly homeViews?: HomeViewSource;
148
152
  }
149
153
  /** What a consumer hands {@link judgeShellRead}: the command as written, the environment whose filesystem
150
154
  * answers where its words land (symlinks resolved, patterns expanded — a `NodeExecutionEnv` over a real
@@ -191,6 +195,11 @@ export interface ShellReadJudgment {
191
195
  * LAXER where only a filesystem sees the escape (an in-root symlink pointing out vouches) and answers a
192
196
  * pattern on its spelling alone, so the two diverge in both directions.
193
197
  *
198
+ * A read target is also judged at its HOME VIEW (a path spelled through a firmlink or a bind mount of a home, respelled
199
+ * at the home): this judgment is its own placement — the views read the environment's declared home and the account
200
+ * home the account database answers once, for this call (`readDenyHomesOf`'s homes); the account home's probes wait at
201
+ * most a short bound of their own.
202
+ *
194
203
  * It carries NO deadline. Bounding an environment-facing wait and substituting a fail-closed verdict is the
195
204
  * gate FOLD's policy on the gate's one deadline seat; the station has never held one on either entry, and a
196
205
  * second default here would decide the same number twice and turn a slow-but-correct filesystem's true
@@ -6,6 +6,7 @@ import { NOT_AUTO_ALLOWED, programPositionRefusalSentence, readProgramPosition }
6
6
  import { bashClassifyDefaultAllow } from "./bash-readonly-classifier.js";
7
7
  import { planShellReads } from "./shell-read-plan.js";
8
8
  import { createShellReadEstablisher, establishShellReadsLexically } from "./shell-read-establish.js";
9
+ import { declaredReadDenyHomes, homeViewsAt } from "./read-deny-home.js";
9
10
  import { programArgs, spellsOption } from "./shell-read-write-targets.js";
10
11
  import { allFindings, decideShellRead, denyRowAtOrBelow, foldShellReadFindings, judgeEstablishedPlan, readRootGrantCandidateOf, } from "./shell-read-judge.js";
11
12
  import { seatOf } from "../../core/tool-name-readings.js";
@@ -326,7 +327,7 @@ async function runShellReadStation(tool, command, declared, seat, readers, estab
326
327
  }
327
328
  export async function judgeShellRead(input) {
328
329
  const readers = input.readers ?? new Set(bashClassifyDefaultAllow());
329
- const run = await runShellReadStation(input.tool ?? "Bash", input.command, input.boundary, input.seat, readers, createShellReadEstablisher(input.env, input.boundary.roots), input.env, input.signal);
330
+ const run = await runShellReadStation(input.tool ?? "Bash", input.command, input.boundary, input.seat, readers, createShellReadEstablisher(input.env, input.boundary.roots, { homeViews: homeViewsAt(input.env, declaredReadDenyHomes(input.env)) }), input.env, input.signal);
330
331
  const offer = normalizeReadRootCandidate(run.verdict.readRootCandidate);
331
332
  return {
332
333
  plan: run.plan,
@@ -349,7 +350,7 @@ export function createShellReadStation(opts) {
349
350
  const key = roots.join("\0");
350
351
  let e = establishers.get(key);
351
352
  if (e === undefined) {
352
- e = createShellReadEstablisher(opts.env, roots, { rootsCanonical: opts.rootsCanonical === true });
353
+ e = createShellReadEstablisher(opts.env, roots, { rootsCanonical: opts.rootsCanonical === true, ...(opts.homeViews !== undefined ? { homeViews: opts.homeViews } : {}) });
353
354
  establishers.set(key, e);
354
355
  }
355
356
  return e;
@@ -40,6 +40,7 @@
40
40
  import type { ExecutionEnv } from "../../internal/harness-types.js";
41
41
  import type { ShellReadPlan, ShellReadSegment } from "./shell-read-plan.js";
42
42
  import type { EstablishedRead, ShellReadBoundary } from "./shell-read-judge.js";
43
+ import type { HomeViewSource } from "./read-deny-home.js";
43
44
  /**
44
45
  * How many directories one glob operand (or one traversal root) may enumerate, and how many names it may
45
46
  * match, before the leg gives up and answers `unestablishable`.
@@ -82,7 +83,9 @@ export declare function establishShellReadsLexically(plan: ShellReadPlan, bounda
82
83
  * The filesystem-resolving establisher for one environment and one root set. `readRoots` are the roots
83
84
  * as declared (canonical by contract); they are resolved once more per instance because the comparison is
84
85
  * against `realpath` output on both sides — an aliased root would otherwise refuse every read under itself.
86
+ * `homeViews`: the home views of the placement the deny seats were compiled at (read-deny-home.ts); absent, the declared home's.
85
87
  */
86
88
  export declare function createShellReadEstablisher(env: ExecutionEnv, readRoots: readonly string[], opts?: {
87
89
  readonly rootsCanonical?: boolean;
90
+ readonly homeViews?: HomeViewSource;
88
91
  }): ShellReadEstablisher;
@@ -534,7 +534,7 @@ export function createShellReadEstablisher(env, readRoots, opts) {
534
534
  if (lexicalOnly)
535
535
  return establishShellReadsLexically(plan, boundary);
536
536
  const roots = await canonicalRoots(signal);
537
- return await withHomeViews(env, await establishPlan(plan, { ...boundary, roots }, roots, signal), signal);
537
+ return await withHomeViews(env, opts, await establishPlan(plan, { ...boundary, roots }, roots, signal), signal);
538
538
  },
539
539
  reestablish: async (previous, boundary, signal) => {
540
540
  if (lexicalOnly)
@@ -9,12 +9,13 @@
9
9
  */
10
10
  import type { EstablishedPlan } from "./shell-read-establish.js";
11
11
  import type { EstablishedRead } from "./shell-read-judge.js";
12
- import { type HomeViewEnv } from "./read-deny-home.js";
12
+ import { type HomeViewEnv, type HomeViewsCarrier } from "./read-deny-home.js";
13
13
  /** Every read of either establishment whose candidate's settled target set differs between the two. */
14
14
  export declare function movedReads(previous: EstablishedPlan, again: EstablishedPlan): EstablishedRead[];
15
15
  /**
16
16
  * The establishment with every read that landed carrying its HOME VIEW (read-deny-home.ts) among its spellings, nested
17
17
  * plans included: the deny judge then places a home-anchored row wherever the target IS below the home, whatever it is
18
- * spelled through. A read that did not land (lexical, unestablishable) is left as it is.
18
+ * spelled through. The views are `placed`'s — the home views of the placement the boundary's deny seats were compiled
19
+ * at. A read that did not land (lexical, unestablishable) is left as it is.
19
20
  */
20
- export declare function withHomeViews(env: HomeViewEnv, established: EstablishedPlan, signal?: AbortSignal): Promise<EstablishedPlan>;
21
+ export declare function withHomeViews(env: HomeViewEnv, placed: HomeViewsCarrier | undefined, established: EstablishedPlan, signal?: AbortSignal): Promise<EstablishedPlan>;
@@ -38,8 +38,8 @@ function targetsByCandidate(e) {
38
38
  function sameTargets(a, b) {
39
39
  return a.size === b.size && [...a].every((t) => b.has(t));
40
40
  }
41
- export async function withHomeViews(env, established, signal) {
42
- const views = homeViewsOf(env, signal);
41
+ export async function withHomeViews(env, placed, established, signal) {
42
+ const views = homeViewsOf(env, placed, signal);
43
43
  const place = async (p) => {
44
44
  const reads = new Map();
45
45
  for (const [segment, rs] of p.reads) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.38.0",
3
+ "version": "7.38.2",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -0,0 +1,56 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.38.1",
4
+ "from": "f195abb9b3764b7d306d30ac7eee0c9ee82719f8",
5
+ "to": "0ee3363eac0ed4103b2598b72279b80b61f30a94",
6
+ "added": [],
7
+ "removed": [],
8
+ "changed": [],
9
+ "narrowed": [],
10
+ "closedSetMembers": [],
11
+ "closedSetsUnreadable": [],
12
+ "typeKeys": [],
13
+ "typeKeysUnreadableArms": [],
14
+ "typeKeysFlattenedCount": 220,
15
+ "declarationMoves": [],
16
+ "mintMoves": [],
17
+ "criteriaObserves": [
18
+ {
19
+ "kind": "taskEventField",
20
+ "name": "tool_end.errorCode",
21
+ "assertions": [
22
+ "G1.a",
23
+ "G1.b",
24
+ "G1.d",
25
+ "G1.e",
26
+ "G1.f"
27
+ ]
28
+ },
29
+ {
30
+ "kind": "taskEventField",
31
+ "name": "tool_end.output",
32
+ "assertions": [
33
+ "G1.a",
34
+ "G1.c",
35
+ "G1.d",
36
+ "G1.f"
37
+ ]
38
+ },
39
+ {
40
+ "kind": "typeMember",
41
+ "name": "ToolCall.id",
42
+ "assertions": [
43
+ "G2.a",
44
+ "G2.b"
45
+ ]
46
+ }
47
+ ],
48
+ "consumersHint": {
49
+ "cli": [],
50
+ "server": [],
51
+ "sdk": [],
52
+ "note": "scanned cli@64a76326 server@61d9a1d1 sdk@925ffec — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it"
53
+ },
54
+ "breakingCount": 0,
55
+ "breakingItems": []
56
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.38.2",
4
+ "from": "a8493dd6305fe6f8b3fea1174b56c30667f3ff1b",
5
+ "to": "201b3b096bc8086ff09caca61683c69acdc8bcbe",
6
+ "added": [],
7
+ "removed": [],
8
+ "changed": [],
9
+ "narrowed": [],
10
+ "closedSetMembers": [],
11
+ "closedSetsUnreadable": [],
12
+ "typeKeys": [],
13
+ "typeKeysUnreadableArms": [],
14
+ "typeKeysFlattenedCount": 220,
15
+ "declarationMoves": [],
16
+ "mintMoves": [],
17
+ "criteriaObserves": [],
18
+ "consumersHint": {
19
+ "cli": [],
20
+ "server": [],
21
+ "sdk": [],
22
+ "note": "scanned cli@64a76326 server@61d9a1d1 sdk@925ffec — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it"
23
+ },
24
+ "breakingCount": 0,
25
+ "breakingItems": []
26
+ }