@theokit/sdk 5.0.0-next.1 → 5.0.0-next.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.
- package/CHANGELOG.md +162 -0
- package/dist/{agent-CgNzshyV.d.cts → agent-C3KO5LKm.d.cts} +49 -3
- package/dist/{agent-CdYJfKr6.d.ts → agent-CvmTR9uf.d.ts} +49 -3
- package/dist/{agent-2E7DI47Y.cjs → agent-GPV2JWZG.cjs} +7 -7
- package/dist/{agent-2E7DI47Y.cjs.map → agent-GPV2JWZG.cjs.map} +1 -1
- package/dist/{agent-XMKRP27S.js → agent-Y24I5JBM.js} +6 -6
- package/dist/{agent-XMKRP27S.js.map → agent-Y24I5JBM.js.map} +1 -1
- package/dist/{chunk-XCCGNU3D.js → chunk-4S5TWFIZ.js} +5 -5
- package/dist/chunk-4S5TWFIZ.js.map +1 -0
- package/dist/{chunk-JTZ74HFD.js → chunk-67ADYSTW.js} +29 -9
- package/dist/chunk-67ADYSTW.js.map +1 -0
- package/dist/{chunk-CEILSTWB.cjs → chunk-GGZ5GPE3.cjs} +29 -8
- package/dist/chunk-GGZ5GPE3.cjs.map +1 -0
- package/dist/{chunk-HWSALKOR.cjs → chunk-H6YM3PV6.cjs} +5 -5
- package/dist/chunk-H6YM3PV6.cjs.map +1 -0
- package/dist/{chunk-NCGWJ3HS.js → chunk-KDR53EO7.js} +71 -32
- package/dist/chunk-KDR53EO7.js.map +1 -0
- package/dist/{chunk-WMH2MSOP.cjs → chunk-QUAEOKDW.cjs} +95 -56
- package/dist/chunk-QUAEOKDW.cjs.map +1 -0
- package/dist/{chunk-G4ZGYKJG.cjs → chunk-SYVWE64W.cjs} +6 -6
- package/dist/chunk-SYVWE64W.cjs.map +1 -0
- package/dist/{chunk-7ZK4DJD7.cjs → chunk-VXDEKILY.cjs} +4 -4
- package/dist/{chunk-7ZK4DJD7.cjs.map → chunk-VXDEKILY.cjs.map} +1 -1
- package/dist/{chunk-IJM7UGS5.js → chunk-XJZEBGXD.js} +5 -5
- package/dist/chunk-XJZEBGXD.js.map +1 -0
- package/dist/{chunk-6HIACV34.js → chunk-ZH26RNQA.js} +3 -3
- package/dist/{chunk-6HIACV34.js.map → chunk-ZH26RNQA.js.map} +1 -1
- package/dist/{context-74SBFD27.cjs → context-NI33FS2R.cjs} +7 -7
- package/dist/{context-74SBFD27.cjs.map → context-NI33FS2R.cjs.map} +1 -1
- package/dist/context-Y7B7SI5X.js +6 -0
- package/dist/{context-NZ2AC6S7.js.map → context-Y7B7SI5X.js.map} +1 -1
- package/dist/{cron-Bw6mSgD4.d.cts → cron-C3PhZED0.d.cts} +1 -1
- package/dist/{cron-DJv9oXSZ.d.ts → cron-crfMMdAw.d.ts} +1 -1
- package/dist/cron.cjs +6 -6
- package/dist/cron.d.cts +3 -3
- package/dist/cron.d.ts +3 -3
- package/dist/cron.js +5 -5
- package/dist/eval.cjs +5 -5
- package/dist/eval.js +4 -4
- package/dist/index.cjs +20 -20
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +7 -7
- package/dist/internal/persistence/index.cjs +4 -4
- package/dist/internal/persistence/index.js +1 -1
- package/dist/internal/persistence/paths.d.cts +25 -12
- package/dist/internal/persistence/paths.d.ts +25 -12
- package/dist/internal/runtime/compat/compat-config-file.d.ts +31 -0
- package/dist/internal/runtime/compat/foreign-config-sources.d.ts +31 -1
- package/dist/internal/runtime/hooks/hooks-executor.d.ts +2 -1
- package/dist/internal/runtime/plugin-loader/plugin-bundles.d.ts +2 -1
- package/dist/{sdk-agent-Dxjb0IfM.d.cts → sdk-agent-BOiKqOgL.d.cts} +28 -1
- package/dist/{sdk-agent-ldzpyAaF.d.ts → sdk-agent-D4a_BR_6.d.ts} +28 -1
- package/dist/subagents-loader-TPZLTXYZ.cjs +16 -0
- package/dist/{subagents-loader-YWFE7KYE.cjs.map → subagents-loader-TPZLTXYZ.cjs.map} +1 -1
- package/dist/subagents-loader-Y6JFYXAY.js +7 -0
- package/dist/{subagents-loader-LSKM2UIK.js.map → subagents-loader-Y6JFYXAY.js.map} +1 -1
- package/dist/subagents-loader.cjs +3 -3
- package/dist/subagents-loader.d.cts +2 -2
- package/dist/subagents-loader.d.ts +2 -2
- package/dist/subagents-loader.js +2 -2
- package/dist/types/agent.d.ts +47 -1
- package/dist/types/sdk-agent.d.ts +28 -1
- package/dist/workflow.d.cts +1 -1
- package/dist/workflow.d.ts +1 -1
- package/docs/error-codes.md +21 -21
- package/docs/harness-capability-map.md +3 -1
- package/package.json +1 -1
- package/dist/chunk-CEILSTWB.cjs.map +0 -1
- package/dist/chunk-G4ZGYKJG.cjs.map +0 -1
- package/dist/chunk-HWSALKOR.cjs.map +0 -1
- package/dist/chunk-IJM7UGS5.js.map +0 -1
- package/dist/chunk-JTZ74HFD.js.map +0 -1
- package/dist/chunk-NCGWJ3HS.js.map +0 -1
- package/dist/chunk-WMH2MSOP.cjs.map +0 -1
- package/dist/chunk-XCCGNU3D.js.map +0 -1
- package/dist/context-NZ2AC6S7.js +0 -6
- package/dist/subagents-loader-LSKM2UIK.js +0 -7
- package/dist/subagents-loader-YWFE7KYE.cjs +0 -16
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,167 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.0.0-next.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 88e87d0: A foreign configuration source can now be admitted to some surfaces and not others.
|
|
8
|
+
|
|
9
|
+
`compatSources: ["claude-code"]` was all-or-nothing: declaring it admitted `.claude/` to hooks,
|
|
10
|
+
plugins, skills AND subagents at once. The four carry very different risk — a skill is text that
|
|
11
|
+
enters the system prompt, a plugin is code loading, a hook is command execution — so a consumer who
|
|
12
|
+
wanted to reuse the skills they had already written was handed arbitrary command execution along
|
|
13
|
+
with them, and had no way to say otherwise.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
local: {
|
|
17
|
+
compatSources: [{ kind: "claude-code", import: ["skills", "subagents"] }],
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Hooks and plugins then resolve `.theokit/` alone. `CompatSurface` and `CompatSourceAdapter` are
|
|
22
|
+
exported.
|
|
23
|
+
|
|
24
|
+
Three rules, each failing closed:
|
|
25
|
+
|
|
26
|
+
- **The bare `"claude-code"` string still admits every surface.** It is what `5.0.0-next.1`
|
|
27
|
+
published, and narrowing it silently would turn a working opt-in into a no-op that says nothing —
|
|
28
|
+
the defect this option exists to fix, one level up.
|
|
29
|
+
- **An adapter with no `import` list admits nothing.** Safe to apply strictly because the object
|
|
30
|
+
form is new and nobody can be relying on it yet.
|
|
31
|
+
- **An unrecognised surface name is dropped**, exactly as an unrecognised `kind` already is. A typo
|
|
32
|
+
must narrow access, never widen it.
|
|
33
|
+
|
|
34
|
+
The `plugins` surface governs reading a foreign plugin directory even when the caller wants the
|
|
35
|
+
SKILLS a bundle carries: a bundle is code, and its skills arrive attached to it, so admitting
|
|
36
|
+
`skills` alone must not reach inside one. Otherwise the narrower permission would silently grant
|
|
37
|
+
the wider one.
|
|
38
|
+
|
|
39
|
+
Closes the per-surface half of usetheokit/theokit-sdk#524. The visibility half — skills, subagents
|
|
40
|
+
and plugins carrying the root they came from, the way hooks already carry `sourcePath` — and the
|
|
41
|
+
declarative `.theokit/config.toml` form are not in this change.
|
|
42
|
+
- 33aa170: A project can now declare its foreign compat sources in `.theokit/config.json`, instead of only in
|
|
43
|
+
code.
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"compat": {
|
|
48
|
+
"adapters": [{ "kind": "claude-code", "import": ["skills", "subagents"] }]
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The DECLARATIVE half usetheokit/theokit-sdk#524 asked for, in a `## Sketch` written against TOML.
|
|
54
|
+
It ships as JSON: this SDK already reads JSON everywhere a project declares something
|
|
55
|
+
(`settings.json`, `mcp.json`, `context.json`) and carries no TOML parser or dependency for one —
|
|
56
|
+
adding one for a single optional section would be the opposite of what #522/#524 are about, reading
|
|
57
|
+
in a new format nobody asked this SDK to speak. The shape is unchanged: `compat.adapters` accepts
|
|
58
|
+
exactly what `local.compatSources` already does in code — a bare kind string, or `{ kind, import }`.
|
|
59
|
+
|
|
60
|
+
**Precedence, decided here because the issue does not state it:** explicit `local.compatSources` in
|
|
61
|
+
code wins over the file. The file is the default for a caller who declared nothing. A test or a
|
|
62
|
+
one-off script can therefore always override the file without editing or deleting it.
|
|
63
|
+
|
|
64
|
+
Read with `readFileSync`, not this package's usual async reader: the caller is `Agent`'s
|
|
65
|
+
synchronous constructor, which resolves `compatSources` before any submanager exists to await a
|
|
66
|
+
promise. `existsSync` already runs in the same constructor for the same reason.
|
|
67
|
+
|
|
68
|
+
One resolver, `resolveCompatSources(options, cwd)`, replaces five call sites that each wrote
|
|
69
|
+
`options.local?.compatSources ?? []` by hand — the same duplication `theokitConfigRoot` closed one
|
|
70
|
+
layer down, closed here one layer up, so the file form reaches all four surfaces (hooks, skills,
|
|
71
|
+
plugins, subagents) through the one place rather than needing five separate edits that could drift.
|
|
72
|
+
|
|
73
|
+
Closes the declarative half of #524. `#524` itself stays open until it is verified in an installed
|
|
74
|
+
release, per this project's issue-lifecycle convention.
|
|
75
|
+
- e7cf2dd: A skill, subagent or plugin now says which directory it was read from.
|
|
76
|
+
|
|
77
|
+
usetheokit/theokit-sdk#524 asks for it in one line — *"whatever is imported should be reportable […]
|
|
78
|
+
silent inheritance is what made this take a debugging session to notice"* — and a consumer listing
|
|
79
|
+
its own skills could not tell that one had arrived from `.claude/skills/` rather than the project's
|
|
80
|
+
own directory.
|
|
81
|
+
|
|
82
|
+
What is new is not the data. It existed on all three and did not reach the caller:
|
|
83
|
+
|
|
84
|
+
- `Skill.source` was already the absolute path to the `SKILL.md`, and the projection that builds
|
|
85
|
+
`agent.skills` mapped it away along with the body. The projection is right to drop the BODY —
|
|
86
|
+
that is what `get()` is for — and dropping the PATH with it answered a question nobody asked.
|
|
87
|
+
- `agent.plugins.list()` has always returned `source` at runtime; the internal type's own docblock
|
|
88
|
+
says it carries provenance "so callers can audit where the plugin came from". `SDKPluginMetadata`
|
|
89
|
+
simply never declared it, so the caller received the field and the compiler denied it existed.
|
|
90
|
+
- `readSubagentsFrom` computes the file path on the line it reads the file, then dropped it.
|
|
91
|
+
`AgentDefinition.source` keeps it.
|
|
92
|
+
|
|
93
|
+
`source` is optional on all three, and absence means something specific: declared in code, not read
|
|
94
|
+
from disk. A subagent passed through `AgentOptions.subagents` has no file and `source` is absent.
|
|
95
|
+
An inline `createSkill` skill has no file either, but already carried the synthetic `inline://<name>`
|
|
96
|
+
marker before this change (`create-skill.ts`) — so a skill's `source` is now populated for every
|
|
97
|
+
entry `list()` returns, either a disk path or that marker, and a first version of this fix wrongly
|
|
98
|
+
described it as absent for that case. An existing regression test (`agent-skills-get.test.ts`,
|
|
99
|
+
SE21) asserted `list()` must NOT carry `source` at all; it predates #524 and is updated here to
|
|
100
|
+
assert the marker instead, while still proving the skill's body and references never leak.
|
|
101
|
+
|
|
102
|
+
`SkillsHandle.list` is now typed as the public `SystemPromptSkillRef` instead of restating
|
|
103
|
+
`{ name; description }` inline. The two had drifted, and an internal handle declaring a narrower
|
|
104
|
+
shape than the contract it serves silently deletes fields the projection produces — which is exactly
|
|
105
|
+
how `source` reached the caller at runtime while not existing to the compiler.
|
|
106
|
+
|
|
107
|
+
Closes the visibility half of #524. The declarative `.theokit/config.toml` form is not in this
|
|
108
|
+
change.
|
|
109
|
+
|
|
110
|
+
### Patch Changes
|
|
111
|
+
|
|
112
|
+
- 070ee92: A foreign plugin's entry file is now checked against the root it was actually discovered under.
|
|
113
|
+
|
|
114
|
+
`refresh()` iterates every root a compat source admits — `.theokit/plugins`, and `.claude/plugins`
|
|
115
|
+
once `compatSources` names the `plugins` surface — and checks each plugin's declared `entry` file
|
|
116
|
+
exists. That check reconstructed the plugin's directory as `.theokit/plugins/<folder>`
|
|
117
|
+
unconditionally, regardless of which root the plugin was actually found under.
|
|
118
|
+
|
|
119
|
+
A plugin discovered at `.claude/plugins/my-plugin/` was therefore checked against
|
|
120
|
+
`.theokit/plugins/my-plugin/` — a directory it never lived in. With nothing there, a legitimate
|
|
121
|
+
foreign plugin was refused as "entry file is missing." Had a same-named folder existed under
|
|
122
|
+
`.theokit/plugins/` instead, its entry file would have been read in place of the real one — a path
|
|
123
|
+
confusion the ADR D79-D80 traversal guard this check calls does not catch, because the guard runs
|
|
124
|
+
against the wrong root rather than against none.
|
|
125
|
+
|
|
126
|
+
This was reachable through the bare `compatSources: ["claude-code"]` form, which has always admitted
|
|
127
|
+
the `plugins` surface — not something the per-surface work landing alongside this introduced.
|
|
128
|
+
|
|
129
|
+
Found while testing the per-surface admission work for usetheokit/theokit-sdk#524.
|
|
130
|
+
- 131ab8b: A foreign plugin's `source` field is now a real relative path instead of a single character.
|
|
131
|
+
|
|
132
|
+
Both manifest loaders (Claude Code's `.claude-plugin/plugin.json` form and this SDK's own
|
|
133
|
+
`PLUGIN.md`/`plugin.json`) built `source` by searching the manifest path for the literal substring
|
|
134
|
+
`.theokit/` and slicing from there. A manifest read from `.claude/plugins/<name>/…` contains no such
|
|
135
|
+
substring: `indexOf` returns `-1`, and `.slice(-1)` silently returned the manifest path's LAST
|
|
136
|
+
CHARACTER — `"n"` from `.json`, `"d"` from `PLUGIN.md` — instead of a path.
|
|
137
|
+
|
|
138
|
+
`source` is exactly the audit trail the visibility half of usetheokit/theokit-sdk#524 exists to
|
|
139
|
+
provide, and this was broken for precisely the case that matters most: a plugin admitted from a
|
|
140
|
+
foreign root. Replaced the substring search with `path.relative(cwd, manifestPath)` — the stdlib
|
|
141
|
+
does this correctly, and it is what the substring search was trying to approximate.
|
|
142
|
+
|
|
143
|
+
Found alongside the entry-file root confusion, testing the same per-surface admission work.
|
|
144
|
+
- 7b4063b: One resolver now answers "where does this project's configuration live?" — `theokitConfigRoot(cwd)`,
|
|
145
|
+
in `internal/persistence/paths.ts`, semver-exempt.
|
|
146
|
+
|
|
147
|
+
Five readers hand-rolled `join(cwd, ".theokit", ...)` independently: `mcp.json`, the context
|
|
148
|
+
directory + `context.json`, the hooks-root fallback check, `registry.json`, and the personality
|
|
149
|
+
`PROJECT_SUBDIR`. `projectConfigRoots` (hooks/skills/subagents/plugins, per usetheokit/theokit-sdk#524)
|
|
150
|
+
already resolved its native root the same way, inline, making six independent copies of one
|
|
151
|
+
constant.
|
|
152
|
+
|
|
153
|
+
No filename, format or resulting path changes — this is a pure consolidation, and the project's own
|
|
154
|
+
lint gate (`no-hardcoded-theokit-path.test.ts`, ratcheted 23 → 14) is the proof: every literal this
|
|
155
|
+
change removed was already flagged as migration debt, and the full suite is unchanged.
|
|
156
|
+
|
|
157
|
+
Deliberately does NOT touch homedir-anchored state (sessions, credentials, the personality
|
|
158
|
+
`USER_SUBDIR`, provider discovery) — those follow `getTheokitHome`/`THEOKIT_HOME` by design, and
|
|
159
|
+
folding them into this resolver would be the exact silent behaviour change
|
|
160
|
+
`theokitConfigRoot`'s own docblock warns against: a project's committed configuration must never
|
|
161
|
+
follow an operator's relocated state directory. A regression test pins this — swapping the
|
|
162
|
+
resolver's body for `getTheokitHome`'s would move all six readers under `THEOKIT_HOME` at once, in
|
|
163
|
+
one line, with no caller-side signal.
|
|
164
|
+
|
|
3
165
|
## 5.0.0-next.1
|
|
4
166
|
|
|
5
167
|
### Major Changes
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as MemoryFact, k as MemoryAdapter, m as MemoryContext, E as SystemPromptSkillRef, C as ContextSettings, P as ProviderRoutingSettings, a as PluginsSettings, S as SDKAgent } from './sdk-agent-
|
|
1
|
+
import { n as MemoryFact, k as MemoryAdapter, m as MemoryContext, E as SystemPromptSkillRef, C as ContextSettings, P as ProviderRoutingSettings, a as PluginsSettings, S as SDKAgent } from './sdk-agent-BOiKqOgL.cjs';
|
|
2
2
|
import { M as ModelSelection, C as CustomTool, c as PermissionMode, a as McpServerConfig, P as Processor } from './run-CTAdRU3U.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -952,7 +952,39 @@ type SettingSource = "project" | "user" | "team" | "mdm" | "plugins" | "all";
|
|
|
952
952
|
*
|
|
953
953
|
* @public
|
|
954
954
|
*/
|
|
955
|
-
type CompatSource = "claude-code";
|
|
955
|
+
type CompatSource = "claude-code" | CompatSourceAdapter;
|
|
956
|
+
/**
|
|
957
|
+
* A surface a foreign configuration source may be admitted to.
|
|
958
|
+
*
|
|
959
|
+
* They are named separately because they carry very different risk. A skill is TEXT that enters the
|
|
960
|
+
* system prompt; a subagent is a definition; a plugin is CODE LOADING; a hook is COMMAND EXECUTION.
|
|
961
|
+
* Reusing the skills you already wrote for another product is a reasonable thing to want, and it is
|
|
962
|
+
* not a reason to hand that product's directory the right to run commands.
|
|
963
|
+
*
|
|
964
|
+
* @public
|
|
965
|
+
*/
|
|
966
|
+
type CompatSurface = "hooks" | "plugins" | "skills" | "subagents";
|
|
967
|
+
/**
|
|
968
|
+
* A foreign source admitted to named surfaces only.
|
|
969
|
+
*
|
|
970
|
+
* ```ts
|
|
971
|
+
* local: { compatSources: [{ kind: "claude-code", import: ["skills", "subagents"] }] }
|
|
972
|
+
* ```
|
|
973
|
+
*
|
|
974
|
+
* `import` is not optional in spirit even though it is in the type: an adapter that omits it
|
|
975
|
+
* imports NOTHING. That is deliberate and it is the fail-closed rule this whole option exists to
|
|
976
|
+
* serve — a typo in a surface name must narrow access, never widen it.
|
|
977
|
+
*
|
|
978
|
+
* The bare `"claude-code"` string keeps meaning every surface. It is what `5.0.0-next.1` published,
|
|
979
|
+
* and silently narrowing it would turn a working opt-in into a no-op that says nothing — which is
|
|
980
|
+
* the defect usetheokit/theokit-sdk#524 reports, one level up.
|
|
981
|
+
*
|
|
982
|
+
* @public
|
|
983
|
+
*/
|
|
984
|
+
interface CompatSourceAdapter {
|
|
985
|
+
readonly kind: "claude-code";
|
|
986
|
+
readonly import?: readonly CompatSurface[];
|
|
987
|
+
}
|
|
956
988
|
/**
|
|
957
989
|
* A tool the SDK declares to the model on its own initiative — not one the consumer passed in
|
|
958
990
|
* {@link AgentOptions.tools}, and not one an MCP server exposed.
|
|
@@ -1098,6 +1130,20 @@ interface CloudOptions {
|
|
|
1098
1130
|
interface AgentDefinition {
|
|
1099
1131
|
description: string;
|
|
1100
1132
|
prompt: string;
|
|
1133
|
+
/**
|
|
1134
|
+
* Absolute path to the `.md` this subagent was read from, when it came from disk.
|
|
1135
|
+
*
|
|
1136
|
+
* ABSENT for a subagent declared in code through {@link AgentOptions.subagents} — "you passed
|
|
1137
|
+
* this one in" is a different fact from "read from disk", and one value for both would trade one
|
|
1138
|
+
* silence for another.
|
|
1139
|
+
*
|
|
1140
|
+
* It exists so a listing can answer which root a subagent came from, which
|
|
1141
|
+
* usetheokit/theokit-sdk#524 asks for by name: a consumer could not tell that an agent arrived
|
|
1142
|
+
* from `.claude/agents/` rather than its own directory, and silent inheritance is what made that
|
|
1143
|
+
* take a debugging session to notice. `HookCommand.sourcePath` and `Skill.source` already
|
|
1144
|
+
* answered it for the other two surfaces.
|
|
1145
|
+
*/
|
|
1146
|
+
source?: string;
|
|
1101
1147
|
model?: ModelSelection | "inherit";
|
|
1102
1148
|
mcpServers?: Array<string | Record<string, McpServerConfig>>;
|
|
1103
1149
|
/**
|
|
@@ -1822,4 +1868,4 @@ interface ListResult<T> {
|
|
|
1822
1868
|
nextCursor?: string;
|
|
1823
1869
|
}
|
|
1824
1870
|
|
|
1825
|
-
export { type
|
|
1871
|
+
export { type SettingSource as $, type AgentOptions as A, type BudgetTracker as B, type CloudOptions as C, type MemoryProviderAgentRef as D, type MemoryProviderFactory as E, type MemoryProviderHandle as F, type GetAgentOptions as G, type HookName as H, type InlineSkill as I, type MemoryProviderInitOptions as J, type PluginContext as K, type LocalOptions as L, type MemorySettings as M, type PluginHookDisposer as N, type PostAssistantReplyContext as O, type Plugin as P, type PostToolCallContext as Q, type PreToolCallContext as R, type SystemPromptResolver as S, type PreUserSendContext as T, type PreUserSendResult as U, type ProviderTransform as V, type ProviderTransformContext as W, type RecordSessionSummaryArgs as X, type SessionLifecycleContext as Y, type SessionRecord as Z, type SessionStore as _, type AgentDefinition as a, Skill as a0, type SkillsResolver as a1, type SkillsResolverContext as a2, type SystemPromptContext as a3, type SystemPromptMemoryFact as a4, type TelemetrySettings as a5, type ToolCallSummary as a6, type ToolResultTransformContext as a7, type TransformContext as a8, type SkillsSettings as b, type ListAgentsOptions as c, type ListResult as d, type SDKAgentInfo as e, type ListRunsOptions as f, type GetRunOptions as g, type AgentOperationOptions as h, type AgentDescription as i, type ProviderProfile as j, type MemoryProvider as k, type PreToolCallDecision as l, type ActiveMemoryPassArgs as m, type ActiveMemoryPassResult as n, type AgentSubagentDescription as o, type AgentToolDescription as p, type BudgetCheck as q, type BudgetTotal as r, type BudgetUsageEvent as s, type BuiltinToolName as t, type CloudEnv as u, type CloudRepo as v, type CompatSource as w, type CompatSourceAdapter as x, type CompatSurface as y, type CreateSkillSpec as z };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as MemoryFact, k as MemoryAdapter, m as MemoryContext, E as SystemPromptSkillRef, C as ContextSettings, P as ProviderRoutingSettings, a as PluginsSettings, S as SDKAgent } from './sdk-agent-
|
|
1
|
+
import { n as MemoryFact, k as MemoryAdapter, m as MemoryContext, E as SystemPromptSkillRef, C as ContextSettings, P as ProviderRoutingSettings, a as PluginsSettings, S as SDKAgent } from './sdk-agent-D4a_BR_6.js';
|
|
2
2
|
import { M as ModelSelection, C as CustomTool, c as PermissionMode, a as McpServerConfig, P as Processor } from './run-CTAdRU3U.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -952,7 +952,39 @@ type SettingSource = "project" | "user" | "team" | "mdm" | "plugins" | "all";
|
|
|
952
952
|
*
|
|
953
953
|
* @public
|
|
954
954
|
*/
|
|
955
|
-
type CompatSource = "claude-code";
|
|
955
|
+
type CompatSource = "claude-code" | CompatSourceAdapter;
|
|
956
|
+
/**
|
|
957
|
+
* A surface a foreign configuration source may be admitted to.
|
|
958
|
+
*
|
|
959
|
+
* They are named separately because they carry very different risk. A skill is TEXT that enters the
|
|
960
|
+
* system prompt; a subagent is a definition; a plugin is CODE LOADING; a hook is COMMAND EXECUTION.
|
|
961
|
+
* Reusing the skills you already wrote for another product is a reasonable thing to want, and it is
|
|
962
|
+
* not a reason to hand that product's directory the right to run commands.
|
|
963
|
+
*
|
|
964
|
+
* @public
|
|
965
|
+
*/
|
|
966
|
+
type CompatSurface = "hooks" | "plugins" | "skills" | "subagents";
|
|
967
|
+
/**
|
|
968
|
+
* A foreign source admitted to named surfaces only.
|
|
969
|
+
*
|
|
970
|
+
* ```ts
|
|
971
|
+
* local: { compatSources: [{ kind: "claude-code", import: ["skills", "subagents"] }] }
|
|
972
|
+
* ```
|
|
973
|
+
*
|
|
974
|
+
* `import` is not optional in spirit even though it is in the type: an adapter that omits it
|
|
975
|
+
* imports NOTHING. That is deliberate and it is the fail-closed rule this whole option exists to
|
|
976
|
+
* serve — a typo in a surface name must narrow access, never widen it.
|
|
977
|
+
*
|
|
978
|
+
* The bare `"claude-code"` string keeps meaning every surface. It is what `5.0.0-next.1` published,
|
|
979
|
+
* and silently narrowing it would turn a working opt-in into a no-op that says nothing — which is
|
|
980
|
+
* the defect usetheokit/theokit-sdk#524 reports, one level up.
|
|
981
|
+
*
|
|
982
|
+
* @public
|
|
983
|
+
*/
|
|
984
|
+
interface CompatSourceAdapter {
|
|
985
|
+
readonly kind: "claude-code";
|
|
986
|
+
readonly import?: readonly CompatSurface[];
|
|
987
|
+
}
|
|
956
988
|
/**
|
|
957
989
|
* A tool the SDK declares to the model on its own initiative — not one the consumer passed in
|
|
958
990
|
* {@link AgentOptions.tools}, and not one an MCP server exposed.
|
|
@@ -1098,6 +1130,20 @@ interface CloudOptions {
|
|
|
1098
1130
|
interface AgentDefinition {
|
|
1099
1131
|
description: string;
|
|
1100
1132
|
prompt: string;
|
|
1133
|
+
/**
|
|
1134
|
+
* Absolute path to the `.md` this subagent was read from, when it came from disk.
|
|
1135
|
+
*
|
|
1136
|
+
* ABSENT for a subagent declared in code through {@link AgentOptions.subagents} — "you passed
|
|
1137
|
+
* this one in" is a different fact from "read from disk", and one value for both would trade one
|
|
1138
|
+
* silence for another.
|
|
1139
|
+
*
|
|
1140
|
+
* It exists so a listing can answer which root a subagent came from, which
|
|
1141
|
+
* usetheokit/theokit-sdk#524 asks for by name: a consumer could not tell that an agent arrived
|
|
1142
|
+
* from `.claude/agents/` rather than its own directory, and silent inheritance is what made that
|
|
1143
|
+
* take a debugging session to notice. `HookCommand.sourcePath` and `Skill.source` already
|
|
1144
|
+
* answered it for the other two surfaces.
|
|
1145
|
+
*/
|
|
1146
|
+
source?: string;
|
|
1101
1147
|
model?: ModelSelection | "inherit";
|
|
1102
1148
|
mcpServers?: Array<string | Record<string, McpServerConfig>>;
|
|
1103
1149
|
/**
|
|
@@ -1822,4 +1868,4 @@ interface ListResult<T> {
|
|
|
1822
1868
|
nextCursor?: string;
|
|
1823
1869
|
}
|
|
1824
1870
|
|
|
1825
|
-
export { type
|
|
1871
|
+
export { type SettingSource as $, type AgentOptions as A, type BudgetTracker as B, type CloudOptions as C, type MemoryProviderAgentRef as D, type MemoryProviderFactory as E, type MemoryProviderHandle as F, type GetAgentOptions as G, type HookName as H, type InlineSkill as I, type MemoryProviderInitOptions as J, type PluginContext as K, type LocalOptions as L, type MemorySettings as M, type PluginHookDisposer as N, type PostAssistantReplyContext as O, type Plugin as P, type PostToolCallContext as Q, type PreToolCallContext as R, type SystemPromptResolver as S, type PreUserSendContext as T, type PreUserSendResult as U, type ProviderTransform as V, type ProviderTransformContext as W, type RecordSessionSummaryArgs as X, type SessionLifecycleContext as Y, type SessionRecord as Z, type SessionStore as _, type AgentDefinition as a, Skill as a0, type SkillsResolver as a1, type SkillsResolverContext as a2, type SystemPromptContext as a3, type SystemPromptMemoryFact as a4, type TelemetrySettings as a5, type ToolCallSummary as a6, type ToolResultTransformContext as a7, type TransformContext as a8, type SkillsSettings as b, type ListAgentsOptions as c, type ListResult as d, type SDKAgentInfo as e, type ListRunsOptions as f, type GetRunOptions as g, type AgentOperationOptions as h, type AgentDescription as i, type ProviderProfile as j, type MemoryProvider as k, type PreToolCallDecision as l, type ActiveMemoryPassArgs as m, type ActiveMemoryPassResult as n, type AgentSubagentDescription as o, type AgentToolDescription as p, type BudgetCheck as q, type BudgetTotal as r, type BudgetUsageEvent as s, type BuiltinToolName as t, type CloudEnv as u, type CloudRepo as v, type CompatSource as w, type CompatSourceAdapter as x, type CompatSurface as y, type CreateSkillSpec as z };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkQUAEOKDW_cjs = require('./chunk-QUAEOKDW.cjs');
|
|
4
4
|
require('./chunk-KVSAY6NZ.cjs');
|
|
5
5
|
require('./chunk-Y2KYR2ED.cjs');
|
|
6
6
|
require('./chunk-BUUUWQMB.cjs');
|
|
7
7
|
require('./chunk-2NE7DTOK.cjs');
|
|
8
|
-
require('./chunk-
|
|
8
|
+
require('./chunk-H6YM3PV6.cjs');
|
|
9
9
|
require('./chunk-BV2MWEMV.cjs');
|
|
10
10
|
require('./chunk-D6POWE7E.cjs');
|
|
11
11
|
require('./chunk-GHX4P3V2.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-
|
|
47
|
-
require('./chunk-
|
|
46
|
+
require('./chunk-SYVWE64W.cjs');
|
|
47
|
+
require('./chunk-GGZ5GPE3.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
|
|
64
|
+
get: function () { return chunkQUAEOKDW_cjs.Agent; }
|
|
65
65
|
});
|
|
66
|
-
//# sourceMappingURL=agent-
|
|
67
|
-
//# sourceMappingURL=agent-
|
|
66
|
+
//# sourceMappingURL=agent-GPV2JWZG.cjs.map
|
|
67
|
+
//# sourceMappingURL=agent-GPV2JWZG.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-GPV2JWZG.cjs"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { Agent } from './chunk-
|
|
1
|
+
export { Agent } from './chunk-KDR53EO7.js';
|
|
2
2
|
import './chunk-K2VMFZQ5.js';
|
|
3
3
|
import './chunk-AWINL3ZC.js';
|
|
4
4
|
import './chunk-K2BQQ445.js';
|
|
5
5
|
import './chunk-2ZLVT7H3.js';
|
|
6
|
-
import './chunk-
|
|
6
|
+
import './chunk-XJZEBGXD.js';
|
|
7
7
|
import './chunk-2SFBB54R.js';
|
|
8
8
|
import './chunk-55GB6JYQ.js';
|
|
9
9
|
import './chunk-H73MEMQB.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-
|
|
45
|
-
import './chunk-
|
|
44
|
+
import './chunk-4S5TWFIZ.js';
|
|
45
|
+
import './chunk-67ADYSTW.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-
|
|
58
|
-
//# sourceMappingURL=agent-
|
|
57
|
+
//# sourceMappingURL=agent-Y24I5JBM.js.map
|
|
58
|
+
//# sourceMappingURL=agent-Y24I5JBM.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"agent-Y24I5JBM.js"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pluginBundleRoots, projectConfigRoots } from './chunk-
|
|
1
|
+
import { pluginBundleRoots, projectConfigRoots } from './chunk-67ADYSTW.js';
|
|
2
2
|
import { readWorkspaceDir, parseSimpleYaml } from './chunk-JNAA4G4H.js';
|
|
3
3
|
import { ConfigurationError } from './chunk-ALUN2B4W.js';
|
|
4
4
|
import { diag } from './chunk-CZJ6Q7CW.js';
|
|
@@ -39,7 +39,7 @@ async function loadSubagents(cwd, settingSourcesIncludeProject, inline, compatSo
|
|
|
39
39
|
}
|
|
40
40
|
async function readProjectSubagents(cwd, compatSources) {
|
|
41
41
|
const subagents = {};
|
|
42
|
-
for (const configRoot of projectConfigRoots(cwd, compatSources)) {
|
|
42
|
+
for (const configRoot of projectConfigRoots(cwd, compatSources, "subagents")) {
|
|
43
43
|
await readSubagentsFrom(join(configRoot, "agents"), subagents);
|
|
44
44
|
}
|
|
45
45
|
for (const bundle of await pluginBundleDirs(cwd, compatSources)) {
|
|
@@ -59,7 +59,7 @@ async function readSubagentsFrom(root, subagents) {
|
|
|
59
59
|
}
|
|
60
60
|
const definition = parseSubagentMarkdown(raw, entry.name);
|
|
61
61
|
if (subagents[definition.name] === void 0) {
|
|
62
|
-
subagents[definition.name] = definition.definition;
|
|
62
|
+
subagents[definition.name] = { ...definition.definition, source: path };
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -165,5 +165,5 @@ function parseFrontmatterFields(frontmatter) {
|
|
|
165
165
|
}
|
|
166
166
|
|
|
167
167
|
export { loadSubagents, pluginBundleDirs };
|
|
168
|
-
//# sourceMappingURL=chunk-
|
|
169
|
-
//# sourceMappingURL=chunk-
|
|
168
|
+
//# sourceMappingURL=chunk-4S5TWFIZ.js.map
|
|
169
|
+
//# sourceMappingURL=chunk-4S5TWFIZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/internal/runtime/plugin-loader/plugin-bundles.ts","../src/internal/runtime/skills/subagents-loader.ts"],"names":["join"],"mappings":"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","file":"chunk-4S5TWFIZ.js","sourcesContent":["/**\n * Locating the plugin bundles a project carries.\n *\n * Shared by the skills and subagents loaders, which both need the same answer to \"which folders in\n * this project are plugins\" and would otherwise each grow their own copy of the directory walk.\n *\n * @internal\n */\n\nimport type { Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { pluginBundleRoots } from \"../../persistence/paths.js\";\nimport type { CompatSourceDeclaration } from \"../compat/foreign-config-sources.js\";\n\n/**\n * Every plugin folder under the project's plugin roots.\n *\n * Returns the FOLDERS, not their contents — what a bundle contributes (`skills/`, `agents/`) is the\n * caller's business, and a loader that also knew the layout would have to change whenever the other\n * one did.\n *\n * A missing root is not an error: most projects carry no plugins, and treating their absence as a\n * failure would make \"none installed\" indistinguishable from \"the directory could not be read\".\n */\nexport async function pluginBundleDirs(\n cwd: string,\n /** Declared foreign dialects (#524). Empty reads `.theokit/plugins` only. */\n compatSources: readonly CompatSourceDeclaration[] = [],\n): Promise<string[]> {\n const dirs: string[] = [];\n for (const root of pluginBundleRoots(cwd, compatSources)) {\n let entries: Dirent[];\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n if (entry.isDirectory()) dirs.push(join(root, entry.name));\n }\n }\n return dirs;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ConfigurationError } from \"../../../errors.js\";\nimport type { AgentDefinition } from \"../../../types/agent.js\";\nimport type { ModelSelection } from \"../../../types/agent-prims.js\";\nimport { diag } from \"../../diagnostics.js\";\nimport { projectConfigRoots } from \"../../persistence/paths.js\";\nimport type { CompatSourceDeclaration } from \"../compat/foreign-config-sources.js\";\nimport { readWorkspaceDir } from \"../config/workspace-dir.js\";\nimport { type FrontmatterValue, parseSimpleYaml } from \"../context/yaml-frontmatter.js\";\nimport { pluginBundleDirs } from \"../plugin-loader/plugin-bundles.js\";\n\n/**\n * Load file-based subagents from `.theokit/agents/*.md` and merge with\n * inline definitions. Inline overrides file-based on name conflict.\n *\n * Each markdown file has YAML frontmatter (description + optional model)\n * and a body that becomes the subagent prompt.\n *\n * @internal\n */\nexport async function loadSubagents(\n cwd: string,\n settingSourcesIncludeProject: boolean,\n inline: Record<string, AgentDefinition> | undefined,\n /** Declared foreign dialects (#524). Empty reads `.theokit/` only. */\n compatSources: readonly CompatSourceDeclaration[] = [],\n): Promise<Record<string, AgentDefinition>> {\n const result: Record<string, AgentDefinition> = {};\n if (settingSourcesIncludeProject) {\n const projectAgents = await readProjectSubagents(cwd, compatSources);\n for (const [name, definition] of Object.entries(projectAgents)) {\n result[name] = definition;\n }\n }\n if (inline !== undefined) {\n for (const [name, definition] of Object.entries(inline)) {\n result[name] = definition;\n }\n }\n return result;\n}\n\n/**\n * Read agent declarations from every project config root (`.theokit`, then `.claude`).\n *\n * FIRST occurrence of a name wins, which is what makes `projectConfigRoots`' order a contract rather\n * than a detail: a project declaring the same agent in both means the explicit namespace.\n */\nasync function readProjectSubagents(\n cwd: string,\n compatSources: readonly CompatSourceDeclaration[],\n): Promise<Record<string, AgentDefinition>> {\n const subagents: Record<string, AgentDefinition> = {};\n for (const configRoot of projectConfigRoots(cwd, compatSources, \"subagents\")) {\n await readSubagentsFrom(join(configRoot, \"agents\"), subagents);\n }\n // A Claude Code plugin is a BUNDLE, and its `agents/` is what it exists to contribute. Read after\n // the project's own, so a project can shadow an agent a plugin ships without editing the plugin.\n for (const bundle of await pluginBundleDirs(cwd, compatSources)) {\n await readSubagentsFrom(join(bundle, \"agents\"), subagents);\n }\n return subagents;\n}\n\nasync function readSubagentsFrom(\n root: string,\n subagents: Record<string, AgentDefinition>,\n): Promise<void> {\n const entries = await readWorkspaceDir(root, \"subagents_read_error\", \"subagents directory\");\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith(\".md\")) continue;\n const path = join(root, entry.name);\n const raw = await readFile(path, \"utf8\");\n // A markdown file with NO frontmatter is not an agent declaration — a directory of agents\n // written for the Claude Code CLI conventionally carries documentation beside them, and\n // `.claude/agents/README.md` exists in this repository. Throwing on it made ONE such file stop\n // every agent in the directory from loading.\n //\n // Skipped with a warn rather than in silence, and ONLY for the no-frontmatter case: a file that\n // HAS frontmatter and gets it wrong is a broken agent and still fails loudly, which is what\n // keeps a typo'd `sandbox` from returning as a silent gate through this door.\n if (!hasFrontmatter(raw)) {\n diag(`[theokit-sdk] ${entry.name} has no frontmatter — not an agent declaration, skipping`);\n continue;\n }\n const definition = parseSubagentMarkdown(raw, entry.name);\n if (subagents[definition.name] === undefined) {\n // `path` is computed above to read the file and was then dropped. Keeping it is the whole\n // visibility fix (#524): without it a listing cannot say which root an agent came from.\n subagents[definition.name] = { ...definition.definition, source: path };\n }\n }\n}\n\n// The frontmatter keys a disk subagent may declare. Any other key is a typed load\n// error rather than a silent drop — a dropped `sandbox` an operator wrote believing\n// it confines the child is exactly the silent-gate failure class this guards against.\nconst ACCEPTED_FIELDS = new Set([\n \"name\",\n \"description\",\n \"model\",\n \"tools\",\n \"reasoning_effort\",\n \"mcp\",\n \"sandbox\",\n]);\n\n// Fields the Claude Code CLI writes that carry NO behaviour for this runtime. Accepted and ignored,\n// so an agent authored for the CLI loads here unchanged — measured 2026-08-26 across the 59 agent\n// files on one machine, where `color` appeared in 38 of them and made every one of those a\n// `subagent_unknown_field` load error.\n//\n// Named explicitly instead of loosening the check above, because that check's reason is sound: a\n// dropped `sandbox` an operator wrote believing it confines the child is a silent gate. A field that\n// COULD change behaviour must still fail loudly. This set is the difference between \"we know this\n// one and it does nothing\" and \"we have never heard of this\" — two facts a bare allow-everything\n// would collapse into one.\n//\n// Anything added here needs the same justification: inert for THIS runtime, not merely unfamiliar.\nconst INERT_CLAUDE_CODE_FIELDS = new Set([\n /** The CLI's label colour for the agent. Presentation only. */\n \"color\",\n]);\n\nfunction parseSubagentMarkdown(\n raw: string,\n filename: string,\n): { name: string; definition: AgentDefinition } {\n const { frontmatter, body } = splitFrontmatter(raw, filename);\n const fields = parseFrontmatterFields(frontmatter);\n rejectUnknownFields(fields, filename);\n rejectMcp(fields, filename);\n\n const definition: AgentDefinition = {\n description: asString(fields.description) ?? \"\",\n prompt: body,\n };\n const model = resolveModel(fields, filename);\n if (model !== undefined) definition.model = model;\n const tools = toStringList(fields.tools);\n if (tools.length > 0) definition.tools = tools;\n const sandbox = resolveSandbox(fields, filename);\n if (sandbox !== undefined) definition.sandbox = sandbox;\n\n const name = asString(fields.name) ?? filename.replace(/\\.md$/, \"\");\n return { name, definition };\n}\n\nfunction rejectUnknownFields(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): void {\n for (const key of Object.keys(fields)) {\n if (INERT_CLAUDE_CODE_FIELDS.has(key)) continue;\n if (!ACCEPTED_FIELDS.has(key)) {\n throw new ConfigurationError(\n `Subagent ${filename}: unknown frontmatter field \"${key}\" (accepted: ${[...ACCEPTED_FIELDS].join(\", \")})`,\n { code: \"subagent_unknown_field\" },\n );\n }\n }\n}\n\n// mcp: a known field, but not yet honored on the LOCAL delegation path. The frontmatter YAML can only\n// express server NAMES (parseSimpleYaml has no nested-object support), while a child's `Agent.create`\n// needs `mcpServers` as a Record<name, config>; resolving names→config per-subagent in local delegation\n// is its own follow-up. Rather than silently drop it (the M26/M32 silent-gate class), it is a typed load\n// error that names the field and points at the alternative.\nfunction rejectMcp(fields: Record<string, FrontmatterValue | undefined>, filename: string): void {\n if (fields.mcp !== undefined) {\n throw new ConfigurationError(\n `Subagent ${filename}: per-subagent \"mcp\" is not yet supported on the local delegation path; declare MCP servers in .theokit/mcp.json (or the parent) instead`,\n { code: \"subagent_mcp_unsupported_local\" },\n );\n }\n}\n\n// model + reasoning_effort — effort rides inside `model.params[thinking]`, so it requires a concrete\n// model id to attach to (a child inheriting the parent's model cannot carry the parent's provider-\n// specific effort param safely).\nfunction resolveModel(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): ModelSelection | \"inherit\" | undefined {\n const modelId = asString(fields.model);\n const effort = asString(fields.reasoning_effort);\n // reasoning_effort rides in model.params[thinking], so it needs a CONCRETE model id to attach to.\n // Neither an absent model NOR `model: inherit` can carry it (the inherited id is unknown at load), so\n // both are typed errors rather than a silently-dropped effort — the silent-gate class this guards.\n if (effort !== undefined && (modelId === undefined || modelId === \"inherit\")) {\n throw new ConfigurationError(\n `Subagent ${filename}: reasoning_effort requires a concrete model (effort is a model parameter; an absent model or \"inherit\" cannot carry it)`,\n { code: \"subagent_reasoning_effort_without_model\" },\n );\n }\n if (modelId === undefined) return undefined;\n if (modelId === \"inherit\") return \"inherit\";\n return effort !== undefined\n ? { id: modelId, params: [{ id: \"thinking\", value: effort }] }\n : { id: modelId };\n}\n\n// sandbox: boolean only. A granular mode string (read-only/…) is unsupported by the SDK runtime and is\n// a typed error rather than a silent coercion to a boolean.\nfunction resolveSandbox(\n fields: Record<string, FrontmatterValue | undefined>,\n filename: string,\n): boolean | undefined {\n if (fields.sandbox === undefined) return undefined;\n if (typeof fields.sandbox !== \"boolean\") {\n throw new ConfigurationError(\n `Subagent ${filename}: sandbox must be a boolean (got \"${String(fields.sandbox)}\"); granular sandbox modes are not supported by the runtime`,\n { code: \"subagent_sandbox_not_boolean\" },\n );\n }\n return fields.sandbox;\n}\n\nfunction asString(v: FrontmatterValue | undefined): string | undefined {\n if (typeof v !== \"string\") return undefined;\n // parseSimpleYaml does not strip quotes (documented), and `model`/`reasoning_effort` are fields users\n // habitually quote (`model: \"openai/gpt-4o\"`). Strip a single matching surrounding quote pair so a\n // quoted id/effort does not slip past validation and fail only at the provider.\n const m = /^([\"'])(.*)\\1$/.exec(v);\n return m ? m[2] : v;\n}\n\n/** Accept a YAML list (`string[]`) or a comma/space-separated scalar; trim + drop empties. */\nfunction toStringList(v: FrontmatterValue | undefined): string[] {\n if (Array.isArray(v)) return v.map((t) => t.trim()).filter((t) => t.length > 0);\n if (typeof v === \"string\") {\n return v\n .split(/[\\s,]+/)\n .map((t) => t.trim())\n .filter((t) => t.length > 0);\n }\n return [];\n}\n\n/** Does this file open with a frontmatter block at all? Its ABSENCE means \"not an agent\". */\nfunction hasFrontmatter(raw: string): boolean {\n return /^---\\s*\\n/.test(raw);\n}\n\nfunction splitFrontmatter(raw: string, filename: string): { frontmatter: string; body: string } {\n const match = /^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n([\\s\\S]*)$/.exec(raw);\n if (match === null) {\n throw new ConfigurationError(`Subagent ${filename} is missing frontmatter`, {\n code: \"subagent_missing_frontmatter\",\n });\n }\n return { frontmatter: match[1] ?? \"\", body: (match[2] ?? \"\").trim() };\n}\n\nfunction parseFrontmatterFields(frontmatter: string): Record<string, FrontmatterValue | undefined> {\n // Preserve the rich YAML value types (boolean/number/string[]): `sandbox: true` and\n // `mcp: [a, b]` are meaningful here, so narrowing everything to string (as the\n // pre-M33 loader did) would drop them. Per-field validation happens in parseSubagentMarkdown.\n return parseSimpleYaml(frontmatter);\n}\n"]}
|
|
@@ -28,6 +28,21 @@ function adaptersFor(kinds) {
|
|
|
28
28
|
}
|
|
29
29
|
return out;
|
|
30
30
|
}
|
|
31
|
+
var COMPAT_SURFACES = ["hooks", "plugins", "skills", "subagents"];
|
|
32
|
+
function adaptersForSurface(sources, surface) {
|
|
33
|
+
const admitted = [];
|
|
34
|
+
for (const source of sources) {
|
|
35
|
+
if (typeof source === "string") {
|
|
36
|
+
admitted.push(source);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const wanted = source.import ?? [];
|
|
40
|
+
if (wanted.some((s) => s === surface && COMPAT_SURFACES.includes(s))) {
|
|
41
|
+
admitted.push(source.kind);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return adaptersFor(admitted);
|
|
45
|
+
}
|
|
31
46
|
function adapterForConfigPath(path) {
|
|
32
47
|
for (const segment of path.split(/[\\/]/)) {
|
|
33
48
|
const adapter = BY_DIR_NAME.get(segment);
|
|
@@ -51,7 +66,9 @@ function undefinedVariablesIn(command, supplied, env = process.env) {
|
|
|
51
66
|
}
|
|
52
67
|
var reported = /* @__PURE__ */ new Set();
|
|
53
68
|
function reportUndeclaredSources(cwd, declared) {
|
|
54
|
-
const declaredKinds = new Set(
|
|
69
|
+
const declaredKinds = new Set(
|
|
70
|
+
adaptersFor(declared.map((d) => typeof d === "string" ? d : d.kind)).map((a) => a.kind)
|
|
71
|
+
);
|
|
55
72
|
for (const adapter of FOREIGN_SOURCES) {
|
|
56
73
|
if (declaredKinds.has(adapter.kind)) continue;
|
|
57
74
|
const dir = join(cwd, adapter.dirName);
|
|
@@ -73,14 +90,17 @@ function getTheokitHome(cwd) {
|
|
|
73
90
|
}
|
|
74
91
|
return join(cwd, THEOKIT_DIR_LITERAL);
|
|
75
92
|
}
|
|
76
|
-
function
|
|
93
|
+
function theokitConfigRoot(cwd) {
|
|
94
|
+
return join(cwd, THEOKIT_DIR_LITERAL);
|
|
95
|
+
}
|
|
96
|
+
function projectConfigRoots(cwd, sources, surface) {
|
|
77
97
|
return [
|
|
78
|
-
|
|
79
|
-
...
|
|
98
|
+
theokitConfigRoot(cwd),
|
|
99
|
+
...adaptersForSurface(sources, surface).map((adapter) => join(cwd, adapter.dirName))
|
|
80
100
|
];
|
|
81
101
|
}
|
|
82
|
-
function pluginBundleRoots(cwd, sources
|
|
83
|
-
return projectConfigRoots(cwd, sources).map((root) => join(root, "plugins"));
|
|
102
|
+
function pluginBundleRoots(cwd, sources) {
|
|
103
|
+
return projectConfigRoots(cwd, sources, "plugins").map((root) => join(root, "plugins"));
|
|
84
104
|
}
|
|
85
105
|
function getProfilesRoot() {
|
|
86
106
|
return join(homedir(), THEOKIT_DIR_LITERAL, "profiles");
|
|
@@ -95,6 +115,6 @@ function displayTheokitHome(cwd) {
|
|
|
95
115
|
return resolved;
|
|
96
116
|
}
|
|
97
117
|
|
|
98
|
-
export { adapterForConfigPath, displayTheokitHome, getProfilesRoot, getTheokitHome, pluginBundleRoots, projectConfigRoots, reportUndeclaredSources, undefinedVariablesIn };
|
|
99
|
-
//# sourceMappingURL=chunk-
|
|
100
|
-
//# sourceMappingURL=chunk-
|
|
118
|
+
export { adapterForConfigPath, displayTheokitHome, getProfilesRoot, getTheokitHome, pluginBundleRoots, projectConfigRoots, reportUndeclaredSources, theokitConfigRoot, undefinedVariablesIn };
|
|
119
|
+
//# sourceMappingURL=chunk-67ADYSTW.js.map
|
|
120
|
+
//# sourceMappingURL=chunk-67ADYSTW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/internal/runtime/compat/foreign-config-sources.ts","../src/internal/persistence/paths.ts"],"names":["join"],"mappings":"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","file":"chunk-67ADYSTW.js","sourcesContent":["import { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { diag } from \"../../diagnostics.js\";\n\n/*\n * The foreign configuration dialects this SDK can read, and what each one PRESUMES.\n *\n * ## Why a registry and not a list of directory names\n *\n * `projectConfigRoots` returned `[\".theokit\", \".claude\"]` — two paths — and that shape is what\n * usetheokit/theokit-sdk#522 fell through. A path says WHERE a file lives. It does not say how the\n * file is parsed, and it does not say what runtime the commands inside it were written against.\n *\n * Claude Code defines `$CLAUDE_PROJECT_DIR` for the hook commands in its `settings.json`, and its\n * documentation tells authors to reach project files through it — an absolute path would break for\n * every other person on the team, so the shape that failed here is the shape upstream recommends.\n * This SDK read the file and ran the command without the variable. `sh` expands an unset variable to\n * the empty string, so\n *\n * bash \"$CLAUDE_PROJECT_DIR/.claude/hooks/guard.sh\" became bash \"/.claude/hooks/guard.sh\"\n *\n * which does not exist, which a hook runner correctly reads as a refusal. Every turn denied, in any\n * repository that also had Claude Code set up, with a message naming a file that was present and\n * executable all along.\n *\n * Importing a format means accepting the contract that format presumes. An adapter is where that\n * contract is written down, so the next dialect (`.codex/` is the obvious one) declares its own\n * instead of inheriting a hole.\n *\n * ## What an adapter deliberately does NOT do\n *\n * It does not make the foreign source trusted, and it does not make its hooks permissive: a script\n * that exits non-zero is still a refusal. It supplies the variables the format's authors were\n * entitled to assume, and nothing else — `env` here is merged over the scrubbed inherit policy by\n * `spawnAndCollect`, so it adds names rather than widening what a child can see.\n *\n * @internal\n */\n\n/**\n * The project config directory literal.\n *\n * Renamed from `THEOKIT_DIR_NAME` in #410. Sharing a name with the (now removed) sovereign env var\n * was the MECHANISM of that defect, not scenery: every grep for the variable landed on that const\n * and looked answered, so \"is it read?\" returned five hits and nobody checked what they were.\n *\n * Lives here rather than in `persistence/paths.ts` because a directory name is one third of what a\n * dialect is — the other two being how it parses and what it presumes — and splitting the three\n * across two modules is what let the third go unwritten.\n */\nexport const THEOKIT_DIR_LITERAL = \".theokit\";\n\n/** The Claude Code CLI's project configuration directory. */\nexport const CLAUDE_DIR_NAME = \".claude\";\n\n/** A configuration dialect this SDK understands. `theokit` is native; the rest are foreign. */\nexport interface ConfigSourceAdapter {\n /** Stable identifier, and what a consumer names to opt in. */\n readonly kind: string;\n /** The project-relative directory the dialect keeps its configuration in. */\n readonly dirName: string;\n /**\n * Variables the dialect's own runtime defines for commands it executes.\n *\n * Empty for the native source: a `.theokit/` hook is written against THIS runtime and inherits it\n * already. Non-empty is what makes a foreign command runnable rather than silently broken.\n */\n runtimeEnv(cwd: string): Record<string, string>;\n}\n\n/** The native source. Always read, never opted into, always first for precedence. */\nexport const NATIVE_SOURCE: ConfigSourceAdapter = {\n kind: \"theokit\",\n dirName: THEOKIT_DIR_LITERAL,\n runtimeEnv: () => ({}),\n};\n\n/**\n * Claude Code.\n *\n * `CLAUDE_PROJECT_DIR` is the documented way for a hook command in `settings.json` to reach a file\n * in the project. Only that one variable is supplied: `$CLAUDE_PLUGIN_ROOT` and the rest of that\n * runtime's surface are NOT defined here, because supplying a name whose value this SDK would have\n * to invent is worse than leaving it unset — an invented root sends a script somewhere real and\n * wrong, where an unset one fails loudly.\n */\nexport const CLAUDE_CODE_SOURCE: ConfigSourceAdapter = {\n kind: \"claude-code\",\n dirName: CLAUDE_DIR_NAME,\n runtimeEnv: (cwd) => ({ CLAUDE_PROJECT_DIR: cwd }),\n};\n\nconst FOREIGN_SOURCES: readonly ConfigSourceAdapter[] = [CLAUDE_CODE_SOURCE];\n\nconst BY_DIR_NAME: ReadonlyMap<string, ConfigSourceAdapter> = new Map(\n [NATIVE_SOURCE, ...FOREIGN_SOURCES].map((a) => [a.dirName, a]),\n);\n\n/**\n * The adapters a caller declared, in declaration order, skipping any name that names no adapter.\n *\n * An unknown name is DROPPED rather than turned into `<cwd>/<name>`: a typo must fail closed. Making\n * a directory out of an unrecognised string would import a dialect nothing knows how to parse — and\n * the whole reason this exists is that a directory name was never enough to describe a dialect.\n */\nexport function adaptersFor(kinds: readonly string[]): ConfigSourceAdapter[] {\n const byKind = new Map(FOREIGN_SOURCES.map((a) => [a.kind, a]));\n const out: ConfigSourceAdapter[] = [];\n for (const kind of kinds) {\n const adapter = byKind.get(kind);\n if (adapter !== undefined && !out.includes(adapter)) out.push(adapter);\n }\n return out;\n}\n\n/**\n * A surface a foreign source may be admitted to. The four the SDK reads a project directory for.\n *\n * They are listed separately because they carry very different risk, which is the whole reason\n * #524 asks for per-surface control: a skill is text that enters the system prompt, a hook is\n * command execution, a plugin is code loading. A consumer who wants their skills back has no\n * reason to be handed the other two along with them.\n */\nexport type CompatSurface = \"hooks\" | \"plugins\" | \"skills\" | \"subagents\";\n\nconst COMPAT_SURFACES: readonly CompatSurface[] = [\"hooks\", \"plugins\", \"skills\", \"subagents\"];\n\n/**\n * A declared foreign source: a bare kind, or a kind with the surfaces it may be read for.\n */\nexport type CompatSourceDeclaration =\n | string\n | { readonly kind: string; readonly import?: readonly string[] };\n\n/**\n * The adapters admitted to ONE surface.\n *\n * Three rules, and each one fails closed:\n *\n * - A bare string admits every surface. It is what `5.0.0-next.1` published, so narrowing it\n * silently would turn a working opt-in into a no-op — the exact defect #524 is about, one level\n * up.\n * - An object with no `import` admits nothing. The issue's own rule, and safe to apply strictly\n * because the object form is new and nobody can be depending on it.\n * - An unrecognised surface name is dropped rather than matched loosely, for the same reason an\n * unrecognised KIND is dropped in {@link adaptersFor}: a typo must not silently widen access.\n */\nexport function adaptersForSurface(\n sources: readonly CompatSourceDeclaration[],\n surface: CompatSurface,\n): ConfigSourceAdapter[] {\n const admitted: string[] = [];\n for (const source of sources) {\n if (typeof source === \"string\") {\n admitted.push(source);\n continue;\n }\n const wanted = source.import ?? [];\n if (wanted.some((s) => s === surface && COMPAT_SURFACES.includes(s as CompatSurface))) {\n admitted.push(source.kind);\n }\n }\n return adaptersFor(admitted);\n}\n\n/**\n * The adapter whose directory an absolute config path sits under, or `undefined` for a path that\n * belongs to no registered dialect.\n *\n * Matched on the path SEGMENT rather than with `includes`, so a workspace that happens to live under\n * `/home/me/.claude-backups/repo` does not read as a Claude Code source.\n */\nexport function adapterForConfigPath(path: string): ConfigSourceAdapter | undefined {\n for (const segment of path.split(/[\\\\/]/)) {\n const adapter = BY_DIR_NAME.get(segment);\n if (adapter !== undefined) return adapter;\n }\n return undefined;\n}\n\n/**\n * Variable references in a shell command that nothing will define.\n *\n * The second half of #522, and the half that cost the debugging session. `sh` expands an unset\n * variable to the empty string and says nothing, so the failure surfaces ten characters later as a\n * path: `bash: /.claude/hooks/guard.sh: No such file or directory` — which reads as \"your script is\n * missing\" while the script is present and executable. Nothing in that message contains the name of\n * the variable that was actually missing, so the reader looks in the wrong place.\n *\n * Checked against BOTH the process environment and the variables the dialect supplies, because\n * either is a legitimate source: a hook may reasonably use `$HOME`.\n *\n * ## What it deliberately does not try to be\n *\n * This is not a shell parser. It finds `$NAME` and `${NAME}` outside single quotes, which is the\n * shape a config file's hook commands take. It does NOT understand `${NAME:-default}` (a default\n * makes the variable optional, so it is not reported), assignments earlier in the same command, or\n * variables a sourced script exports. A false NEGATIVE there costs the old behaviour — the confusing\n * path error — and a false positive would deny a hook that would have worked, so the parse errs\n * toward silence and the check only ever ADDS a name to a failure that already happened.\n */\nexport function undefinedVariablesIn(\n command: string,\n supplied: Readonly<Record<string, string>>,\n env: Readonly<Record<string, string | undefined>> = process.env,\n): string[] {\n // Single-quoted spans are literal in `sh`: `echo '$FOO'` prints the dollar sign.\n const unquoted = command.replace(/'[^']*'/g, \" \");\n const names = new Set<string>();\n for (const match of unquoted.matchAll(\n /\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}|\\$([A-Za-z_][A-Za-z0-9_]*)/g,\n )) {\n const name = match[1] ?? match[2];\n if (name === undefined) continue;\n if (name in supplied) continue;\n if (env[name] !== undefined) continue;\n names.add(name);\n }\n return [...names];\n}\n\n/**\n * Workspaces already reported, so repeated agent construction in one process says it once.\n *\n * Keyed by the resolved directory rather than by dialect kind, so a long-lived host that drives\n * several workspaces still reports each of them.\n */\nconst reported = new Set<string>();\n\n/**\n * Reports a foreign configuration directory that exists in the workspace and was not declared.\n *\n * ## Why the flip needs a voice\n *\n * Before #524 a `.claude/` was read with no opt-in; after it, the same directory is ignored. From\n * inside the repository the two states are indistinguishable — the hook file is there, it is\n * executable, and it does not run. The only remaining way to learn why is a CHANGELOG entry for a\n * version the reader may not know they crossed.\n *\n * ## Why `diag` rather than `diagFailure`\n *\n * `diagFailure` falls back to stderr, and this is not a failure: ignoring an undeclared foreign\n * directory is precisely what #524 asked for. Every repository that has Claude Code set up and does\n * NOT want it imported would pay a stderr line at every agent start — on a TUI host's render\n * surface — for behaving as instructed. That is the corruption `diagnostics.ts` exists to prevent.\n *\n * So it goes on the interceptable channel, for the reader holding the question it answers.\n */\nexport function reportUndeclaredSources(\n cwd: string,\n declared: readonly CompatSourceDeclaration[],\n): void {\n // A kind named with a NARROW import list has still been declared: the consumer knows the\n // directory is there and chose which surfaces to admit. Warning them anyway would be the noise\n // that gets a warning ignored, and this one has exactly one job — telling somebody who does NOT\n // know the directory is being skipped.\n const declaredKinds = new Set(\n adaptersFor(declared.map((d) => (typeof d === \"string\" ? d : d.kind))).map((a) => a.kind),\n );\n for (const adapter of FOREIGN_SOURCES) {\n if (declaredKinds.has(adapter.kind)) continue;\n const dir = join(cwd, adapter.dirName);\n if (!existsSync(dir)) continue;\n if (reported.has(dir)) continue;\n reported.add(dir);\n diag(\n `[theokit] ${adapter.dirName}/ is present but not declared, so its hooks, skills, subagents ` +\n `and plugins are ignored. To read it, pass ` +\n `local: { compatSources: [\"${adapter.kind}\"] } (usetheokit/theokit-sdk#524).\\n`,\n );\n }\n}\n","/**\n * Path resolution for SDK state files (ADR D60).\n *\n * Theokit anchors state at `<cwd>/.theokit/` by default (per-cwd). An\n * optional `THEOKIT_HOME` environment variable overrides this, enabling\n * test isolation, profile switching, and multi-tenant deployments.\n *\n * Rules:\n * - `getTheokitHome(cwd)` is the canonical resolver **for cwd-anchored state**. Never hardcode\n * `path.join(cwd, \".theokit\")` in callers — use this function so tests\n * and overrides stay consistent.\n *\n * M94 — this comment said \"the ONLY canonical resolver\", and stopped being true: the\n * transcript gained `transcriptRoot()`, which is **home-anchored** (`~/.theokit`) with the same\n * `THEOKIT_HOME` override. The two defaults differ on purpose — unifying would move the\n * transcript of everyone who does NOT set the variable, which is a data migration and not a\n * re-export.\n *\n * A consequence worth writing down: **without `THEOKIT_HOME` the state stays split in two**\n * — registry in `<cwd>/.theokit`, transcript in `~/.theokit`. M94 unifies only for those who set\n * the variable. Unifying both defaults is another milestone's work.\n * - `getProfilesRoot()` is intentionally home-anchored (not affected by\n * `THEOKIT_HOME`) so `theokit profile list` discovers all profiles\n * regardless of which is active.\n * - `displayTheokitHome(cwd)` returns a human-readable path for logs.\n *\n * @internal\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport {\n adaptersForSurface,\n type CompatSourceDeclaration,\n type CompatSurface,\n THEOKIT_DIR_LITERAL,\n} from \"../runtime/compat/foreign-config-sources.js\";\n\n// The directory names live with the dialect registry that owns them — a name is one third of what a\n// configuration dialect is, and keeping the three together is what stops the next one shipping\n// without its runtime contract (#522).\n\n/**\n * Resolve the directory cwd-anchored SDK state lives in.\n *\n * `THEOKIT_HOME` wins when it is set and not blank after trimming; the trimmed value is used, and\n * it is used VERBATIM — it is not resolved against `cwd`, so a relative value stays relative and\n * `.theokit` is not appended to it. Otherwise the answer is `<cwd>/.theokit`.\n *\n * The environment is read on every call, so a change to the variable takes effect immediately\n * rather than being frozen at import.\n *\n * This creates nothing and checks nothing: the returned path may not exist, and the caller owns\n * the `mkdir`. Call it instead of writing `join(cwd, \".theokit\")` by hand, or the override stops\n * working for that one call site and tests silently touch the real home.\n *\n * Not the whole story about where state lives — the transcript is home-anchored via\n * `transcriptRoot()`, honoring the same variable but defaulting to `~/.theokit`. With\n * `THEOKIT_HOME` unset, state is genuinely split between two roots.\n *\n * Semver-exempt: reachable via the `@theokit/sdk/internal/persistence` sub-path, which the package\n * declares in `exports` but does NOT cover with its semver contract.\n */\nexport function getTheokitHome(cwd: string): string {\n const override = process.env.THEOKIT_HOME?.trim();\n if (override !== undefined && override.length > 0) {\n return override;\n }\n return join(cwd, THEOKIT_DIR_LITERAL);\n}\n\n/**\n * The project's own configuration root: `<cwd>/.theokit`, always — never `THEOKIT_HOME`.\n *\n * `THEOKIT_HOME` relocates cwd-anchored SDK STATE (sessions, credentials). A project's\n * CONFIGURATION belongs to the repository: hooks, MCP servers, context sources, subagents, the\n * personality a project declares, all committed to git and shared by a team. Following the\n * override for any of them would move where a project's declared capabilities come from — a\n * behaviour change wearing the costume of a refactor, which is exactly what this function exists\n * to make impossible to do by accident: every config-class reader calls this instead of writing\n * `join(cwd, \".theokit\")` by hand.\n *\n * NOT for the `.claude/`-style foreign roots {@link adaptersForSurface} adds — those are additive,\n * opt-in, and each has its own directory name.\n *\n * Semver-exempt: reachable via the `@theokit/sdk/internal/persistence` sub-path, which the package\n * declares in `exports` but does NOT cover with its semver contract.\n */\nexport function theokitConfigRoot(cwd: string): string {\n return join(cwd, THEOKIT_DIR_LITERAL);\n}\n\n/**\n * Every directory a project's configuration may be read from, in precedence order.\n *\n * `.theokit` first — via {@link theokitConfigRoot}, so it is NEVER affected by `THEOKIT_HOME` for\n * the reason documented there — then `.claude`. The order is the whole contract: a project that\n * declares a skill, agent or rule in both means the explicit namespace to win, and a caller merging\n * these roots must therefore keep the FIRST occurrence of a name rather than the last.\n *\n * `.claude` is read because the formats already agree and only the location did not. Measured\n * 2026-08-26: the SKILL.md frontmatter this SDK requires (`name` + `description`) is exactly what\n * the CLI writes, its hook config is the same JSON shape, and 59 of the CLI's agent declarations\n * parse here unchanged. A repository set up for the CLI was failing on the directory name alone.\n *\n * NOT a rename of `.theokit`, and not a migration. Both are read, so nothing that works today stops\n * working — which is why this returns a LIST and not a single resolved answer.\n *\n * Creates nothing and checks nothing; either path may not exist, and the caller owns that.\n *\n * Semver-exempt: reachable via the `@theokit/sdk/internal/persistence` sub-path, which the package\n * declares in `exports` but does NOT cover with its semver contract.\n */\nexport function projectConfigRoots(\n cwd: string,\n sources: readonly CompatSourceDeclaration[],\n surface: CompatSurface,\n): string[] {\n return [\n theokitConfigRoot(cwd),\n ...adaptersForSurface(sources, surface).map((adapter) => join(cwd, adapter.dirName)),\n ];\n}\n\n/**\n * Every directory that may hold a plugin BUNDLE contributed by the Claude Code CLI.\n *\n * A CLI plugin is not a JS entry point — it is a folder whose `skills/` and `agents/` are what it\n * exists to provide. Measured 2026-08-26 on an installed one: seven agents and three skills beside\n * a manifest in `.claude-plugin/plugin.json`. Parsing that manifest and stopping there produced a\n * plugin that loaded and did nothing.\n *\n * Project-scoped deliberately. The CLI also keeps plugins under `~/.claude/plugins/cache`, behind\n * its own installer and enable/disable state — reproducing that is an installation system, not\n * reading a project's configuration, and guessing at someone's enablement would run code they\n * turned off.\n */\nexport function pluginBundleRoots(\n cwd: string,\n sources: readonly CompatSourceDeclaration[],\n): string[] {\n // Always the `plugins` surface, including when the caller wants the SKILLS a bundle carries.\n // A bundle is code, and its skills arrive attached to it: admitting `skills` alone must not\n // reach inside a foreign plugin directory, or the narrower permission would silently grant the\n // wider one. `skills-manager` and `subagents-loader` both read bundle contents and both go\n // through here, so the rule holds in one place rather than three.\n return projectConfigRoots(cwd, sources, \"plugins\").map((root) => join(root, \"plugins\"));\n}\n\n/**\n * The directory holding every profile: always `~/.theokit/profiles`, from `os.homedir()`.\n *\n * Deliberately NOT affected by `THEOKIT_HOME`, which is the one thing to remember about it. If it\n * followed the override, a session pointed at one profile would only be able to see that profile,\n * and `theokit profile list` could never enumerate the rest. Profiles are the thing the override\n * switches between, so their index cannot live behind it.\n *\n * Takes no `cwd` for the same reason. Creates nothing; the path may not exist.\n *\n * Semver-exempt: reachable via the `@theokit/sdk/internal/persistence` sub-path, which the package\n * declares in `exports` but does NOT cover with its semver contract.\n */\nexport function getProfilesRoot(): string {\n return join(homedir(), THEOKIT_DIR_LITERAL, \"profiles\");\n}\n\n/**\n * The same path `getTheokitHome(cwd)` returns, shortened for display: the home directory prefix\n * collapses to `~`, so `/home/ada/.theokit` prints as `~/.theokit`.\n *\n * For humans only — log lines, CLI output, error messages. The result is NOT a usable path: `~`\n * is a shell convention that `fs` does not expand, so passing this to a filesystem call resolves\n * a literal directory named `~` relative to the process cwd. Use `getTheokitHome` for anything\n * that touches disk.\n *\n * Collapsing is a prefix match on the home directory followed by a literal `/`, so a sibling like\n * `/home/adalovelace` is left alone even though `/home/ada` is a string prefix of it. A path\n * outside the home directory comes back unchanged — and so does a Windows path, where the\n * separator is a backslash and the prefix test therefore never matches.\n *\n * Semver-exempt: reachable via the `@theokit/sdk/internal/persistence` sub-path, which the package\n * declares in `exports` but does NOT cover with its semver contract.\n */\nexport function displayTheokitHome(cwd: string): string {\n const resolved = getTheokitHome(cwd);\n const home = homedir();\n if (resolved === home) return \"~\";\n if (resolved.startsWith(`${home}/`)) {\n return `~${resolved.slice(home.length)}`;\n }\n return resolved;\n}\n"]}
|