@sema-agent/core 7.49.1 → 7.49.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/core/arg-summary.js +23 -5
  3. package/dist/core/credential-vocabulary.js +19 -2
  4. package/dist/core/gate-fold.js +2 -2
  5. package/dist/core/runner/prepare-gate-stations.js +2 -2
  6. package/dist/core/runner/prepare-lsp.d.ts +4 -4
  7. package/dist/core/runner/prepare-lsp.js +2 -2
  8. package/dist/core/runner/prepare-safety-scan.js +10 -6
  9. package/dist/core/runner-deps.d.ts +2 -2
  10. package/dist/core/task-spec.d.ts +2 -2
  11. package/dist/core/tool-catalog-entries.js +1 -1
  12. package/dist/core/tool-conformance.js +2 -1
  13. package/dist/core/tool-roster.d.ts +11 -6
  14. package/dist/core/tool-roster.js +8 -4
  15. package/dist/core/write-protect.d.ts +3 -1
  16. package/dist/core/write-protect.js +4 -5
  17. package/dist/tools/fs/bash-readonly-classifier.d.ts +2 -2
  18. package/dist/tools/fs/bash-readonly-classifier.js +5 -3
  19. package/dist/tools/fs/read-deny-home.d.ts +5 -1
  20. package/dist/tools/fs/read-deny-home.js +40 -19
  21. package/dist/tools/fs/shell-read-check.d.ts +1 -1
  22. package/dist/tools/fs/shell-read-check.js +29 -15
  23. package/dist/tools/fs/shell-read-environment.d.ts +74 -0
  24. package/dist/tools/fs/shell-read-environment.js +71 -0
  25. package/dist/tools/fs/shell-read-establish.d.ts +8 -4
  26. package/dist/tools/fs/shell-read-establish.js +34 -36
  27. package/dist/tools/fs/shell-read-identity.d.ts +3 -2
  28. package/dist/tools/fs/shell-read-identity.js +5 -3
  29. package/dist/tools/fs/shell-read-judge.d.ts +69 -18
  30. package/dist/tools/fs/shell-read-judge.js +27 -14
  31. package/package.json +1 -1
  32. package/wire-changes/core@7.49.1.json +57 -0
  33. package/wire-changes/core@7.49.2.json +138 -0
@@ -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, placed, established, signal) {
42
- const views = homeViewsOf(env, placed, signal);
41
+ export async function withHomeViews(door, placed, established, signal) {
42
+ const views = homeViewsOf(door.fs, placed, signal);
43
43
  const place = async (p) => {
44
44
  const reads = new Map();
45
45
  for (const [segment, rs] of p.reads) {
@@ -56,5 +56,7 @@ export async function withHomeViews(env, placed, established, signal) {
56
56
  nested.set(n, await place(np));
57
57
  return { ...p, reads, nested };
58
58
  };
59
- return await place(established);
59
+ const withViews = await place(established);
60
+ door.adopt(views.unread.map((p) => ({ op: "fileIdentity", detail: `"${p}" cannot be identified against the home directories` })));
61
+ return withViews;
60
62
  }
@@ -11,7 +11,7 @@
11
11
  * judge is `withinAnyRoot` over the roots the boundary declares — a WRITE target's over the write roots, at the
12
12
  * seat it is written, under the write face in force ({@link judgeWrite}).
13
13
  * · `foldShellReadFindings` folds a command's findings — every segment, every nested plan — to ONE word by
14
- * the priority `identity_changed > deny_hit > outside_roots > unestablishable > declined > none`.
14
+ * the priority `identity_changed > deny_hit > unanswered > outside_roots > unestablishable > declined > none`.
15
15
  * · `SHELL_READ_DECISION` is the total table (finding × seat → disposition) that is the ONLY source of
16
16
  * "refuse / mandated ask / ordinary ask / vouch" for a shell read. A seat is a FACE word, not a tool name
17
17
  * and not a permission mode: which shell face the call runs on (the full shell, the read-only shell) or
@@ -22,11 +22,12 @@
22
22
  */
23
23
  import type { BashReadonlyRootBoundary } from "./bash-readonly-classifier.js";
24
24
  import type { ReadCandidate, ShellReadPlan, ShellReadSegment } from "./shell-read-plan.js";
25
+ import type { Incomplete, ObservedFilesystem } from "./shell-read-environment.js";
25
26
  import type { WriteSeat } from "./shell-read-write-targets.js";
26
27
  import { type ContainmentFace } from "./containment-face.js";
27
28
  import type { AssertAllKeysHandled } from "../../core/ask-origin.js";
28
29
  /** WHAT the judge found about a command — a closed set, registered in `docs/CLOSED-SETS.md`. */
29
- export declare const SHELL_READ_FINDINGS: readonly ["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "none"];
30
+ export declare const SHELL_READ_FINDINGS: readonly ["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "unanswered", "none"];
30
31
  export type ShellReadFinding = (typeof SHELL_READ_FINDINGS)[number];
31
32
  /** WHERE a read is judged — the seats the decision table is keyed on, one per FACE: `full_shell` the
32
33
  * writable shell (`Bash`, `Monitor`) under every permission mode and every shell-gate floor; `readonly`
@@ -38,9 +39,10 @@ export type ShellReadSeat = (typeof SHELL_READ_SEATS)[number];
38
39
  export declare const SHELL_READ_FINDING_RANK: {
39
40
  readonly identity_changed: 6;
40
41
  readonly deny_hit: 5;
41
- readonly outside_roots: 4;
42
- readonly unestablishable: 3;
43
- readonly declined: 2;
42
+ readonly unanswered: 4;
43
+ readonly outside_roots: 3;
44
+ readonly unestablishable: 2;
45
+ readonly declined: 1;
44
46
  readonly none: 0;
45
47
  };
46
48
  /** Compile-time fence: `never` while every finding has a rank. */
@@ -50,6 +52,14 @@ export type RankTableCoversEveryFinding = AssertAllKeysHandled<Exclude<ShellRead
50
52
  * the auto-mode classifier, a stored allow rule) but no answerless engine table may; `vouch` = the station
51
53
  * has no question. */
52
54
  export type ShellReadDisposition = "refuse" | "mandated" | "ordinary" | "vouch";
55
+ /** One cell of the decision table: a disposition, or — where the READ FACE the question was raised under decides it — the two
56
+ * readings, `narrowed` (the `roots` face: the fence the deployment narrowed, and the engine default) and `open`. */
57
+ export type ShellReadCell = ShellReadDisposition | {
58
+ readonly narrowed: ShellReadDisposition;
59
+ readonly open: ShellReadDisposition;
60
+ };
61
+ /** A cell, read for a question raised under a narrowed read face (`true`) or an open one (`false`). */
62
+ export declare function dispositionOfCell(cell: ShellReadCell, narrowedReadFace: boolean): ShellReadDisposition;
53
63
  /**
54
64
  * THE decision table — total over findings × seats; no cell is n/a. Row by row:
55
65
  * · `deny_hit` — refused on every seat, for a spelling the station can establish: a deny row is a floor
@@ -58,8 +68,14 @@ export type ShellReadDisposition = "refuse" | "mandated" | "ordinary" | "vouch";
58
68
  * · `outside_roots` — asked where a person can be asked (the full shell), refused where none can (the
59
69
  * read-only face has no approval channel; a rewrite that leaves the roots after approval was seen by
60
70
  * nobody).
61
- * · `unestablishable` — the same shape: the floor could not say where the command reads, so it is not
62
- * vouched anywhere; a person may still answer it on the full shell.
71
+ * · `unestablishable` — the floor could not say where the command reads, so it is not vouched anywhere: asked
72
+ * where a person can be asked (the full shell), refused where none can be asked. The full shell's cell is read by the read face
73
+ * the question was raised under: on a NARROWED (`roots`) face — the engine default — the deployment asked to be asked, so the
74
+ * ask is MANDATED and no automatic lane answers; on the OPEN face (where the station asks only because a deny list has
75
+ * rows), and for a written target alone (a narrowed WRITE face fences what is written; it is no request to be asked about
76
+ * every word the floor cannot place), it is the ORDINARY ask — the reference implementation's plain permission ask (CC
77
+ * 2.1.296 `sR`, cli296.js @13116941, reason `other`), which a whole-tool allow (`$pn` @18717070), bypass (`$pn` @18716980)
78
+ * and the auto-mode classifier release and a prefix allow does not.
63
79
  * · `declined` — the one deliberate fail-open of this table: the scan could not read the program bash
64
80
  * will run, or the operands arrive on a stream. On the full shell it is an ORDINARY ask — an answerer
65
81
  * may settle it, and an out-of-root read hidden inside such a command is then not asked again. The
@@ -67,6 +83,15 @@ export type ShellReadDisposition = "refuse" | "mandated" | "ordinary" | "vouch";
67
83
  * n/a.
68
84
  * · `identity_changed` — a candidate established at approval time resolves elsewhere at spawn time:
69
85
  * refused everywhere (it is only ever produced on the `rejudge` seat).
86
+ * · `unanswered` — the judge did not FINISH: it threw or timed out, the lookup it stands on was absent, or — recorded at the
87
+ * one door to the environment ({@link import("./shell-read-environment.js").Incomplete}) — an environment lookup gave no
88
+ * answer (an error that is no conclusive "not there"), the station stopped at its own bound (more directories or names than
89
+ * it enumerates, a link chain past its hop bound), or a home view could not be read. Any one makes the whole command
90
+ * `unanswered`, whatever the other words found. Not a fact about the command but the state of the station, so it is not
91
+ * the `unestablishable` row's question (a text the station cannot place — a word the shell rewrites, a lost working
92
+ * directory, a pattern its matcher does not model). Absence is not
93
+ * "nothing there": the full shell asks it MANDATED on every read face — a standing allow was given on the premise that the
94
+ * judge works, and a broken judge is not cleared by it — and the read-only face refuses.
70
95
  * · `none` — vouched: the station has no question (the full shell's shape tier may still ask).
71
96
  */
72
97
  export declare const SHELL_READ_DECISION: {
@@ -81,7 +106,10 @@ export declare const SHELL_READ_DECISION: {
81
106
  readonly rejudge: "refuse";
82
107
  };
83
108
  readonly unestablishable: {
84
- readonly full_shell: "mandated";
109
+ readonly full_shell: {
110
+ readonly narrowed: "mandated";
111
+ readonly open: "ordinary";
112
+ };
85
113
  readonly readonly: "refuse";
86
114
  readonly rejudge: "refuse";
87
115
  };
@@ -95,6 +123,11 @@ export declare const SHELL_READ_DECISION: {
95
123
  readonly readonly: "refuse";
96
124
  readonly rejudge: "refuse";
97
125
  };
126
+ readonly unanswered: {
127
+ readonly full_shell: "mandated";
128
+ readonly readonly: "refuse";
129
+ readonly rejudge: "refuse";
130
+ };
98
131
  readonly none: {
99
132
  readonly full_shell: "vouch";
100
133
  readonly readonly: "vouch";
@@ -109,10 +142,15 @@ export type DecisionTableCoversEverySeat = AssertAllKeysHandled<Exclude<ShellRea
109
142
  /** The disposition of one command-level finding on one seat — the table, read. A seat word outside
110
143
  * {@link SHELL_READ_SEATS} (an untyped caller, or one still passing a retired word) is refused loudly: an
111
144
  * absent disposition would read as "no verdict", which no caller can act on safely. */
112
- export declare function decideShellRead(finding: ShellReadFinding, seat: ShellReadSeat): ShellReadDisposition;
113
- /** {@link decideShellRead} for a command whose containment findings are all output redirections (`redirectsOnly`) or not — the
114
- * cell {@link SHELL_REDIRECT_DECISION} states where it states one, else the table's. */
115
- export declare function decideShellReadForRedirects(finding: ShellReadFinding, seat: ShellReadSeat, redirectsOnly: boolean): ShellReadDisposition;
145
+ export declare function decideShellRead(finding: ShellReadFinding, seat: ShellReadSeat, context?: ShellReadCellContext): ShellReadDisposition;
146
+ /** What the table is read for beyond (finding, seat): the two facts of a judged command a cell can depend on. */
147
+ export interface ShellReadCellContext {
148
+ /** Every containment finding is an output redirection outside the write roots ({@link SHELL_REDIRECT_DECISION}). Absent ⇒ no. */
149
+ readonly redirectsOnly?: boolean;
150
+ /** The question was raised under a NARROWED (`roots`) read face — a read candidate or the text's own structure while the read
151
+ * face runs the roots containment; `false` for the open face and for a written target alone. Absent ⇒ narrowed, the engine default. */
152
+ readonly narrowedReadFace?: boolean;
153
+ }
116
154
  /**
117
155
  * The boundary a shell read is judged against: the declared roots (canonical), the working directory and
118
156
  * home the plan's bases start from, the deny seat (the SAME `denyMatch` closure every read face mounts),
@@ -143,8 +181,11 @@ export interface ShellReadBoundary extends BashReadonlyRootBoundary {
143
181
  * the path is a key the station established (judged as a key, never as a spelling). `"protected"`: the table covers it —
144
182
  * the target is not placed and the verdict says so ({@link import("./shell-read-check.js").ShellReadVerdict.writeProtected});
145
183
  * `"guarded"`: a deployment row covers it — the target is not placed; `undefined`: nothing covers it. Read by the
146
- * station's write facts only. A judgment that throws fails the station's answer (the caller's fail-closed arm). */
147
- readonly writeTargetJudge?: (target: string, opts?: {
184
+ * station's write facts only. A judgment that throws fails the station's answer (the caller's fail-closed arm). Every lookup
185
+ * it makes goes through `fs` — the command's door — and through no environment of its own: the station's one decision about
186
+ * what a silence means reads the answers the judgment got as well as the ones it did not. */
187
+ readonly writeTargetJudge?: (target: string, opts: {
188
+ readonly fs: ObservedFilesystem;
148
189
  readonly signal?: AbortSignal;
149
190
  readonly canonical?: true;
150
191
  }) => Promise<"protected" | "guarded" | undefined>;
@@ -177,7 +218,8 @@ export interface EstablishedRead {
177
218
  /** The candidate's spelling WAS placed and the environment could not resolve where it leads (the whole chain unanswered by
178
219
  * a resolver that declares itself authoritative, or a component it could not follow) — the reading's
179
220
  * `target_unresolved` fact, as opposed to a text the station cannot read (a rewritten word, an unsettled working
180
- * directory). Present only on an `unestablishable` read. */
221
+ * directory). Present only on an `unestablishable` read. (That the environment gave no answer is the establishment's
222
+ * `incomplete`, which makes the command `unanswered` whether or not a candidate carries this mark.) */
181
223
  readonly unresolved?: true;
182
224
  /** WHERE the command's program writes this target — present only on a write target the program itself writes, at the
183
225
  * seat this read was established at (`landing`: through the path's links; `entry`: the directory entry, a link there
@@ -189,7 +231,8 @@ export interface EstablishedRead {
189
231
  };
190
232
  }
191
233
  /** What the judge found about ONE candidate. `kind` is one of the four candidate-level findings
192
- * (`declined` is a segment fact, `identity_changed` a re-establishment fact — neither is a candidate's). */
234
+ * (`declined` is a segment fact, `identity_changed` a re-establishment fact, `unanswered` a fact of the whole establishment —
235
+ * none is a candidate's). */
193
236
  export interface ReadFinding {
194
237
  readonly read: EstablishedRead;
195
238
  readonly kind: Extract<ShellReadFinding, "deny_hit" | "outside_roots" | "unestablishable" | "none">;
@@ -255,6 +298,8 @@ export interface JudgedPlan {
255
298
  readonly guards: boolean;
256
299
  /** {@link writeFaceGuards} of the same boundary — what a WRITE target's finding folds by. */
257
300
  readonly writeGuards: boolean;
301
+ /** What the command could not finish (the station's one door, decided after the write guards asked); on the top plan only. */
302
+ readonly incomplete?: readonly Incomplete[];
258
303
  }
259
304
  /**
260
305
  * Does the station GUARD anything for this boundary — a closed face (roots: containment is what it guards; an absent
@@ -281,12 +326,18 @@ export interface ShellReadFold {
281
326
  readonly finding: ShellReadFinding;
282
327
  readonly witness?: ReadFinding;
283
328
  readonly declined?: ShellReadSegment;
284
- /** Some read of the text could not be established (an `unestablishable` or `declined` finding anywhere, winning or not). */
329
+ /** What the judge did not finish, for an `unanswered` finding: the first thing the establishment recorded ({@link Incomplete.detail}). */
330
+ readonly cause?: string;
331
+ /** Some read of the text could not be established (an `unestablishable`, `unanswered` or `declined` finding anywhere, winning or not). */
285
332
  readonly unestablished?: true;
333
+ /** Some `unestablishable` finding anywhere is about the READ face — a read candidate, or the text's own structure (a rewritten
334
+ * word, a re-entered shell text) — rather than a written target alone. The cell of the row reads it with the read face in force
335
+ * ({@link decideShellRead}). */
336
+ readonly unplacedRead?: true;
286
337
  }
287
338
  /**
288
339
  * Fold a judged plan to ONE finding by {@link SHELL_READ_FINDING_RANK}, over every segment and every nested
289
- * plan. Where the station guards nothing an `unestablishable` or `declined` finding is no finding: there is nothing to
340
+ * plan. Where the station guards nothing an `unestablishable`, `unanswered` or `declined` finding is no finding: there is nothing to
290
341
  * confirm it against. Which guard is asked is the face the finding is about — a read candidate's by the read face's
291
342
  * ({@link JudgedPlan.guards}), a write target's by the write face's ({@link JudgedPlan.writeGuards}), and a finding about
292
343
  * the text's own structure (no candidate stands in for it) by either ({@link anyFaceGuards}). Two structural rules ride the fold:
@@ -2,39 +2,43 @@ import { hasWin32AliasedComponent, normalizeAbsPathLexically, withinAnyRoot } fr
2
2
  import { globInWord } from "./bash-readonly-classifier.js";
3
3
  import { readOfText } from "./shell-read-word.js";
4
4
  import { skipsRootsContainment } from "./containment-face.js";
5
- export const SHELL_READ_FINDINGS = Object.freeze(["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "none"]);
5
+ export const SHELL_READ_FINDINGS = Object.freeze(["deny_hit", "outside_roots", "unestablishable", "declined", "identity_changed", "unanswered", "none"]);
6
6
  export const SHELL_READ_SEATS = Object.freeze(["full_shell", "readonly", "rejudge"]);
7
7
  export const SHELL_READ_FINDING_RANK = {
8
8
  identity_changed: 6,
9
9
  deny_hit: 5,
10
- outside_roots: 4,
11
- unestablishable: 3,
12
- declined: 2,
10
+ unanswered: 4,
11
+ outside_roots: 3,
12
+ unestablishable: 2,
13
+ declined: 1,
13
14
  none: 0,
14
15
  };
16
+ export function dispositionOfCell(cell, narrowedReadFace) {
17
+ return typeof cell === "string" ? cell : narrowedReadFace ? cell.narrowed : cell.open;
18
+ }
15
19
  export const SHELL_READ_DECISION = {
16
20
  deny_hit: { full_shell: "refuse", readonly: "refuse", rejudge: "refuse" },
17
21
  outside_roots: { full_shell: "mandated", readonly: "refuse", rejudge: "refuse" },
18
- unestablishable: { full_shell: "mandated", readonly: "refuse", rejudge: "refuse" },
22
+ unestablishable: { full_shell: { narrowed: "mandated", open: "ordinary" }, readonly: "refuse", rejudge: "refuse" },
19
23
  declined: { full_shell: "ordinary", readonly: "refuse", rejudge: "refuse" },
20
24
  identity_changed: { full_shell: "refuse", readonly: "refuse", rejudge: "refuse" },
25
+ unanswered: { full_shell: "mandated", readonly: "refuse", rejudge: "refuse" },
21
26
  none: { full_shell: "vouch", readonly: "vouch", rejudge: "vouch" },
22
27
  };
23
- export function decideShellRead(finding, seat) {
28
+ export function decideShellRead(finding, seat, context = {}) {
29
+ const redirectCell = context.redirectsOnly === true && Object.hasOwn(SHELL_REDIRECT_DECISION, finding) ? SHELL_REDIRECT_DECISION[finding]?.[seat] : undefined;
30
+ if (redirectCell !== undefined)
31
+ return redirectCell;
24
32
  const row = Object.hasOwn(SHELL_READ_DECISION, finding) ? SHELL_READ_DECISION[finding] : undefined;
25
- const disposition = row !== undefined && Object.hasOwn(row, seat) ? row[seat] : undefined;
26
- if (disposition === undefined) {
33
+ const cell = row !== undefined && Object.hasOwn(row, seat) ? row[seat] : undefined;
34
+ if (cell === undefined) {
27
35
  throw new Error(`shell read decision: no cell for finding ${JSON.stringify(finding)} on seat ${JSON.stringify(seat)} — the seats are ${SHELL_READ_SEATS.map((w) => JSON.stringify(w)).join(", ")} (a seat names the face the command runs on)`);
28
36
  }
29
- return disposition;
37
+ return dispositionOfCell(cell, context.narrowedReadFace !== false);
30
38
  }
31
39
  const SHELL_REDIRECT_DECISION = {
32
40
  outside_roots: { full_shell: "ordinary" },
33
41
  };
34
- export function decideShellReadForRedirects(finding, seat, redirectsOnly) {
35
- const cell = redirectsOnly && Object.hasOwn(SHELL_REDIRECT_DECISION, finding) ? SHELL_REDIRECT_DECISION[finding]?.[seat] : undefined;
36
- return cell ?? decideShellRead(finding, seat);
37
- }
38
42
  export function judgeRead(read, boundary) {
39
43
  const writeTarget = read.candidate.face === "write";
40
44
  const deny = writeTarget ? boundary.writeDenyMatch : boundary.denyMatch;
@@ -110,12 +114,15 @@ export function anyFaceGuards(boundary) {
110
114
  export function foldShellReadFindings(judged) {
111
115
  let best = { finding: "none" };
112
116
  let unestablished = false;
117
+ let unplacedRead = false;
113
118
  const raise = (next) => {
114
119
  if (next.finding === "unestablishable" || next.finding === "declined") {
115
120
  const face = next.witness?.read.candidate.face;
116
121
  if (!(next.witness === undefined ? judged.guards || judged.writeGuards : face === "write" ? judged.writeGuards : judged.guards))
117
122
  return;
118
123
  unestablished = true;
124
+ if (next.finding === "unestablishable" && face !== "write")
125
+ unplacedRead = true;
119
126
  }
120
127
  const rank = SHELL_READ_FINDING_RANK[next.finding] - SHELL_READ_FINDING_RANK[best.finding];
121
128
  if (rank > 0 || (rank === 0 && next.witness?.read.candidate.face === "write" && best.witness?.read.candidate.face !== "write"))
@@ -148,7 +155,12 @@ export function foldShellReadFindings(judged) {
148
155
  }
149
156
  };
150
157
  walk(judged, false);
151
- return unestablished ? { ...best, unestablished: true } : best;
158
+ const unfinished = judged.incomplete?.[0];
159
+ if (unfinished !== undefined && (judged.guards || judged.writeGuards) && SHELL_READ_FINDING_RANK.unanswered > SHELL_READ_FINDING_RANK[best.finding]) {
160
+ unestablished = true;
161
+ best = { finding: "unanswered", cause: unfinished.detail, ...(best.finding === "unestablishable" ? { ...(best.witness !== undefined ? { witness: best.witness } : {}), ...(best.declined !== undefined ? { declined: best.declined } : {}) } : {}) };
162
+ }
163
+ return { ...best, ...(unestablished ? { unestablished: true } : {}), ...(unplacedRead ? { unplacedRead: true } : {}) };
152
164
  }
153
165
  export function judgeEstablishedPlan(plan, established, boundary, nestedOf) {
154
166
  return {
@@ -244,5 +256,6 @@ export function rejudge(judged, boundary) {
244
256
  })),
245
257
  guards: stationGuards(boundary),
246
258
  writeGuards: writeFaceGuards(boundary),
259
+ ...(judged.incomplete !== undefined ? { incomplete: judged.incomplete } : {}),
247
260
  };
248
261
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.49.1",
3
+ "version": "7.49.2",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -0,0 +1,57 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.49.1",
4
+ "from": "a58f6fef9c81bf031cc3dc1a12a8c5bc72d35193",
5
+ "to": "57363d52a115a659d902a81e8aad865ed98e2419",
6
+ "added": [],
7
+ "removed": [],
8
+ "changed": [],
9
+ "narrowed": [],
10
+ "closedSetMembers": [
11
+ {
12
+ "set": "OPTION_MODES",
13
+ "at": [
14
+ "src/tools/fs/program-read-model.ts:38"
15
+ ],
16
+ "newSet": false,
17
+ "added": [
18
+ "queries"
19
+ ],
20
+ "removed": [],
21
+ "breaking": false,
22
+ "criteriaCovered": false
23
+ },
24
+ {
25
+ "set": "ToolTurnOutcome",
26
+ "at": [
27
+ "src/core/runner/tool-turn-repair-seat.ts:50"
28
+ ],
29
+ "newSet": true,
30
+ "added": [
31
+ "reissued",
32
+ "terminal"
33
+ ],
34
+ "removed": [],
35
+ "breaking": false,
36
+ "criteriaCovered": false
37
+ }
38
+ ],
39
+ "closedSetsUnreadable": [],
40
+ "typeKeys": [],
41
+ "typeKeysUnreadableArms": [],
42
+ "typeKeysFlattenedCount": 223,
43
+ "signatures": [],
44
+ "declarationMoves": [],
45
+ "mintMoves": [],
46
+ "criteriaObserves": [],
47
+ "consumersHint": {
48
+ "cli": [
49
+ "OPTION_MODES"
50
+ ],
51
+ "server": [],
52
+ "sdk": [],
53
+ "note": "scanned cli@82bb8c2d server@a51468d9 sdk@006ce24 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it"
54
+ },
55
+ "breakingCount": 0,
56
+ "breakingItems": []
57
+ }
@@ -0,0 +1,138 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.49.2",
4
+ "from": "57363d52a115a659d902a81e8aad865ed98e2419",
5
+ "to": "50ffffb636bb70863f86ee9a74aee0c0a82891a0",
6
+ "added": [],
7
+ "removed": [],
8
+ "changed": [],
9
+ "narrowed": [],
10
+ "closedSetMembers": [
11
+ {
12
+ "set": "SHELL_READ_FINDINGS",
13
+ "at": [
14
+ "src/tools/fs/shell-read-judge.ts:34"
15
+ ],
16
+ "newSet": false,
17
+ "added": [
18
+ "unanswered"
19
+ ],
20
+ "removed": [],
21
+ "breaking": false,
22
+ "criteriaCovered": false
23
+ }
24
+ ],
25
+ "closedSetsUnreadable": [],
26
+ "typeKeys": [],
27
+ "typeKeysUnreadableArms": [],
28
+ "typeKeysFlattenedCount": 223,
29
+ "signatures": [
30
+ {
31
+ "name": "ShellReadBoundary.writeTargetJudge",
32
+ "at": [
33
+ "src/tools/fs/shell-read-judge.ts:191"
34
+ ],
35
+ "from": [
36
+ "(target: string, opts?: { readonly signal?: AbortSignal; readonly canonical?: true; }): Promise<\"protected\" | \"guarded\" | undefined>"
37
+ ],
38
+ "to": [
39
+ "(target: string, opts: { readonly fs: ObservedFilesystem; readonly signal?: AbortSignal; readonly canonical?: true; }): Promise<\"protected\" | \"guarded\" | undefined>"
40
+ ],
41
+ "changes": [
42
+ {
43
+ "aspect": "param",
44
+ "detail": "param 2 `opts` type changed, direction not read: { readonly [ -> fs: ObservedFilesystem; readonly ]signal?: AbortSignal; re…",
45
+ "breaking": true,
46
+ "uncertain": true
47
+ },
48
+ {
49
+ "aspect": "param",
50
+ "detail": "param 2 `opts` is now required",
51
+ "breaking": true
52
+ }
53
+ ],
54
+ "uncertain": "param 2 `opts` type changed, direction not read: { readonly [ -> fs: ObservedFilesystem; readonly ]signal?: AbortSignal; re… — the direction of a type change is not read syntactically, so it is reported breaking: check whether existing call sites still type-check before writing the BREAKING line",
55
+ "breaking": true,
56
+ "criteriaCovered": false
57
+ }
58
+ ],
59
+ "declarationMoves": [],
60
+ "mintMoves": [],
61
+ "criteriaObserves": [
62
+ {
63
+ "kind": "taskEventField",
64
+ "name": "tool_end.gate",
65
+ "assertions": [
66
+ "G3.a",
67
+ "G4.a"
68
+ ]
69
+ },
70
+ {
71
+ "kind": "typeMember",
72
+ "name": "AskRequest.askClass",
73
+ "assertions": [
74
+ "G1.b"
75
+ ]
76
+ },
77
+ {
78
+ "kind": "typeMember",
79
+ "name": "AskRequest.requiresRealApproval",
80
+ "assertions": [
81
+ "G1.a",
82
+ "G2.a",
83
+ "G3.a"
84
+ ]
85
+ },
86
+ {
87
+ "kind": "typeMember",
88
+ "name": "RedactionFinding.kind",
89
+ "assertions": [
90
+ "G5.a",
91
+ "G5.b"
92
+ ]
93
+ },
94
+ {
95
+ "kind": "typeMember",
96
+ "name": "RedactionFinding.span",
97
+ "assertions": [
98
+ "G5.a"
99
+ ]
100
+ },
101
+ {
102
+ "kind": "typeMember",
103
+ "name": "ShellReadVerdict.face",
104
+ "assertions": [
105
+ "G1.a",
106
+ "G2.a",
107
+ "G3.b"
108
+ ]
109
+ },
110
+ {
111
+ "kind": "typeMember",
112
+ "name": "ToolCatalogEntry.mountedBy",
113
+ "assertions": [
114
+ "G4.a"
115
+ ]
116
+ },
117
+ {
118
+ "kind": "typeMember",
119
+ "name": "ToolSpec.pathTarget",
120
+ "assertions": [
121
+ "G4.b"
122
+ ]
123
+ }
124
+ ],
125
+ "consumersHint": {
126
+ "cli": [
127
+ "SHELL_READ_FINDINGS",
128
+ "ShellReadBoundary"
129
+ ],
130
+ "server": [],
131
+ "sdk": [],
132
+ "note": "scanned cli@1aef2b83 server@5a38b2ce sdk@46baee2 — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it. Ledger files (**/docs/core-consumption/**, **/docs/wire-consumption/**, **/*LEDGER*.json) are not evidence of use — server: 2 name(s) matched ONLY in bookkeeping files and were set aside (SHELL_READ_FINDINGS, ShellReadBoundary)"
133
+ },
134
+ "breakingCount": 1,
135
+ "breakingItems": [
136
+ "signature changed: ShellReadBoundary.writeTargetJudge — param 2 `opts` type changed, direction not read: { readonly [ -> fs: ObservedFilesystem; readonly ]signal?: AbortSignal; re…; param 2 `opts` is now required"
137
+ ]
138
+ }