@theokit/sdk 5.4.0 → 5.5.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 (46) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/{agent-Bmy2G_ml.d.ts → agent-CjMVbhhY.d.ts} +22 -0
  3. package/dist/{agent-C1Efo7PI.d.cts → agent-DyB_lzrx.d.cts} +22 -0
  4. package/dist/{agent-MNINE73R.js → agent-G3T7Q3SQ.js} +4 -4
  5. package/dist/{agent-MNINE73R.js.map → agent-G3T7Q3SQ.js.map} +1 -1
  6. package/dist/{agent-AUVD4TI4.cjs → agent-YWSIHHFM.cjs} +5 -5
  7. package/dist/{agent-AUVD4TI4.cjs.map → agent-YWSIHHFM.cjs.map} +1 -1
  8. package/dist/{chunk-J6KZE2ZQ.cjs → chunk-2ZLQZHZC.cjs} +4 -4
  9. package/dist/{chunk-J6KZE2ZQ.cjs.map → chunk-2ZLQZHZC.cjs.map} +1 -1
  10. package/dist/{chunk-KWGSBZ2Q.js → chunk-M3ZGRGOG.js} +3 -3
  11. package/dist/{chunk-KWGSBZ2Q.js.map → chunk-M3ZGRGOG.js.map} +1 -1
  12. package/dist/{chunk-IKBLU7ZS.js → chunk-ODBID5TG.js} +11 -6
  13. package/dist/chunk-ODBID5TG.js.map +1 -0
  14. package/dist/{chunk-XD3FS5OI.js → chunk-S6B5XYC3.js} +3 -3
  15. package/dist/chunk-S6B5XYC3.js.map +1 -0
  16. package/dist/{chunk-UALC6Q3J.cjs → chunk-UKJJRU7C.cjs} +28 -23
  17. package/dist/chunk-UKJJRU7C.cjs.map +1 -0
  18. package/dist/{chunk-3FDU5JFE.cjs → chunk-VY6NKMOA.cjs} +3 -3
  19. package/dist/chunk-VY6NKMOA.cjs.map +1 -0
  20. package/dist/{context-EGM6CHXD.js → context-3HPU754C.js} +3 -3
  21. package/dist/{context-EGM6CHXD.js.map → context-3HPU754C.js.map} +1 -1
  22. package/dist/{context-4AIK26QB.cjs → context-JTGSBJT6.cjs} +6 -6
  23. package/dist/{context-4AIK26QB.cjs.map → context-JTGSBJT6.cjs.map} +1 -1
  24. package/dist/{cron-DSMdlhyF.d.cts → cron-Bgivg88c.d.cts} +1 -1
  25. package/dist/{cron-Dcdrdv_T.d.ts → cron-CNUa7PDo.d.ts} +1 -1
  26. package/dist/cron.cjs +4 -4
  27. package/dist/cron.d.cts +2 -2
  28. package/dist/cron.d.ts +2 -2
  29. package/dist/cron.js +3 -3
  30. package/dist/eval.cjs +3 -3
  31. package/dist/eval.js +2 -2
  32. package/dist/index.cjs +19 -19
  33. package/dist/index.d.cts +3 -3
  34. package/dist/index.d.ts +3 -3
  35. package/dist/index.js +5 -5
  36. package/dist/internal/runtime/hooks/hooks-executor.d.ts +10 -0
  37. package/dist/internal/runtime/hooks/hooks-source.d.ts +10 -0
  38. package/dist/subagents-loader.d.cts +1 -1
  39. package/dist/subagents-loader.d.ts +1 -1
  40. package/dist/types/hooks.d.ts +22 -0
  41. package/docs/error-codes.md +4 -4
  42. package/package.json +1 -1
  43. package/dist/chunk-3FDU5JFE.cjs.map +0 -1
  44. package/dist/chunk-IKBLU7ZS.js.map +0 -1
  45. package/dist/chunk-UALC6Q3J.cjs.map +0 -1
  46. package/dist/chunk-XD3FS5OI.js.map +0 -1
@@ -140,7 +140,7 @@ function parseClaudeCodeCommand(raw, matcher, path, ccEvent) {
140
140
  code: "hooks_invalid_command"
141
141
  });
142
142
  }
143
- const hc = { command: cmd.command };
143
+ const hc = { command: cmd.command, sourceEvent: ccEvent };
144
144
  if (matcher !== void 0) hc.matcher = matcher;
145
145
  if (typeof cmd.timeout === "number" && cmd.timeout > 0) {
146
146
  hc.timeoutMs = Math.round(cmd.timeout * 1e3);
@@ -164,5 +164,5 @@ function warnPersonalitySwitchInsideFork(agentId) {
164
164
  }
165
165
 
166
166
  export { currentPersonalityContext, loadHookConfig, warnOnce, warnPersonalitySwitchInsideFork, withPersonalityContext };
167
- //# sourceMappingURL=chunk-XD3FS5OI.js.map
168
- //# sourceMappingURL=chunk-XD3FS5OI.js.map
167
+ //# sourceMappingURL=chunk-S6B5XYC3.js.map
168
+ //# sourceMappingURL=chunk-S6B5XYC3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/runtime/hooks/hooks-source.ts","../src/internal/personality/context.ts"],"names":[],"mappings":"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","file":"chunk-S6B5XYC3.js","sourcesContent":["/**\n * Single source of truth for loading the hooks config (ADR 0016 — reverses\n * D74/D77 for hooks: JSON is canonical again, in the Claude Code shape).\n *\n * `.theokit/hooks.json` (Claude-Code-shaped JSON) is the only supported form.\n * A stray legacy `.theokit/hooks/*.md` dir (no hooks.json) is NOT loaded — it\n * warns to migrate and yields no hooks. Absent both → empty config.\n *\n * Consumed by `hooks-executor.ts` (runtime dispatch).\n *\n * Config shape (identical to Claude Code's `settings.json` hooks):\n * { \"hooks\": { \"PreToolUse\": [ { \"matcher\": \"shell\",\n * \"hooks\": [ { \"type\": \"command\", \"command\": \"…\", \"timeout\": 30 } ] } ] } }\n *\n * @internal\n */\n\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { ConfigurationError } from \"../../../errors.js\";\nimport { diag } from \"../../diagnostics.js\";\nimport { projectConfigRoots, theokitConfigRoot } from \"../../persistence/paths.js\";\nimport type { CompatSourceDeclaration } from \"../compat/foreign-config-sources.js\";\n\n/** The five lifecycle events the SDK runtime actually fires. */\nexport type HookEvent = \"preRun\" | \"postRun\" | \"preToolUse\" | \"postToolUse\" | \"stop\";\n\n/**\n * Claude Code event name → the SDK firing event. Only events the runtime\n * genuinely emits are mapped; a Claude Code event with no SDK firing point\n * (SessionStart / SubagentStop / PreCompact / Notification / SessionEnd) is\n * skipped with a warn rather than silently accepted (it would never run).\n */\nconst CLAUDE_CODE_EVENT_MAP: Readonly<Record<string, HookEvent>> = {\n PreToolUse: \"preToolUse\",\n PostToolUse: \"postToolUse\",\n UserPromptSubmit: \"preRun\",\n Stop: \"stop\",\n};\n\nexport interface HookCommand {\n command: string;\n matcher?: string;\n timeoutMs?: number;\n /**\n * #637 — the event key as written in the config file (`PreToolUse`), carried so the approval\n * gate can report the vocabulary the consumer's stored fingerprint was taken against.\n *\n * REQUIRED, not optional: `parseClaudeCodeCommand` is the only producer of a `HookCommand` in\n * this package, so every command has one. An optional field would hand every reader a fallback\n * branch for a case that cannot occur — and if an in-memory producer is added later, required is\n * what forces it to supply a value instead of inheriting a silent `undefined`.\n */\n sourceEvent: string;\n /**\n * The config file this command was declared in.\n *\n * Carried so the executor can supply the runtime contract the declaring DIALECT presumes — a\n * command from `.claude/settings.json` is written against Claude Code's runtime and expects\n * `$CLAUDE_PROJECT_DIR` to exist (#522). Absent for a command built in memory, which is native by\n * construction.\n */\n sourcePath?: string;\n}\n\nexport interface HookConfig {\n hooks?: Partial<Record<HookEvent, HookCommand[]>>;\n}\n\nconst warned = new Set<string>();\n\n/**\n * Emit a stderr warn once per process per unique key. Helps surface the\n * deprecation path without spamming when the loader is called many times\n * during a session (cron + send + skills all hit this).\n *\n * Note: spawned workers (cron, subagent) start fresh processes — warn\n * re-emits there, by design (1 per process boot, not per call).\n *\n * @internal\n */\nexport function warnOnce(key: string, message: string): void {\n if (warned.has(key)) return;\n warned.add(key);\n diag(`${message}\\n`);\n}\n\n/** Reset for tests; not exported via barrel. @internal */\nexport function _resetWarnOnceForTests(): void {\n warned.clear();\n}\n\n/**\n * Load hooks from `.theokit/hooks.json` (Claude-Code-shaped — the only supported\n * form). A stray legacy `.theokit/hooks/*.md` markdown dir (no `hooks.json`) is\n * NOT loaded — it emits a one-time migration warn and yields no hooks.\n *\n * @internal\n */\nexport async function loadHookConfig(\n cwd: string,\n compatSources: readonly CompatSourceDeclaration[] = [],\n): Promise<HookConfig> {\n const merged: HookConfig = {};\n let sawAny = false;\n for (const path of hookConfigCandidates(cwd, compatSources)) {\n if (!existsSync(path)) continue;\n sawAny = true;\n // Stamped at merge, where the file is still known. One line later the commands are pooled per\n // event and every trace of which dialect declared them is gone — which is how a Claude Code\n // command came to be run without Claude Code's runtime (#522).\n mergeInto(merged, stampSource(await readHookFile(path), path));\n }\n if (!sawAny && existsSync(join(theokitConfigRoot(cwd), \"hooks\"))) {\n warnOnce(\n \"hooks-md-unsupported\",\n \"[theokit-sdk] .theokit/hooks/*.md hooks are no longer supported (ADR 0016) — migrate to a Claude-Code-shaped .theokit/hooks.json\",\n );\n }\n return merged;\n}\n\n/**\n * Every file that may declare hooks, in precedence order.\n *\n * `hooks.json` under each project config root, then the Claude Code CLI's own settings files — which\n * is where the CLI actually keeps hooks, so a repository set up for it presents its hooks here\n * without being converted. `settings.local.json` is the CLI's personal-override file and sits beside\n * the shared one rather than replacing it.\n *\n * The shape never needed translating: `parseClaudeCodeConfig` reads the `hooks` key off whatever\n * object it is given, and a settings file is that same object with other keys alongside.\n */\nfunction hookConfigCandidates(\n cwd: string,\n compatSources: readonly CompatSourceDeclaration[],\n): string[] {\n const roots = projectConfigRoots(cwd, compatSources, \"hooks\");\n return [\n ...roots.map((root) => join(root, \"hooks.json\")),\n ...roots.map((root) => join(root, \"settings.json\")),\n ...roots.map((root) => join(root, \"settings.local.json\")),\n ];\n}\n\n/**\n * Record which file each command came from.\n *\n * A command already carrying a `sourcePath` keeps it: nothing produces that today, and a nested\n * config that declared its own origin would be describing something this function cannot see.\n */\nfunction stampSource(config: HookConfig, sourcePath: string): HookConfig {\n if (config.hooks === undefined) return config;\n const hooks: NonNullable<HookConfig[\"hooks\"]> = {};\n for (const [event, commands] of Object.entries(config.hooks) as [\n HookEvent,\n HookCommand[] | undefined,\n ][]) {\n if (commands === undefined) continue;\n hooks[event] = commands.map((c) => ({ sourcePath, ...c }));\n }\n return { hooks };\n}\n\n/**\n * Append one source's commands onto the accumulator, per event.\n *\n * MERGED, not first-wins, and the distinction is deliberate. An agent or a skill is a NAMED\n * declaration: two files claiming one name collide, and the explicit namespace should win. Hooks are\n * unnamed lists — two files declaring `PreToolUse` are two sets of commands an operator wrote, and\n * keeping only one drops the other in silence, which is the failure class this package guards\n * against everywhere else.\n */\nfunction mergeInto(target: HookConfig, source: HookConfig): void {\n for (const [event, commands] of Object.entries(source.hooks ?? {}) as [\n HookEvent,\n HookCommand[] | undefined,\n ][]) {\n if (commands === undefined || commands.length === 0) continue;\n target.hooks ??= {};\n target.hooks[event] = [...(target.hooks[event] ?? []), ...commands];\n }\n}\n\nasync function readHookFile(jsonPath: string): Promise<HookConfig> {\n let raw: string;\n try {\n raw = await readFile(jsonPath, \"utf8\");\n } catch (cause) {\n throw new ConfigurationError(`Failed to read hooks config: ${jsonPath}`, {\n code: \"hooks_read_error\",\n cause,\n });\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (cause) {\n throw new ConfigurationError(`Invalid JSON in hooks config: ${jsonPath}`, {\n code: \"hooks_json_invalid\",\n cause,\n });\n }\n return parseClaudeCodeConfig(parsed, jsonPath);\n}\n\n/**\n * Narrow an unknown to a record, or throw a typed config error.\n *\n * `hint` names the shape that WOULD be accepted, and exists because the message without it names\n * only the validator's expectation. Measured on a consumer in 2026-09: a flat `hooks` array in a\n * `.theokit/settings.json` made this throw on every turn, and `expected an object at \"hooks\"` gave\n * the operator nothing to act on — the file parses fine for the product that wrote it, and it is\n * this independent read of the same path that fails. An error on a refusal path should carry the\n * fix, not the diagnosis.\n */\nfunction asRecord(\n value: unknown,\n path: string,\n where: string,\n hint?: string,\n): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ConfigurationError(\n `hooks: expected an object at ${where} in ${path}${hint === undefined ? \"\" : ` — ${hint}`}`,\n { code: \"hooks_json_invalid\" },\n );\n }\n return value as Record<string, unknown>;\n}\n\n/**\n * The shape this loader accepts, quoted back on the one refusal an operator is most likely to hit:\n * `hooks` keyed by event, each event an array of matcher groups.\n */\nconst HOOKS_SHAPE_HINT =\n 'hooks are keyed by event, e.g. { \"hooks\": { \"PreToolUse\": [ { \"hooks\": ' +\n '[ { \"type\": \"command\", \"command\": \"…\" } ] } ] } }';\n\n/** Narrow an unknown to an array, or throw a typed config error. */\nfunction asArray(value: unknown, path: string, where: string): unknown[] {\n if (!Array.isArray(value)) {\n throw new ConfigurationError(`hooks: expected an array at ${where} in ${path}`, {\n code: \"hooks_json_invalid\",\n });\n }\n return value;\n}\n\n/**\n * Parse Claude Code's nested hooks config into the SDK's flat internal shape:\n * `{ hooks: { PreToolUse: [{ matcher?, hooks: [{ type:\"command\", command, timeout? }] }] } }`\n * → `{ hooks: { preToolUse: [{ command, matcher?, timeoutMs? }] } }`. Each group's\n * `matcher` applies to every command it wraps; `timeout` (seconds) → `timeoutMs`.\n */\nfunction parseClaudeCodeConfig(raw: unknown, path: string): HookConfig {\n const root = asRecord(raw, path, \"the root\");\n if (root.hooks === undefined) return {};\n const hooksRec = asRecord(root.hooks, path, `\"hooks\"`, HOOKS_SHAPE_HINT);\n const grouped: Partial<Record<HookEvent, HookCommand[]>> = {};\n\n for (const [ccEvent, groups] of Object.entries(hooksRec)) {\n const event = CLAUDE_CODE_EVENT_MAP[ccEvent];\n if (event === undefined) {\n warnOnce(\n `hooks-event-${ccEvent}`,\n `[theokit-sdk] hooks: event \"${ccEvent}\" is not fired by the SDK runtime (supported: ${Object.keys(CLAUDE_CODE_EVENT_MAP).join(\", \")}) — skipping`,\n );\n continue;\n }\n grouped[event] = [...(grouped[event] ?? []), ...flattenEventGroups(groups, path, ccEvent)];\n }\n return { hooks: grouped };\n}\n\n/** Flatten one Claude Code event's matcher-groups into internal HookCommands. */\nfunction flattenEventGroups(groups: unknown, path: string, ccEvent: string): HookCommand[] {\n const commands: HookCommand[] = [];\n for (const rawGroup of asArray(groups, path, `hooks.${ccEvent}`)) {\n const group = asRecord(rawGroup, path, `hooks.${ccEvent}[]`);\n const matcher = group.matcher === undefined ? undefined : String(group.matcher);\n for (const rawCmd of asArray(group.hooks, path, `hooks.${ccEvent}[].hooks`)) {\n commands.push(parseClaudeCodeCommand(rawCmd, matcher, path, ccEvent));\n }\n }\n return commands;\n}\n\n/** One `{ type:\"command\", command, timeout? }` entry → an internal HookCommand. */\nfunction parseClaudeCodeCommand(\n raw: unknown,\n matcher: string | undefined,\n path: string,\n ccEvent: string,\n): HookCommand {\n const cmd = asRecord(raw, path, `hooks.${ccEvent}[].hooks[]`);\n if (cmd.type !== \"command\") {\n throw new ConfigurationError(\n `hooks: only { \"type\": \"command\" } is supported (got ${JSON.stringify(cmd.type)}) in ${path}`,\n { code: \"hooks_unsupported_type\" },\n );\n }\n if (typeof cmd.command !== \"string\" || cmd.command.length === 0) {\n throw new ConfigurationError(`hooks: \"command\" must be a non-empty string in ${path}`, {\n code: \"hooks_invalid_command\",\n });\n }\n const hc: HookCommand = { command: cmd.command, sourceEvent: ccEvent };\n if (matcher !== undefined) hc.matcher = matcher;\n if (typeof cmd.timeout === \"number\" && cmd.timeout > 0) {\n hc.timeoutMs = Math.round(cmd.timeout * 1000);\n }\n return hc;\n}\n","/**\n * Personality fork-context (ADR D168 + EC-A snapshot semantic).\n *\n * Uses Node's `AsyncLocalStorage` so a fork's execution chain can know\n * that it is running inside a fork AND can see the slug that was active\n * on the parent **at fork-construction time**.\n *\n * **EC-A:** The slug stored here is captured ONCE at the wrap site\n * (`localAgentFork`) — passing `parentStore.active(parentAgentId)`\n * returns a primitive `string | undefined`, which is then frozen\n * inside the ALS context object. Subsequent `usePersonality` calls on\n * the parent do NOT mutate the fork's view, because the fork reads from\n * its own ALS frame, not from the parent's store.\n *\n * @internal\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\n\nimport { warnOnce } from \"../runtime/hooks/hooks-source.js\";\n\n/**\n * Snapshot data carried into a fork's async context.\n *\n * @internal\n */\nexport interface PersonalityForkContext {\n /** Parent's active personality slug at fork-construction time. */\n readonly slug: string | undefined;\n /** Always `true` inside this scope (used by guards). */\n readonly isFork: true;\n}\n\nconst storage = new AsyncLocalStorage<PersonalityForkContext>();\n\n/**\n * Run `fn` with `ctx` bound as the active fork context. Nested calls\n * shadow the outer context (EC-22).\n *\n * @internal\n */\nexport function withPersonalityContext<T>(\n ctx: PersonalityForkContext,\n fn: () => Promise<T>,\n): Promise<T> {\n return storage.run(ctx, fn);\n}\n\n/**\n * Return the active fork context, or `undefined` when called outside a\n * fork scope.\n *\n * @internal\n */\nexport function currentPersonalityContext(): PersonalityForkContext | undefined {\n return storage.getStore();\n}\n\n/**\n * Emit one warning per agentId stating that personality switches inside\n * a fork are no-ops. The fork inherits the parent snapshot — runtime\n * mutation is intentionally rejected to keep fork voice deterministic.\n *\n * @internal\n */\nexport function warnPersonalitySwitchInsideFork(agentId: string): void {\n warnOnce(\n `personality-switch-in-fork-${agentId}`,\n `[theokit-sdk] usePersonality is a no-op inside a fork (D168). Subagents inherit the parent's active personality at fork-construction time.`,\n );\n}\n"]}
@@ -3,7 +3,7 @@
3
3
  var chunkKVSAY6NZ_cjs = require('./chunk-KVSAY6NZ.cjs');
4
4
  var chunkDZG77WU7_cjs = require('./chunk-DZG77WU7.cjs');
5
5
  var chunkZ2JFX372_cjs = require('./chunk-Z2JFX372.cjs');
6
- var chunk3FDU5JFE_cjs = require('./chunk-3FDU5JFE.cjs');
6
+ var chunkVY6NKMOA_cjs = require('./chunk-VY6NKMOA.cjs');
7
7
  var chunkBV2MWEMV_cjs = require('./chunk-BV2MWEMV.cjs');
8
8
  var chunkD6POWE7E_cjs = require('./chunk-D6POWE7E.cjs');
9
9
  var chunkTMKTSYDS_cjs = require('./chunk-TMKTSYDS.cjs');
@@ -2122,14 +2122,14 @@ async function readState(filePath) {
2122
2122
  try {
2123
2123
  parsed = JSON.parse(raw);
2124
2124
  } catch {
2125
- chunk3FDU5JFE_cjs.warnOnce(
2125
+ chunkVY6NKMOA_cjs.warnOnce(
2126
2126
  "personality-store-json-parse",
2127
2127
  "[theokit-sdk] personality.json is malformed; treating as empty"
2128
2128
  );
2129
2129
  return emptyState();
2130
2130
  }
2131
2131
  if (!isStateV1(parsed)) {
2132
- chunk3FDU5JFE_cjs.warnOnce(
2132
+ chunkVY6NKMOA_cjs.warnOnce(
2133
2133
  "personality-store-bad-version",
2134
2134
  `[theokit-sdk] personality.json has unknown version; treating as empty (file kept untouched)`
2135
2135
  );
@@ -2160,7 +2160,7 @@ var PersonalityStore = class {
2160
2160
  try {
2161
2161
  await this.#persist(agentId, slug);
2162
2162
  } catch (err) {
2163
- chunk3FDU5JFE_cjs.warnOnce(
2163
+ chunkVY6NKMOA_cjs.warnOnce(
2164
2164
  `personality-store-persist-failure-${agentId}`,
2165
2165
  `[theokit-sdk] personality persist failed for ${chunk6LHQPOMI_cjs.redactSecrets(agentId)}: ${chunk6LHQPOMI_cjs.redactSecrets(
2166
2166
  err.message
@@ -2177,7 +2177,7 @@ var PersonalityStore = class {
2177
2177
  try {
2178
2178
  state = await readState(filePath);
2179
2179
  } catch (err) {
2180
- chunk3FDU5JFE_cjs.warnOnce(
2180
+ chunkVY6NKMOA_cjs.warnOnce(
2181
2181
  `personality-store-hydrate-failure-${agentId}`,
2182
2182
  `[theokit-sdk] personality hydrate failed for ${chunk6LHQPOMI_cjs.redactSecrets(agentId)}: ${chunk6LHQPOMI_cjs.redactSecrets(
2183
2183
  err.message
@@ -2617,7 +2617,7 @@ var HooksExecutor = class {
2617
2617
  this.config = {};
2618
2618
  return;
2619
2619
  }
2620
- this.config = await chunk3FDU5JFE_cjs.loadHookConfig(this.cwd, this.compatSources);
2620
+ this.config = await chunkVY6NKMOA_cjs.loadHookConfig(this.cwd, this.compatSources);
2621
2621
  }
2622
2622
  /** Fire every hook registered for `event` and aggregate the decisions. */
2623
2623
  async run(payload) {
@@ -2659,19 +2659,24 @@ var HooksExecutor = class {
2659
2659
  *
2660
2660
  * No gate means no refusal, which is what every consumer gets today.
2661
2661
  */
2662
- async refusedByConsumer(command, payload) {
2662
+ async refusedByConsumer(command, payload, timeoutMs) {
2663
2663
  if (this.gate?.approve === void 0) return false;
2664
2664
  const request = {
2665
2665
  command: command.command,
2666
2666
  event: payload.event,
2667
+ // #637 — the EFFECTIVE timeout, passed in rather than recomputed here, so the number the
2668
+ // consumer is shown and the number `spawnAndCollect` enforces are the same expression.
2669
+ // Recomputing would be one line and would be the place they later diverge.
2670
+ timeoutMs,
2671
+ sourceEvent: command.sourceEvent,
2667
2672
  ...command.sourcePath === void 0 ? {} : { sourcePath: command.sourcePath },
2668
2673
  ...command.matcher === void 0 ? {} : { matcher: command.matcher }
2669
2674
  };
2670
2675
  return !await this.gate.approve(request);
2671
2676
  }
2672
2677
  async executeOne(command, payload) {
2673
- if (await this.refusedByConsumer(command, payload)) return { decision: "allow" };
2674
2678
  const timeoutMs = command.timeoutMs ?? 3e4;
2679
+ if (await this.refusedByConsumer(command, payload, timeoutMs)) return { decision: "allow" };
2675
2680
  const env = runtimeEnvFor(command.sourcePath, this.cwd);
2676
2681
  const result = await spawnAndCollect({
2677
2682
  command: "sh",
@@ -3470,7 +3475,7 @@ var HISTOGRAM_NAMES = {
3470
3475
  };
3471
3476
  function safeRequire(moduleName) {
3472
3477
  try {
3473
- const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-UALC6Q3J.cjs', document.baseURI).href)));
3478
+ const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-UKJJRU7C.cjs', document.baseURI).href)));
3474
3479
  return r(moduleName);
3475
3480
  } catch {
3476
3481
  return void 0;
@@ -3713,7 +3718,7 @@ var cachedOtel;
3713
3718
  function loadOtel() {
3714
3719
  if (cachedOtel === void 0) {
3715
3720
  try {
3716
- const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-UALC6Q3J.cjs', document.baseURI).href)));
3721
+ const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('chunk-UKJJRU7C.cjs', document.baseURI).href)));
3717
3722
  const mod = r("@opentelemetry/api");
3718
3723
  cachedOtel = mod;
3719
3724
  } catch {
@@ -4177,7 +4182,7 @@ async function loadContextConfig(cwd) {
4177
4182
  });
4178
4183
  if (mdEntities.length > 0) {
4179
4184
  if (fs.existsSync(jsonPath)) {
4180
- chunk3FDU5JFE_cjs.warnOnce(
4185
+ chunkVY6NKMOA_cjs.warnOnce(
4181
4186
  "context-both-present",
4182
4187
  "[theokit-sdk] both .theokit/context/ and .theokit/context.json detected \u2014 using markdown; remove context.json"
4183
4188
  );
@@ -4187,7 +4192,7 @@ async function loadContextConfig(cwd) {
4187
4192
  };
4188
4193
  }
4189
4194
  if (!fs.existsSync(jsonPath)) return { sources: [] };
4190
- chunk3FDU5JFE_cjs.warnOnce(
4195
+ chunkVY6NKMOA_cjs.warnOnce(
4191
4196
  "context-json-deprecated",
4192
4197
  // Names no command: `theokit-migrate-config` was unpublished with the `bin` entry, and a warning
4193
4198
  // that tells you to run something the package does not ship is worse than one that tells you
@@ -4350,13 +4355,13 @@ var PluginsManager = class {
4350
4355
  const jsonPath = path.join(pluginsRoot, folderName, "plugin.json");
4351
4356
  const metadata = fs.existsSync(mdPath) ? await loadPluginManifestFromMarkdown(this.cwd, pluginsRoot, folderName) : await loadPluginManifestFromJson(this.cwd, jsonPath, folderName);
4352
4357
  if (fs.existsSync(mdPath) && fs.existsSync(jsonPath)) {
4353
- chunk3FDU5JFE_cjs.warnOnce(
4358
+ chunkVY6NKMOA_cjs.warnOnce(
4354
4359
  `plugin-${folderName}-both`,
4355
4360
  `[theokit-sdk] both ${folderName}/PLUGIN.md and ${folderName}/plugin.json detected \u2014 using markdown; remove plugin.json`
4356
4361
  );
4357
4362
  }
4358
4363
  if (!fs.existsSync(mdPath) && fs.existsSync(jsonPath)) {
4359
- chunk3FDU5JFE_cjs.warnOnce(
4364
+ chunkVY6NKMOA_cjs.warnOnce(
4360
4365
  "plugin-json-deprecated",
4361
4366
  // Same reason as the context.json warning: the CLI it used to name is no longer published.
4362
4367
  "[theokit-sdk] plugin.json manifests are deprecated; replace each with a PLUGIN.md"
@@ -7246,7 +7251,7 @@ function applyPersonalityFilter(exposedTools, whitelist, opts) {
7246
7251
  if (exposedSet.has(name)) continue;
7247
7252
  const hint = suggestClosest(name, exposedSet);
7248
7253
  const message = hint !== void 0 ? `[theokit-sdk] personality "${opts?.personalityName ?? "?"}" references unknown tool "${name}"; did you mean "${hint}"?` : `[theokit-sdk] personality "${opts?.personalityName ?? "?"}" references unknown tool "${name}" (not exposed)`;
7249
- chunk3FDU5JFE_cjs.warnOnce(
7254
+ chunkVY6NKMOA_cjs.warnOnce(
7250
7255
  `personality-tool-missing|${opts?.agentId ?? "?"}|${opts?.personalityName ?? "?"}|${name}`,
7251
7256
  message
7252
7257
  );
@@ -9023,7 +9028,7 @@ function addEntity(byName, entity, origin, collisionMap) {
9023
9028
  );
9024
9029
  }
9025
9030
  if (origin === "project" && collisionMap?.has(fm.name)) {
9026
- chunk3FDU5JFE_cjs.warnOnce(
9031
+ chunkVY6NKMOA_cjs.warnOnce(
9027
9032
  `personality-collision-${fm.name}`,
9028
9033
  `[theokit-sdk] personality "${fm.name}" overridden by project preset`
9029
9034
  );
@@ -9073,14 +9078,14 @@ async function performPersonalitySwitch(args) {
9073
9078
 
9074
9079
  // src/internal/local-agent/local-agent-personality-extensions.ts
9075
9080
  function resolveActivePersonalityPreset(args) {
9076
- const forkCtx = chunk3FDU5JFE_cjs.currentPersonalityContext();
9081
+ const forkCtx = chunkVY6NKMOA_cjs.currentPersonalityContext();
9077
9082
  const slug = forkCtx !== void 0 ? forkCtx.slug : args.personalityStore.active(args.agentId);
9078
9083
  if (slug === void 0) return void 0;
9079
9084
  return args.personalityRegistry?.get(slug);
9080
9085
  }
9081
9086
  async function ensurePersonalityRegistryIfNeeded(args) {
9082
9087
  if (args.personalityRegistry !== void 0) return args.personalityRegistry;
9083
- const forkSlug = chunk3FDU5JFE_cjs.currentPersonalityContext()?.slug;
9088
+ const forkSlug = chunkVY6NKMOA_cjs.currentPersonalityContext()?.slug;
9084
9089
  const ownSlug = args.personalityStore.active(args.agentId);
9085
9090
  if (forkSlug === void 0 && ownSlug === void 0) return void 0;
9086
9091
  return await PersonalityRegistry.load(args.workspaceCwd);
@@ -9093,8 +9098,8 @@ function applyPersonalityOverlay(preset, base) {
9093
9098
  ${preset.systemPrompt}`;
9094
9099
  }
9095
9100
  async function localAgentUsePersonality(agent, name, opts) {
9096
- if (chunk3FDU5JFE_cjs.currentPersonalityContext() !== void 0) {
9097
- chunk3FDU5JFE_cjs.warnPersonalitySwitchInsideFork(agent.agentId);
9101
+ if (chunkVY6NKMOA_cjs.currentPersonalityContext() !== void 0) {
9102
+ chunkVY6NKMOA_cjs.warnPersonalitySwitchInsideFork(agent.agentId);
9098
9103
  return null;
9099
9104
  }
9100
9105
  if (agent.personalityRegistry === void 0) {
@@ -9155,7 +9160,7 @@ async function* localAgentStreamToCompletion(agent, message, options) {
9155
9160
  async function localAgentFork(parent, options) {
9156
9161
  const { forkAgentImpl } = await import('./fork-agent-WAEQI2DL.cjs');
9157
9162
  const { getAgentFacade } = await import('./agent-factory-registry-UU46BUMU.cjs');
9158
- const { withPersonalityContext } = await import('./context-4AIK26QB.cjs');
9163
+ const { withPersonalityContext } = await import('./context-JTGSBJT6.cjs');
9159
9164
  const create = getAgentFacade().create;
9160
9165
  return withPersonalityContext(
9161
9166
  { slug: parent.personalitySlugSnapshot, isFork: true },
@@ -11050,5 +11055,5 @@ exports.generateCronId = generateCronId;
11050
11055
  exports.getPricingEntry = getPricingEntry;
11051
11056
  exports.openRouterMemoryEmbeddingProviderAdapter = openRouterMemoryEmbeddingProviderAdapter;
11052
11057
  exports.resolveSessionDir = resolveSessionDir;
11053
- //# sourceMappingURL=chunk-UALC6Q3J.cjs.map
11054
- //# sourceMappingURL=chunk-UALC6Q3J.cjs.map
11058
+ //# sourceMappingURL=chunk-UKJJRU7C.cjs.map
11059
+ //# sourceMappingURL=chunk-UKJJRU7C.cjs.map