@sema-agent/core 7.30.0 → 7.31.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.
Files changed (90) hide show
  1. package/CHANGELOG.md +274 -0
  2. package/dist/agents/cross-session-judge.d.ts +4 -12
  3. package/dist/agents/cross-session-judge.js +4 -11
  4. package/dist/agents/peer-session-drain.js +0 -5
  5. package/dist/agents/send-message-tool.js +1 -0
  6. package/dist/agents/subagent.d.ts +1 -0
  7. package/dist/agents/subagent.js +1 -0
  8. package/dist/core/ask-origin.d.ts +6 -0
  9. package/dist/core/ask-origin.js +10 -0
  10. package/dist/core/checkpoint-store.d.ts +14 -0
  11. package/dist/core/checkpoint-store.js +1 -0
  12. package/dist/core/engine-notice.d.ts +4 -0
  13. package/dist/core/governance-codes.d.ts +1 -1
  14. package/dist/core/governance-codes.js +3 -0
  15. package/dist/core/memory-engine/data-plane.d.ts +3 -1
  16. package/dist/core/memory-engine/data-plane.js +1 -1
  17. package/dist/core/memory-engine/delegation-settlement.d.ts +44 -3
  18. package/dist/core/memory-engine/delegation-settlement.js +38 -3
  19. package/dist/core/memory-engine/engine.d.ts +123 -26
  20. package/dist/core/memory-engine/engine.js +426 -149
  21. package/dist/core/memory-engine/entry-scan.d.ts +23 -0
  22. package/dist/core/memory-engine/entry-scan.js +55 -0
  23. package/dist/core/memory-engine/file-backend.d.ts +16 -23
  24. package/dist/core/memory-engine/file-backend.js +122 -99
  25. package/dist/core/memory-engine/layer-observations.d.ts +109 -0
  26. package/dist/core/memory-engine/layer-observations.js +148 -0
  27. package/dist/core/memory-engine/layout.d.ts +11 -0
  28. package/dist/core/memory-engine/layout.js +20 -4
  29. package/dist/core/memory-engine/types.d.ts +26 -2
  30. package/dist/core/parent-spec-seat.d.ts +4 -1
  31. package/dist/core/parent-spec-seat.js +2 -0
  32. package/dist/core/park-selfcheck.js +1 -0
  33. package/dist/core/runner/announce-once-ledger.d.ts +26 -0
  34. package/dist/core/runner/announce-once-ledger.js +37 -0
  35. package/dist/core/runner/contracts.d.ts +22 -5
  36. package/dist/core/runner/denial-limit-arms.d.ts +2 -2
  37. package/dist/core/runner/prepare-acquire-reconcile.d.ts +0 -4
  38. package/dist/core/runner/prepare-acquire-reconcile.js +1 -3
  39. package/dist/core/runner/prepare-file-history.d.ts +13 -15
  40. package/dist/core/runner/prepare-file-history.js +57 -43
  41. package/dist/core/runner/prepare-hands-readface.d.ts +2 -2
  42. package/dist/core/runner/prepare-listings.d.ts +3 -1
  43. package/dist/core/runner/prepare-listings.js +2 -2
  44. package/dist/core/runner/prepare-memory.js +16 -5
  45. package/dist/core/runner/prepare-park-ask.js +27 -16
  46. package/dist/core/runner/prepare-prompt-inputs.d.ts +8 -1
  47. package/dist/core/runner/prepare-prompt-inputs.js +5 -3
  48. package/dist/core/runner/prepare-task.js +7 -5
  49. package/dist/core/runner/prepare-wiring-manifest.d.ts +1 -0
  50. package/dist/core/runner/prepare-wiring-manifest.js +2 -1
  51. package/dist/core/runner/run-attachment-seats.js +1 -1
  52. package/dist/core/runner/run-leg.js +61 -52
  53. package/dist/core/runner/run-settle-and-teardown.js +4 -0
  54. package/dist/core/runner/run-turn-boundary.js +6 -6
  55. package/dist/core/runner/turn-attachments.d.ts +6 -6
  56. package/dist/core/runner-deps.d.ts +3 -1
  57. package/dist/core/secret-env.d.ts +11 -0
  58. package/dist/core/secret-env.js +22 -1
  59. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +2 -0
  60. package/dist/core/store-contracts/checkpoint-store-contract.js +22 -0
  61. package/dist/core/task-result.d.ts +1 -1
  62. package/dist/core/task-spec.d.ts +17 -8
  63. package/dist/core/tool-spec.d.ts +1 -1
  64. package/dist/core/wiring-manifest.d.ts +10 -0
  65. package/dist/core/wiring-manifest.js +7 -1
  66. package/dist/engine/execution-env/node-execution-env.d.ts +6 -0
  67. package/dist/engine/execution-env/node-execution-env.js +15 -17
  68. package/dist/engine/harness/agent-harness.js +7 -5
  69. package/dist/engine/lsp/node-lsp-manager.d.ts +7 -0
  70. package/dist/engine/lsp/node-lsp-manager.js +11 -3
  71. package/dist/index.d.ts +1 -1
  72. package/dist/index.js +1 -1
  73. package/dist/shell/lex.d.ts +8 -3
  74. package/dist/shell/lex.js +2 -2
  75. package/dist/tools/fs/bash-readonly-classifier.d.ts +7 -1
  76. package/dist/tools/fs/bash-readonly-classifier.js +7 -3
  77. package/dist/tools/fs/shell-read-establish.d.ts +1 -1
  78. package/dist/tools/fs/shell-read-establish.js +6 -34
  79. package/dist/tools/fs/shell-read-identity.d.ts +13 -0
  80. package/dist/tools/fs/shell-read-identity.js +39 -0
  81. package/dist/tools/fs/shell-read-judge.d.ts +8 -0
  82. package/dist/tools/fs/shell-read-judge.js +7 -0
  83. package/dist/tools/fs/shell-read-plan.d.ts +5 -1
  84. package/dist/tools/fs/shell-read-plan.js +13 -21
  85. package/dist/tools/fs/shell-read-word.d.ts +16 -2
  86. package/dist/tools/fs/shell-read-word.js +40 -5
  87. package/package.json +1 -1
  88. package/test/export-surface.snapshot.json +7 -1
  89. package/wire-changes/core@7.30.1.json +154 -0
  90. package/wire-changes/core@7.31.0.json +705 -0
@@ -4,7 +4,7 @@
4
4
  * (the home-directory word spelled with the declared home, as bash hands it to the program), and what the shell
5
5
  * does to the word before the program sees it.
6
6
  */
7
- import { type LexedToken, type LexedWord, type WordPiece } from "../../shell/lex.js";
7
+ import { type LexedCommand, type LexedToken, type LexedWord, type WordPiece } from "../../shell/lex.js";
8
8
  /** `"glob"` = an unquoted pathname-expansion character; `"unresolvable"` = the shell rewrites the word (a brace,
9
9
  * variable or command substitution) so its text is not the path. The read candidate's own field, spelled here. */
10
10
  export type WordExpands = false | "glob" | "unresolvable";
@@ -35,13 +35,27 @@ export declare function spelledWithHome(spelled: string, raw: string, home: stri
35
35
  * spelling. The lexer puts the body's compound command back at command position after the head, so a definition
36
36
  * nested in a body is dropped the same way; after a drop the token that moved up is looked at again. */
37
37
  export declare function dropDefinitionHeads(tokens: LexedToken[]): void;
38
+ /** Why a lexed text's reads cannot all be named — the plan's `unreadable` floor, or `undefined`: the first word whose
39
+ * value the text does not contain (an unresolved word), or an unquoted extended-glob opener anywhere a word, a
40
+ * redirection target or a here-document delimiter stands (`pack@(age.json)`, `<<@(x)`). After `shopt -s extglob`
41
+ * bash expands the pattern (or reads another delimiter) where the lexer reads a split word, so what the text opens is
42
+ * not what the plan names: the whole text asks, and a deny hit anywhere still refuses. `globs: false` = the text is an
43
+ * arithmetic expression (`$((2*(3+4)))`), which bash evaluates and never globs. */
44
+ export declare function unreadableSentenceOf(lexed: LexedCommand, text: string, globs?: boolean): string | undefined;
38
45
  /** The elements of a compound array value `(e1 [k]=e2 …)`, read with the one lexer as the words bash assigns (a
39
46
  * `[k]=` subscript prefix dropped): each is a value spelling the deny judge reads, as a scalar value is. The list is
40
47
  * words across lines and comments, so every segment's words count, whatever else a segment carries (a word bash
41
48
  * would reject leaves its siblings readable). None when the list does not lex — the value stays the unread list. */
42
49
  export declare function compoundArrayElements(value: {
43
50
  readonly raw: string;
44
- }): readonly Read[];
51
+ }): readonly (Read & {
52
+ readonly denyOnly?: true;
53
+ })[];
54
+ /** An `$((…))` body the shell reads as ARITHMETIC: one parenthesised group spanning the whole body (`(2*(3+4))`),
55
+ * its bounds read off the lexer's structure — a quoted, escaped or commented parenthesis is text, not a bound — across
56
+ * the segments the lexer cuts at `&&` `||` `&` `|` and line breaks (operators arithmetic shares with the shell).
57
+ * `$((cat x); :)` opens the same way but its first group closes early: a command substitution holding a subshell. */
58
+ export declare function isArithmeticBody(body: string): boolean;
45
59
  /** What the shell does to a word (or an assignment's value) before the program sees it, read off its pieces. */
46
60
  export declare function expandsOf(w: {
47
61
  readonly pieces: readonly WordPiece[];
@@ -1,5 +1,5 @@
1
- import { argvOf, lexShell, literalTildeSpelling } from "../../shell/lex.js";
2
- import { expansionInWord, globInWord, homeExpansionOf } from "./bash-readonly-classifier.js";
1
+ import { argvOf, lexShell, literalTildeSpelling, UNRESOLVED_SENTENCE } from "../../shell/lex.js";
2
+ import { expansionInWord, extglobOpenerIn, globInWord, homeExpansionOf } from "./bash-readonly-classifier.js";
3
3
  export function readsOf(words, home) {
4
4
  return words.map((word) => {
5
5
  const spelled = home === undefined ? undefined : homeExpansionOf(word, home)?.spelled;
@@ -39,17 +39,52 @@ export function dropDefinitionHeads(tokens) {
39
39
  tokens.splice(k, 3);
40
40
  }
41
41
  }
42
+ export function unreadableSentenceOf(lexed, text, globs = true) {
43
+ for (const segment of lexed.segments) {
44
+ for (const token of segment.tokens) {
45
+ const word = token.kind === "word" ? token : token.kind === "redirect" ? token.target : undefined;
46
+ if (word?.unresolved !== undefined)
47
+ return UNRESOLVED_SENTENCE[word.unresolved];
48
+ }
49
+ }
50
+ return globs && extglobOpenerIn(lexed, text) ? "an extended pattern (`?(…)` `*(…)` `+(…)` `@(…)` `!(…)`) is one this reader does not expand" : undefined;
51
+ }
42
52
  export function compoundArrayElements(value) {
43
53
  const inner = /^\(([\s\S]*)\)$/.exec(value.raw)?.[1];
44
54
  const l = inner === undefined ? undefined : lexShell(inner);
45
55
  if (l === undefined || "parseFailure" in l)
46
56
  return [];
47
- return l.segments.flatMap((sg) => argvOf(sg)).map((word) => {
48
- const folded = word.folded.replace(/^\[[^\]]*\]\+?=/, "");
57
+ return l.segments.flatMap((sg) => argvOf(sg)).flatMap((element) => {
58
+ const sub = /^\[[^\]]*\]\+?=/.exec(element.raw)?.[0];
59
+ const value = sub === undefined ? undefined : readOfText(`V=${element.raw.slice(sub.length)}`).word.assignment?.value;
60
+ const word = value === undefined ? element : { ...element, raw: value.raw, folded: value.folded, pieces: value.pieces };
49
61
  const tilde = word.pieces.some((q) => q.expansion?.kind === "tilde");
50
- return { word, raw: word.raw, folded: tilde ? folded : literalTildeSpelling(folded), expands: expandsOf(word) };
62
+ const read = { word, raw: word.raw, folded: tilde ? word.folded : literalTildeSpelling(word.folded), expands: expandsOf(word) };
63
+ const prefix = /^\[[^\]]*\]\+?=/.exec(element.folded)?.[0];
64
+ if (prefix === undefined)
65
+ return [read];
66
+ const spelled = element.pieces.some((q) => q.expansion?.kind === "tilde") ? element.folded.slice(prefix.length) : literalTildeSpelling(element.folded.slice(prefix.length));
67
+ return [read, { word: element, raw: element.raw, folded: spelled, expands: expandsOf(element), denyOnly: true }];
51
68
  });
52
69
  }
70
+ export function isArithmeticBody(body) {
71
+ const l = body.startsWith("(") && body.endsWith(")") ? lexShell(body) : undefined;
72
+ if (l === undefined || "parseFailure" in l)
73
+ return false;
74
+ const tokens = l.segments.flatMap((sg) => sg.tokens);
75
+ if (tokens[0]?.kind !== "group" || tokens[0].op !== "(")
76
+ return false;
77
+ let depth = 0;
78
+ for (const [i, t] of tokens.entries()) {
79
+ if (t.kind !== "group")
80
+ continue;
81
+ if (t.op === "(")
82
+ depth++;
83
+ else if (--depth === 0)
84
+ return i === tokens.length - 1;
85
+ }
86
+ return false;
87
+ }
53
88
  export function expandsOf(w) {
54
89
  if (expansionInWord(w) || /[`()]/.test(w.raw))
55
90
  return "unresolvable";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "7.30.0",
3
+ "version": "7.31.0",
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": 2475,
4
+ "count": 2478,
5
5
  "exports": {
6
6
  "A2ATaskState": "type",
7
7
  "A2ATaskStateReversal": "type",
@@ -688,6 +688,7 @@
688
688
  "MEMORY_INSTRUCTION_TEMPLATE": "variable",
689
689
  "MEMORY_ORIGIN_CAUSES": "variable",
690
690
  "MEMORY_PREFERENCE_DISCIPLINE": "variable",
691
+ "MEMORY_PROJECT_KEY_ABSENT_REASONS": "variable",
691
692
  "MEMORY_READONLY_NOTICE": "variable",
692
693
  "MEMORY_RECALL_DISCIPLINE": "variable",
693
694
  "MEMORY_SAFETY": "variable",
@@ -769,6 +770,8 @@
769
770
  "MemoryNoteRecord": "interface",
770
771
  "MemoryNoteType": "type",
771
772
  "MemoryOriginCause": "type",
773
+ "MemoryProjectKey": "type",
774
+ "MemoryProjectKeyAbsentReason": "type",
772
775
  "MemoryProjectionError": "class",
773
776
  "MemoryPromptArtifactStore": "class",
774
777
  "MemoryPromptSourceStateStore": "class",
@@ -3165,6 +3168,7 @@
3165
3168
  "MEMORY_INSTRUCTION_TEMPLATE": "advanced",
3166
3169
  "MEMORY_ORIGIN_CAUSES": "advanced",
3167
3170
  "MEMORY_PREFERENCE_DISCIPLINE": "advanced",
3171
+ "MEMORY_PROJECT_KEY_ABSENT_REASONS": "advanced",
3168
3172
  "MEMORY_READONLY_NOTICE": "advanced",
3169
3173
  "MEMORY_RECALL_DISCIPLINE": "advanced",
3170
3174
  "MEMORY_SAFETY": "advanced",
@@ -3246,6 +3250,8 @@
3246
3250
  "MemoryNoteRecord": "stable",
3247
3251
  "MemoryNoteType": "advanced",
3248
3252
  "MemoryOriginCause": "advanced",
3253
+ "MemoryProjectKey": "advanced",
3254
+ "MemoryProjectKeyAbsentReason": "advanced",
3249
3255
  "MemoryProjectionError": "advanced",
3250
3256
  "MemoryPromptArtifactStore": "advanced",
3251
3257
  "MemoryPromptSourceStateStore": "advanced",
@@ -0,0 +1,154 @@
1
+ {
2
+ "repo": "core",
3
+ "version": "7.30.1",
4
+ "from": "3a100146dad04ac157def06e16d624fc8c1fe6a1",
5
+ "to": "v7.30.1",
6
+ "added": [],
7
+ "removed": [],
8
+ "changed": [],
9
+ "narrowed": [
10
+ {
11
+ "id": "F1",
12
+ "source": "behaviorFlips.summary",
13
+ "text": "NARROWING (#1064 ⑨, shell read boundary): an unquoted extended-glob opener (`?(` `*(` `+(` `@(` `!(`) in an argv word, a redirection target or a here-document delimiter makes the WHOLE text unestablishable — it joins the plan's `unreadable` floor, so both full-shell seats raise one MANDATED card, the read-only face and every headless face refuse, and a deny hit elsewhere in the same text still refuses outright. An `$((…))` arithmetic body keeps its reading only when the whole body is ONE complete parenthesised group, read off the lexer's structure (a quoted parenthesis is text) and followed across the segments the lexer cuts at `&&` `||` `&` `|` and line breaks; a quoted opener and a here-document body are the text they always were."
14
+ },
15
+ {
16
+ "id": "F2",
17
+ "source": "behaviorFlips.summary",
18
+ "text": "NARROWING (#1064 ⑬, shell read boundary; the CHANGELOG reads it as the repair of a 7.30.0 regression against 7.29.0 on the answered seats — 7.29.0 is not measured here): the declared-home spelling of an unplaced home word becomes a deny-only SHADOW candidate (`ReadCandidate.denyOnly`) established exactly as a read is — canonical target, a pattern's matches, a traversal root's tree — and judged for deny rows only; a bare `cd` / `cd --` puts the declared home on the deny floor; a `[k]=` compound element is read as the value bash assigns. The pre-spawn identity re-check compares each candidate's targets with its own re-establishment (keyed by plan position and candidate identity, deny-only reads their own class), and candidate de-duplication keys on `denyOnly`."
19
+ },
20
+ {
21
+ "id": "F3",
22
+ "source": "behaviorFlips.summary",
23
+ "text": "NARROWING (#1072, spawned-environment scrub): `SECRET_ENV_RE` reads `KEYS`, `TOKENS` and `PASSWORDS` as it reads their singulars, so `SERVICE_AUTH_TOKENS`, `API_KEYS`, `DB_PASSWORDS`, `GITHUB_TOKENS` no longer reach a tool's child shell; a `TOKENS` right after a count word (`TOKEN_COUNT_WORDS`: MAX OUTPUT INPUT THINKING NUM TOTAL) is a token count and is kept. The singular `TOKEN` and the exact-name exemptions keep their 7.30.0 reading."
24
+ },
25
+ {
26
+ "id": "F4",
27
+ "source": "behaviorFlips.summary",
28
+ "text": "NARROWING + additive option (#1073, language-server environment): `defaultLspSpawn` passes `scrubSecretEnv(process.env)` to `child_process.spawn` instead of no `env` at all, so a language server no longer inherits credential-shaped host variables; `NodeLspManagerOptions.env?` (new, optional) is the server's environment used VERBATIM by the manager's default spawn. A host-supplied `spawn` still owns its child's environment. The LSP scrub reports nothing (no findings collector)."
29
+ }
30
+ ],
31
+ "closedSetMembers": [],
32
+ "closedSetsUnreadable": [],
33
+ "typeKeys": [
34
+ {
35
+ "type": "NodeLspManagerOptions",
36
+ "at": [
37
+ "src/engine/lsp/node-lsp-manager.ts:76"
38
+ ],
39
+ "added": [
40
+ "env"
41
+ ],
42
+ "addedDetail": [
43
+ {
44
+ "key": "env",
45
+ "optional": true
46
+ }
47
+ ],
48
+ "addedRequired": [],
49
+ "removed": [],
50
+ "breaking": false,
51
+ "criteriaCovered": true
52
+ },
53
+ {
54
+ "type": "ReadCandidate",
55
+ "at": [
56
+ "src/tools/fs/shell-read-plan.ts:104"
57
+ ],
58
+ "added": [
59
+ "denyOnly"
60
+ ],
61
+ "addedDetail": [
62
+ {
63
+ "key": "denyOnly",
64
+ "optional": true
65
+ }
66
+ ],
67
+ "addedRequired": [],
68
+ "removed": [],
69
+ "breaking": false,
70
+ "criteriaCovered": true
71
+ }
72
+ ],
73
+ "typeKeysUnreadableArms": [],
74
+ "typeKeysFlattenedCount": 215,
75
+ "declarationMoves": [],
76
+ "mintMoves": [],
77
+ "criteriaObserves": [
78
+ {
79
+ "kind": "taskEventField",
80
+ "name": "tool_end.gate",
81
+ "assertions": [
82
+ "G1.a",
83
+ "G1.b",
84
+ "G2.a"
85
+ ]
86
+ },
87
+ {
88
+ "kind": "taskEventField",
89
+ "name": "tool_end.isError",
90
+ "assertions": [
91
+ "G1.b",
92
+ "G3.a"
93
+ ]
94
+ },
95
+ {
96
+ "kind": "taskEventField",
97
+ "name": "tool_end.output",
98
+ "assertions": [
99
+ "G1.b",
100
+ "G2.a",
101
+ "G3.a",
102
+ "G4.a",
103
+ "G4.b"
104
+ ]
105
+ },
106
+ {
107
+ "kind": "taskEventField",
108
+ "name": "tool_end.structured",
109
+ "assertions": [
110
+ "G1.b",
111
+ "G2.a",
112
+ "G3.a"
113
+ ]
114
+ },
115
+ {
116
+ "kind": "typeMember",
117
+ "name": "AskRequest.mandated",
118
+ "assertions": [
119
+ "G1.a",
120
+ "G2.b",
121
+ "G3.a"
122
+ ]
123
+ },
124
+ {
125
+ "kind": "typeMember",
126
+ "name": "NodeLspManagerOptions.env",
127
+ "assertions": [
128
+ "G5.a",
129
+ "G5.b"
130
+ ]
131
+ },
132
+ {
133
+ "kind": "typeMember",
134
+ "name": "ReadCandidate.denyOnly",
135
+ "assertions": [
136
+ "G2.b",
137
+ "G3.b"
138
+ ]
139
+ }
140
+ ],
141
+ "consumersHint": {
142
+ "cli": [
143
+ "ReadCandidate"
144
+ ],
145
+ "server": [
146
+ "ReadCandidate"
147
+ ],
148
+ "sdk": [],
149
+ "note": "scanned cli@4e593722 server@fa3e0b9b sdk@350f64f — 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: 1 name(s) matched ONLY in bookkeeping files and were set aside (NodeLspManagerOptions)"
150
+ },
151
+ "breakingCount": 0,
152
+ "breakingItems": [],
153
+ "toResolvedAt": "0034a646af1de9c0cdd8ad7bd9b56234ec527c2c"
154
+ }