@theokit/sdk 4.57.0 → 4.58.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/CHANGELOG.md +99 -0
  2. package/dist/{agent-ZIYCVEZL.js → agent-6WM4QOWS.js} +10 -9
  3. package/dist/{agent-ZIYCVEZL.js.map → agent-6WM4QOWS.js.map} +1 -1
  4. package/dist/{agent-2T2EJIP6.cjs → agent-MIYY7TXV.cjs} +11 -10
  5. package/dist/{agent-2T2EJIP6.cjs.map → agent-MIYY7TXV.cjs.map} +1 -1
  6. package/dist/{chunk-E7JHD6QJ.cjs → chunk-27AXGJMV.cjs} +25 -15
  7. package/dist/chunk-27AXGJMV.cjs.map +1 -0
  8. package/dist/{chunk-LEM2GOMI.js → chunk-5QOIQJ5J.js} +3 -3
  9. package/dist/{chunk-LEM2GOMI.js.map → chunk-5QOIQJ5J.js.map} +1 -1
  10. package/dist/{chunk-E3WZ6Y4H.cjs → chunk-7BG5UH3T.cjs} +8 -8
  11. package/dist/{chunk-E3WZ6Y4H.cjs.map → chunk-7BG5UH3T.cjs.map} +1 -1
  12. package/dist/chunk-AQO3NSRG.cjs +41 -0
  13. package/dist/chunk-AQO3NSRG.cjs.map +1 -0
  14. package/dist/{chunk-7TCRNXNK.js → chunk-CF5OMCZG.js} +40 -16
  15. package/dist/chunk-CF5OMCZG.js.map +1 -0
  16. package/dist/{chunk-U2AC6JUP.cjs → chunk-J2UROOIG.cjs} +2 -27
  17. package/dist/chunk-J2UROOIG.cjs.map +1 -0
  18. package/dist/{chunk-ZNW6V4Y6.cjs → chunk-LKFET5A3.cjs} +23 -2
  19. package/dist/chunk-LKFET5A3.cjs.map +1 -0
  20. package/dist/{chunk-YMA4S2WO.js → chunk-MZ2FGBLZ.js} +33 -11
  21. package/dist/chunk-MZ2FGBLZ.js.map +1 -0
  22. package/dist/{chunk-M2JWHKO6.cjs → chunk-N47KLTKD.cjs} +76 -52
  23. package/dist/chunk-N47KLTKD.cjs.map +1 -0
  24. package/dist/{chunk-53CBTBWO.cjs → chunk-P6H23T43.cjs} +33 -11
  25. package/dist/chunk-P6H23T43.cjs.map +1 -0
  26. package/dist/{chunk-X7O4255I.cjs → chunk-QIRDQZYL.cjs} +4 -4
  27. package/dist/{chunk-X7O4255I.cjs.map → chunk-QIRDQZYL.cjs.map} +1 -1
  28. package/dist/{chunk-7FHZ4VQX.js → chunk-SAVIWMZB.js} +3 -3
  29. package/dist/{chunk-7FHZ4VQX.js.map → chunk-SAVIWMZB.js.map} +1 -1
  30. package/dist/{chunk-UPRJR6IP.js → chunk-UCBJBJ27.js} +3 -25
  31. package/dist/chunk-UCBJBJ27.js.map +1 -0
  32. package/dist/chunk-UFLD2HEV.js +35 -0
  33. package/dist/chunk-UFLD2HEV.js.map +1 -0
  34. package/dist/{chunk-GTKFV7O5.js → chunk-WFC26L6Y.js} +23 -2
  35. package/dist/chunk-WFC26L6Y.js.map +1 -0
  36. package/dist/{chunk-G6EEYRDD.js → chunk-WLZ7XRWH.js} +24 -14
  37. package/dist/chunk-WLZ7XRWH.js.map +1 -0
  38. package/dist/{chunk-HJBMA5MB.cjs → chunk-WNTAPVU5.cjs} +47 -6
  39. package/dist/chunk-WNTAPVU5.cjs.map +1 -0
  40. package/dist/{chunk-2QKTVKH3.js → chunk-ZHPWGIUX.js} +48 -8
  41. package/dist/chunk-ZHPWGIUX.js.map +1 -0
  42. package/dist/context/index.cjs +7 -7
  43. package/dist/context/index.js +3 -3
  44. package/dist/{context-VMIE4BMD.cjs → context-LCKNH2XI.cjs} +7 -6
  45. package/dist/{context-VMIE4BMD.cjs.map → context-LCKNH2XI.cjs.map} +1 -1
  46. package/dist/context-MZSKGKYR.js +7 -0
  47. package/dist/{context-FDOON2DB.js.map → context-MZSKGKYR.js.map} +1 -1
  48. package/dist/cron.cjs +10 -9
  49. package/dist/cron.js +9 -8
  50. package/dist/eval.cjs +9 -8
  51. package/dist/eval.cjs.map +1 -1
  52. package/dist/eval.js +8 -7
  53. package/dist/eval.js.map +1 -1
  54. package/dist/{index-manager-AO4LJQZ4.cjs → index-manager-J2QIDI6I.cjs} +5 -4
  55. package/dist/{index-manager-AO4LJQZ4.cjs.map → index-manager-J2QIDI6I.cjs.map} +1 -1
  56. package/dist/{index-manager-QDPIYIGV.js → index-manager-WYESAVTX.js} +4 -3
  57. package/dist/{index-manager-QDPIYIGV.js.map → index-manager-WYESAVTX.js.map} +1 -1
  58. package/dist/index.cjs +32 -33
  59. package/dist/index.cjs.map +1 -1
  60. package/dist/index.d.cts +1 -1
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.js +12 -13
  63. package/dist/index.js.map +1 -1
  64. package/dist/internal/memory/storage/markdown-store.d.ts +13 -0
  65. package/dist/internal/persistence/index.cjs +17 -16
  66. package/dist/internal/persistence/index.cjs.map +1 -1
  67. package/dist/internal/persistence/index.js +2 -1
  68. package/dist/internal/persistence/index.js.map +1 -1
  69. package/dist/internal/persistence/paths.d.cts +42 -0
  70. package/dist/internal/persistence/paths.d.ts +42 -0
  71. package/dist/internal/runtime/plugins/plugin-bundles.d.ts +19 -0
  72. package/dist/project.cjs +3 -3
  73. package/dist/project.js +1 -1
  74. package/dist/subagents-loader-6ATCDEKN.js +8 -0
  75. package/dist/{subagents-loader-J54ESLDV.js.map → subagents-loader-6ATCDEKN.js.map} +1 -1
  76. package/dist/subagents-loader-X5QKODCL.cjs +17 -0
  77. package/dist/{subagents-loader-AZIXJ7D3.cjs.map → subagents-loader-X5QKODCL.cjs.map} +1 -1
  78. package/dist/subagents-loader.cjs +3 -2
  79. package/dist/subagents-loader.cjs.map +1 -1
  80. package/dist/subagents-loader.js +2 -1
  81. package/dist/subagents-loader.js.map +1 -1
  82. package/docs/error-codes.md +15 -15
  83. package/package.json +1 -1
  84. package/dist/chunk-2QKTVKH3.js.map +0 -1
  85. package/dist/chunk-53CBTBWO.cjs.map +0 -1
  86. package/dist/chunk-7TCRNXNK.js.map +0 -1
  87. package/dist/chunk-E7JHD6QJ.cjs.map +0 -1
  88. package/dist/chunk-G6EEYRDD.js.map +0 -1
  89. package/dist/chunk-GTKFV7O5.js.map +0 -1
  90. package/dist/chunk-HJBMA5MB.cjs.map +0 -1
  91. package/dist/chunk-M2JWHKO6.cjs.map +0 -1
  92. package/dist/chunk-U2AC6JUP.cjs.map +0 -1
  93. package/dist/chunk-UPRJR6IP.js.map +0 -1
  94. package/dist/chunk-YMA4S2WO.js.map +0 -1
  95. package/dist/chunk-ZNW6V4Y6.cjs.map +0 -1
  96. package/dist/context-FDOON2DB.js +0 -6
  97. package/dist/subagents-loader-AZIXJ7D3.cjs +0 -16
  98. package/dist/subagents-loader-J54ESLDV.js +0 -7
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var chunkAQO3NSRG_cjs = require('./chunk-AQO3NSRG.cjs');
3
4
  var chunkK3FW2XZD_cjs = require('./chunk-K3FW2XZD.cjs');
4
5
  var chunkNUKRL3I6_cjs = require('./chunk-NUKRL3I6.cjs');
5
6
  var async_hooks = require('async_hooks');
@@ -21,16 +22,37 @@ function warnOnce(key, message) {
21
22
  `);
22
23
  }
23
24
  async function loadHookConfig(cwd) {
24
- const jsonPath = path.join(cwd, ".theokit", "hooks.json");
25
- if (!fs.existsSync(jsonPath)) {
26
- if (fs.existsSync(path.join(cwd, ".theokit", "hooks"))) {
27
- warnOnce(
28
- "hooks-md-unsupported",
29
- "[theokit-sdk] .theokit/hooks/*.md hooks are no longer supported (ADR 0016) \u2014 migrate to a Claude-Code-shaped .theokit/hooks.json"
30
- );
31
- }
32
- return {};
25
+ const merged = {};
26
+ let sawAny = false;
27
+ for (const path of hookConfigCandidates(cwd)) {
28
+ if (!fs.existsSync(path)) continue;
29
+ sawAny = true;
30
+ mergeInto(merged, await readHookFile(path));
31
+ }
32
+ if (!sawAny && fs.existsSync(path.join(cwd, ".theokit", "hooks"))) {
33
+ warnOnce(
34
+ "hooks-md-unsupported",
35
+ "[theokit-sdk] .theokit/hooks/*.md hooks are no longer supported (ADR 0016) \u2014 migrate to a Claude-Code-shaped .theokit/hooks.json"
36
+ );
33
37
  }
38
+ return merged;
39
+ }
40
+ function hookConfigCandidates(cwd) {
41
+ const roots = chunkAQO3NSRG_cjs.projectConfigRoots(cwd);
42
+ return [
43
+ ...roots.map((root) => path.join(root, "hooks.json")),
44
+ ...roots.map((root) => path.join(root, "settings.json")),
45
+ ...roots.map((root) => path.join(root, "settings.local.json"))
46
+ ];
47
+ }
48
+ function mergeInto(target, source) {
49
+ for (const [event, commands] of Object.entries(source.hooks ?? {})) {
50
+ if (commands === void 0 || commands.length === 0) continue;
51
+ target.hooks ??= {};
52
+ target.hooks[event] = [...target.hooks[event] ?? [], ...commands];
53
+ }
54
+ }
55
+ async function readHookFile(jsonPath) {
34
56
  let raw;
35
57
  try {
36
58
  raw = await promises.readFile(jsonPath, "utf8");
@@ -137,5 +159,5 @@ exports.loadHookConfig = loadHookConfig;
137
159
  exports.warnOnce = warnOnce;
138
160
  exports.warnPersonalitySwitchInsideFork = warnPersonalitySwitchInsideFork;
139
161
  exports.withPersonalityContext = withPersonalityContext;
140
- //# sourceMappingURL=chunk-53CBTBWO.cjs.map
141
- //# sourceMappingURL=chunk-53CBTBWO.cjs.map
162
+ //# sourceMappingURL=chunk-P6H23T43.cjs.map
163
+ //# sourceMappingURL=chunk-P6H23T43.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/internal/runtime/hooks/hooks-source.ts","../src/internal/personality/context.ts"],"names":["diag","existsSync","join","projectConfigRoots","readFile","ConfigurationError","AsyncLocalStorage"],"mappings":"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","file":"chunk-P6H23T43.cjs","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 } from \"../../persistence/paths.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\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(cwd: string): Promise<HookConfig> {\n const merged: HookConfig = {};\n let sawAny = false;\n for (const path of hookConfigCandidates(cwd)) {\n if (!existsSync(path)) continue;\n sawAny = true;\n mergeInto(merged, await readHookFile(path));\n }\n if (!sawAny && existsSync(join(cwd, \".theokit\", \"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(cwd: string): string[] {\n const roots = projectConfigRoots(cwd);\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 * 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/** Narrow an unknown to a record, or throw a typed config error. */\nfunction asRecord(value: unknown, path: string, where: string): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new ConfigurationError(`hooks: expected an object at ${where} in ${path}`, {\n code: \"hooks_json_invalid\",\n });\n }\n return value as Record<string, unknown>;\n}\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\"`);\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 };\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"]}
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkM2JWHKO6_cjs = require('./chunk-M2JWHKO6.cjs');
3
+ var chunkN47KLTKD_cjs = require('./chunk-N47KLTKD.cjs');
4
4
  var chunkNGESVVJN_cjs = require('./chunk-NGESVVJN.cjs');
5
5
  var chunkNINIJCHU_cjs = require('./chunk-NINIJCHU.cjs');
6
6
  var chunkK3FW2XZD_cjs = require('./chunk-K3FW2XZD.cjs');
@@ -377,7 +377,7 @@ async function createCronJob(options) {
377
377
  const runtime = detectRuntime(options);
378
378
  const now = Date.now();
379
379
  const job = {
380
- id: chunkM2JWHKO6_cjs.generateCronId(),
380
+ id: chunkN47KLTKD_cjs.generateCronId(),
381
381
  cron: options.cron,
382
382
  timezone,
383
383
  enabled: options.enabled ?? true,
@@ -454,5 +454,5 @@ async function updateJobStatus(jobId, enabled) {
454
454
  }
455
455
 
456
456
  exports.Cron = Cron;
457
- //# sourceMappingURL=chunk-X7O4255I.cjs.map
458
- //# sourceMappingURL=chunk-X7O4255I.cjs.map
457
+ //# sourceMappingURL=chunk-QIRDQZYL.cjs.map
458
+ //# sourceMappingURL=chunk-QIRDQZYL.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/cron/run-job.ts","../src/internal/cron/fire-handler.ts","../src/internal/cron/store.ts","../src/internal/cron/scheduler.ts","../src/internal/cron/validate.ts","../src/cron.ts"],"names":["ConfigurationError","getAgentFacade","UnknownAgentError","submit","Croner","resolveApiKey","generateCronId"],"mappings":"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","file":"chunk-X7O4255I.cjs","sourcesContent":["import { ConfigurationError, UnknownAgentError } from \"../../errors.js\";\nimport type { AgentOptions } from \"../../types/agent.js\";\nimport type { CronJob } from \"../../types/cron.js\";\nimport type { Run, SDKUserMessage } from \"../../types/run.js\";\nimport type { WorkflowRun } from \"../../types/workflow.js\";\nimport { getAgentFacade } from \"../runtime/registry/agent-factory-registry.js\";\n\n/**\n * Execute a cron job. Dispatches to one of three targets:\n * - `workflow` (SE35) → `workflow.run(inputData)` on the held instance (the\n * instance carries its own `.run`, so this module never imports `workflow.ts`),\n * returning the already-terminal {@link WorkflowRun}.\n * - `agent` → an ephemeral agent per fire; `agent.send(message)` → {@link Run}.\n * - `agentId` → reuse an existing agent; `agent.send(message)` → {@link Run}.\n *\n * Used by both `Cron.run(jobId)` (manual off-schedule fire) and the scheduler's\n * default fire handler. ADR 0014.\n *\n * @internal\n */\nexport async function runCronJob(job: CronJob): Promise<Run | WorkflowRun> {\n // `Workflow.run()` resolves only on a TERMINAL run (completed/failed/suspended/\n // cancelled — the executor never returns `status: \"running\"`), so the fire\n // handler treats the returned WorkflowRun as terminal (no `.wait()`).\n if (job.workflow !== undefined) return job.workflow.run(job.inputData);\n if (job.agent !== undefined) return runWithEphemeralAgent(job.agent, requireMessage(job));\n if (job.agentId !== undefined) return runWithExistingAgent(job.agentId, requireMessage(job));\n throw new ConfigurationError(\n `Cron job ${job.id} has no target (agent, agentId, or workflow) — cannot run.`,\n { code: \"cron_no_target\" },\n );\n}\n\n/**\n * Discriminate the {@link runCronJob} union: an agent `Run` is deferred (carries\n * `.wait()`/`.cancel()`); a {@link WorkflowRun} is already terminal (no `.wait()`).\n * @internal\n */\nexport function isAgentRun(outcome: Run | WorkflowRun): outcome is Run {\n return typeof (outcome as Run).wait === \"function\";\n}\n\n/** Agent targets require a message; fail-loud if one somehow reached a fire without it. */\nfunction requireMessage(job: CronJob): string | SDKUserMessage {\n if (job.message === undefined) {\n throw new ConfigurationError(`Cron job ${job.id} is an agent target but has no message.`, {\n code: \"cron_missing_message\",\n });\n }\n return job.message;\n}\n\nasync function runWithExistingAgent(\n agentId: string,\n message: string | SDKUserMessage,\n): Promise<Run> {\n const info = await getAgentFacade()\n .get(agentId)\n .catch(() => undefined);\n if (info === undefined) {\n throw new UnknownAgentError(\n `Cron job references agentId \"${agentId}\" but no such agent is registered. The agent may have been disposed or the process restarted without persisting the agent registry.`,\n { code: \"agent_not_registered\" },\n );\n }\n const agent = await getAgentFacade().resume(agentId);\n return agent.send(message);\n}\n\nasync function runWithEphemeralAgent(\n baseOptions: AgentOptions,\n message: string | SDKUserMessage,\n): Promise<Run> {\n const agent = await getAgentFacade().create(baseOptions);\n return agent.send(message);\n}\n","/**\n * Default cron fire handler (extracted from `Cron.start` for testability + G8).\n *\n * Every fire registers as a Task (ADRs D363/D374) so callers observe it via\n * `Task.list` / `Task.subscribe`. SE35 (ADR 0014): the fire target may be an\n * agent (a deferred {@link Run} — abort-wire + `wait()`) OR a workflow (an\n * already-terminal {@link WorkflowRun} — no `wait()`); `isAgentRun` discriminates\n * so the handler records the correct terminal status/runId for each shape.\n *\n * @internal\n */\n\nimport type { CronJob } from \"../../types/cron.js\";\nimport { submit as taskRegistrySubmit } from \"../task/registry.js\";\nimport { isAgentRun, runCronJob } from \"./run-job.js\";\n\nexport async function fireCronJobAsTask(job: CronJob): Promise<void> {\n // The task id namespace `cron-{jobId}-{fireEpochMs}` honors D368/EC-5.\n const fireTs = Date.now();\n const taskId = `cron-${job.id}-${fireTs}`;\n try {\n await taskRegistrySubmit({\n kind: \"cron\",\n id: taskId,\n allowReservedPrefix: true,\n meta: { jobId: job.id, jobName: job.name, schedule: job.cron, firedAt: fireTs },\n work: async (ctx) => {\n const outcome = await runCronJob(job);\n if (isAgentRun(outcome)) {\n // Agent target — the Run is deferred: abort-wire + await terminal.\n ctx.signal.addEventListener(\"abort\", () => void outcome.cancel().catch(() => {}), {\n once: true,\n });\n const result = await outcome.wait();\n ctx.emit({ status: result.status, runId: outcome.id });\n return { status: result.status, runId: outcome.id };\n }\n // SE35 workflow target — the WorkflowRun is ALREADY terminal (no wait()).\n ctx.emit({ status: outcome.status, runId: outcome.id });\n return { status: outcome.status, runId: outcome.id };\n },\n });\n } catch {\n // Task registry must not break cron — fall through to a direct run. No\n // double-execution: `taskRegistrySubmit` runs `work` (which calls\n // `runCronJob`) fire-and-forget, so a throw here means the SUBMIT itself\n // failed (id/registry setup) BEFORE `work` started — the job never ran, and\n // this is its first + only execution.\n const outcome = await runCronJob(job);\n if (isAgentRun(outcome)) await outcome.wait();\n }\n}\n","import type { CronJob } from \"../../types/cron.js\";\n\n/**\n * Process-wide cron job store. In Phase 1 we keep all jobs in memory\n * (across local + cloud runtimes). Local-runtime persistence to\n * `.theokit/cron/jobs.json` lands when the local runtime adapter is wired.\n *\n * @internal\n */\nconst jobs = new Map<string, CronJob>();\n\n/** Snapshot of every known cron job. @internal */\nexport function listJobs(): CronJob[] {\n return Array.from(jobs.values());\n}\n\n/** Total job count across runtimes. @internal */\nexport function jobCount(): number {\n return jobs.size;\n}\n\n/** Fetch a single job by id, or `undefined` if it does not exist. @internal */\nexport function getJob(jobId: string): CronJob | undefined {\n return jobs.get(jobId);\n}\n\n/** Insert or replace a job. @internal */\nexport function upsertJob(job: CronJob): void {\n jobs.set(job.id, job);\n}\n\n/** Delete a job. Returns `true` if a job was removed. @internal */\nexport function deleteJob(jobId: string): boolean {\n return jobs.delete(jobId);\n}\n\n/** Test-only: drop every job. @internal */\nexport function clearJobs(): void {\n jobs.clear();\n}\n","import { Cron as Croner } from \"croner\";\n\nimport type { CronJob } from \"../../types/cron.js\";\nimport { listJobs, upsertJob } from \"./store.js\";\n\n/**\n * Real local cron scheduler. When `Cron.start()` is called the scheduler\n * installs a Croner timer per enabled local job; on fire the registered\n * fire handler runs the underlying agent. `Cron.stop()` tears every timer\n * down but keeps the jobs in the store.\n *\n * @internal\n */\n\nexport type CronFireHandler = (job: CronJob) => Promise<void> | void;\n\ninterface SchedulerState {\n running: boolean;\n cwd?: string;\n timers: Map<string, Croner>;\n fireHandler?: CronFireHandler;\n}\n\nconst state: SchedulerState = { running: false, timers: new Map() };\n\n/**\n * Register the callback invoked when a job fires. The runtime adapter\n * supplies a handler that actually executes the agent; fixture-mode tests\n * leave it unset so timers tick without side effects.\n *\n * @internal\n */\nexport function setCronFireHandler(handler: CronFireHandler | undefined): void {\n state.fireHandler = handler;\n}\n\n/** Activate the scheduler and install timers for every enabled local job. @internal */\nexport function startScheduler(cwd?: string): void {\n state.running = true;\n if (cwd !== undefined) state.cwd = cwd;\n for (const job of listJobs()) {\n if (job.runtime === \"local\" && job.enabled !== false) scheduleJob(job);\n }\n}\n\n/** Deactivate the scheduler. Stops every timer; jobs remain in the store. @internal */\nexport function stopScheduler(): void {\n state.running = false;\n for (const timer of state.timers.values()) timer.stop();\n state.timers.clear();\n}\n\n/** Schedule a single job. No-op if the scheduler is not running. @internal */\nexport function scheduleJob(job: CronJob): void {\n if (!state.running) return;\n unscheduleJob(job.id);\n const expression = normalizeExpression(job.cron);\n const timer = new Croner(\n expression,\n { timezone: job.timezone, name: job.id, protect: true },\n () => {\n void fireJob(job.id);\n },\n );\n state.timers.set(job.id, timer);\n refreshNextRunAt(job.id, timer);\n}\n\n/** Tear down the timer for a single job. @internal */\nexport function unscheduleJob(jobId: string): boolean {\n const timer = state.timers.get(jobId);\n if (timer === undefined) return false;\n timer.stop();\n state.timers.delete(jobId);\n return true;\n}\n\n/** Snapshot of the scheduler's running flag and configured workspace. @internal */\nexport function getSchedulerState(): { running: boolean; cwd?: string } {\n const result: { running: boolean; cwd?: string } = { running: state.running };\n if (state.cwd !== undefined) result.cwd = state.cwd;\n return result;\n}\n\nasync function fireJob(jobId: string): Promise<void> {\n const fresh = listJobs().find((entry) => entry.id === jobId);\n if (fresh === undefined || fresh.enabled === false) return;\n const handler = state.fireHandler;\n upsertJob({ ...fresh, lastRunAt: Date.now() });\n if (handler === undefined) return;\n try {\n await handler(fresh);\n } catch {\n // Swallow handler errors — the scheduler must keep ticking. Real\n // surface for run failures lives on the Run.wait() result itself.\n }\n}\n\nfunction refreshNextRunAt(jobId: string, timer: Croner): void {\n const next = timer.nextRun();\n if (next === null) return;\n const existing = listJobs().find((entry) => entry.id === jobId);\n if (existing === undefined) return;\n upsertJob({ ...existing, nextRunAt: next.getTime() });\n}\n\nfunction normalizeExpression(cron: string): string {\n switch (cron) {\n case \"@hourly\":\n return \"0 * * * *\";\n case \"@daily\":\n return \"0 0 * * *\";\n case \"@weekly\":\n return \"0 0 * * 0\";\n case \"@monthly\":\n return \"0 0 1 * *\";\n case \"@yearly\":\n return \"0 0 1 1 *\";\n default:\n return cron;\n }\n}\n","import { ConfigurationError } from \"../../errors.js\";\n\n/**\n * POSIX-cron + shorthand validators used by `Cron.create()`. Throws\n * `ConfigurationError` with a stable message and code on invalid input.\n *\n * @internal\n */\n\nconst SHORTHANDS = new Set([\"@hourly\", \"@daily\", \"@weekly\", \"@monthly\", \"@yearly\"]);\n\ninterface FieldRange {\n min: number;\n max: number;\n}\n\nconst FIELD_RANGES: readonly FieldRange[] = [\n { min: 0, max: 59 }, // minute\n { min: 0, max: 23 }, // hour\n { min: 1, max: 31 }, // day-of-month\n { min: 1, max: 12 }, // month\n { min: 0, max: 6 }, // day-of-week\n];\n\n/**\n * Validate a cron expression. Accepts shorthand (`@hourly`, ..., `@yearly`)\n * or 5-field POSIX cron with star, literals, star/N step, N-M range, and\n * N,M,P list.\n *\n * @internal\n */\nexport function validateCronExpression(cron: string): void {\n if (typeof cron !== \"string\" || cron.length === 0) {\n throw new ConfigurationError(\"Invalid cron expression: empty\", {\n code: \"invalid_cron\",\n });\n }\n if (cron.startsWith(\"@\")) {\n if (!SHORTHANDS.has(cron)) {\n throw new ConfigurationError(`Invalid cron expression: unknown shorthand ${cron}`, {\n code: \"invalid_cron\",\n });\n }\n return;\n }\n\n const fields = cron.trim().split(/\\s+/);\n if (fields.length !== FIELD_RANGES.length) {\n throw new ConfigurationError(\n `Invalid cron expression: ${cron} (expected ${FIELD_RANGES.length} fields, got ${fields.length})`,\n { code: \"invalid_cron\" },\n );\n }\n for (const [index, range] of FIELD_RANGES.entries()) {\n // The length check above already established one field per range, so the lookup is total.\n // B-116: this replaces a `range === undefined` guard that no caller could reach — its single\n // caller only ran with exactly 5 fields, and FIELD_RANGES has exactly 5 entries, so the branch\n // stayed at 0 executions through 37 tests written specifically to enter it.\n const field = fields[index] as string;\n if (!isValidCronField(field, range)) {\n throw new ConfigurationError(`Invalid cron expression: ${cron} (field ${index + 1})`, {\n code: \"invalid_cron\",\n });\n }\n }\n}\n\nfunction isValidCronField(field: string, range: FieldRange): boolean {\n if (field === \"*\") return true;\n if (field.startsWith(\"*/\")) return isValidStep(field.slice(2), range);\n if (field.includes(\",\")) {\n return field.split(\",\").every((part) => isValidCronField(part, range));\n }\n if (field.includes(\"-\")) return isValidRange(field, range);\n return isValidLiteral(field, range);\n}\n\n/**\n * Digits, and nothing else. `Number.parseInt` stops at the first non-digit, so it reads `\"5abc\"` as\n * `5` and `\"0x5\"` as `0` — a numeric field parsed that way accepts garbage that happens to start\n * with a digit.\n *\n * This replaces the `String(n) === field` round-trip the literal and step validators used to carry.\n * The round-trip refused the garbage correctly but also refused `\"07\"`, because `String(7) !== \"07\"`\n * — and `isValidRange` never had it at all, so `\"1-5abc\"` was accepted while `\"5abc\"` was refused\n * (B-121). One predicate, applied to every field shape, closes both halves.\n *\n * The boundary that matters is croner 9, the scheduler this SDK actually fires jobs with. Measured\n * 2026-08-19: it ACCEPTS `\"07 * * * *\"` (next run at :07) and REFUSES `\"5abc\"`, `\"1-5abc\"`,\n * `\"1abc-5\"`, `\"0x5\"`, `\"5.9\"`, `\"+5\"` and `\"1e1\"` as \"illegal character\" (B-122). Validating\n * stricter than the engine rejects schedules that would have run; validating looser only moves the\n * failure from `Cron.create()` to fire time, where nobody is watching.\n *\n * @internal\n */\nconst DIGITS_ONLY = /^\\d+$/;\n\nfunction parseFieldNumber(text: string): number | undefined {\n if (!DIGITS_ONLY.test(text)) return undefined;\n return Number.parseInt(text, 10);\n}\n\nfunction isValidStep(stepStr: string, range: FieldRange): boolean {\n const step = parseFieldNumber(stepStr);\n return step !== undefined && step > 0 && step <= range.max;\n}\n\nfunction isValidRange(field: string, range: FieldRange): boolean {\n const parts = field.split(\"-\");\n if (parts.length !== 2) return false;\n const [startStr, endStr] = parts;\n if (startStr === undefined || endStr === undefined) return false;\n const start = parseFieldNumber(startStr);\n const end = parseFieldNumber(endStr);\n if (start === undefined || end === undefined) return false;\n return start >= range.min && end <= range.max && start <= end;\n}\n\nfunction isValidLiteral(field: string, range: FieldRange): boolean {\n const n = parseFieldNumber(field);\n return n !== undefined && n >= range.min && n <= range.max;\n}\n\n/**\n * Validate an IANA timezone. Uses `Intl.DateTimeFormat`'s strict timezone\n * lookup; invalid values raise `RangeError` which we wrap.\n *\n * @internal\n */\nexport function validateTimezone(timezone: string): void {\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: timezone });\n } catch {\n throw new ConfigurationError(`Invalid IANA timezone: ${timezone}`, {\n code: \"invalid_timezone\",\n });\n }\n}\n\n/**\n * Heuristic next-fire-at estimator for fixture mode. Returns a timestamp\n * one hour in the future for shorthand/POSIX inputs. Real scheduling uses\n * a proper evaluator wired in by the local scheduler.\n *\n * @internal\n */\nexport function estimateNextRunAt(_cron: string, _timezone: string): number {\n return Date.now() + 60 * 60 * 1000;\n}\n","// Bootstrap import: loading this facade must register the public Agent facade\n// into the agent-factory-registry seam, because `internal/cron/run-job.ts`\n// resolves it via `getAgentFacade()` at runtime instead of importing `agent.ts`\n// directly (which would invert the public-api -> internal dependency\n// direction). The `@theokit/sdk/cron` sub-path entry would otherwise throw\n// \"Agent facade not registered\" at runtime.\nimport \"./agent.js\";\nimport { ConfigurationError, UnknownAgentError } from \"./errors.js\";\nimport { fireCronJobAsTask } from \"./internal/cron/fire-handler.js\";\nimport { runCronJob } from \"./internal/cron/run-job.js\";\nimport {\n getSchedulerState,\n scheduleJob,\n setCronFireHandler,\n startScheduler,\n stopScheduler,\n unscheduleJob,\n} from \"./internal/cron/scheduler.js\";\nimport { deleteJob, getJob, jobCount, listJobs, upsertJob } from \"./internal/cron/store.js\";\nimport {\n estimateNextRunAt,\n validateCronExpression,\n validateTimezone,\n} from \"./internal/cron/validate.js\";\nimport { resolveApiKey } from \"./internal/env.js\";\nimport { generateCronId } from \"./internal/ids.js\";\nimport type { AgentOptions, ListResult } from \"./types/agent.js\";\nimport type {\n CronCreateOptions,\n CronGetOptions,\n CronJob,\n CronListOptions,\n CronOperationOptions,\n CronRunOptions,\n CronRuntime,\n CronSchedulerStatus,\n CronStartOptions,\n} from \"./types/cron.js\";\nimport type { Run } from \"./types/run.js\";\n\n/**\n * Static façade for scheduling Theo agent runs on a cron expression.\n *\n * @public\n */\nexport class Cron {\n private constructor() {\n // Static-only façade.\n }\n\n /**\n * Create and persist a cron job.\n *\n * @public\n */\n static async create(options: CronCreateOptions): Promise<CronJob> {\n const job = await createCronJob(options);\n if (job.runtime === \"local\" && job.enabled !== false) scheduleJob(job);\n return job;\n }\n\n /**\n * List cron jobs (local, cloud, or both).\n *\n * @public\n */\n static list(options: CronListOptions = {}): Promise<ListResult<CronJob>> {\n const runtimeFilter = options.runtime;\n const items = listJobs().filter((job) =>\n runtimeFilter === undefined ? true : job.runtime === runtimeFilter,\n );\n return Promise.resolve({ items });\n }\n\n /**\n * Get a single cron job by ID.\n *\n * @public\n */\n static get(jobId: string, _options: CronGetOptions = {}): Promise<CronJob> {\n const job = getJob(jobId);\n if (job === undefined) {\n return Promise.reject(\n new UnknownAgentError(`Cron job ${jobId} not found`, { code: \"unknown_cron_job\" }),\n );\n }\n return Promise.resolve(job);\n }\n\n /**\n * Delete a cron job permanently.\n *\n * @public\n */\n static delete(jobId: string, _options: CronOperationOptions = {}): Promise<void> {\n unscheduleJob(jobId);\n deleteJob(jobId);\n return Promise.resolve();\n }\n\n /**\n * Re-enable a paused cron job.\n *\n * @public\n */\n static async enable(jobId: string, _options: CronOperationOptions = {}): Promise<CronJob> {\n return updateJobStatus(jobId, true);\n }\n\n /**\n * Pause a cron job without deleting it.\n *\n * @public\n */\n static async disable(jobId: string, _options: CronOperationOptions = {}): Promise<CronJob> {\n return updateJobStatus(jobId, false);\n }\n\n /**\n * Manually trigger a cron job off-schedule. Returns the resulting `Run`\n * (agent target) or `WorkflowRun` (workflow target — SE35).\n *\n * @public\n */\n static async run(\n jobId: string,\n _options: CronRunOptions = {},\n ): Promise<Run | import(\"./types/workflow.js\").WorkflowRun> {\n const job = getJob(jobId);\n if (job === undefined) {\n throw new UnknownAgentError(`Cron job ${jobId} not found`, { code: \"unknown_cron_job\" });\n }\n return runCronJob(job);\n }\n\n /**\n * Activate the in-process scheduler for local cron jobs.\n *\n * @public\n */\n static start(options: CronStartOptions = {}): Promise<void> {\n // Install the default fire handler so timer ticks actually drive a real\n // agent/workflow run. Users can override via `setCronFireHandler` from\n // `@theokit/sdk/internal` (test-mode hook). Handler body lives in\n // `internal/cron/fire-handler.ts` (testable + G8).\n setCronFireHandler(fireCronJobAsTask);\n startScheduler(options.cwd);\n return Promise.resolve();\n }\n\n /**\n * Stop the in-process scheduler. Jobs are preserved.\n *\n * @public\n */\n static stop(): Promise<void> {\n stopScheduler();\n return Promise.resolve();\n }\n\n /**\n * Snapshot of the local scheduler.\n *\n * @public\n */\n static status(_options: CronStartOptions = {}): Promise<CronSchedulerStatus> {\n const scheduler = getSchedulerState();\n return Promise.resolve({ running: scheduler.running, jobCount: jobCount() });\n }\n}\n\nasync function createCronJob(options: CronCreateOptions): Promise<CronJob> {\n validateCronTarget(options);\n\n validateCronExpression(options.cron);\n const timezone = options.timezone ?? \"UTC\";\n validateTimezone(timezone);\n\n // apiKey is accepted but not required for cron-create in fixture mode.\n resolveApiKey(options.apiKey);\n\n const runtime = detectRuntime(options);\n const now = Date.now();\n const job: CronJob = {\n id: generateCronId(),\n cron: options.cron,\n timezone,\n enabled: options.enabled ?? true,\n status: options.enabled === false ? \"paused\" : \"scheduled\",\n runtime,\n createdAt: now,\n nextRunAt: estimateNextRunAt(options.cron, timezone),\n ...(options.name !== undefined ? { name: options.name } : {}),\n ...(options.message !== undefined ? { message: options.message } : {}),\n ...(options.agent !== undefined ? { agent: options.agent } : {}),\n ...(options.agentId !== undefined ? { agentId: options.agentId } : {}),\n ...(options.workflow !== undefined ? { workflow: options.workflow } : {}),\n ...(options.inputData !== undefined ? { inputData: options.inputData } : {}),\n };\n upsertJob(job);\n return job;\n}\n\n/**\n * SE35 (ADR 0014) — exactly ONE target (`agent` | `agentId` | `workflow`).\n * Agent targets require `message`; a workflow target takes `inputData` and MUST\n * NOT set `message`.\n */\nfunction validateCronTarget(options: CronCreateOptions): void {\n const targets = [options.agent, options.agentId, options.workflow].filter(\n (t) => t !== undefined,\n ).length;\n if (targets > 1) {\n throw new ConfigurationError(\n \"agent, agentId, and workflow are mutually exclusive — pass exactly one target.\",\n { code: \"cron_ambiguous_target\" },\n );\n }\n if (targets === 0) {\n throw new ConfigurationError(\n \"Cron job requires exactly one target: agent, agentId, or workflow.\",\n { code: \"cron_no_target\" },\n );\n }\n if (options.workflow !== undefined && options.message !== undefined) {\n throw new ConfigurationError(\n \"A workflow cron target takes inputData, not a message — remove `message`.\",\n { code: \"cron_workflow_message\" },\n );\n }\n if (options.workflow === undefined && options.message === undefined) {\n throw new ConfigurationError(\"An agent cron target requires a message.\", {\n code: \"cron_missing_message\",\n });\n }\n}\n\nfunction detectRuntime(options: CronCreateOptions): CronRuntime {\n // SE35 — a workflow target is a held in-memory instance; it can only run in\n // the local (in-process) scheduler. A workflow instance cannot cross the\n // cloud process boundary (ADR 0014).\n if (options.workflow !== undefined) return \"local\";\n if (options.agentId !== undefined) {\n return options.agentId.startsWith(\"bc-\") ? \"cloud\" : \"local\";\n }\n const agent = options.agent as AgentOptions | undefined;\n if (agent?.cloud !== undefined) return \"cloud\";\n return \"local\";\n}\n\nasync function updateJobStatus(jobId: string, enabled: boolean): Promise<CronJob> {\n const existing = getJob(jobId);\n if (existing === undefined) {\n throw new UnknownAgentError(`Cron job ${jobId} not found`, { code: \"unknown_cron_job\" });\n }\n const updated: CronJob = {\n ...existing,\n enabled,\n status: enabled ? \"scheduled\" : \"paused\",\n };\n upsertJob(updated);\n if (updated.runtime === \"local\") {\n if (enabled) {\n scheduleJob(updated);\n } else {\n unscheduleJob(updated.id);\n }\n }\n return updated;\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/cron/run-job.ts","../src/internal/cron/fire-handler.ts","../src/internal/cron/store.ts","../src/internal/cron/scheduler.ts","../src/internal/cron/validate.ts","../src/cron.ts"],"names":["ConfigurationError","getAgentFacade","UnknownAgentError","submit","Croner","resolveApiKey","generateCronId"],"mappings":"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","file":"chunk-QIRDQZYL.cjs","sourcesContent":["import { ConfigurationError, UnknownAgentError } from \"../../errors.js\";\nimport type { AgentOptions } from \"../../types/agent.js\";\nimport type { CronJob } from \"../../types/cron.js\";\nimport type { Run, SDKUserMessage } from \"../../types/run.js\";\nimport type { WorkflowRun } from \"../../types/workflow.js\";\nimport { getAgentFacade } from \"../runtime/registry/agent-factory-registry.js\";\n\n/**\n * Execute a cron job. Dispatches to one of three targets:\n * - `workflow` (SE35) → `workflow.run(inputData)` on the held instance (the\n * instance carries its own `.run`, so this module never imports `workflow.ts`),\n * returning the already-terminal {@link WorkflowRun}.\n * - `agent` → an ephemeral agent per fire; `agent.send(message)` → {@link Run}.\n * - `agentId` → reuse an existing agent; `agent.send(message)` → {@link Run}.\n *\n * Used by both `Cron.run(jobId)` (manual off-schedule fire) and the scheduler's\n * default fire handler. ADR 0014.\n *\n * @internal\n */\nexport async function runCronJob(job: CronJob): Promise<Run | WorkflowRun> {\n // `Workflow.run()` resolves only on a TERMINAL run (completed/failed/suspended/\n // cancelled — the executor never returns `status: \"running\"`), so the fire\n // handler treats the returned WorkflowRun as terminal (no `.wait()`).\n if (job.workflow !== undefined) return job.workflow.run(job.inputData);\n if (job.agent !== undefined) return runWithEphemeralAgent(job.agent, requireMessage(job));\n if (job.agentId !== undefined) return runWithExistingAgent(job.agentId, requireMessage(job));\n throw new ConfigurationError(\n `Cron job ${job.id} has no target (agent, agentId, or workflow) — cannot run.`,\n { code: \"cron_no_target\" },\n );\n}\n\n/**\n * Discriminate the {@link runCronJob} union: an agent `Run` is deferred (carries\n * `.wait()`/`.cancel()`); a {@link WorkflowRun} is already terminal (no `.wait()`).\n * @internal\n */\nexport function isAgentRun(outcome: Run | WorkflowRun): outcome is Run {\n return typeof (outcome as Run).wait === \"function\";\n}\n\n/** Agent targets require a message; fail-loud if one somehow reached a fire without it. */\nfunction requireMessage(job: CronJob): string | SDKUserMessage {\n if (job.message === undefined) {\n throw new ConfigurationError(`Cron job ${job.id} is an agent target but has no message.`, {\n code: \"cron_missing_message\",\n });\n }\n return job.message;\n}\n\nasync function runWithExistingAgent(\n agentId: string,\n message: string | SDKUserMessage,\n): Promise<Run> {\n const info = await getAgentFacade()\n .get(agentId)\n .catch(() => undefined);\n if (info === undefined) {\n throw new UnknownAgentError(\n `Cron job references agentId \"${agentId}\" but no such agent is registered. The agent may have been disposed or the process restarted without persisting the agent registry.`,\n { code: \"agent_not_registered\" },\n );\n }\n const agent = await getAgentFacade().resume(agentId);\n return agent.send(message);\n}\n\nasync function runWithEphemeralAgent(\n baseOptions: AgentOptions,\n message: string | SDKUserMessage,\n): Promise<Run> {\n const agent = await getAgentFacade().create(baseOptions);\n return agent.send(message);\n}\n","/**\n * Default cron fire handler (extracted from `Cron.start` for testability + G8).\n *\n * Every fire registers as a Task (ADRs D363/D374) so callers observe it via\n * `Task.list` / `Task.subscribe`. SE35 (ADR 0014): the fire target may be an\n * agent (a deferred {@link Run} — abort-wire + `wait()`) OR a workflow (an\n * already-terminal {@link WorkflowRun} — no `wait()`); `isAgentRun` discriminates\n * so the handler records the correct terminal status/runId for each shape.\n *\n * @internal\n */\n\nimport type { CronJob } from \"../../types/cron.js\";\nimport { submit as taskRegistrySubmit } from \"../task/registry.js\";\nimport { isAgentRun, runCronJob } from \"./run-job.js\";\n\nexport async function fireCronJobAsTask(job: CronJob): Promise<void> {\n // The task id namespace `cron-{jobId}-{fireEpochMs}` honors D368/EC-5.\n const fireTs = Date.now();\n const taskId = `cron-${job.id}-${fireTs}`;\n try {\n await taskRegistrySubmit({\n kind: \"cron\",\n id: taskId,\n allowReservedPrefix: true,\n meta: { jobId: job.id, jobName: job.name, schedule: job.cron, firedAt: fireTs },\n work: async (ctx) => {\n const outcome = await runCronJob(job);\n if (isAgentRun(outcome)) {\n // Agent target — the Run is deferred: abort-wire + await terminal.\n ctx.signal.addEventListener(\"abort\", () => void outcome.cancel().catch(() => {}), {\n once: true,\n });\n const result = await outcome.wait();\n ctx.emit({ status: result.status, runId: outcome.id });\n return { status: result.status, runId: outcome.id };\n }\n // SE35 workflow target — the WorkflowRun is ALREADY terminal (no wait()).\n ctx.emit({ status: outcome.status, runId: outcome.id });\n return { status: outcome.status, runId: outcome.id };\n },\n });\n } catch {\n // Task registry must not break cron — fall through to a direct run. No\n // double-execution: `taskRegistrySubmit` runs `work` (which calls\n // `runCronJob`) fire-and-forget, so a throw here means the SUBMIT itself\n // failed (id/registry setup) BEFORE `work` started — the job never ran, and\n // this is its first + only execution.\n const outcome = await runCronJob(job);\n if (isAgentRun(outcome)) await outcome.wait();\n }\n}\n","import type { CronJob } from \"../../types/cron.js\";\n\n/**\n * Process-wide cron job store. In Phase 1 we keep all jobs in memory\n * (across local + cloud runtimes). Local-runtime persistence to\n * `.theokit/cron/jobs.json` lands when the local runtime adapter is wired.\n *\n * @internal\n */\nconst jobs = new Map<string, CronJob>();\n\n/** Snapshot of every known cron job. @internal */\nexport function listJobs(): CronJob[] {\n return Array.from(jobs.values());\n}\n\n/** Total job count across runtimes. @internal */\nexport function jobCount(): number {\n return jobs.size;\n}\n\n/** Fetch a single job by id, or `undefined` if it does not exist. @internal */\nexport function getJob(jobId: string): CronJob | undefined {\n return jobs.get(jobId);\n}\n\n/** Insert or replace a job. @internal */\nexport function upsertJob(job: CronJob): void {\n jobs.set(job.id, job);\n}\n\n/** Delete a job. Returns `true` if a job was removed. @internal */\nexport function deleteJob(jobId: string): boolean {\n return jobs.delete(jobId);\n}\n\n/** Test-only: drop every job. @internal */\nexport function clearJobs(): void {\n jobs.clear();\n}\n","import { Cron as Croner } from \"croner\";\n\nimport type { CronJob } from \"../../types/cron.js\";\nimport { listJobs, upsertJob } from \"./store.js\";\n\n/**\n * Real local cron scheduler. When `Cron.start()` is called the scheduler\n * installs a Croner timer per enabled local job; on fire the registered\n * fire handler runs the underlying agent. `Cron.stop()` tears every timer\n * down but keeps the jobs in the store.\n *\n * @internal\n */\n\nexport type CronFireHandler = (job: CronJob) => Promise<void> | void;\n\ninterface SchedulerState {\n running: boolean;\n cwd?: string;\n timers: Map<string, Croner>;\n fireHandler?: CronFireHandler;\n}\n\nconst state: SchedulerState = { running: false, timers: new Map() };\n\n/**\n * Register the callback invoked when a job fires. The runtime adapter\n * supplies a handler that actually executes the agent; fixture-mode tests\n * leave it unset so timers tick without side effects.\n *\n * @internal\n */\nexport function setCronFireHandler(handler: CronFireHandler | undefined): void {\n state.fireHandler = handler;\n}\n\n/** Activate the scheduler and install timers for every enabled local job. @internal */\nexport function startScheduler(cwd?: string): void {\n state.running = true;\n if (cwd !== undefined) state.cwd = cwd;\n for (const job of listJobs()) {\n if (job.runtime === \"local\" && job.enabled !== false) scheduleJob(job);\n }\n}\n\n/** Deactivate the scheduler. Stops every timer; jobs remain in the store. @internal */\nexport function stopScheduler(): void {\n state.running = false;\n for (const timer of state.timers.values()) timer.stop();\n state.timers.clear();\n}\n\n/** Schedule a single job. No-op if the scheduler is not running. @internal */\nexport function scheduleJob(job: CronJob): void {\n if (!state.running) return;\n unscheduleJob(job.id);\n const expression = normalizeExpression(job.cron);\n const timer = new Croner(\n expression,\n { timezone: job.timezone, name: job.id, protect: true },\n () => {\n void fireJob(job.id);\n },\n );\n state.timers.set(job.id, timer);\n refreshNextRunAt(job.id, timer);\n}\n\n/** Tear down the timer for a single job. @internal */\nexport function unscheduleJob(jobId: string): boolean {\n const timer = state.timers.get(jobId);\n if (timer === undefined) return false;\n timer.stop();\n state.timers.delete(jobId);\n return true;\n}\n\n/** Snapshot of the scheduler's running flag and configured workspace. @internal */\nexport function getSchedulerState(): { running: boolean; cwd?: string } {\n const result: { running: boolean; cwd?: string } = { running: state.running };\n if (state.cwd !== undefined) result.cwd = state.cwd;\n return result;\n}\n\nasync function fireJob(jobId: string): Promise<void> {\n const fresh = listJobs().find((entry) => entry.id === jobId);\n if (fresh === undefined || fresh.enabled === false) return;\n const handler = state.fireHandler;\n upsertJob({ ...fresh, lastRunAt: Date.now() });\n if (handler === undefined) return;\n try {\n await handler(fresh);\n } catch {\n // Swallow handler errors — the scheduler must keep ticking. Real\n // surface for run failures lives on the Run.wait() result itself.\n }\n}\n\nfunction refreshNextRunAt(jobId: string, timer: Croner): void {\n const next = timer.nextRun();\n if (next === null) return;\n const existing = listJobs().find((entry) => entry.id === jobId);\n if (existing === undefined) return;\n upsertJob({ ...existing, nextRunAt: next.getTime() });\n}\n\nfunction normalizeExpression(cron: string): string {\n switch (cron) {\n case \"@hourly\":\n return \"0 * * * *\";\n case \"@daily\":\n return \"0 0 * * *\";\n case \"@weekly\":\n return \"0 0 * * 0\";\n case \"@monthly\":\n return \"0 0 1 * *\";\n case \"@yearly\":\n return \"0 0 1 1 *\";\n default:\n return cron;\n }\n}\n","import { ConfigurationError } from \"../../errors.js\";\n\n/**\n * POSIX-cron + shorthand validators used by `Cron.create()`. Throws\n * `ConfigurationError` with a stable message and code on invalid input.\n *\n * @internal\n */\n\nconst SHORTHANDS = new Set([\"@hourly\", \"@daily\", \"@weekly\", \"@monthly\", \"@yearly\"]);\n\ninterface FieldRange {\n min: number;\n max: number;\n}\n\nconst FIELD_RANGES: readonly FieldRange[] = [\n { min: 0, max: 59 }, // minute\n { min: 0, max: 23 }, // hour\n { min: 1, max: 31 }, // day-of-month\n { min: 1, max: 12 }, // month\n { min: 0, max: 6 }, // day-of-week\n];\n\n/**\n * Validate a cron expression. Accepts shorthand (`@hourly`, ..., `@yearly`)\n * or 5-field POSIX cron with star, literals, star/N step, N-M range, and\n * N,M,P list.\n *\n * @internal\n */\nexport function validateCronExpression(cron: string): void {\n if (typeof cron !== \"string\" || cron.length === 0) {\n throw new ConfigurationError(\"Invalid cron expression: empty\", {\n code: \"invalid_cron\",\n });\n }\n if (cron.startsWith(\"@\")) {\n if (!SHORTHANDS.has(cron)) {\n throw new ConfigurationError(`Invalid cron expression: unknown shorthand ${cron}`, {\n code: \"invalid_cron\",\n });\n }\n return;\n }\n\n const fields = cron.trim().split(/\\s+/);\n if (fields.length !== FIELD_RANGES.length) {\n throw new ConfigurationError(\n `Invalid cron expression: ${cron} (expected ${FIELD_RANGES.length} fields, got ${fields.length})`,\n { code: \"invalid_cron\" },\n );\n }\n for (const [index, range] of FIELD_RANGES.entries()) {\n // The length check above already established one field per range, so the lookup is total.\n // B-116: this replaces a `range === undefined` guard that no caller could reach — its single\n // caller only ran with exactly 5 fields, and FIELD_RANGES has exactly 5 entries, so the branch\n // stayed at 0 executions through 37 tests written specifically to enter it.\n const field = fields[index] as string;\n if (!isValidCronField(field, range)) {\n throw new ConfigurationError(`Invalid cron expression: ${cron} (field ${index + 1})`, {\n code: \"invalid_cron\",\n });\n }\n }\n}\n\nfunction isValidCronField(field: string, range: FieldRange): boolean {\n if (field === \"*\") return true;\n if (field.startsWith(\"*/\")) return isValidStep(field.slice(2), range);\n if (field.includes(\",\")) {\n return field.split(\",\").every((part) => isValidCronField(part, range));\n }\n if (field.includes(\"-\")) return isValidRange(field, range);\n return isValidLiteral(field, range);\n}\n\n/**\n * Digits, and nothing else. `Number.parseInt` stops at the first non-digit, so it reads `\"5abc\"` as\n * `5` and `\"0x5\"` as `0` — a numeric field parsed that way accepts garbage that happens to start\n * with a digit.\n *\n * This replaces the `String(n) === field` round-trip the literal and step validators used to carry.\n * The round-trip refused the garbage correctly but also refused `\"07\"`, because `String(7) !== \"07\"`\n * — and `isValidRange` never had it at all, so `\"1-5abc\"` was accepted while `\"5abc\"` was refused\n * (B-121). One predicate, applied to every field shape, closes both halves.\n *\n * The boundary that matters is croner 9, the scheduler this SDK actually fires jobs with. Measured\n * 2026-08-19: it ACCEPTS `\"07 * * * *\"` (next run at :07) and REFUSES `\"5abc\"`, `\"1-5abc\"`,\n * `\"1abc-5\"`, `\"0x5\"`, `\"5.9\"`, `\"+5\"` and `\"1e1\"` as \"illegal character\" (B-122). Validating\n * stricter than the engine rejects schedules that would have run; validating looser only moves the\n * failure from `Cron.create()` to fire time, where nobody is watching.\n *\n * @internal\n */\nconst DIGITS_ONLY = /^\\d+$/;\n\nfunction parseFieldNumber(text: string): number | undefined {\n if (!DIGITS_ONLY.test(text)) return undefined;\n return Number.parseInt(text, 10);\n}\n\nfunction isValidStep(stepStr: string, range: FieldRange): boolean {\n const step = parseFieldNumber(stepStr);\n return step !== undefined && step > 0 && step <= range.max;\n}\n\nfunction isValidRange(field: string, range: FieldRange): boolean {\n const parts = field.split(\"-\");\n if (parts.length !== 2) return false;\n const [startStr, endStr] = parts;\n if (startStr === undefined || endStr === undefined) return false;\n const start = parseFieldNumber(startStr);\n const end = parseFieldNumber(endStr);\n if (start === undefined || end === undefined) return false;\n return start >= range.min && end <= range.max && start <= end;\n}\n\nfunction isValidLiteral(field: string, range: FieldRange): boolean {\n const n = parseFieldNumber(field);\n return n !== undefined && n >= range.min && n <= range.max;\n}\n\n/**\n * Validate an IANA timezone. Uses `Intl.DateTimeFormat`'s strict timezone\n * lookup; invalid values raise `RangeError` which we wrap.\n *\n * @internal\n */\nexport function validateTimezone(timezone: string): void {\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: timezone });\n } catch {\n throw new ConfigurationError(`Invalid IANA timezone: ${timezone}`, {\n code: \"invalid_timezone\",\n });\n }\n}\n\n/**\n * Heuristic next-fire-at estimator for fixture mode. Returns a timestamp\n * one hour in the future for shorthand/POSIX inputs. Real scheduling uses\n * a proper evaluator wired in by the local scheduler.\n *\n * @internal\n */\nexport function estimateNextRunAt(_cron: string, _timezone: string): number {\n return Date.now() + 60 * 60 * 1000;\n}\n","// Bootstrap import: loading this facade must register the public Agent facade\n// into the agent-factory-registry seam, because `internal/cron/run-job.ts`\n// resolves it via `getAgentFacade()` at runtime instead of importing `agent.ts`\n// directly (which would invert the public-api -> internal dependency\n// direction). The `@theokit/sdk/cron` sub-path entry would otherwise throw\n// \"Agent facade not registered\" at runtime.\nimport \"./agent.js\";\nimport { ConfigurationError, UnknownAgentError } from \"./errors.js\";\nimport { fireCronJobAsTask } from \"./internal/cron/fire-handler.js\";\nimport { runCronJob } from \"./internal/cron/run-job.js\";\nimport {\n getSchedulerState,\n scheduleJob,\n setCronFireHandler,\n startScheduler,\n stopScheduler,\n unscheduleJob,\n} from \"./internal/cron/scheduler.js\";\nimport { deleteJob, getJob, jobCount, listJobs, upsertJob } from \"./internal/cron/store.js\";\nimport {\n estimateNextRunAt,\n validateCronExpression,\n validateTimezone,\n} from \"./internal/cron/validate.js\";\nimport { resolveApiKey } from \"./internal/env.js\";\nimport { generateCronId } from \"./internal/ids.js\";\nimport type { AgentOptions, ListResult } from \"./types/agent.js\";\nimport type {\n CronCreateOptions,\n CronGetOptions,\n CronJob,\n CronListOptions,\n CronOperationOptions,\n CronRunOptions,\n CronRuntime,\n CronSchedulerStatus,\n CronStartOptions,\n} from \"./types/cron.js\";\nimport type { Run } from \"./types/run.js\";\n\n/**\n * Static façade for scheduling Theo agent runs on a cron expression.\n *\n * @public\n */\nexport class Cron {\n private constructor() {\n // Static-only façade.\n }\n\n /**\n * Create and persist a cron job.\n *\n * @public\n */\n static async create(options: CronCreateOptions): Promise<CronJob> {\n const job = await createCronJob(options);\n if (job.runtime === \"local\" && job.enabled !== false) scheduleJob(job);\n return job;\n }\n\n /**\n * List cron jobs (local, cloud, or both).\n *\n * @public\n */\n static list(options: CronListOptions = {}): Promise<ListResult<CronJob>> {\n const runtimeFilter = options.runtime;\n const items = listJobs().filter((job) =>\n runtimeFilter === undefined ? true : job.runtime === runtimeFilter,\n );\n return Promise.resolve({ items });\n }\n\n /**\n * Get a single cron job by ID.\n *\n * @public\n */\n static get(jobId: string, _options: CronGetOptions = {}): Promise<CronJob> {\n const job = getJob(jobId);\n if (job === undefined) {\n return Promise.reject(\n new UnknownAgentError(`Cron job ${jobId} not found`, { code: \"unknown_cron_job\" }),\n );\n }\n return Promise.resolve(job);\n }\n\n /**\n * Delete a cron job permanently.\n *\n * @public\n */\n static delete(jobId: string, _options: CronOperationOptions = {}): Promise<void> {\n unscheduleJob(jobId);\n deleteJob(jobId);\n return Promise.resolve();\n }\n\n /**\n * Re-enable a paused cron job.\n *\n * @public\n */\n static async enable(jobId: string, _options: CronOperationOptions = {}): Promise<CronJob> {\n return updateJobStatus(jobId, true);\n }\n\n /**\n * Pause a cron job without deleting it.\n *\n * @public\n */\n static async disable(jobId: string, _options: CronOperationOptions = {}): Promise<CronJob> {\n return updateJobStatus(jobId, false);\n }\n\n /**\n * Manually trigger a cron job off-schedule. Returns the resulting `Run`\n * (agent target) or `WorkflowRun` (workflow target — SE35).\n *\n * @public\n */\n static async run(\n jobId: string,\n _options: CronRunOptions = {},\n ): Promise<Run | import(\"./types/workflow.js\").WorkflowRun> {\n const job = getJob(jobId);\n if (job === undefined) {\n throw new UnknownAgentError(`Cron job ${jobId} not found`, { code: \"unknown_cron_job\" });\n }\n return runCronJob(job);\n }\n\n /**\n * Activate the in-process scheduler for local cron jobs.\n *\n * @public\n */\n static start(options: CronStartOptions = {}): Promise<void> {\n // Install the default fire handler so timer ticks actually drive a real\n // agent/workflow run. Users can override via `setCronFireHandler` from\n // `@theokit/sdk/internal` (test-mode hook). Handler body lives in\n // `internal/cron/fire-handler.ts` (testable + G8).\n setCronFireHandler(fireCronJobAsTask);\n startScheduler(options.cwd);\n return Promise.resolve();\n }\n\n /**\n * Stop the in-process scheduler. Jobs are preserved.\n *\n * @public\n */\n static stop(): Promise<void> {\n stopScheduler();\n return Promise.resolve();\n }\n\n /**\n * Snapshot of the local scheduler.\n *\n * @public\n */\n static status(_options: CronStartOptions = {}): Promise<CronSchedulerStatus> {\n const scheduler = getSchedulerState();\n return Promise.resolve({ running: scheduler.running, jobCount: jobCount() });\n }\n}\n\nasync function createCronJob(options: CronCreateOptions): Promise<CronJob> {\n validateCronTarget(options);\n\n validateCronExpression(options.cron);\n const timezone = options.timezone ?? \"UTC\";\n validateTimezone(timezone);\n\n // apiKey is accepted but not required for cron-create in fixture mode.\n resolveApiKey(options.apiKey);\n\n const runtime = detectRuntime(options);\n const now = Date.now();\n const job: CronJob = {\n id: generateCronId(),\n cron: options.cron,\n timezone,\n enabled: options.enabled ?? true,\n status: options.enabled === false ? \"paused\" : \"scheduled\",\n runtime,\n createdAt: now,\n nextRunAt: estimateNextRunAt(options.cron, timezone),\n ...(options.name !== undefined ? { name: options.name } : {}),\n ...(options.message !== undefined ? { message: options.message } : {}),\n ...(options.agent !== undefined ? { agent: options.agent } : {}),\n ...(options.agentId !== undefined ? { agentId: options.agentId } : {}),\n ...(options.workflow !== undefined ? { workflow: options.workflow } : {}),\n ...(options.inputData !== undefined ? { inputData: options.inputData } : {}),\n };\n upsertJob(job);\n return job;\n}\n\n/**\n * SE35 (ADR 0014) — exactly ONE target (`agent` | `agentId` | `workflow`).\n * Agent targets require `message`; a workflow target takes `inputData` and MUST\n * NOT set `message`.\n */\nfunction validateCronTarget(options: CronCreateOptions): void {\n const targets = [options.agent, options.agentId, options.workflow].filter(\n (t) => t !== undefined,\n ).length;\n if (targets > 1) {\n throw new ConfigurationError(\n \"agent, agentId, and workflow are mutually exclusive — pass exactly one target.\",\n { code: \"cron_ambiguous_target\" },\n );\n }\n if (targets === 0) {\n throw new ConfigurationError(\n \"Cron job requires exactly one target: agent, agentId, or workflow.\",\n { code: \"cron_no_target\" },\n );\n }\n if (options.workflow !== undefined && options.message !== undefined) {\n throw new ConfigurationError(\n \"A workflow cron target takes inputData, not a message — remove `message`.\",\n { code: \"cron_workflow_message\" },\n );\n }\n if (options.workflow === undefined && options.message === undefined) {\n throw new ConfigurationError(\"An agent cron target requires a message.\", {\n code: \"cron_missing_message\",\n });\n }\n}\n\nfunction detectRuntime(options: CronCreateOptions): CronRuntime {\n // SE35 — a workflow target is a held in-memory instance; it can only run in\n // the local (in-process) scheduler. A workflow instance cannot cross the\n // cloud process boundary (ADR 0014).\n if (options.workflow !== undefined) return \"local\";\n if (options.agentId !== undefined) {\n return options.agentId.startsWith(\"bc-\") ? \"cloud\" : \"local\";\n }\n const agent = options.agent as AgentOptions | undefined;\n if (agent?.cloud !== undefined) return \"cloud\";\n return \"local\";\n}\n\nasync function updateJobStatus(jobId: string, enabled: boolean): Promise<CronJob> {\n const existing = getJob(jobId);\n if (existing === undefined) {\n throw new UnknownAgentError(`Cron job ${jobId} not found`, { code: \"unknown_cron_job\" });\n }\n const updated: CronJob = {\n ...existing,\n enabled,\n status: enabled ? \"scheduled\" : \"paused\",\n };\n upsertJob(updated);\n if (updated.runtime === \"local\") {\n if (enabled) {\n scheduleJob(updated);\n } else {\n unscheduleJob(updated.id);\n }\n }\n return updated;\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { splitFrontmatter, parseSimpleYaml } from './chunk-KVNWIAO4.js';
2
- import { findGitRoot, DEFAULT_DISCOVERY_SPECS, walkUpForFile, walkUpForGlob } from './chunk-GTKFV7O5.js';
2
+ import { findGitRoot, DEFAULT_DISCOVERY_SPECS, walkUpForFile, walkUpForGlob } from './chunk-WFC26L6Y.js';
3
3
  import { insideRoot } from './chunk-RIAM53CP.js';
4
4
  import { homedir } from 'os';
5
5
  import { dirname, relative, resolve, join, isAbsolute } from 'path';
@@ -277,5 +277,5 @@ async function loadPlainMarkdownSource(spec, path, id, opts, gitRoot) {
277
277
  }
278
278
 
279
279
  export { DEFAULT_MAX_BYTES_PER_FILE, parseRules, resolveImports, runDiscovery, shouldActivateRule, truncateWithMarker };
280
- //# sourceMappingURL=chunk-7FHZ4VQX.js.map
281
- //# sourceMappingURL=chunk-7FHZ4VQX.js.map
280
+ //# sourceMappingURL=chunk-SAVIWMZB.js.map
281
+ //# sourceMappingURL=chunk-SAVIWMZB.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/runtime/context/context-loaders.ts","../src/internal/runtime/context/context-import-resolver.ts","../src/internal/runtime/context/context-glob.ts","../src/internal/runtime/context/context-rules-frontmatter.ts","../src/internal/runtime/context/context-mdc-parser.ts","../src/internal/runtime/context/context-discovery-runner.ts"],"names":["resolvePath","z","dirname","readFile"],"mappings":"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","file":"chunk-7FHZ4VQX.js","sourcesContent":["/**\n * Context file loaders + truncation (T1.2, ADRs D154 / D155 / D159).\n *\n * Reads context source files from disk, applies the per-file size cap\n * with 70%/20% head/tail truncation, and emits the\n * `context_files_truncated` telemetry counter when the cap fires.\n * Pure (no I/O) for `truncateWithMarker` — testable in isolation.\n *\n * @internal\n */\n\nimport { readFile } from \"node:fs/promises\";\n\nconst HEAD_RATIO = 0.7;\nconst TAIL_RATIO = 0.2;\nconst MARKER = \"\\n\\n…[truncated by theokit]\\n\\n\";\n\n/** Default per-file cap (40k chars ≈ 10k tokens). D155. */\nexport const DEFAULT_MAX_BYTES_PER_FILE = 40_000;\n\nexport interface LoadedSource {\n /** Absolute path the content came from. */\n readonly source: string;\n readonly content: string;\n readonly originalBytes: number;\n readonly truncated: boolean;\n}\n\nexport interface TruncateResult {\n readonly truncated: boolean;\n readonly finalContent: string;\n}\n\n/**\n * Cap `content` at `max` characters with 70%/20% head/tail truncation\n * and an explicit marker. Pure — no I/O, no telemetry.\n *\n * EC-C: when `max <= MARKER.length`, skip the marker entirely and\n * return a head-only slice. Without this guard, `budget = max -\n * MARKER.length` would go negative and `content.slice(-tailBytes)`\n * would slice from the END of the string rather than truncating.\n *\n * EC-H: codepoint integrity — `String.slice()` operates on UTF-16\n * code units, which can split surrogate pairs. We accept that\n * trailing/leading replacement chars (U+FFFD) may appear at boundaries.\n * Modern LLMs tolerate them; byte-exact safety would require Buffer\n * slicing + TextDecoder with `fatal: true` retry, which adds complexity\n * without value.\n *\n * @public\n */\nexport function truncateWithMarker(content: string, max: number): TruncateResult {\n if (content.length <= max) {\n return { truncated: false, finalContent: content };\n }\n // EC-C: max too small to fit even the marker — return head-only slice.\n if (max <= MARKER.length) {\n return { truncated: true, finalContent: content.slice(0, max) };\n }\n const budget = max - MARKER.length;\n const headBytes = Math.floor(budget * (HEAD_RATIO / (HEAD_RATIO + TAIL_RATIO)));\n const tailBytes = budget - headBytes;\n return {\n truncated: true,\n finalContent: content.slice(0, headBytes) + MARKER + content.slice(-tailBytes),\n };\n}\n\n/**\n * Read a file from disk and apply the per-file cap. Emits telemetry\n * counter when truncation fires.\n *\n * EC-G: file deleted between discovery and read (FS race) → returns\n * `undefined`, never throws.\n *\n * @internal\n */\nexport async function loadPlainMarkdown(\n absPath: string,\n opts: { maxBytesPerFile?: number } = {},\n): Promise<LoadedSource | undefined> {\n const max = opts.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE;\n let content: string;\n try {\n content = await readFile(absPath, \"utf8\");\n } catch {\n // EC-G: ENOENT / EACCES / etc → caller treats as missing.\n return undefined;\n }\n const { truncated, finalContent } = truncateWithMarker(content, max);\n if (truncated) {\n emitTruncationCounter(absPath);\n }\n return {\n source: absPath,\n content: finalContent,\n originalBytes: content.length,\n truncated,\n };\n}\n\n/**\n * EC-L: telemetry no-op when OTel is not imported. We import the tracer\n * lazily and use `safeCall` so the lookup never throws and never pulls\n * OTel into the import graph for users without `@opentelemetry/api`\n * installed.\n *\n * @internal\n */\nfunction emitTruncationCounter(source: string): void {\n // Lazy resolution via globalThis avoids static import of telemetry/tracer.\n // Tests can spy via the same path; production users without OTel see no-op.\n const tracer = (\n globalThis as { __theokit_tracer?: { inc?: (k: string, attrs: unknown) => void } }\n ).__theokit_tracer;\n if (tracer?.inc === undefined) return;\n try {\n tracer.inc(\"context_files_truncated\", { file: source });\n } catch {\n // Telemetry must never break the loader.\n }\n}\n","/**\n * `@path/to/file` import resolver (T2.1, ADR D156).\n *\n * Anthropic/Gemini convention: lines that are EXACTLY `@path` get\n * replaced with the imported file's content, recursively (5-hop cap),\n * with cycle detection. Inline `see @x.md, also @y.md` references are\n * NOT resolved (EC-Q — own-line only, mirrors Anthropic's actual\n * behavior).\n *\n * EC-D fix: every imported file is itself capped at `maxBytesPerFile`\n * via `loadPlainMarkdown` BEFORE concatenation. Prevents a CLAUDE.md\n * with 5 imports of 30k each from ballooning to 150k of imported\n * content before the outer cap fires.\n *\n * @internal\n */\n\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join, resolve as resolvePath } from \"node:path\";\n\nimport { loadPlainMarkdown } from \"./context-loaders.js\";\nimport { insideRoot } from \"./path-containment.js\";\n\n/** EC-Q: line-anchored. `@path` must be alone on its line. */\nconst IMPORT_RE = /^@(\\S+)\\s*$/gm;\nconst MAX_HOPS = 5;\n\nexport interface ResolveImportsOptions {\n /** Absolute paths already resolved (cycle detection). */\n readonly visited: Set<string>;\n /** Current recursion depth — caps at MAX_HOPS. */\n readonly depth: number;\n /** Per-import file cap (EC-D). Forwarded to loadPlainMarkdown. */\n readonly maxBytesPerFile: number;\n /**\n * The directory an import may not escape. When set, a target resolving outside it is\n * refused and replaced with a placeholder.\n *\n * The file carrying the import is REPOSITORY-CONTROLLED — `CLAUDE.md` and `GEMINI.md`\n * are the two default specs with `followImports: true`, and both are found by\n * `git-root-walk` inside the tree the agent was pointed at. Without a root, a cloned\n * repository could name `@~/.ssh/id_rsa` or any absolute path and have its contents\n * inlined into the system prompt, and from there sent to the model provider. The\n * traversal guard that already existed (`isSafePattern`) guards the discovery PATTERN,\n * not the import TARGET, so it never saw this.\n *\n * OPTIONAL, so a caller outside the discovery path keeps the previous behaviour rather\n * than breaking on an upgrade. `runDiscovery` always supplies `gitRoot ?? cwd` — the\n * same value it already uses to keep absolute paths out of `<source name=\"\">`.\n */\n readonly projectRoot?: string;\n}\n\n/**\n * Resolve `@path` directives in `content`. Each match is replaced with\n * the imported file content (already cap-truncated per EC-D), and\n * recursion continues on the resolved content until MAX_HOPS or cycle.\n *\n * Failure modes (placeholders, never throws):\n * - file not found → `[@import not found: <path>]`\n * - cycle detected → `[@import cycle detected: <path>]`\n * - depth exceeded → trailing `\\n\\n…[@import depth limit 5 reached]\\n\\n`\n *\n * @internal\n */\nexport async function resolveImports(\n content: string,\n basePath: string,\n opts: ResolveImportsOptions,\n): Promise<string> {\n if (opts.depth >= MAX_HOPS) {\n return `${content}\\n\\n…[@import depth limit ${MAX_HOPS} reached]\\n\\n`;\n }\n const baseDir = dirname(basePath);\n return replaceAsync(content, IMPORT_RE, async (raw) => {\n const absolute = resolveImportPath(raw, baseDir);\n // Containment BEFORE the read. Reporting the refusal after loading the file would\n // already have put the bytes in memory, and the placeholder names the path the author\n // wrote rather than the resolved one — echoing `/home/<user>/.ssh/id_rsa` back into the\n // prompt would leak the layout of the machine to the same untrusted document.\n if (opts.projectRoot !== undefined && !insideRoot(absolute, opts.projectRoot)) {\n return `[@import outside the project root, refused: ${raw}]`;\n }\n if (opts.visited.has(absolute)) {\n return `[@import cycle detected: ${raw}]`;\n }\n opts.visited.add(absolute);\n const loaded = await loadPlainMarkdown(absolute, { maxBytesPerFile: opts.maxBytesPerFile });\n if (loaded === undefined) {\n return `[@import not found: ${raw}]`;\n }\n // Recurse with same visited set + incremented depth. `projectRoot` is FORWARDED: an\n // imported file is repository-controlled too, so a root that applied only at depth 0\n // would be escapable in one extra hop.\n return resolveImports(loaded.content, absolute, {\n visited: opts.visited,\n depth: opts.depth + 1,\n maxBytesPerFile: opts.maxBytesPerFile,\n ...(opts.projectRoot === undefined ? {} : { projectRoot: opts.projectRoot }),\n });\n });\n}\n\nfunction resolveImportPath(raw: string, baseDir: string): string {\n if (raw.startsWith(\"~/\")) {\n return resolvePath(join(homedir(), raw.slice(2)));\n }\n if (isAbsolute(raw)) {\n return resolvePath(raw);\n }\n return resolvePath(join(baseDir, raw));\n}\n\n/**\n * Async equivalent of `String.prototype.replace` — sequential. Returns\n * `content` with every `re` match replaced by `await replacer(match)`.\n *\n * @internal\n */\nasync function replaceAsync(\n content: string,\n re: RegExp,\n replacer: (raw: string) => Promise<string>,\n): Promise<string> {\n const matches: Array<{ match: string; raw: string; index: number }> = [];\n // Reset lastIndex; clone the regex to avoid stateful traps.\n const localRe = new RegExp(re.source, re.flags);\n let m: RegExpExecArray | null;\n // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex loop\n while ((m = localRe.exec(content)) !== null) {\n matches.push({ match: m[0], raw: m[1] ?? \"\", index: m.index });\n if (m.index === localRe.lastIndex) localRe.lastIndex += 1;\n }\n if (matches.length === 0) return content;\n let result = \"\";\n let cursor = 0;\n for (const entry of matches) {\n result += content.slice(cursor, entry.index);\n result += await replacer(entry.raw);\n cursor = entry.index + entry.match.length;\n }\n result += content.slice(cursor);\n return result;\n}\n","/**\n * Shared glob → RegExp compiler for context discovery (extracted from the\n * MDC parser so the `.cursor/rules/*.mdc` and `.theokit/rules/*.md` parsers\n * share ONE implementation — DRY, no new dependency).\n *\n * Supports `**` (any depth), `*` (single path segment, no `/`), `?` (single\n * non-separator char). Sufficient for the patterns Cursor and Claude Code\n * themselves recommend.\n *\n * @internal\n */\nexport function globToRegex(glob: string): RegExp {\n // Support **/ (zero-or-more path segments), ** (any depth), * (single\n // segment), ? (single non-separator char). `**/` collapses so `src/**/*.ts`\n // matches `src/foo.ts` AND `src/a/b/foo.ts` — the semantics Cursor and Claude\n // Code document (\"src/**/* → all files under src/\"). `*` and `?` never cross a\n // `/` (strict glob segment semantics). Escape other regex metas.\n const compiled = glob\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*\\//g, \"::GLOBSTAR_SLASH::\")\n .replace(/\\*\\*/g, \"::GLOBSTAR::\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/\\?/g, \"[^/]\")\n .replace(/::GLOBSTAR_SLASH::/g, \"(?:.*/)?\")\n .replace(/::GLOBSTAR::/g, \".*\");\n return new RegExp(`^${compiled}$`);\n}\n\n/**\n * True when any of `patterns` glob-matches any of `paths`. Central helper so\n * both rule parsers agree on activation semantics.\n *\n * @internal\n */\nexport function anyGlobMatches(\n patterns: ReadonlyArray<string>,\n paths: ReadonlyArray<string>,\n): boolean {\n if (patterns.length === 0 || paths.length === 0) return false;\n const res = patterns.map(globToRegex);\n return paths.some((p) => res.some((re) => re.test(p)));\n}\n","/**\n * Parser for `.theokit/rules/*.md` — theokit-native path-scoped rules,\n * mirroring Claude Code's `.claude/rules/`.\n *\n * Frontmatter fields:\n * - `paths` — glob-pattern array (Claude Code parity: `.claude/rules` uses `paths:`).\n * - `globs` — glob-pattern array (Cursor-compatible alias; unioned with `paths`).\n * - `alwaysApply` — activate unconditionally (no scope needed).\n * - `enabled` — set `false` to disable the rule entirely (wins over everything).\n * - `description` — human note; not used for activation in v1.\n *\n * Activation (`shouldActivateRule`):\n * - `enabled: false` → never activates.\n * - `alwaysApply: true` → always activates.\n * - otherwise → activates iff a `paths`/`globs` pattern matches an in-scope\n * file (the caller's `agent.send(..., { contextPaths })`). With no in-scope\n * files, a scoped rule stays dormant (parity with Cursor `.mdc`).\n *\n * A file with no `---` frontmatter is treated as an unconditional rule\n * (`alwaysApply: true`). Malformed YAML → `undefined` (caller drops + counts).\n *\n * Glob + YAML subset are shared with the MDC parser (DRY, no new dependency).\n *\n * NOTE — no internal-visibility tag in this block. `tsconfig.base.json` sets `stripInternal: true`,\n * and TypeScript scans EVERY leading comment range of the declaration that follows, including the\n * import right below this one. The tag that used to sit here deleted that import from the emitted\n * `.d.ts`, leaving the types it binds unresolvable for any consumer running type-aware lint\n * (usetheodev/theokit-sdk#283 records the same trap on a declaration).\n */\n\nimport { z } from \"zod\";\n\nimport { anyGlobMatches } from \"./context-glob.js\";\nimport { parseSimpleYaml, splitFrontmatter } from \"./context-yaml-lite.js\";\n\n/**\n * YAML frontmatter schema for `.theokit/rules/*.md` files.\n *\n * Every field is optional, and unknown keys are dropped rather than rejected — `safeParse` failing\n * therefore means a declared key had the wrong TYPE (`paths` as a bare string, `enabled` as the\n * string `\"false\"`), never that an unexpected key was present.\n *\n * Exported because {@link RulesFrontmatter} is inferred from it and appears in the signature of\n * {@link shouldActivateRule}, which `@theokit/sdk/context` publishes: the constant has to reach the\n * emitted declarations for that inferred type to resolve in a consumer's project.\n */\nexport const RulesFrontmatterSchema = z.object({\n description: z.string().optional(),\n paths: z.array(z.string()).optional(),\n globs: z.array(z.string()).optional(),\n alwaysApply: z.boolean().optional(),\n enabled: z.boolean().optional(),\n});\n\nexport type RulesFrontmatter = z.infer<typeof RulesFrontmatterSchema>;\n\nexport interface RulesParseResult {\n readonly frontmatter: RulesFrontmatter;\n readonly body: string;\n}\n\n/**\n * Split a `.theokit/rules/*.md` document into its frontmatter and its body.\n *\n * A file with no `---` fence is not an error: the whole text becomes the body and the frontmatter\n * is synthesised as `{ alwaysApply: true }`, so a plain markdown rule with no metadata applies\n * unconditionally. That default is the one thing to know before adding a fence — adding one and\n * omitting both `alwaysApply` and a path pattern turns an always-on rule into a dormant one.\n *\n * `undefined` means the fence was there and its contents did not survive: YAML the lite parser\n * could not read, or a shape the schema rejected (`paths` as a bare string rather than a list,\n * `enabled` as `\"false\"` rather than `false`). It never throws, and it does not say WHICH of the\n * two happened — the caller drops the file and counts it.\n *\n * Unknown frontmatter keys are dropped rather than rejected, so a misspelled `alwaysAply` parses\n * fine and simply has no effect.\n *\n * Nothing here decides whether the rule applies; that is `shouldActivateRule`.\n *\n * @public — re-exported from `@theokit/sdk/context`, and therefore under semver.\n */\nexport function parseRules(content: string): RulesParseResult | undefined {\n const { yaml, body } = splitFrontmatter(content);\n if (yaml === undefined) {\n return { frontmatter: { alwaysApply: true }, body: content };\n }\n try {\n const parsed = parseSimpleYaml(yaml);\n const validated = RulesFrontmatterSchema.safeParse(parsed);\n if (!validated.success) return undefined;\n return { frontmatter: validated.data, body };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Decide whether a parsed rule applies to this turn, given the files in scope.\n *\n * Checked in strict order, first match wins:\n *\n * 1. `enabled: false` — never applies, whatever else the frontmatter says. This overrides\n * `alwaysApply: true`, which is the point of having it.\n * 2. `alwaysApply: true` — applies, and `inScopePaths` is not consulted.\n * 3. otherwise — applies only if some pattern from `paths` or `globs` matches some path in\n * `inScopePaths`. The two lists are a union, not alternatives; `globs` exists for\n * Cursor compatibility and behaves identically.\n *\n * A scoped rule with an EMPTY `inScopePaths` never applies. That is the case worth planning for:\n * `contextPaths` is empty on a plain `agent.send()`, so a rule scoped by path stays dormant until\n * the caller declares which files the turn is about. It is quiet — a dormant rule looks exactly\n * like a rule that was never written.\n *\n * A rule with a fence but no patterns and no `alwaysApply` also never applies, since step 3 has\n * nothing to match.\n *\n * `description` is not consulted. It is a note for humans, not an activation condition.\n *\n * @public — re-exported from `@theokit/sdk/context`, and therefore under semver.\n */\nexport function shouldActivateRule(\n fm: RulesFrontmatter,\n inScopePaths: ReadonlyArray<string>,\n): boolean {\n if (fm.enabled === false) return false;\n if (fm.alwaysApply === true) return true;\n const patterns = [...(fm.paths ?? []), ...(fm.globs ?? [])];\n if (patterns.length === 0) return false;\n return anyGlobMatches(patterns, inScopePaths);\n}\n","/**\n * MDC (Markdown Cursor) parser for `.cursor/rules/*.mdc` (T3.1, ADR D154).\n *\n * Parses YAML frontmatter with `description` / `globs` / `alwaysApply`\n * fields. Honors activation per Cursor's docs:\n * - `alwaysApply: true` → activates unconditionally.\n * - `alwaysApply: false` + matching glob in `touchedFiles` → activates.\n * - `alwaysApply: false` + no glob match → skipped.\n *\n * **EC-I (v1 semantic):** at `agent.send()` time, `touchedFiles` is empty\n * UNLESS the caller passes `contextPaths` (the in-scope file set). When\n * `contextPaths` is provided, per-glob activation fires; otherwise only\n * `alwaysApply: true` rules activate. Description-based \"agent requested\"\n * classification is out of scope.\n *\n * Glob matching + the YAML subset are shared with the `.theokit/rules/*.md`\n * parser via `context-glob.ts` / `context-yaml-lite.ts` (DRY, no new dep).\n *\n * @internal\n */\n\nimport { z } from \"zod\";\n\nimport { anyGlobMatches } from \"./context-glob.js\";\nimport { parseSimpleYaml, splitFrontmatter } from \"./context-yaml-lite.js\";\n\n/** YAML frontmatter schema for MDC files. @internal */\nexport const McdFrontmatterSchema = z.object({\n description: z.string().optional(),\n globs: z.array(z.string()).optional(),\n alwaysApply: z.boolean().optional(),\n});\n\nexport type McdFrontmatter = z.infer<typeof McdFrontmatterSchema>;\n\nexport interface McdParseResult {\n readonly frontmatter: McdFrontmatter;\n readonly body: string;\n}\n\n/**\n * Parse `.mdc` content. Returns frontmatter + body. EC-18: when the\n * file has no `---` frontmatter, returns `frontmatter: {alwaysApply:\n * true}` so the body is treated as an unconditional rule.\n *\n * On YAML parse error, returns `undefined` and the caller emits a\n * telemetry counter (EC-21).\n *\n * @internal\n */\nexport function parseMdc(content: string): McdParseResult | undefined {\n const { yaml, body } = splitFrontmatter(content);\n if (yaml === undefined) {\n // EC-18: no frontmatter — treat as alwaysApply\n return { frontmatter: { alwaysApply: true }, body: content };\n }\n try {\n const parsed = parseSimpleYaml(yaml);\n const validated = McdFrontmatterSchema.safeParse(parsed);\n if (!validated.success) return undefined;\n return { frontmatter: validated.data, body };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Decide whether an MDC rule activates given the currently-touched\n * files. EC-I: empty `touchedFiles` → only `alwaysApply: true`\n * activates.\n *\n * @internal\n */\nexport function shouldActivate(fm: McdFrontmatter, touchedFiles: ReadonlyArray<string>): boolean {\n if (fm.alwaysApply === true) return true;\n if (fm.globs === undefined || fm.globs.length === 0) return false;\n return anyGlobMatches(fm.globs, touchedFiles);\n}\n","/**\n * Multi-format context discovery runner (T5.1, ADRs D150-D156).\n *\n * Walks `DEFAULT_DISCOVERY_SPECS` (or caller override), loads each\n * spec via the appropriate parser, applies `@import` resolution where\n * declared, and returns a flat list of `AggregatorSource[]` ready for\n * the aggregate cap.\n *\n * **EC-E privacy fix:** source disambiguation uses\n * `relative(gitRoot ?? cwd, ...)` — NEVER absolute paths in\n * `<source name=\"\">`.\n *\n * @internal\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, relative } from \"node:path\";\n\nimport type { AggregatorSource } from \"./context-aggregator.js\";\nimport {\n DEFAULT_DISCOVERY_SPECS,\n type DiscoverySpec,\n findGitRoot,\n walkUpForFile,\n walkUpForGlob,\n} from \"./context-discovery.js\";\nimport { resolveImports } from \"./context-import-resolver.js\";\nimport { loadPlainMarkdown } from \"./context-loaders.js\";\nimport { parseMdc, shouldActivate } from \"./context-mdc-parser.js\";\nimport { parseRules, shouldActivateRule } from \"./context-rules-frontmatter.js\";\n\n/**\n * Input to the context-discovery run: where to walk, how much of each file to keep, and which\n * trust boundary an `@import` may not cross.\n *\n * `cwd` and `maxBytesPerFile` are required because neither has a safe default — an unset root walks\n * the wrong tree, and an unset cap lets one large file consume the context window.\n *\n * `importRoot` is the field to reach for when the caller's trust boundary is narrower than the\n * repository. Left unset, the repository IS the boundary (`gitRoot ?? cwd`), which is the honest\n * default for a document found by walking the repository — but it does mean an `@import` can pull\n * in any file the repo contains.\n *\n * @public — re-exported from '@theokit/sdk/context', and therefore under semver.\n */\nexport interface DiscoveryRunnerOptions {\n /** Workspace root passed to all discovery scopes. */\n readonly cwd: string;\n /** Per-file truncation cap (D155). */\n readonly maxBytesPerFile: number;\n /** Optional override of the default registry. */\n readonly specs?: ReadonlyArray<DiscoverySpec>;\n /** Cursor MDC: file paths the LLM has touched this turn (EC-I: empty at send-time). */\n readonly touchedFiles?: ReadonlyArray<string>;\n /** When true, skip `theokit-context` spec — caller already handles the legacy path. */\n readonly skipLegacyTheokitContext?: boolean;\n /**\n * The root an `@import` may not escape. Defaults to `gitRoot ?? cwd` — the same value\n * this runner already uses to keep absolute paths out of `<source name=\"\">`.\n *\n * Present so an embedder with a trust boundary narrower than the repository can declare\n * it. Absent, the repository IS the boundary, which is the honest default for a document\n * discovered by walking the repository.\n */\n readonly importRoot?: string;\n}\n\n/**\n * Find, read and parse every context file the specs describe, and return them ready for the\n * aggregator.\n *\n * Specs are processed in the order given — `opts.specs` when supplied, otherwise\n * `DEFAULT_DISCOVERY_SPECS` — and within a spec, in the order its scope resolves paths. The\n * returned array carries `priority` on each source; it is NOT sorted here, so the aggregator is\n * what applies the ordering.\n *\n * A path already emitted is skipped, across specs as well as within one. Paths arrive resolved\n * through `realpath`, so two specs pointing at the same physical file through a symlink produce\n * one source rather than two.\n *\n * Missing and unreadable files are not errors: a file that does not exist is simply not matched,\n * and one that fails to read or parse is dropped and the run continues. A frontmatter file whose\n * activation conditions do not hold — `enabled: false`, or a scope that no touched file matches —\n * is dropped the same way. So a shorter result than expected means \"nothing qualified\", and this\n * function will not tell you which of those it was.\n *\n * Reads the filesystem and nothing else. No network, no writes, and no mutation of `opts`.\n *\n * Privacy: `<source name=\"\">` is built from the path RELATIVE to the git root (or `cwd` when\n * there is no git root), never an absolute path, so a home directory never reaches the prompt.\n * `@import` resolution is bounded by `opts.importRoot`, defaulting to that same root — a document\n * cannot pull in a file from outside the repository.\n *\n * @public — re-exported from `@theokit/sdk/context`, and therefore under semver.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: per-spec dispatch ladder + cross-spec dedup is a flat orchestrator; splitting would obscure the priority-merge invariant.\nexport async function runDiscovery(opts: DiscoveryRunnerOptions): Promise<AggregatorSource[]> {\n const gitRoot = findGitRoot(opts.cwd);\n const specs = opts.specs ?? DEFAULT_DISCOVERY_SPECS;\n const out: AggregatorSource[] = [];\n const seenReal = new Set<string>();\n\n for (const spec of specs) {\n if (opts.skipLegacyTheokitContext && spec.id === \"theokit-context\") continue;\n const paths = await resolvePathsForSpec(spec, opts.cwd, gitRoot);\n for (const path of paths) {\n if (seenReal.has(path)) continue;\n seenReal.add(path);\n const source = await loadOneSource(spec, path, opts, gitRoot);\n if (source !== undefined) out.push(source);\n }\n }\n return out;\n}\n\nasync function resolvePathsForSpec(\n spec: DiscoverySpec,\n cwd: string,\n gitRoot: string | undefined,\n): Promise<string[]> {\n if (spec.scope === \"cwd-only\") {\n return walkUpForFile(cwd, spec.pattern, cwd);\n }\n if (spec.scope === \"git-root-walk\") {\n return walkUpForFile(cwd, spec.pattern, gitRoot ?? cwd);\n }\n // globbed\n return walkUpForGlob(cwd, spec.pattern);\n}\n\nasync function loadOneSource(\n spec: DiscoverySpec,\n path: string,\n opts: DiscoveryRunnerOptions,\n gitRoot: string | undefined,\n): Promise<AggregatorSource | undefined> {\n // EC-E privacy: name uses relative-to-git-root for disambiguation;\n // NEVER absolute paths in the public `<source name=\"\">` attribute.\n // For cwd-only specs (THEO.md), no disambiguation is needed because\n // the scope can only ever match a single file.\n const relPath = relative(gitRoot ?? opts.cwd, dirname(path));\n const needsSuffix = spec.scope !== \"cwd-only\" && relPath !== \"\" && relPath !== \".\";\n const id = needsSuffix ? `${spec.id}@${relPath}` : spec.id;\n\n if (spec.parser === \"mdc\") {\n return loadMdcSource(spec, path, id, opts);\n }\n if (spec.parser === \"rules-frontmatter\") {\n return loadRulesSource(spec, path, id, opts);\n }\n if (spec.parser === \"frontmatter-zod\") {\n // Legacy `.theokit/context/*.md` — handled by `loadContextConfig` in\n // `context-manager.ts` for backward compat. We skip here unless caller\n // explicitly wants us to load it (currently always skipped).\n return undefined;\n }\n // plain-markdown\n return loadPlainMarkdownSource(spec, path, id, opts, gitRoot);\n}\n\n/**\n * Shared read → parse → activation-gate → source pipeline for the frontmatter\n * discovery parsers (mdc, rules). Binds the parser + the activation predicate so\n * the mdc and rules loaders differ only in those two, not in the surrounding\n * read/guard/shape boilerplate (DRY).\n */\nasync function loadParsedSource<F>(\n spec: DiscoverySpec,\n path: string,\n id: string,\n parse: (raw: string) => { frontmatter: F; body: string } | undefined,\n isActive: (frontmatter: F) => boolean,\n): Promise<AggregatorSource | undefined> {\n let raw: string;\n try {\n raw = await readFile(path, \"utf8\");\n } catch {\n return undefined;\n }\n const parsed = parse(raw);\n if (parsed === undefined || !isActive(parsed.frontmatter)) return undefined;\n return { id, source: path, content: parsed.body, priority: spec.priority, truncated: false };\n}\n\nfunction loadMdcSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n): Promise<AggregatorSource | undefined> {\n return loadParsedSource(spec, path, id, parseMdc, (fm) =>\n shouldActivate(fm, opts.touchedFiles ?? []),\n );\n}\n\nfunction loadRulesSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n): Promise<AggregatorSource | undefined> {\n return loadParsedSource(spec, path, id, parseRules, (fm) =>\n shouldActivateRule(fm, opts.touchedFiles ?? []),\n );\n}\n\nasync function loadPlainMarkdownSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n gitRoot: string | undefined,\n): Promise<AggregatorSource | undefined> {\n const loaded = await loadPlainMarkdown(path, { maxBytesPerFile: opts.maxBytesPerFile });\n if (loaded === undefined) return undefined;\n let content = loaded.content;\n if (spec.followImports) {\n content = await resolveImports(content, path, {\n visited: new Set([path]),\n depth: 0,\n maxBytesPerFile: opts.maxBytesPerFile,\n // The document carrying the import is repository-controlled, so the repository is the\n // boundary it may not cross. Without this, `CLAUDE.md` / `GEMINI.md` — the two specs\n // with `followImports: true` — could name any absolute or `~/` path and have it\n // inlined into the system prompt.\n projectRoot: opts.importRoot ?? gitRoot ?? opts.cwd,\n });\n }\n return {\n id,\n source: path,\n content,\n priority: spec.priority,\n truncated: loaded.truncated,\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/runtime/context/context-loaders.ts","../src/internal/runtime/context/context-import-resolver.ts","../src/internal/runtime/context/context-glob.ts","../src/internal/runtime/context/context-rules-frontmatter.ts","../src/internal/runtime/context/context-mdc-parser.ts","../src/internal/runtime/context/context-discovery-runner.ts"],"names":["resolvePath","z","dirname","readFile"],"mappings":"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","file":"chunk-SAVIWMZB.js","sourcesContent":["/**\n * Context file loaders + truncation (T1.2, ADRs D154 / D155 / D159).\n *\n * Reads context source files from disk, applies the per-file size cap\n * with 70%/20% head/tail truncation, and emits the\n * `context_files_truncated` telemetry counter when the cap fires.\n * Pure (no I/O) for `truncateWithMarker` — testable in isolation.\n *\n * @internal\n */\n\nimport { readFile } from \"node:fs/promises\";\n\nconst HEAD_RATIO = 0.7;\nconst TAIL_RATIO = 0.2;\nconst MARKER = \"\\n\\n…[truncated by theokit]\\n\\n\";\n\n/** Default per-file cap (40k chars ≈ 10k tokens). D155. */\nexport const DEFAULT_MAX_BYTES_PER_FILE = 40_000;\n\nexport interface LoadedSource {\n /** Absolute path the content came from. */\n readonly source: string;\n readonly content: string;\n readonly originalBytes: number;\n readonly truncated: boolean;\n}\n\nexport interface TruncateResult {\n readonly truncated: boolean;\n readonly finalContent: string;\n}\n\n/**\n * Cap `content` at `max` characters with 70%/20% head/tail truncation\n * and an explicit marker. Pure — no I/O, no telemetry.\n *\n * EC-C: when `max <= MARKER.length`, skip the marker entirely and\n * return a head-only slice. Without this guard, `budget = max -\n * MARKER.length` would go negative and `content.slice(-tailBytes)`\n * would slice from the END of the string rather than truncating.\n *\n * EC-H: codepoint integrity — `String.slice()` operates on UTF-16\n * code units, which can split surrogate pairs. We accept that\n * trailing/leading replacement chars (U+FFFD) may appear at boundaries.\n * Modern LLMs tolerate them; byte-exact safety would require Buffer\n * slicing + TextDecoder with `fatal: true` retry, which adds complexity\n * without value.\n *\n * @public\n */\nexport function truncateWithMarker(content: string, max: number): TruncateResult {\n if (content.length <= max) {\n return { truncated: false, finalContent: content };\n }\n // EC-C: max too small to fit even the marker — return head-only slice.\n if (max <= MARKER.length) {\n return { truncated: true, finalContent: content.slice(0, max) };\n }\n const budget = max - MARKER.length;\n const headBytes = Math.floor(budget * (HEAD_RATIO / (HEAD_RATIO + TAIL_RATIO)));\n const tailBytes = budget - headBytes;\n return {\n truncated: true,\n finalContent: content.slice(0, headBytes) + MARKER + content.slice(-tailBytes),\n };\n}\n\n/**\n * Read a file from disk and apply the per-file cap. Emits telemetry\n * counter when truncation fires.\n *\n * EC-G: file deleted between discovery and read (FS race) → returns\n * `undefined`, never throws.\n *\n * @internal\n */\nexport async function loadPlainMarkdown(\n absPath: string,\n opts: { maxBytesPerFile?: number } = {},\n): Promise<LoadedSource | undefined> {\n const max = opts.maxBytesPerFile ?? DEFAULT_MAX_BYTES_PER_FILE;\n let content: string;\n try {\n content = await readFile(absPath, \"utf8\");\n } catch {\n // EC-G: ENOENT / EACCES / etc → caller treats as missing.\n return undefined;\n }\n const { truncated, finalContent } = truncateWithMarker(content, max);\n if (truncated) {\n emitTruncationCounter(absPath);\n }\n return {\n source: absPath,\n content: finalContent,\n originalBytes: content.length,\n truncated,\n };\n}\n\n/**\n * EC-L: telemetry no-op when OTel is not imported. We import the tracer\n * lazily and use `safeCall` so the lookup never throws and never pulls\n * OTel into the import graph for users without `@opentelemetry/api`\n * installed.\n *\n * @internal\n */\nfunction emitTruncationCounter(source: string): void {\n // Lazy resolution via globalThis avoids static import of telemetry/tracer.\n // Tests can spy via the same path; production users without OTel see no-op.\n const tracer = (\n globalThis as { __theokit_tracer?: { inc?: (k: string, attrs: unknown) => void } }\n ).__theokit_tracer;\n if (tracer?.inc === undefined) return;\n try {\n tracer.inc(\"context_files_truncated\", { file: source });\n } catch {\n // Telemetry must never break the loader.\n }\n}\n","/**\n * `@path/to/file` import resolver (T2.1, ADR D156).\n *\n * Anthropic/Gemini convention: lines that are EXACTLY `@path` get\n * replaced with the imported file's content, recursively (5-hop cap),\n * with cycle detection. Inline `see @x.md, also @y.md` references are\n * NOT resolved (EC-Q — own-line only, mirrors Anthropic's actual\n * behavior).\n *\n * EC-D fix: every imported file is itself capped at `maxBytesPerFile`\n * via `loadPlainMarkdown` BEFORE concatenation. Prevents a CLAUDE.md\n * with 5 imports of 30k each from ballooning to 150k of imported\n * content before the outer cap fires.\n *\n * @internal\n */\n\nimport { homedir } from \"node:os\";\nimport { dirname, isAbsolute, join, resolve as resolvePath } from \"node:path\";\n\nimport { loadPlainMarkdown } from \"./context-loaders.js\";\nimport { insideRoot } from \"./path-containment.js\";\n\n/** EC-Q: line-anchored. `@path` must be alone on its line. */\nconst IMPORT_RE = /^@(\\S+)\\s*$/gm;\nconst MAX_HOPS = 5;\n\nexport interface ResolveImportsOptions {\n /** Absolute paths already resolved (cycle detection). */\n readonly visited: Set<string>;\n /** Current recursion depth — caps at MAX_HOPS. */\n readonly depth: number;\n /** Per-import file cap (EC-D). Forwarded to loadPlainMarkdown. */\n readonly maxBytesPerFile: number;\n /**\n * The directory an import may not escape. When set, a target resolving outside it is\n * refused and replaced with a placeholder.\n *\n * The file carrying the import is REPOSITORY-CONTROLLED — `CLAUDE.md` and `GEMINI.md`\n * are the two default specs with `followImports: true`, and both are found by\n * `git-root-walk` inside the tree the agent was pointed at. Without a root, a cloned\n * repository could name `@~/.ssh/id_rsa` or any absolute path and have its contents\n * inlined into the system prompt, and from there sent to the model provider. The\n * traversal guard that already existed (`isSafePattern`) guards the discovery PATTERN,\n * not the import TARGET, so it never saw this.\n *\n * OPTIONAL, so a caller outside the discovery path keeps the previous behaviour rather\n * than breaking on an upgrade. `runDiscovery` always supplies `gitRoot ?? cwd` — the\n * same value it already uses to keep absolute paths out of `<source name=\"\">`.\n */\n readonly projectRoot?: string;\n}\n\n/**\n * Resolve `@path` directives in `content`. Each match is replaced with\n * the imported file content (already cap-truncated per EC-D), and\n * recursion continues on the resolved content until MAX_HOPS or cycle.\n *\n * Failure modes (placeholders, never throws):\n * - file not found → `[@import not found: <path>]`\n * - cycle detected → `[@import cycle detected: <path>]`\n * - depth exceeded → trailing `\\n\\n…[@import depth limit 5 reached]\\n\\n`\n *\n * @internal\n */\nexport async function resolveImports(\n content: string,\n basePath: string,\n opts: ResolveImportsOptions,\n): Promise<string> {\n if (opts.depth >= MAX_HOPS) {\n return `${content}\\n\\n…[@import depth limit ${MAX_HOPS} reached]\\n\\n`;\n }\n const baseDir = dirname(basePath);\n return replaceAsync(content, IMPORT_RE, async (raw) => {\n const absolute = resolveImportPath(raw, baseDir);\n // Containment BEFORE the read. Reporting the refusal after loading the file would\n // already have put the bytes in memory, and the placeholder names the path the author\n // wrote rather than the resolved one — echoing `/home/<user>/.ssh/id_rsa` back into the\n // prompt would leak the layout of the machine to the same untrusted document.\n if (opts.projectRoot !== undefined && !insideRoot(absolute, opts.projectRoot)) {\n return `[@import outside the project root, refused: ${raw}]`;\n }\n if (opts.visited.has(absolute)) {\n return `[@import cycle detected: ${raw}]`;\n }\n opts.visited.add(absolute);\n const loaded = await loadPlainMarkdown(absolute, { maxBytesPerFile: opts.maxBytesPerFile });\n if (loaded === undefined) {\n return `[@import not found: ${raw}]`;\n }\n // Recurse with same visited set + incremented depth. `projectRoot` is FORWARDED: an\n // imported file is repository-controlled too, so a root that applied only at depth 0\n // would be escapable in one extra hop.\n return resolveImports(loaded.content, absolute, {\n visited: opts.visited,\n depth: opts.depth + 1,\n maxBytesPerFile: opts.maxBytesPerFile,\n ...(opts.projectRoot === undefined ? {} : { projectRoot: opts.projectRoot }),\n });\n });\n}\n\nfunction resolveImportPath(raw: string, baseDir: string): string {\n if (raw.startsWith(\"~/\")) {\n return resolvePath(join(homedir(), raw.slice(2)));\n }\n if (isAbsolute(raw)) {\n return resolvePath(raw);\n }\n return resolvePath(join(baseDir, raw));\n}\n\n/**\n * Async equivalent of `String.prototype.replace` — sequential. Returns\n * `content` with every `re` match replaced by `await replacer(match)`.\n *\n * @internal\n */\nasync function replaceAsync(\n content: string,\n re: RegExp,\n replacer: (raw: string) => Promise<string>,\n): Promise<string> {\n const matches: Array<{ match: string; raw: string; index: number }> = [];\n // Reset lastIndex; clone the regex to avoid stateful traps.\n const localRe = new RegExp(re.source, re.flags);\n let m: RegExpExecArray | null;\n // biome-ignore lint/suspicious/noAssignInExpressions: idiomatic regex loop\n while ((m = localRe.exec(content)) !== null) {\n matches.push({ match: m[0], raw: m[1] ?? \"\", index: m.index });\n if (m.index === localRe.lastIndex) localRe.lastIndex += 1;\n }\n if (matches.length === 0) return content;\n let result = \"\";\n let cursor = 0;\n for (const entry of matches) {\n result += content.slice(cursor, entry.index);\n result += await replacer(entry.raw);\n cursor = entry.index + entry.match.length;\n }\n result += content.slice(cursor);\n return result;\n}\n","/**\n * Shared glob → RegExp compiler for context discovery (extracted from the\n * MDC parser so the `.cursor/rules/*.mdc` and `.theokit/rules/*.md` parsers\n * share ONE implementation — DRY, no new dependency).\n *\n * Supports `**` (any depth), `*` (single path segment, no `/`), `?` (single\n * non-separator char). Sufficient for the patterns Cursor and Claude Code\n * themselves recommend.\n *\n * @internal\n */\nexport function globToRegex(glob: string): RegExp {\n // Support **/ (zero-or-more path segments), ** (any depth), * (single\n // segment), ? (single non-separator char). `**/` collapses so `src/**/*.ts`\n // matches `src/foo.ts` AND `src/a/b/foo.ts` — the semantics Cursor and Claude\n // Code document (\"src/**/* → all files under src/\"). `*` and `?` never cross a\n // `/` (strict glob segment semantics). Escape other regex metas.\n const compiled = glob\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*\\*\\//g, \"::GLOBSTAR_SLASH::\")\n .replace(/\\*\\*/g, \"::GLOBSTAR::\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/\\?/g, \"[^/]\")\n .replace(/::GLOBSTAR_SLASH::/g, \"(?:.*/)?\")\n .replace(/::GLOBSTAR::/g, \".*\");\n return new RegExp(`^${compiled}$`);\n}\n\n/**\n * True when any of `patterns` glob-matches any of `paths`. Central helper so\n * both rule parsers agree on activation semantics.\n *\n * @internal\n */\nexport function anyGlobMatches(\n patterns: ReadonlyArray<string>,\n paths: ReadonlyArray<string>,\n): boolean {\n if (patterns.length === 0 || paths.length === 0) return false;\n const res = patterns.map(globToRegex);\n return paths.some((p) => res.some((re) => re.test(p)));\n}\n","/**\n * Parser for `.theokit/rules/*.md` — theokit-native path-scoped rules,\n * mirroring Claude Code's `.claude/rules/`.\n *\n * Frontmatter fields:\n * - `paths` — glob-pattern array (Claude Code parity: `.claude/rules` uses `paths:`).\n * - `globs` — glob-pattern array (Cursor-compatible alias; unioned with `paths`).\n * - `alwaysApply` — activate unconditionally (no scope needed).\n * - `enabled` — set `false` to disable the rule entirely (wins over everything).\n * - `description` — human note; not used for activation in v1.\n *\n * Activation (`shouldActivateRule`):\n * - `enabled: false` → never activates.\n * - `alwaysApply: true` → always activates.\n * - otherwise → activates iff a `paths`/`globs` pattern matches an in-scope\n * file (the caller's `agent.send(..., { contextPaths })`). With no in-scope\n * files, a scoped rule stays dormant (parity with Cursor `.mdc`).\n *\n * A file with no `---` frontmatter is treated as an unconditional rule\n * (`alwaysApply: true`). Malformed YAML → `undefined` (caller drops + counts).\n *\n * Glob + YAML subset are shared with the MDC parser (DRY, no new dependency).\n *\n * NOTE — no internal-visibility tag in this block. `tsconfig.base.json` sets `stripInternal: true`,\n * and TypeScript scans EVERY leading comment range of the declaration that follows, including the\n * import right below this one. The tag that used to sit here deleted that import from the emitted\n * `.d.ts`, leaving the types it binds unresolvable for any consumer running type-aware lint\n * (usetheodev/theokit-sdk#283 records the same trap on a declaration).\n */\n\nimport { z } from \"zod\";\n\nimport { anyGlobMatches } from \"./context-glob.js\";\nimport { parseSimpleYaml, splitFrontmatter } from \"./context-yaml-lite.js\";\n\n/**\n * YAML frontmatter schema for `.theokit/rules/*.md` files.\n *\n * Every field is optional, and unknown keys are dropped rather than rejected — `safeParse` failing\n * therefore means a declared key had the wrong TYPE (`paths` as a bare string, `enabled` as the\n * string `\"false\"`), never that an unexpected key was present.\n *\n * Exported because {@link RulesFrontmatter} is inferred from it and appears in the signature of\n * {@link shouldActivateRule}, which `@theokit/sdk/context` publishes: the constant has to reach the\n * emitted declarations for that inferred type to resolve in a consumer's project.\n */\nexport const RulesFrontmatterSchema = z.object({\n description: z.string().optional(),\n paths: z.array(z.string()).optional(),\n globs: z.array(z.string()).optional(),\n alwaysApply: z.boolean().optional(),\n enabled: z.boolean().optional(),\n});\n\nexport type RulesFrontmatter = z.infer<typeof RulesFrontmatterSchema>;\n\nexport interface RulesParseResult {\n readonly frontmatter: RulesFrontmatter;\n readonly body: string;\n}\n\n/**\n * Split a `.theokit/rules/*.md` document into its frontmatter and its body.\n *\n * A file with no `---` fence is not an error: the whole text becomes the body and the frontmatter\n * is synthesised as `{ alwaysApply: true }`, so a plain markdown rule with no metadata applies\n * unconditionally. That default is the one thing to know before adding a fence — adding one and\n * omitting both `alwaysApply` and a path pattern turns an always-on rule into a dormant one.\n *\n * `undefined` means the fence was there and its contents did not survive: YAML the lite parser\n * could not read, or a shape the schema rejected (`paths` as a bare string rather than a list,\n * `enabled` as `\"false\"` rather than `false`). It never throws, and it does not say WHICH of the\n * two happened — the caller drops the file and counts it.\n *\n * Unknown frontmatter keys are dropped rather than rejected, so a misspelled `alwaysAply` parses\n * fine and simply has no effect.\n *\n * Nothing here decides whether the rule applies; that is `shouldActivateRule`.\n *\n * @public — re-exported from `@theokit/sdk/context`, and therefore under semver.\n */\nexport function parseRules(content: string): RulesParseResult | undefined {\n const { yaml, body } = splitFrontmatter(content);\n if (yaml === undefined) {\n return { frontmatter: { alwaysApply: true }, body: content };\n }\n try {\n const parsed = parseSimpleYaml(yaml);\n const validated = RulesFrontmatterSchema.safeParse(parsed);\n if (!validated.success) return undefined;\n return { frontmatter: validated.data, body };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Decide whether a parsed rule applies to this turn, given the files in scope.\n *\n * Checked in strict order, first match wins:\n *\n * 1. `enabled: false` — never applies, whatever else the frontmatter says. This overrides\n * `alwaysApply: true`, which is the point of having it.\n * 2. `alwaysApply: true` — applies, and `inScopePaths` is not consulted.\n * 3. otherwise — applies only if some pattern from `paths` or `globs` matches some path in\n * `inScopePaths`. The two lists are a union, not alternatives; `globs` exists for\n * Cursor compatibility and behaves identically.\n *\n * A scoped rule with an EMPTY `inScopePaths` never applies. That is the case worth planning for:\n * `contextPaths` is empty on a plain `agent.send()`, so a rule scoped by path stays dormant until\n * the caller declares which files the turn is about. It is quiet — a dormant rule looks exactly\n * like a rule that was never written.\n *\n * A rule with a fence but no patterns and no `alwaysApply` also never applies, since step 3 has\n * nothing to match.\n *\n * `description` is not consulted. It is a note for humans, not an activation condition.\n *\n * @public — re-exported from `@theokit/sdk/context`, and therefore under semver.\n */\nexport function shouldActivateRule(\n fm: RulesFrontmatter,\n inScopePaths: ReadonlyArray<string>,\n): boolean {\n if (fm.enabled === false) return false;\n if (fm.alwaysApply === true) return true;\n const patterns = [...(fm.paths ?? []), ...(fm.globs ?? [])];\n if (patterns.length === 0) return false;\n return anyGlobMatches(patterns, inScopePaths);\n}\n","/**\n * MDC (Markdown Cursor) parser for `.cursor/rules/*.mdc` (T3.1, ADR D154).\n *\n * Parses YAML frontmatter with `description` / `globs` / `alwaysApply`\n * fields. Honors activation per Cursor's docs:\n * - `alwaysApply: true` → activates unconditionally.\n * - `alwaysApply: false` + matching glob in `touchedFiles` → activates.\n * - `alwaysApply: false` + no glob match → skipped.\n *\n * **EC-I (v1 semantic):** at `agent.send()` time, `touchedFiles` is empty\n * UNLESS the caller passes `contextPaths` (the in-scope file set). When\n * `contextPaths` is provided, per-glob activation fires; otherwise only\n * `alwaysApply: true` rules activate. Description-based \"agent requested\"\n * classification is out of scope.\n *\n * Glob matching + the YAML subset are shared with the `.theokit/rules/*.md`\n * parser via `context-glob.ts` / `context-yaml-lite.ts` (DRY, no new dep).\n *\n * @internal\n */\n\nimport { z } from \"zod\";\n\nimport { anyGlobMatches } from \"./context-glob.js\";\nimport { parseSimpleYaml, splitFrontmatter } from \"./context-yaml-lite.js\";\n\n/** YAML frontmatter schema for MDC files. @internal */\nexport const McdFrontmatterSchema = z.object({\n description: z.string().optional(),\n globs: z.array(z.string()).optional(),\n alwaysApply: z.boolean().optional(),\n});\n\nexport type McdFrontmatter = z.infer<typeof McdFrontmatterSchema>;\n\nexport interface McdParseResult {\n readonly frontmatter: McdFrontmatter;\n readonly body: string;\n}\n\n/**\n * Parse `.mdc` content. Returns frontmatter + body. EC-18: when the\n * file has no `---` frontmatter, returns `frontmatter: {alwaysApply:\n * true}` so the body is treated as an unconditional rule.\n *\n * On YAML parse error, returns `undefined` and the caller emits a\n * telemetry counter (EC-21).\n *\n * @internal\n */\nexport function parseMdc(content: string): McdParseResult | undefined {\n const { yaml, body } = splitFrontmatter(content);\n if (yaml === undefined) {\n // EC-18: no frontmatter — treat as alwaysApply\n return { frontmatter: { alwaysApply: true }, body: content };\n }\n try {\n const parsed = parseSimpleYaml(yaml);\n const validated = McdFrontmatterSchema.safeParse(parsed);\n if (!validated.success) return undefined;\n return { frontmatter: validated.data, body };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Decide whether an MDC rule activates given the currently-touched\n * files. EC-I: empty `touchedFiles` → only `alwaysApply: true`\n * activates.\n *\n * @internal\n */\nexport function shouldActivate(fm: McdFrontmatter, touchedFiles: ReadonlyArray<string>): boolean {\n if (fm.alwaysApply === true) return true;\n if (fm.globs === undefined || fm.globs.length === 0) return false;\n return anyGlobMatches(fm.globs, touchedFiles);\n}\n","/**\n * Multi-format context discovery runner (T5.1, ADRs D150-D156).\n *\n * Walks `DEFAULT_DISCOVERY_SPECS` (or caller override), loads each\n * spec via the appropriate parser, applies `@import` resolution where\n * declared, and returns a flat list of `AggregatorSource[]` ready for\n * the aggregate cap.\n *\n * **EC-E privacy fix:** source disambiguation uses\n * `relative(gitRoot ?? cwd, ...)` — NEVER absolute paths in\n * `<source name=\"\">`.\n *\n * @internal\n */\n\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, relative } from \"node:path\";\n\nimport type { AggregatorSource } from \"./context-aggregator.js\";\nimport {\n DEFAULT_DISCOVERY_SPECS,\n type DiscoverySpec,\n findGitRoot,\n walkUpForFile,\n walkUpForGlob,\n} from \"./context-discovery.js\";\nimport { resolveImports } from \"./context-import-resolver.js\";\nimport { loadPlainMarkdown } from \"./context-loaders.js\";\nimport { parseMdc, shouldActivate } from \"./context-mdc-parser.js\";\nimport { parseRules, shouldActivateRule } from \"./context-rules-frontmatter.js\";\n\n/**\n * Input to the context-discovery run: where to walk, how much of each file to keep, and which\n * trust boundary an `@import` may not cross.\n *\n * `cwd` and `maxBytesPerFile` are required because neither has a safe default — an unset root walks\n * the wrong tree, and an unset cap lets one large file consume the context window.\n *\n * `importRoot` is the field to reach for when the caller's trust boundary is narrower than the\n * repository. Left unset, the repository IS the boundary (`gitRoot ?? cwd`), which is the honest\n * default for a document found by walking the repository — but it does mean an `@import` can pull\n * in any file the repo contains.\n *\n * @public — re-exported from '@theokit/sdk/context', and therefore under semver.\n */\nexport interface DiscoveryRunnerOptions {\n /** Workspace root passed to all discovery scopes. */\n readonly cwd: string;\n /** Per-file truncation cap (D155). */\n readonly maxBytesPerFile: number;\n /** Optional override of the default registry. */\n readonly specs?: ReadonlyArray<DiscoverySpec>;\n /** Cursor MDC: file paths the LLM has touched this turn (EC-I: empty at send-time). */\n readonly touchedFiles?: ReadonlyArray<string>;\n /** When true, skip `theokit-context` spec — caller already handles the legacy path. */\n readonly skipLegacyTheokitContext?: boolean;\n /**\n * The root an `@import` may not escape. Defaults to `gitRoot ?? cwd` — the same value\n * this runner already uses to keep absolute paths out of `<source name=\"\">`.\n *\n * Present so an embedder with a trust boundary narrower than the repository can declare\n * it. Absent, the repository IS the boundary, which is the honest default for a document\n * discovered by walking the repository.\n */\n readonly importRoot?: string;\n}\n\n/**\n * Find, read and parse every context file the specs describe, and return them ready for the\n * aggregator.\n *\n * Specs are processed in the order given — `opts.specs` when supplied, otherwise\n * `DEFAULT_DISCOVERY_SPECS` — and within a spec, in the order its scope resolves paths. The\n * returned array carries `priority` on each source; it is NOT sorted here, so the aggregator is\n * what applies the ordering.\n *\n * A path already emitted is skipped, across specs as well as within one. Paths arrive resolved\n * through `realpath`, so two specs pointing at the same physical file through a symlink produce\n * one source rather than two.\n *\n * Missing and unreadable files are not errors: a file that does not exist is simply not matched,\n * and one that fails to read or parse is dropped and the run continues. A frontmatter file whose\n * activation conditions do not hold — `enabled: false`, or a scope that no touched file matches —\n * is dropped the same way. So a shorter result than expected means \"nothing qualified\", and this\n * function will not tell you which of those it was.\n *\n * Reads the filesystem and nothing else. No network, no writes, and no mutation of `opts`.\n *\n * Privacy: `<source name=\"\">` is built from the path RELATIVE to the git root (or `cwd` when\n * there is no git root), never an absolute path, so a home directory never reaches the prompt.\n * `@import` resolution is bounded by `opts.importRoot`, defaulting to that same root — a document\n * cannot pull in a file from outside the repository.\n *\n * @public — re-exported from `@theokit/sdk/context`, and therefore under semver.\n */\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: per-spec dispatch ladder + cross-spec dedup is a flat orchestrator; splitting would obscure the priority-merge invariant.\nexport async function runDiscovery(opts: DiscoveryRunnerOptions): Promise<AggregatorSource[]> {\n const gitRoot = findGitRoot(opts.cwd);\n const specs = opts.specs ?? DEFAULT_DISCOVERY_SPECS;\n const out: AggregatorSource[] = [];\n const seenReal = new Set<string>();\n\n for (const spec of specs) {\n if (opts.skipLegacyTheokitContext && spec.id === \"theokit-context\") continue;\n const paths = await resolvePathsForSpec(spec, opts.cwd, gitRoot);\n for (const path of paths) {\n if (seenReal.has(path)) continue;\n seenReal.add(path);\n const source = await loadOneSource(spec, path, opts, gitRoot);\n if (source !== undefined) out.push(source);\n }\n }\n return out;\n}\n\nasync function resolvePathsForSpec(\n spec: DiscoverySpec,\n cwd: string,\n gitRoot: string | undefined,\n): Promise<string[]> {\n if (spec.scope === \"cwd-only\") {\n return walkUpForFile(cwd, spec.pattern, cwd);\n }\n if (spec.scope === \"git-root-walk\") {\n return walkUpForFile(cwd, spec.pattern, gitRoot ?? cwd);\n }\n // globbed\n return walkUpForGlob(cwd, spec.pattern);\n}\n\nasync function loadOneSource(\n spec: DiscoverySpec,\n path: string,\n opts: DiscoveryRunnerOptions,\n gitRoot: string | undefined,\n): Promise<AggregatorSource | undefined> {\n // EC-E privacy: name uses relative-to-git-root for disambiguation;\n // NEVER absolute paths in the public `<source name=\"\">` attribute.\n // For cwd-only specs (THEO.md), no disambiguation is needed because\n // the scope can only ever match a single file.\n const relPath = relative(gitRoot ?? opts.cwd, dirname(path));\n const needsSuffix = spec.scope !== \"cwd-only\" && relPath !== \"\" && relPath !== \".\";\n const id = needsSuffix ? `${spec.id}@${relPath}` : spec.id;\n\n if (spec.parser === \"mdc\") {\n return loadMdcSource(spec, path, id, opts);\n }\n if (spec.parser === \"rules-frontmatter\") {\n return loadRulesSource(spec, path, id, opts);\n }\n if (spec.parser === \"frontmatter-zod\") {\n // Legacy `.theokit/context/*.md` — handled by `loadContextConfig` in\n // `context-manager.ts` for backward compat. We skip here unless caller\n // explicitly wants us to load it (currently always skipped).\n return undefined;\n }\n // plain-markdown\n return loadPlainMarkdownSource(spec, path, id, opts, gitRoot);\n}\n\n/**\n * Shared read → parse → activation-gate → source pipeline for the frontmatter\n * discovery parsers (mdc, rules). Binds the parser + the activation predicate so\n * the mdc and rules loaders differ only in those two, not in the surrounding\n * read/guard/shape boilerplate (DRY).\n */\nasync function loadParsedSource<F>(\n spec: DiscoverySpec,\n path: string,\n id: string,\n parse: (raw: string) => { frontmatter: F; body: string } | undefined,\n isActive: (frontmatter: F) => boolean,\n): Promise<AggregatorSource | undefined> {\n let raw: string;\n try {\n raw = await readFile(path, \"utf8\");\n } catch {\n return undefined;\n }\n const parsed = parse(raw);\n if (parsed === undefined || !isActive(parsed.frontmatter)) return undefined;\n return { id, source: path, content: parsed.body, priority: spec.priority, truncated: false };\n}\n\nfunction loadMdcSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n): Promise<AggregatorSource | undefined> {\n return loadParsedSource(spec, path, id, parseMdc, (fm) =>\n shouldActivate(fm, opts.touchedFiles ?? []),\n );\n}\n\nfunction loadRulesSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n): Promise<AggregatorSource | undefined> {\n return loadParsedSource(spec, path, id, parseRules, (fm) =>\n shouldActivateRule(fm, opts.touchedFiles ?? []),\n );\n}\n\nasync function loadPlainMarkdownSource(\n spec: DiscoverySpec,\n path: string,\n id: string,\n opts: DiscoveryRunnerOptions,\n gitRoot: string | undefined,\n): Promise<AggregatorSource | undefined> {\n const loaded = await loadPlainMarkdown(path, { maxBytesPerFile: opts.maxBytesPerFile });\n if (loaded === undefined) return undefined;\n let content = loaded.content;\n if (spec.followImports) {\n content = await resolveImports(content, path, {\n visited: new Set([path]),\n depth: 0,\n maxBytesPerFile: opts.maxBytesPerFile,\n // The document carrying the import is repository-controlled, so the repository is the\n // boundary it may not cross. Without this, `CLAUDE.md` / `GEMINI.md` — the two specs\n // with `followImports: true` — could name any absolute or `~/` path and have it\n // inlined into the system prompt.\n projectRoot: opts.importRoot ?? gitRoot ?? opts.cwd,\n });\n }\n return {\n id,\n source: path,\n content,\n priority: spec.priority,\n truncated: loaded.truncated,\n };\n}\n"]}
@@ -1,8 +1,6 @@
1
1
  import { atomicWriteJson } from './chunk-VF7EWVDG.js';
2
2
  import { diag } from './chunk-T7O6K6PX.js';
3
3
  import { readFile, rename } from 'fs/promises';
4
- import { homedir } from 'os';
5
- import { join } from 'path';
6
4
 
7
5
  function migrateSchema(opts) {
8
6
  const { db, currentVersion, migrations, label = "db" } = opts;
@@ -77,27 +75,7 @@ async function writeVersionedJson(path, data, currentVersion) {
77
75
  };
78
76
  await atomicWriteJson(path, file);
79
77
  }
80
- var THEOKIT_DIR_NAME = ".theokit";
81
- function getTheokitHome(cwd) {
82
- const override = process.env.THEOKIT_HOME?.trim();
83
- if (override !== void 0 && override.length > 0) {
84
- return override;
85
- }
86
- return join(cwd, THEOKIT_DIR_NAME);
87
- }
88
- function getProfilesRoot() {
89
- return join(homedir(), THEOKIT_DIR_NAME, "profiles");
90
- }
91
- function displayTheokitHome(cwd) {
92
- const resolved = getTheokitHome(cwd);
93
- const home = homedir();
94
- if (resolved === home) return "~";
95
- if (resolved.startsWith(`${home}/`)) {
96
- return `~${resolved.slice(home.length)}`;
97
- }
98
- return resolved;
99
- }
100
78
 
101
- export { displayTheokitHome, getProfilesRoot, getTheokitHome, migrateSchema, readVersionedJson, writeVersionedJson };
102
- //# sourceMappingURL=chunk-UPRJR6IP.js.map
103
- //# sourceMappingURL=chunk-UPRJR6IP.js.map
79
+ export { migrateSchema, readVersionedJson, writeVersionedJson };
80
+ //# sourceMappingURL=chunk-UCBJBJ27.js.map
81
+ //# sourceMappingURL=chunk-UCBJBJ27.js.map