@theokit/sdk 5.0.1 → 5.1.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 (98) hide show
  1. package/CHANGELOG.md +267 -0
  2. package/dist/a2a/index.cjs +3 -3
  3. package/dist/a2a/index.js +1 -1
  4. package/dist/a2a/subagent.d.cts +22 -3
  5. package/dist/a2a/subagent.d.ts +22 -3
  6. package/dist/{agent-TKJBWGGQ.cjs → agent-ARLOD4JX.cjs} +9 -9
  7. package/dist/{agent-TKJBWGGQ.cjs.map → agent-ARLOD4JX.cjs.map} +1 -1
  8. package/dist/{agent-UGYIYC3R.js → agent-N6WJ54ML.js} +8 -8
  9. package/dist/{agent-UGYIYC3R.js.map → agent-N6WJ54ML.js.map} +1 -1
  10. package/dist/{chunk-CC7EYKBJ.cjs → chunk-67SBTGMA.cjs} +4 -4
  11. package/dist/{chunk-CC7EYKBJ.cjs.map → chunk-67SBTGMA.cjs.map} +1 -1
  12. package/dist/{chunk-D7WAROJR.js → chunk-AW6F6HZR.js} +3 -3
  13. package/dist/{chunk-D7WAROJR.js.map → chunk-AW6F6HZR.js.map} +1 -1
  14. package/dist/{chunk-6WAKKTBO.js → chunk-CFE6QF2Q.js} +19 -3
  15. package/dist/chunk-CFE6QF2Q.js.map +1 -0
  16. package/dist/{chunk-CQLVA4CO.cjs → chunk-D3CCY3A2.cjs} +60 -53
  17. package/dist/chunk-D3CCY3A2.cjs.map +1 -0
  18. package/dist/{chunk-UFPUHJWS.js → chunk-IUMAQURF.js} +7 -2
  19. package/dist/chunk-IUMAQURF.js.map +1 -0
  20. package/dist/{chunk-LTLPBGHC.cjs → chunk-KGANQYP7.cjs} +5 -5
  21. package/dist/{chunk-LTLPBGHC.cjs.map → chunk-KGANQYP7.cjs.map} +1 -1
  22. package/dist/{chunk-XDANGA2C.js → chunk-LX7SEXOQ.js} +6 -3
  23. package/dist/chunk-LX7SEXOQ.js.map +1 -0
  24. package/dist/{chunk-QME6FDFG.cjs → chunk-NQTD6QOW.cjs} +19 -3
  25. package/dist/chunk-NQTD6QOW.cjs.map +1 -0
  26. package/dist/{chunk-DLRP7BI6.cjs → chunk-NYQ3IS7K.cjs} +3 -3
  27. package/dist/chunk-NYQ3IS7K.cjs.map +1 -0
  28. package/dist/{chunk-7RHC7HMS.js → chunk-OQRGVTQF.js} +3 -3
  29. package/dist/{chunk-7RHC7HMS.js.map → chunk-OQRGVTQF.js.map} +1 -1
  30. package/dist/{chunk-SVWMQCXF.js → chunk-OYD3U3LY.js} +19 -12
  31. package/dist/chunk-OYD3U3LY.js.map +1 -0
  32. package/dist/{chunk-UGRS7ZA7.cjs → chunk-QATRS7JD.cjs} +6 -2
  33. package/dist/chunk-QATRS7JD.cjs.map +1 -0
  34. package/dist/{chunk-DRL7URI4.cjs → chunk-QDM3OHUT.cjs} +7 -2
  35. package/dist/chunk-QDM3OHUT.cjs.map +1 -0
  36. package/dist/{chunk-5AXMNUCY.cjs → chunk-QYLZQ43D.cjs} +5 -5
  37. package/dist/{chunk-5AXMNUCY.cjs.map → chunk-QYLZQ43D.cjs.map} +1 -1
  38. package/dist/{chunk-GUKPXDGJ.js → chunk-WMWEI3NS.js} +3 -3
  39. package/dist/chunk-WMWEI3NS.js.map +1 -0
  40. package/dist/{chunk-YEL3SP6X.js → chunk-XU6MLSC6.js} +3 -3
  41. package/dist/{chunk-YEL3SP6X.js.map → chunk-XU6MLSC6.js.map} +1 -1
  42. package/dist/{context-XQJIGZMR.cjs → context-4QOEWRDF.cjs} +7 -7
  43. package/dist/{context-XQJIGZMR.cjs.map → context-4QOEWRDF.cjs.map} +1 -1
  44. package/dist/context-Z3CFTT3H.js +6 -0
  45. package/dist/{context-FM6UZPTL.js.map → context-Z3CFTT3H.js.map} +1 -1
  46. package/dist/cron.cjs +8 -8
  47. package/dist/cron.js +7 -7
  48. package/dist/eval.cjs +22 -7
  49. package/dist/eval.cjs.map +1 -1
  50. package/dist/eval.js +21 -6
  51. package/dist/eval.js.map +1 -1
  52. package/dist/index.cjs +26 -26
  53. package/dist/index.js +11 -11
  54. package/dist/internal/concurrency/subagent-credentials.d.ts +45 -0
  55. package/dist/internal/persistence/index.cjs +4 -4
  56. package/dist/internal/persistence/index.js +1 -1
  57. package/dist/internal/runtime/registry/agent-registry-store.d.ts +1 -0
  58. package/dist/internal/runtime/skills/discover-skills.d.ts +35 -0
  59. package/dist/judge-call-46M2E5FA.cjs +22 -0
  60. package/dist/{judge-call-I3P4D5QR.cjs.map → judge-call-46M2E5FA.cjs.map} +1 -1
  61. package/dist/judge-call-FGUNNWEI.js +5 -0
  62. package/dist/{judge-call-6MVARKU2.js.map → judge-call-FGUNNWEI.js.map} +1 -1
  63. package/dist/persistence.cjs +8 -0
  64. package/dist/persistence.d.cts +1 -1
  65. package/dist/persistence.d.ts +1 -1
  66. package/dist/persistence.js +1 -1
  67. package/dist/skills.cjs +7 -3
  68. package/dist/skills.d.cts +1 -1
  69. package/dist/skills.d.ts +1 -1
  70. package/dist/skills.js +1 -1
  71. package/dist/subagents-loader-DOBTTICM.js +7 -0
  72. package/dist/{subagents-loader-7ES7PJNM.js.map → subagents-loader-DOBTTICM.js.map} +1 -1
  73. package/dist/subagents-loader-GEHYCMEX.cjs +16 -0
  74. package/dist/{subagents-loader-OMOH6ERO.cjs.map → subagents-loader-GEHYCMEX.cjs.map} +1 -1
  75. package/dist/subagents-loader.cjs +3 -3
  76. package/dist/subagents-loader.cjs.map +1 -1
  77. package/dist/subagents-loader.d.cts +34 -1
  78. package/dist/subagents-loader.d.ts +34 -1
  79. package/dist/subagents-loader.js +3 -3
  80. package/dist/subagents-loader.js.map +1 -1
  81. package/docs/error-codes.md +2 -2
  82. package/docs/harness-capability-map.md +5 -1
  83. package/package.json +1 -1
  84. package/dist/chunk-6WAKKTBO.js.map +0 -1
  85. package/dist/chunk-CQLVA4CO.cjs.map +0 -1
  86. package/dist/chunk-DLRP7BI6.cjs.map +0 -1
  87. package/dist/chunk-DRL7URI4.cjs.map +0 -1
  88. package/dist/chunk-GUKPXDGJ.js.map +0 -1
  89. package/dist/chunk-QME6FDFG.cjs.map +0 -1
  90. package/dist/chunk-SVWMQCXF.js.map +0 -1
  91. package/dist/chunk-UFPUHJWS.js.map +0 -1
  92. package/dist/chunk-UGRS7ZA7.cjs.map +0 -1
  93. package/dist/chunk-XDANGA2C.js.map +0 -1
  94. package/dist/context-FM6UZPTL.js +0 -6
  95. package/dist/judge-call-6MVARKU2.js +0 -5
  96. package/dist/judge-call-I3P4D5QR.cjs +0 -22
  97. package/dist/subagents-loader-7ES7PJNM.js +0 -7
  98. package/dist/subagents-loader-OMOH6ERO.cjs +0 -16
package/CHANGELOG.md CHANGED
@@ -1,5 +1,272 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#579](https://github.com/usetheokit/theokit-sdk/pull/579) [`f08b330`](https://github.com/usetheokit/theokit-sdk/commit/f08b330fd6ca03049dd5fded5d76250263972691) Thanks [@usetheodev](https://github.com/usetheodev)! - `discoverSubagents` can read a declared foreign dialect, closing an asymmetry against the agent's own registry
8
+
9
+ `[#524](https://github.com/usetheokit/theokit-sdk/issues/524)` made foreign configuration opt-in and reached the agent's subagent registry — which resolves
10
+ through `settingSources` + `compatSources` — but not `discoverSubagents`, the public selector over
11
+ the same material. The reader underneath already accepted `compatSources`; this entry point simply
12
+ never passed it.
13
+
14
+ Measured by the `theocode` session on `5.0.1`, both arms in fresh trusted directories with the same
15
+ task:
16
+
17
+ ```
18
+ roles in .theokit/agents/ delegate_to_team works
19
+ the SAME files in .claude/agents/ "the `explorer` role is not configured"
20
+ ```
21
+
22
+ So a repository adopting the product could **delegate to** a `.claude/agents/` subagent by name and
23
+ could **not define its team's roles** there. One dialect, two answers, depending on which selector
24
+ asked.
25
+
26
+ ```ts
27
+ await discoverSubagents(cwd, { compatSources: ["claude-code"] });
28
+ ```
29
+
30
+ `compatSources` is a **separate option from `settingSources`**, deliberately. That one answers
31
+ *which sources* (project, and one day user or team); this one answers *which dialects* within them.
32
+ Folding `"claude-code"` into `SubagentSource` would conflate two orthogonal axes, and the internal
33
+ loader has kept them apart since `[#524](https://github.com/usetheokit/theokit-sdk/issues/524)` for exactly that reason.
34
+
35
+ **The opt-in still holds**: with nothing declared, `.claude/agents/` is not read. That is covered by
36
+ a test whose only job is to fail if the option ever became a no-op.
37
+
38
+ `CompatSourceDeclaration` is re-exported from `@theokit/sdk/subagents-loader` for the same reason
39
+ `AgentDefinition` is — an option whose type is unreachable is an option only `any` can call.
40
+
41
+ - [#579](https://github.com/usetheokit/theokit-sdk/pull/579) [`8a59217`](https://github.com/usetheokit/theokit-sdk/commit/8a592174f76ea85f8d75d7446ebd1ea5e3094d50) Thanks [@usetheodev](https://github.com/usetheodev)! - `@theokit/sdk/persistence` exposes `sessionUuidFor` and `legacyTranscriptPath` ([#577](https://github.com/usetheokit/theokit-sdk/issues/577))
42
+
43
+ Every transcript helper on this entry point went **id → path**. Nothing went the other way, and
44
+ nothing let a caller compute the forward mapping to match against — so a consumer enumerating
45
+ `projects/<encoded-cwd>/*.jsonl`, which is how you list sessions without a registry, received
46
+ filenames it could not relate to any agent id it held.
47
+
48
+ The naming scheme is deliberately one-way: a UUIDv8 over SHA-256, so the Claude Code CLI can
49
+ `--continue` a session this SDK wrote. The 5.0.0 notes say *"nothing has to be persisted to map one
50
+ back to the other"* — true of the scheme, and not true in practice, because `sessionUuidFor` lived
51
+ in the compiled JS and in zero `.d.ts`. The only route left was to reimplement the hash: an SDK
52
+ internal, copied into a consumer, silently wrong the day the scheme moves.
53
+
54
+ ```ts
55
+ import { sessionUuidFor, transcriptRoot } from "@theokit/sdk/persistence";
56
+
57
+ const wanted = `${sessionUuidFor(agentId)}.jsonl`;
58
+ const mine = (await readdir(dir)).filter((f) => f === wanted);
59
+ ```
60
+
61
+ **What crosses is the forward mapping, not an inverse.** A path → id function cannot exist over a
62
+ hash, and shipping one would be a lie about it. `legacyTranscriptPath` crosses alongside because a
63
+ directory written before [#400](https://github.com/usetheokit/theokit-sdk/issues/400) holds both spellings, and a consumer matching only the new one
64
+ reports its own history as missing — the same false absence, one rename later.
65
+
66
+ Measured on `@theokit/agents` 4.x against `5.0.1`: 29 unit tests failing from this single cause,
67
+ seen from four angles — listing, protection, GC and deletion.
68
+
69
+ - [#579](https://github.com/usetheokit/theokit-sdk/pull/579) [`b182d84`](https://github.com/usetheokit/theokit-sdk/commit/b182d847725038ed173423d64106024d149e5984) Thanks [@usetheodev](https://github.com/usetheodev)! - `loadSkillInstructions` — turn a discovered skill into an inline one without a second parser
70
+
71
+ `SkillsSettings.inline` requires `instructions`, and `discoverSkills` returns only the frontmatter
72
+ fields plus `source`. So a consumer wanting to feed discovered skills back in had one route: open
73
+ `source` and split the frontmatter by hand.
74
+
75
+ That is a second implementation of this module's own convention — the thing
76
+ `@theokit/sdk/subagents-loader` was published to end — and it fails **silently** if the format ever
77
+ moves: the frontmatter lands inside the instructions and nothing says so.
78
+
79
+ ```ts
80
+ import { discoverSkills, loadSkillInstructions } from "@theokit/sdk/skills";
81
+
82
+ const skills = await discoverSkills(dir);
83
+ const inline = await Promise.all(
84
+ skills.map(async (s) => ({ ...s, instructions: await loadSkillInstructions(s) })),
85
+ );
86
+ ```
87
+
88
+ **`Skill` is unchanged**, deliberately. Its docblock says *"the skill BODY is never included"* — a
89
+ written contract whose reason is not written down, and the likely one (a catalog you can put in a
90
+ prompt without carrying every body) is worth keeping intact. The body was never expensive to
91
+ obtain: discovery already reads each file in full and discards all but the frontmatter. What was
92
+ missing was a door that hands it over, which is what this is — the same relationship
93
+ `loadSubagentDefinition` has to `discoverSubagents`.
94
+
95
+ It **throws** on an unreadable `source`, unlike discovery, which skips what it cannot read. A caller
96
+ naming one skill has asked about that skill, and an empty string would answer a question it did not
97
+ ask.
98
+
99
+ Reported by the `theocode` session, which needed an operator's `~/.theokit/skills/` to reach an
100
+ agent through this SDK's parser rather than a copy of it.
101
+
102
+ ### Patch Changes
103
+
104
+ - [#579](https://github.com/usetheokit/theokit-sdk/pull/579) [`0894dda`](https://github.com/usetheokit/theokit-sdk/commit/0894ddad430b1ac5b1e2ba222a9527c1143d9722) Thanks [@usetheodev](https://github.com/usetheodev)! - `local.compatSources` survives delegation and resume ([#578](https://github.com/usetheokit/theokit-sdk/issues/578))
105
+
106
+ `[#524](https://github.com/usetheokit/theokit-sdk/issues/524)` added `compatSources` to `AgentOptions["local"]`, so a project can declare that `.claude/`
107
+ hooks, skills, subagents and plugins may be read. Two places carry a parent's `local` config across
108
+ a hop, and **neither was updated**:
109
+
110
+ | Carrier | Was missing |
111
+ |---|---|
112
+ | `buildChildCreateOptions` — parent → delegated child | `settingSources`, `compatSources` |
113
+ | `serializeLocal` — agent → registry → resumed agent | `compatSources` |
114
+
115
+ So a parent declaring `compatSources: ["claude-code"]` read `.claude/agents/` and its delegated
116
+ child did not: a team could delegate TO a role by name while the child could not resolve the rest of
117
+ the team. And an agent resumed from the registry silently stopped reading the surfaces it was
118
+ created to read.
119
+
120
+ Both the field and the code that carries it landed on the same day, which is what an omission looks
121
+ like rather than a decision — and `serializeLocal` documents the one inclusion that *was* decided,
122
+ right beside the gap.
123
+
124
+ **Inheriting is safe here, and it is the opposite direction from every other inherited field.** The
125
+ others hand down a restriction (the sandbox posture, the permission plugins) and the hazard is a
126
+ child escaping it. Here the child is *more* restricted than its parent, so the failure is a missing
127
+ capability rather than an open door. Inheritance cannot widen: the child gets what the parent
128
+ already resolved and runs in the parent's cwd, so it reaches no directory the parent could not. A
129
+ role's explicit value still wins.
130
+
131
+ **The one hazard in the fix, since it is the kind that trades a bug for a worse bug:**
132
+ `buildChildCreateOptions` used to write `local` whole from the sandbox posture alone, so adding a
133
+ second `local` spread beside it would have silently dropped that posture — turning a
134
+ missing-capability defect into a default-open one. `local` is now accumulated once from all three
135
+ contributors, and a test asserts the sandbox posture survives inheritance.
136
+
137
+ Reported by the `theocode` session. Its measurement also narrowed who is affected: a consumer that
138
+ rebuilds agent options per invocation never reaches `serializeLocal` and is exposed only to the
139
+ delegation half.
140
+
141
+ - [#582](https://github.com/usetheokit/theokit-sdk/pull/582) [`95a2e9d`](https://github.com/usetheokit/theokit-sdk/commit/95a2e9de364df5a161671fa0c845e0b6a8208392) Thanks [@usetheodev](https://github.com/usetheodev)! - The built-in judges no longer hold a `shell` they never asked for ([#581](https://github.com/usetheokit/theokit-sdk/issues/581))
142
+
143
+ `internal/scorers/llm-judge.ts` and `internal/judge/judge-call.ts` each create a short-lived agent to
144
+ score or adjudicate. Neither wants a tool. One passed no `tools` at all; the other passed `tools: []`.
145
+
146
+ Neither is enough: **a `shell` tool is always registered on a local agent, including when `tools: []`
147
+ is passed.** Withholding is the only mechanism that removes it, and neither judge used it.
148
+
149
+ The scorer was the worse of the two, because it also carried `sandboxOptions: { enabled: false }` —
150
+ which reads like a restriction and is the opposite of one. It does not restrict the shell; it removes
151
+ the sandbox around it. So the scorer held an **unsandboxed** shell in `process.cwd()` while reading
152
+ content produced by the very thing it was evaluating. `types/agent.ts` § LocalOptions records the
153
+ case that already happened to somebody: the working directory held the benchmark's answer key, and
154
+ two transcripts show the model citing it.
155
+
156
+ Both now pass `withheldBuiltinTools: ["shell"]`. The scorer's `sandboxOptions` line is left as it
157
+ was: with no shell there is nothing for it to govern, and changing it would be a second, unrelated
158
+ decision.
159
+
160
+ Neither line had a recorded reason — `git log -S` puts both inside large feature commits whose
161
+ messages never mention the sandbox, the shell, or a tool surface. If either was deliberate, this
162
+ commit and [#581](https://github.com/usetheokit/theokit-sdk/issues/581) are the trail back.
163
+
164
+ - [#584](https://github.com/usetheokit/theokit-sdk/pull/584) [`69e8dda`](https://github.com/usetheokit/theokit-sdk/commit/69e8dda6be4489f462a031166bdc1f6f06cbe7ac) Thanks [@usetheodev](https://github.com/usetheodev)! - Snapshot versions now sort ABOVE the release they are cut from
165
+
166
+ `changeset version --snapshot` defaults to a `0.0.0-` base, so every snapshot this repository has
167
+ ever published was `0.0.0-<tag>-<timestamp>` — which **sorts below every real release**, because
168
+ semver compares `major.minor.patch` numerically before it looks at a prerelease suffix.
169
+
170
+ Any consumer with a version floor therefore read a snapshot as older than the release it was cut
171
+ from. Measured by the `theokit/agents` layer against `0.0.0-compat-580-20260905204608`, on every
172
+ run:
173
+
174
+ ```
175
+ `compatSources` was declared, but @theokit/sdk@0.0.0-compat-580-… does not know that option and
176
+ will ignore it — the foreign configuration root will NOT be read. It landed in 5.0.0.
177
+ ```
178
+
179
+ The code in that snapshot knew the option perfectly well. **The version number said it did not, so
180
+ the feature was switched off** — silently for anyone not reading stderr, and precisely the feature
181
+ the snapshot existed to deliver.
182
+
183
+ `snapshot.useCalculatedVersion: true` bases the snapshot on the version the pending changesets
184
+ would produce, so the same cut becomes `5.0.2-compat-580-…`: still a prerelease, still off `latest`,
185
+ still never resolved by a caret range — and now correctly ordered against the floor.
186
+
187
+ Reported by the `theocode` session, which caught it in the only way it was catchable: its first run
188
+ piped the output through `tail -3`, which cut the warning off, and the second kept the whole thing.
189
+
190
+ - [#576](https://github.com/usetheokit/theokit-sdk/pull/576) [`945e999`](https://github.com/usetheokit/theokit-sdk/commit/945e99906180bdd83d9d40845988907e22a08ec4) Thanks [@usetheodev](https://github.com/usetheodev)! - The undeclared-`.claude/` warning now names the file you can edit, not only the option your host passes
191
+
192
+ `5.0.1` made this warning reach stderr regardless of any diagnostics sink ([#563](https://github.com/usetheokit/theokit-sdk/issues/563)), which was the
193
+ right fix and created a smaller problem underneath it: the message told you to pass
194
+ `local: { compatSources: ["claude-code"] }`, and `local` is an argument **the code embedding this
195
+ SDK** passes. If you are using a tool built on the SDK rather than calling it yourself, that option
196
+ does not exist on your surface — so the line was true about the mechanism and unusable as an action.
197
+
198
+ Reported by the `theocode` session running `5.0.1` as an embedding host, and their framing is the
199
+ one worth keeping: *"correct about the mechanism and misleading about the action — it sends the
200
+ person looking for an option that is not on their surface."*
201
+
202
+ [#524](https://github.com/usetheokit/theokit-sdk/issues/524) gives the declaration **two entry points for one shape**, and the warning named only one:
203
+
204
+ | entry point | who can use it |
205
+ |---|---|
206
+ | `.theokit/config.json` → `{"compat":{"adapters":["claude-code"]}}` | anyone holding the workspace |
207
+ | `local: { compatSources: ["claude-code"] }` | whoever embeds the SDK in code |
208
+
209
+ The message now names the file first, because that is the entry point its reader can reach, and
210
+ keeps the code option for the embedder for whom it is the right answer. Nothing about the
211
+ behaviour changes — only what the line tells you to do.
212
+
213
+ ## Still open, and worth knowing
214
+
215
+ There is no way to say *"I know, and I want none"*. `compatSources: []` would be the natural
216
+ spelling, but `resolveCompatSources` collapses it into the same `[]` an absent option produces, so
217
+ the two cannot be told apart. `theocode` measured one warning per process, and a CLI invocation is
218
+ a process — so a shell loop prints one line per iteration. They explicitly did not ask for a change
219
+ on the volume; if it starts to matter, threading that distinction through is the shape of the fix.
220
+
221
+ - [#582](https://github.com/usetheokit/theokit-sdk/pull/582) [`1b088c4`](https://github.com/usetheokit/theokit-sdk/commit/1b088c4be2b895b7c442b00055fc34a6c9bf4eb4) Thanks [@usetheodev](https://github.com/usetheodev)! - A delegated child can no longer recover a builtin tool its parent withheld ([#580](https://github.com/usetheokit/theokit-sdk/issues/580))
222
+
223
+ **This is a security fix.** Measured before the change:
224
+
225
+ ```
226
+ parent: withheldBuiltinTools: ["shell"]
227
+ child: undefined
228
+ ```
229
+
230
+ `withheldBuiltinTools` crossed no carrier at all — not `InheritedCredentials`, not
231
+ `buildChildCreateOptions` — so delegation **widened** authority the operator had revoked. That is the
232
+ inverse of [#578](https://github.com/usetheokit/theokit-sdk/issues/578) and materially worse: there the child was merely over-restricted.
233
+
234
+ It bites because of a documented default: a `shell` tool is always registered on a local agent,
235
+ *including when you pass `tools: []`*. Withholding is the only mechanism that removes it, so a
236
+ withholding that does not survive delegation leaves a child no way to be without a shell. Nor is
237
+ `sandboxOptions` a substitute — `{ enabled: false }` does not restrict the shell, it removes the
238
+ sandbox around it.
239
+
240
+ Two changes:
241
+
242
+ - The parent's withheld set is carried to the child.
243
+ - `SubAgentSpec` accepts `withheldBuiltinTools`, so a role declared read-only can actually be one.
244
+
245
+ **The child's list is the UNION of its own and the parent's, never a replacement.** Every other field
246
+ on the spec lets the role's value win — `model`, and `sandbox` (an explicit `sandbox: false` really
247
+ does turn confinement off for a child of a confined parent, which is documented and intended). That
248
+ asymmetry is deliberate: a posture is declared, whereas withholding removes a capability from the
249
+ catalog, and the failure is silent. So `withheldBuiltinTools: []` on a role subtracts nothing — a
250
+ restriction may be tightened by a child and never loosened.
251
+
252
+ Verified with a negative control: 6 of the 7 new tests fail against the pre-fix sources, and the one
253
+ that passes is the control asserting unchanged behaviour.
254
+
255
+ **There is no known limit on reaching this field from a wrapping layer.** An earlier draft of this
256
+ entry claimed one — that a layer re-exporting `Agent` under a narrowed type could not pass it — and
257
+ that was wrong. Checked against the published declaration: such a narrowing is written as
258
+ `Omit<typeof Agent, 'list'> & { list(…) }`, which narrows only `list`, so `create` keeps this
259
+ package's signature and the field crosses with types and without a cast. The claim came from
260
+ searching a wrapper's `.d.ts` for the field NAME, which is absent there because the type composes by
261
+ reference rather than redeclaring it — the wrong artefact for the question.
262
+
263
+ It is corrected here rather than deleted because a false limit recorded upstream is worse than none:
264
+ a reader takes it as settled and stops trying.
265
+
266
+ Found by the `theocode` session, which discovered its own "read-only" role holding a `shell` by
267
+ enumerating the tool catalog — after two probes that asked the model instead, and got answers that
268
+ contradicted it.
269
+
3
270
  ## 5.0.1
4
271
 
5
272
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkQME6FDFG_cjs = require('../chunk-QME6FDFG.cjs');
3
+ var chunkNQTD6QOW_cjs = require('../chunk-NQTD6QOW.cjs');
4
4
  require('../chunk-NINIJCHU.cjs');
5
5
  var chunkJ7J7J2GN_cjs = require('../chunk-J7J7J2GN.cjs');
6
6
  var chunk6LHQPOMI_cjs = require('../chunk-6LHQPOMI.cjs');
@@ -124,11 +124,11 @@ var MessageBus = class {
124
124
 
125
125
  Object.defineProperty(exports, "MaxDelegationDepthError", {
126
126
  enumerable: true,
127
- get: function () { return chunkQME6FDFG_cjs.MaxDelegationDepthError; }
127
+ get: function () { return chunkNQTD6QOW_cjs.MaxDelegationDepthError; }
128
128
  });
129
129
  Object.defineProperty(exports, "SubAgent", {
130
130
  enumerable: true,
131
- get: function () { return chunkQME6FDFG_cjs.SubAgent; }
131
+ get: function () { return chunkNQTD6QOW_cjs.SubAgent; }
132
132
  });
133
133
  exports.A2APeerNotRegisteredError = A2APeerNotRegisteredError;
134
134
  exports.A2ARequestTimeoutError = A2ARequestTimeoutError;
package/dist/a2a/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { MaxDelegationDepthError, SubAgent } from '../chunk-6WAKKTBO.js';
1
+ export { MaxDelegationDepthError, SubAgent } from '../chunk-CFE6QF2Q.js';
2
2
  import '../chunk-6X6ID4MO.js';
3
3
  import { TheokitAgentError } from '../chunk-ALUN2B4W.js';
4
4
  import { diag } from '../chunk-CZJ6Q7CW.js';
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import { TheokitAgentError } from "../errors.js";
18
18
  import { type InheritedCredentials } from "../internal/concurrency/subagent-credentials.js";
19
- import type { AgentOptions, CustomTool, ToolContextMessage } from "../types/agent.js";
19
+ import type { AgentOptions, BuiltinToolName, CustomTool, ToolContextMessage } from "../types/agent.js";
20
20
  import type { ModelSelection } from "../types/agent-prims.js";
21
21
  /** Arguments passed to {@link SubAgentSpec.messageFilter} (SE12). */
22
22
  export interface MessageFilterArgs {
@@ -128,6 +128,24 @@ export interface SubAgentSpec {
128
128
  tools?: CustomTool[];
129
129
  /** Per-subagent shell sandbox toggle (M33). `true` ⇒ child `local.sandboxOptions.enabled`. */
130
130
  sandbox?: boolean;
131
+ /**
132
+ * #580 — builtin tools this role removes from its child's catalog, UNIONED with whatever the
133
+ * parent already withheld.
134
+ *
135
+ * A role declared read-only in prose is not read-only: a `shell` tool is always registered on a
136
+ * local agent, including when `tools: []` is passed, so withholding is the only mechanism that
137
+ * removes it — and until #580 a spec could not ask for it and a parent's withholding did not
138
+ * survive delegation either.
139
+ *
140
+ * ## Union, not override — and this is the one field here that works that way
141
+ *
142
+ * `model` and `sandbox` let the role's own value WIN, including `sandbox: false` turning
143
+ * confinement off for a child of a confined parent. That asymmetry is deliberate: a posture is
144
+ * declared, whereas withholding removes a capability from the catalog. Letting a role override a
145
+ * withholding would let a child recover a tool its parent revoked, which is the defect #580
146
+ * reports — so a child may only ever ADD to the set.
147
+ */
148
+ withheldBuiltinTools?: readonly BuiltinToolName[];
131
149
  /**
132
150
  * Maximum length of the delegation CHAIN rooted at this tool, counted at dispatch
133
151
  * (default 3). Depth 1 is this subagent; a subagent it delegates to is depth 2.
@@ -197,8 +215,9 @@ export declare class MaxDelegationDepthError extends TheokitAgentError {
197
215
  /**
198
216
  * Build the child agent's `Agent.create` options: the child inherits the parent's
199
217
  * apiKey (else `Agent.create` throws "Missing API key"), its model (unless the spec
200
- * overrides it), and — #55 — the parent's plugins (permission gate/guards) so the
201
- * child's inner tool calls run under the same policy.
218
+ * overrides it), — #55 — the parent's plugins (permission gate/guards) so the
219
+ * child's inner tool calls run under the same policy, and — #578 — the configuration
220
+ * surfaces the parent was declared to read (see {@link buildChildLocalOptions}).
202
221
  */
203
222
  export declare function buildChildCreateOptions(spec: SubAgentSpec, inherited: InheritedCredentials | undefined): AgentOptions;
204
223
  /** SE36 — `SubAgent.create` replaces `defineSubAgent` (ADR 0015). @public *
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import { TheokitAgentError } from "../errors.js";
18
18
  import { type InheritedCredentials } from "../internal/concurrency/subagent-credentials.js";
19
- import type { AgentOptions, CustomTool, ToolContextMessage } from "../types/agent.js";
19
+ import type { AgentOptions, BuiltinToolName, CustomTool, ToolContextMessage } from "../types/agent.js";
20
20
  import type { ModelSelection } from "../types/agent-prims.js";
21
21
  /** Arguments passed to {@link SubAgentSpec.messageFilter} (SE12). */
22
22
  export interface MessageFilterArgs {
@@ -128,6 +128,24 @@ export interface SubAgentSpec {
128
128
  tools?: CustomTool[];
129
129
  /** Per-subagent shell sandbox toggle (M33). `true` ⇒ child `local.sandboxOptions.enabled`. */
130
130
  sandbox?: boolean;
131
+ /**
132
+ * #580 — builtin tools this role removes from its child's catalog, UNIONED with whatever the
133
+ * parent already withheld.
134
+ *
135
+ * A role declared read-only in prose is not read-only: a `shell` tool is always registered on a
136
+ * local agent, including when `tools: []` is passed, so withholding is the only mechanism that
137
+ * removes it — and until #580 a spec could not ask for it and a parent's withholding did not
138
+ * survive delegation either.
139
+ *
140
+ * ## Union, not override — and this is the one field here that works that way
141
+ *
142
+ * `model` and `sandbox` let the role's own value WIN, including `sandbox: false` turning
143
+ * confinement off for a child of a confined parent. That asymmetry is deliberate: a posture is
144
+ * declared, whereas withholding removes a capability from the catalog. Letting a role override a
145
+ * withholding would let a child recover a tool its parent revoked, which is the defect #580
146
+ * reports — so a child may only ever ADD to the set.
147
+ */
148
+ withheldBuiltinTools?: readonly BuiltinToolName[];
131
149
  /**
132
150
  * Maximum length of the delegation CHAIN rooted at this tool, counted at dispatch
133
151
  * (default 3). Depth 1 is this subagent; a subagent it delegates to is depth 2.
@@ -197,8 +215,9 @@ export declare class MaxDelegationDepthError extends TheokitAgentError {
197
215
  /**
198
216
  * Build the child agent's `Agent.create` options: the child inherits the parent's
199
217
  * apiKey (else `Agent.create` throws "Missing API key"), its model (unless the spec
200
- * overrides it), and — #55 — the parent's plugins (permission gate/guards) so the
201
- * child's inner tool calls run under the same policy.
218
+ * overrides it), — #55 — the parent's plugins (permission gate/guards) so the
219
+ * child's inner tool calls run under the same policy, and — #578 — the configuration
220
+ * surfaces the parent was declared to read (see {@link buildChildLocalOptions}).
202
221
  */
203
222
  export declare function buildChildCreateOptions(spec: SubAgentSpec, inherited: InheritedCredentials | undefined): AgentOptions;
204
223
  /** SE36 — `SubAgent.create` replaces `defineSubAgent` (ADR 0015). @public *
@@ -1,11 +1,11 @@
1
1
  'use strict';
2
2
 
3
- var chunkCQLVA4CO_cjs = require('./chunk-CQLVA4CO.cjs');
3
+ var chunkD3CCY3A2_cjs = require('./chunk-D3CCY3A2.cjs');
4
4
  require('./chunk-KVSAY6NZ.cjs');
5
5
  require('./chunk-Y2KYR2ED.cjs');
6
6
  require('./chunk-BUUUWQMB.cjs');
7
7
  require('./chunk-Z2JFX372.cjs');
8
- require('./chunk-LTLPBGHC.cjs');
8
+ require('./chunk-KGANQYP7.cjs');
9
9
  require('./chunk-BV2MWEMV.cjs');
10
10
  require('./chunk-D6POWE7E.cjs');
11
11
  require('./chunk-GHX4P3V2.cjs');
@@ -26,9 +26,9 @@ require('./chunk-MUUQ2WFJ.cjs');
26
26
  require('./chunk-AA27GEYS.cjs');
27
27
  require('./chunk-YSTXFWQE.cjs');
28
28
  require('./chunk-FRITRLZQ.cjs');
29
- require('./chunk-QME6FDFG.cjs');
29
+ require('./chunk-NQTD6QOW.cjs');
30
30
  require('./chunk-NINIJCHU.cjs');
31
- require('./chunk-UGRS7ZA7.cjs');
31
+ require('./chunk-QATRS7JD.cjs');
32
32
  require('./chunk-LOHMT36V.cjs');
33
33
  require('./chunk-IJ7M6GOG.cjs');
34
34
  require('./chunk-7A6535RA.cjs');
@@ -43,8 +43,8 @@ require('./chunk-BJUJT5ED.cjs');
43
43
  require('./chunk-ZF2LDKQQ.cjs');
44
44
  require('./chunk-HCT4HPCL.cjs');
45
45
  require('./chunk-JLRLCBJ4.cjs');
46
- require('./chunk-5AXMNUCY.cjs');
47
- require('./chunk-DLRP7BI6.cjs');
46
+ require('./chunk-QYLZQ43D.cjs');
47
+ require('./chunk-NYQ3IS7K.cjs');
48
48
  require('./chunk-HW7SEELD.cjs');
49
49
  require('./chunk-ATT276RD.cjs');
50
50
  require('./chunk-3EE6LVWT.cjs');
@@ -61,7 +61,7 @@ require('./chunk-6LHQPOMI.cjs');
61
61
 
62
62
  Object.defineProperty(exports, "Agent", {
63
63
  enumerable: true,
64
- get: function () { return chunkCQLVA4CO_cjs.Agent; }
64
+ get: function () { return chunkD3CCY3A2_cjs.Agent; }
65
65
  });
66
- //# sourceMappingURL=agent-TKJBWGGQ.cjs.map
67
- //# sourceMappingURL=agent-TKJBWGGQ.cjs.map
66
+ //# sourceMappingURL=agent-ARLOD4JX.cjs.map
67
+ //# sourceMappingURL=agent-ARLOD4JX.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"agent-TKJBWGGQ.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"agent-ARLOD4JX.cjs"}
@@ -1,9 +1,9 @@
1
- export { Agent } from './chunk-SVWMQCXF.js';
1
+ export { Agent } from './chunk-OYD3U3LY.js';
2
2
  import './chunk-K2VMFZQ5.js';
3
3
  import './chunk-AWINL3ZC.js';
4
4
  import './chunk-K2BQQ445.js';
5
5
  import './chunk-7SZAV6QG.js';
6
- import './chunk-D7WAROJR.js';
6
+ import './chunk-AW6F6HZR.js';
7
7
  import './chunk-2SFBB54R.js';
8
8
  import './chunk-55GB6JYQ.js';
9
9
  import './chunk-H73MEMQB.js';
@@ -24,9 +24,9 @@ import './chunk-FD2UT76F.js';
24
24
  import './chunk-7I5Z3UBJ.js';
25
25
  import './chunk-FJWQP6EE.js';
26
26
  import './chunk-NAF4L3T6.js';
27
- import './chunk-6WAKKTBO.js';
27
+ import './chunk-CFE6QF2Q.js';
28
28
  import './chunk-6X6ID4MO.js';
29
- import './chunk-XDANGA2C.js';
29
+ import './chunk-LX7SEXOQ.js';
30
30
  import './chunk-2XRAWOZZ.js';
31
31
  import './chunk-SAGRF4IB.js';
32
32
  import './chunk-EH6XD3FY.js';
@@ -41,8 +41,8 @@ import './chunk-TA3K7SBK.js';
41
41
  import './chunk-Q5EWJPRY.js';
42
42
  import './chunk-EIQFAOFD.js';
43
43
  import './chunk-3JHIFQ4I.js';
44
- import './chunk-7RHC7HMS.js';
45
- import './chunk-GUKPXDGJ.js';
44
+ import './chunk-OQRGVTQF.js';
45
+ import './chunk-WMWEI3NS.js';
46
46
  import './chunk-JNAA4G4H.js';
47
47
  import './chunk-6M2OIS4Y.js';
48
48
  import './chunk-R7WIIPUR.js';
@@ -54,5 +54,5 @@ import './chunk-V22DZIXO.js';
54
54
  import './chunk-NJWYQWDL.js';
55
55
  import './chunk-ALUN2B4W.js';
56
56
  import './chunk-CZJ6Q7CW.js';
57
- //# sourceMappingURL=agent-UGYIYC3R.js.map
58
- //# sourceMappingURL=agent-UGYIYC3R.js.map
57
+ //# sourceMappingURL=agent-N6WJ54ML.js.map
58
+ //# sourceMappingURL=agent-N6WJ54ML.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"agent-UGYIYC3R.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"agent-N6WJ54ML.js"}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkCQLVA4CO_cjs = require('./chunk-CQLVA4CO.cjs');
3
+ var chunkD3CCY3A2_cjs = require('./chunk-D3CCY3A2.cjs');
4
4
  var chunkKVSAY6NZ_cjs = require('./chunk-KVSAY6NZ.cjs');
5
5
  var chunkNINIJCHU_cjs = require('./chunk-NINIJCHU.cjs');
6
6
  var chunkJ7J7J2GN_cjs = require('./chunk-J7J7J2GN.cjs');
@@ -376,7 +376,7 @@ async function createCronJob(options) {
376
376
  const now = Date.now();
377
377
  const nextFireAt = nextRunAt(options.cron, timezone);
378
378
  const job = {
379
- id: chunkCQLVA4CO_cjs.generateCronId(),
379
+ id: chunkD3CCY3A2_cjs.generateCronId(),
380
380
  cron: options.cron,
381
381
  timezone,
382
382
  enabled: options.enabled ?? true,
@@ -453,5 +453,5 @@ async function updateJobStatus(jobId, enabled) {
453
453
  }
454
454
 
455
455
  exports.Cron = Cron2;
456
- //# sourceMappingURL=chunk-CC7EYKBJ.cjs.map
457
- //# sourceMappingURL=chunk-CC7EYKBJ.cjs.map
456
+ //# sourceMappingURL=chunk-67SBTGMA.cjs.map
457
+ //# sourceMappingURL=chunk-67SBTGMA.cjs.map