@theokit/sdk 4.49.0 → 4.51.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 (91) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/{agent-JA4ILE5O.cjs → agent-B2WU3JP6.cjs} +10 -9
  3. package/dist/{agent-JA4ILE5O.cjs.map → agent-B2WU3JP6.cjs.map} +1 -1
  4. package/dist/{agent-GKX5FE5K.js → agent-DI2QQHSJ.js} +9 -8
  5. package/dist/{agent-GKX5FE5K.js.map → agent-DI2QQHSJ.js.map} +1 -1
  6. package/dist/{chunk-3NLOQEJR.js → chunk-34XOCZJO.js} +5 -16
  7. package/dist/chunk-34XOCZJO.js.map +1 -0
  8. package/dist/{chunk-64TJCXY5.cjs → chunk-3G6ZDZ6L.cjs} +5 -5
  9. package/dist/{chunk-64TJCXY5.cjs.map → chunk-3G6ZDZ6L.cjs.map} +1 -1
  10. package/dist/{chunk-JO76RWCA.cjs → chunk-72HEBGWN.cjs} +4 -4
  11. package/dist/{chunk-JO76RWCA.cjs.map → chunk-72HEBGWN.cjs.map} +1 -1
  12. package/dist/{chunk-XARLSCKA.js → chunk-ACHVCIDQ.js} +11 -11
  13. package/dist/chunk-ACHVCIDQ.js.map +1 -0
  14. package/dist/{chunk-RJBHWM6D.js → chunk-E54KDYOE.js} +3 -3
  15. package/dist/{chunk-RJBHWM6D.js.map → chunk-E54KDYOE.js.map} +1 -1
  16. package/dist/{chunk-2S6B5B2A.js → chunk-E7WDXT4X.js} +3 -3
  17. package/dist/{chunk-2S6B5B2A.js.map → chunk-E7WDXT4X.js.map} +1 -1
  18. package/dist/{chunk-TSK4VVBW.cjs → chunk-F7OBYH2X.cjs} +52 -52
  19. package/dist/chunk-F7OBYH2X.cjs.map +1 -0
  20. package/dist/{chunk-6FSQ3CHQ.js → chunk-JGYYNDAZ.js} +5 -6
  21. package/dist/chunk-JGYYNDAZ.js.map +1 -0
  22. package/dist/{chunk-UU7MAO2D.cjs → chunk-OKLYRPKL.cjs} +4 -16
  23. package/dist/chunk-OKLYRPKL.cjs.map +1 -0
  24. package/dist/{chunk-EON4YTR6.js → chunk-R2A3WIJY.js} +3 -3
  25. package/dist/{chunk-EON4YTR6.js.map → chunk-R2A3WIJY.js.map} +1 -1
  26. package/dist/chunk-RIAM53CP.js +22 -0
  27. package/dist/chunk-RIAM53CP.js.map +1 -0
  28. package/dist/{chunk-GH52NOCL.cjs → chunk-RWMNTFHZ.cjs} +9 -9
  29. package/dist/{chunk-GH52NOCL.cjs.map → chunk-RWMNTFHZ.cjs.map} +1 -1
  30. package/dist/{chunk-MZQHVN7C.js → chunk-SEZJGV7C.js} +3 -3
  31. package/dist/{chunk-MZQHVN7C.js.map → chunk-SEZJGV7C.js.map} +1 -1
  32. package/dist/{chunk-FAUKVJCC.cjs → chunk-UQHIEUDY.cjs} +3 -3
  33. package/dist/{chunk-FAUKVJCC.cjs.map → chunk-UQHIEUDY.cjs.map} +1 -1
  34. package/dist/{chunk-UJ7HK7BX.js → chunk-VK7SIDYI.js} +3 -3
  35. package/dist/{chunk-UJ7HK7BX.js.map → chunk-VK7SIDYI.js.map} +1 -1
  36. package/dist/chunk-VKJ7V7EB.cjs +25 -0
  37. package/dist/chunk-VKJ7V7EB.cjs.map +1 -0
  38. package/dist/{chunk-74VVGK7P.cjs → chunk-WUUSAMFC.cjs} +5 -5
  39. package/dist/{chunk-74VVGK7P.cjs.map → chunk-WUUSAMFC.cjs.map} +1 -1
  40. package/dist/{chunk-XA3TSBAH.cjs → chunk-XABN5HY6.cjs} +4 -5
  41. package/dist/chunk-XABN5HY6.cjs.map +1 -0
  42. package/dist/{compact-session-UUCBTBCZ.cjs → compact-session-FKYCJRAK.cjs} +4 -3
  43. package/dist/{compact-session-UUCBTBCZ.cjs.map → compact-session-FKYCJRAK.cjs.map} +1 -1
  44. package/dist/{compact-session-GF2CBKXB.js → compact-session-LF4YOT5S.js} +4 -3
  45. package/dist/{compact-session-GF2CBKXB.js.map → compact-session-LF4YOT5S.js.map} +1 -1
  46. package/dist/context/index.cjs +6 -5
  47. package/dist/context/index.cjs.map +1 -1
  48. package/dist/context/index.js +3 -2
  49. package/dist/context/index.js.map +1 -1
  50. package/dist/cron.cjs +9 -8
  51. package/dist/cron.js +8 -7
  52. package/dist/eval.cjs +8 -7
  53. package/dist/eval.cjs.map +1 -1
  54. package/dist/eval.js +7 -6
  55. package/dist/eval.js.map +1 -1
  56. package/dist/filesystem/index.cjs +6 -5
  57. package/dist/filesystem/index.cjs.map +1 -1
  58. package/dist/filesystem/index.js +2 -1
  59. package/dist/filesystem/index.js.map +1 -1
  60. package/dist/{index-manager-YFFEPISE.cjs → index-manager-34ELCOAP.cjs} +6 -5
  61. package/dist/{index-manager-YFFEPISE.cjs.map → index-manager-34ELCOAP.cjs.map} +1 -1
  62. package/dist/index-manager-OMJVYS2U.js +12 -0
  63. package/dist/{index-manager-X5IPG2JL.js.map → index-manager-OMJVYS2U.js.map} +1 -1
  64. package/dist/index.cjs +183 -35
  65. package/dist/index.cjs.map +1 -1
  66. package/dist/index.d.cts +320 -1
  67. package/dist/index.d.ts +320 -1
  68. package/dist/index.js +152 -13
  69. package/dist/index.js.map +1 -1
  70. package/dist/{inject-session-I3HK3AHB.cjs → inject-session-J7Y6XACY.cjs} +4 -4
  71. package/dist/{inject-session-I3HK3AHB.cjs.map → inject-session-J7Y6XACY.cjs.map} +1 -1
  72. package/dist/{inject-session-NR64GB3T.js → inject-session-MWRJENH4.js} +3 -3
  73. package/dist/{inject-session-NR64GB3T.js.map → inject-session-MWRJENH4.js.map} +1 -1
  74. package/dist/internal/memory/adapters/index.cjs +2 -1
  75. package/dist/internal/memory/adapters/index.js +2 -1
  76. package/dist/internal/security/index.cjs +9 -8
  77. package/dist/internal/security/index.js +2 -1
  78. package/dist/path-safety.cjs +9 -8
  79. package/dist/path-safety.js +2 -1
  80. package/dist/skills.cjs +5 -4
  81. package/dist/skills.js +3 -2
  82. package/dist/workflow.cjs +11 -10
  83. package/dist/workflow.js +3 -2
  84. package/package.json +1 -1
  85. package/dist/chunk-3NLOQEJR.js.map +0 -1
  86. package/dist/chunk-6FSQ3CHQ.js.map +0 -1
  87. package/dist/chunk-TSK4VVBW.cjs.map +0 -1
  88. package/dist/chunk-UU7MAO2D.cjs.map +0 -1
  89. package/dist/chunk-XA3TSBAH.cjs.map +0 -1
  90. package/dist/chunk-XARLSCKA.js.map +0 -1
  91. package/dist/index-manager-X5IPG2JL.js +0 -11
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/filesystem/types.ts","../../src/filesystem/local-filesystem.ts"],"names":["fsReadFile","fsWriteFile","fsStat"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Filesystem backend protocol — a pluggable file *storage* provider for agent\n * tools, the storage-side twin of {@link SandboxBackend} (execution-side).\n *\n * SE31 (a peer framework Workspaces comparison). Mirrors `SandboxBackend`'s shape: a small\n * set of abstract methods (`readFile` / `writeFile` / `stat` / `list`) with\n * `exists()` derived on the base class, a boundary `basePath`, a `readOnly`\n * flag, and typed errors. Unlike `SandboxBackend` (whose file ops shell out via\n * `execute`, requiring command execution and giving NO structured `stat`), a\n * `FilesystemBackend` serves a *filesystem-only* workspace with no sandbox and\n * exposes a real `stat().mtimeMs` — the primitive SE32's read-before-write\n * safety compares against. See ADR 0011.\n *\n * New backends (S3, GCS, in-memory) implement the four abstract methods; higher\n * level helpers derive on the base. This is the backend *seam* — it does NOT\n * ship agent-facing tools nor a bundled workspace (bring-your-own-tools stands).\n *\n * @public\n */\n\n/** Structured file metadata. `mtimeMs` is the read-before-write oracle (SE32). */\nexport interface FileStat {\n readonly size: number;\n readonly mtimeMs: number;\n readonly isFile: boolean;\n readonly isDirectory: boolean;\n}\n\n/** Options a write may carry. SE32 adds `expectedMtime` (stale-write guard). */\nexport interface WriteFileOptions {\n /**\n * SE32 — when set, the write fails with {@link StaleFileError} if the file's\n * current `mtimeMs` differs (someone changed it since it was last read).\n */\n readonly expectedMtime?: number;\n}\n\nexport interface FilesystemConfig {\n /** Boundary root. Every path is resolved within it; escapes are rejected. */\n readonly basePath?: string;\n /** When true, every write throws {@link FilesystemReadOnlyError}. */\n readonly readOnly?: boolean;\n}\n\n/** A path escaped the backend's `basePath` (traversal or symlink). */\nexport class FilesystemSecurityError extends Error {\n readonly code = \"filesystem_security\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"FilesystemSecurityError\";\n }\n}\n\n/** A write was attempted on a read-only backend. */\nexport class FilesystemReadOnlyError extends Error {\n readonly code = \"filesystem_readonly\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"FilesystemReadOnlyError\";\n }\n}\n\n/** A read/stat targeted a path that does not exist. */\nexport class FileNotFoundError extends Error {\n readonly code = \"filesystem_not_found\" as const;\n constructor(public readonly path: string) {\n super(`File not found: ${path}`);\n this.name = \"FileNotFoundError\";\n }\n}\n\n/**\n * A filesystem I/O operation failed for a reason other than not-found /\n * read-only / stale / security (e.g. `ENOTDIR` — a path component is a file, or\n * `EACCES` / `ENOSPC`). Carries the original error as `cause` so no raw,\n * untyped Node `SystemError` ever escapes the backend (Unbreakable Rule 8).\n */\nexport class FilesystemError extends Error {\n readonly code = \"filesystem_io\" as const;\n constructor(\n public readonly path: string,\n cause: unknown,\n ) {\n super(\n `Filesystem operation failed on \"${path}\": ${(cause as { message?: string })?.message ?? cause}`,\n {\n cause,\n },\n );\n this.name = \"FilesystemError\";\n }\n}\n\n/**\n * SE32 — a write's `expectedMtime` did not match the file's current mtime: the\n * file changed since it was last read, so the write would silently clobber.\n */\nexport class StaleFileError extends Error {\n readonly code = \"filesystem_stale\" as const;\n constructor(\n public readonly path: string,\n public readonly expectedMtime: number,\n public readonly actualMtime: number,\n ) {\n super(\n `Stale write to \"${path}\": expected mtime ${expectedMtime}, found ${actualMtime} ` +\n `(file changed since last read — re-read before writing)`,\n );\n this.name = \"StaleFileError\";\n }\n}\n\n/**\n * Pluggable filesystem backend. Implement the four abstract methods; `exists()`\n * and the `readOnly`/`basePath` accessors derive on the base class.\n *\n * @public\n */\nexport abstract class FilesystemBackend {\n protected readonly _basePath: string;\n protected readonly _readOnly: boolean;\n\n constructor(config: FilesystemConfig = {}) {\n this._basePath = config.basePath ?? process.cwd();\n this._readOnly = config.readOnly ?? false;\n }\n\n /** Read a boundary-relative file as UTF-8. Throws {@link FileNotFoundError}. */\n abstract readFile(path: string): Promise<string>;\n\n /**\n * Write UTF-8 content to a boundary-relative path (creating parents). Returns\n * the new {@link FileStat}. Throws {@link FilesystemReadOnlyError} on a\n * read-only backend and {@link StaleFileError} when `opts.expectedMtime`\n * mismatches (SE32).\n */\n abstract writeFile(path: string, content: string, opts?: WriteFileOptions): Promise<FileStat>;\n\n /** Structured metadata for a path. Throws {@link FileNotFoundError}. */\n abstract stat(path: string): Promise<FileStat>;\n\n /** Directory entry names (not recursive). Throws {@link FileNotFoundError}. */\n abstract list(path: string): Promise<string[]>;\n\n /** Derived — true iff `stat(path)` resolves (absent ⇒ false). */\n async exists(path: string): Promise<boolean> {\n try {\n await this.stat(path);\n return true;\n } catch (err) {\n if (err instanceof FileNotFoundError) return false;\n throw err;\n }\n }\n\n /** Throw {@link FilesystemReadOnlyError} when the backend is read-only. */\n protected assertWritable(): void {\n if (this._readOnly) {\n throw new FilesystemReadOnlyError(`Filesystem is read-only (basePath: ${this._basePath})`);\n }\n }\n\n get readOnly(): boolean {\n return this._readOnly;\n }\n\n get basePath(): string {\n return this._basePath;\n }\n}\n\n/**\n * A backend OR a per-request resolver of one. A resolver runs at tool-execution\n * time (the request scope), so multi-tenant / multi-role agents get a distinct\n * root or permission set per request without a shared mutable backend.\n *\n * @public\n */\nexport type FilesystemProvider<Ctx = unknown> =\n | FilesystemBackend\n | ((ctx: Ctx) => FilesystemBackend | Promise<FilesystemBackend>);\n\n/** Resolve a {@link FilesystemProvider} to a concrete backend for `ctx`. */\nexport async function resolveFilesystem<Ctx>(\n provider: FilesystemProvider<Ctx>,\n ctx: Ctx,\n): Promise<FilesystemBackend> {\n return provider instanceof FilesystemBackend ? provider : provider(ctx);\n}\n","/**\n * LocalFilesystem — a {@link FilesystemBackend} over the local process\n * filesystem (`node:fs/promises`), boundary-enforced against `basePath`.\n *\n * **This is NOT an isolation boundary** (same OS, same user). Its safety\n * affordances are path-boundary enforcement (traversal + symlink escape,\n * reusing the core `internal/security/path-guard` primitives) and the optional\n * `readOnly` flag. For untrusted code, run it inside a container/VM sandbox.\n *\n * The check-then-use gap between `assertNoSymlinkEscape` and the subsequent\n * `fs` call is a known TOCTOU: a local attacker could atomically swap an\n * in-boundary symlink after the check. Closing it needs `O_NOFOLLOW`, which\n * Node's `fs/promises` does not expose — accepted for same-user local contexts.\n *\n * SE31 (a peer framework Workspaces comparison). See ADR 0011.\n *\n * @public\n */\n\nimport {\n readFile as fsReadFile,\n stat as fsStat,\n writeFile as fsWriteFile,\n mkdir,\n readdir,\n} from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport {\n assertNoSymlinkEscape,\n PathTraversalError,\n safePathJoin,\n} from \"../internal/security/path-guard.js\";\nimport {\n FileNotFoundError,\n type FileStat,\n FilesystemBackend,\n type FilesystemConfig,\n FilesystemError,\n FilesystemSecurityError,\n StaleFileError,\n type WriteFileOptions,\n} from \"./types.js\";\n\nexport class LocalFilesystem extends FilesystemBackend {\n constructor(config: FilesystemConfig = {}) {\n super(config);\n }\n\n async readFile(path: string): Promise<string> {\n const abs = this.resolve(path);\n try {\n return await fsReadFile(abs, \"utf-8\");\n } catch (err) {\n throw this.mapError(err, path);\n }\n }\n\n async writeFile(path: string, content: string, opts?: WriteFileOptions): Promise<FileStat> {\n // Security boundary FIRST (a traversal path on a read-only backend must\n // report the security error, not the read-only one — fail-clear).\n const abs = this.resolve(path);\n this.assertWritable();\n // SE32 — stale-write guard: if the caller passed the mtime it last read,\n // reject when the file changed underneath it (never a silent clobber).\n if (opts?.expectedMtime !== undefined) {\n await this.assertNotStale(path, abs, opts.expectedMtime);\n }\n try {\n await mkdir(dirname(abs), { recursive: true });\n await fsWriteFile(abs, content, \"utf-8\");\n } catch (err) {\n throw this.mapError(err, path);\n }\n return this.statAbs(abs, path);\n }\n\n async stat(path: string): Promise<FileStat> {\n const abs = this.resolve(path);\n return this.statAbs(abs, path);\n }\n\n async list(path: string): Promise<string[]> {\n const abs = this.resolve(path);\n try {\n return await readdir(abs);\n } catch (err) {\n throw this.mapError(err, path);\n }\n }\n\n private async statAbs(abs: string, relPath: string): Promise<FileStat> {\n try {\n const s = await fsStat(abs);\n return {\n size: s.size,\n mtimeMs: s.mtimeMs,\n isFile: s.isFile(),\n isDirectory: s.isDirectory(),\n };\n } catch (err) {\n throw this.mapError(err, relPath);\n }\n }\n\n /** SE32 — compare the on-disk mtime against the caller's expected value. */\n private async assertNotStale(relPath: string, abs: string, expectedMtime: number): Promise<void> {\n let current: number | undefined;\n try {\n current = (await fsStat(abs)).mtimeMs;\n } catch (err) {\n // A brand-new file (does not exist yet) cannot be stale — allow the write.\n if ((err as { code?: string }).code === \"ENOENT\") return;\n throw this.mapError(err, relPath);\n }\n if (current !== expectedMtime) {\n throw new StaleFileError(relPath, expectedMtime, current);\n }\n }\n\n /**\n * Resolve a boundary-relative path to an absolute one, rejecting lexical\n * traversal (`..`, absolute, NUL) and symlink escape — both reusing the core\n * path-guard primitives, remapped to {@link FilesystemSecurityError}.\n */\n private resolve(path: string): string {\n let abs: string;\n try {\n abs = safePathJoin(this._basePath, path);\n } catch (err) {\n if (err instanceof PathTraversalError) {\n throw new FilesystemSecurityError(`Path escapes basePath: ${path}`);\n }\n throw err;\n }\n try {\n assertNoSymlinkEscape(abs, this._basePath);\n } catch (err) {\n if (err instanceof PathTraversalError) {\n throw new FilesystemSecurityError(`Path escapes basePath via symlink: ${path}`);\n }\n throw err;\n }\n return abs;\n }\n\n private mapError(err: unknown, path: string): Error {\n if (\n err instanceof FilesystemSecurityError ||\n err instanceof FilesystemError ||\n err instanceof FileNotFoundError ||\n err instanceof StaleFileError\n ) {\n return err;\n }\n if ((err as { code?: string }).code === \"ENOENT\") return new FileNotFoundError(path);\n // ENOTDIR (a path component is a file), EACCES, ENOSPC, … — never leak a\n // raw untyped Node SystemError (Rule 8); wrap with the original as cause.\n return new FilesystemError(path, err);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/filesystem/types.ts","../../src/filesystem/local-filesystem.ts"],"names":["fsReadFile","fsWriteFile","fsStat"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Filesystem backend protocol — a pluggable file *storage* provider for agent\n * tools, the storage-side twin of {@link SandboxBackend} (execution-side).\n *\n * SE31 (a peer framework Workspaces comparison). Mirrors `SandboxBackend`'s shape: a small\n * set of abstract methods (`readFile` / `writeFile` / `stat` / `list`) with\n * `exists()` derived on the base class, a boundary `basePath`, a `readOnly`\n * flag, and typed errors. Unlike `SandboxBackend` (whose file ops shell out via\n * `execute`, requiring command execution and giving NO structured `stat`), a\n * `FilesystemBackend` serves a *filesystem-only* workspace with no sandbox and\n * exposes a real `stat().mtimeMs` — the primitive SE32's read-before-write\n * safety compares against. See ADR 0011.\n *\n * New backends (S3, GCS, in-memory) implement the four abstract methods; higher\n * level helpers derive on the base. This is the backend *seam* — it does NOT\n * ship agent-facing tools nor a bundled workspace (bring-your-own-tools stands).\n *\n * @public\n */\n\n/** Structured file metadata. `mtimeMs` is the read-before-write oracle (SE32). */\nexport interface FileStat {\n readonly size: number;\n readonly mtimeMs: number;\n readonly isFile: boolean;\n readonly isDirectory: boolean;\n}\n\n/** Options a write may carry. SE32 adds `expectedMtime` (stale-write guard). */\nexport interface WriteFileOptions {\n /**\n * SE32 — when set, the write fails with {@link StaleFileError} if the file's\n * current `mtimeMs` differs (someone changed it since it was last read).\n */\n readonly expectedMtime?: number;\n}\n\nexport interface FilesystemConfig {\n /** Boundary root. Every path is resolved within it; escapes are rejected. */\n readonly basePath?: string;\n /** When true, every write throws {@link FilesystemReadOnlyError}. */\n readonly readOnly?: boolean;\n}\n\n/** A path escaped the backend's `basePath` (traversal or symlink). */\nexport class FilesystemSecurityError extends Error {\n readonly code = \"filesystem_security\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"FilesystemSecurityError\";\n }\n}\n\n/** A write was attempted on a read-only backend. */\nexport class FilesystemReadOnlyError extends Error {\n readonly code = \"filesystem_readonly\" as const;\n constructor(message: string) {\n super(message);\n this.name = \"FilesystemReadOnlyError\";\n }\n}\n\n/** A read/stat targeted a path that does not exist. */\nexport class FileNotFoundError extends Error {\n readonly code = \"filesystem_not_found\" as const;\n constructor(public readonly path: string) {\n super(`File not found: ${path}`);\n this.name = \"FileNotFoundError\";\n }\n}\n\n/**\n * A filesystem I/O operation failed for a reason other than not-found /\n * read-only / stale / security (e.g. `ENOTDIR` — a path component is a file, or\n * `EACCES` / `ENOSPC`). Carries the original error as `cause` so no raw,\n * untyped Node `SystemError` ever escapes the backend (Unbreakable Rule 8).\n */\nexport class FilesystemError extends Error {\n readonly code = \"filesystem_io\" as const;\n constructor(\n public readonly path: string,\n cause: unknown,\n ) {\n super(\n `Filesystem operation failed on \"${path}\": ${(cause as { message?: string })?.message ?? cause}`,\n {\n cause,\n },\n );\n this.name = \"FilesystemError\";\n }\n}\n\n/**\n * SE32 — a write's `expectedMtime` did not match the file's current mtime: the\n * file changed since it was last read, so the write would silently clobber.\n */\nexport class StaleFileError extends Error {\n readonly code = \"filesystem_stale\" as const;\n constructor(\n public readonly path: string,\n public readonly expectedMtime: number,\n public readonly actualMtime: number,\n ) {\n super(\n `Stale write to \"${path}\": expected mtime ${expectedMtime}, found ${actualMtime} ` +\n `(file changed since last read — re-read before writing)`,\n );\n this.name = \"StaleFileError\";\n }\n}\n\n/**\n * Pluggable filesystem backend. Implement the four abstract methods; `exists()`\n * and the `readOnly`/`basePath` accessors derive on the base class.\n *\n * @public\n */\nexport abstract class FilesystemBackend {\n protected readonly _basePath: string;\n protected readonly _readOnly: boolean;\n\n constructor(config: FilesystemConfig = {}) {\n this._basePath = config.basePath ?? process.cwd();\n this._readOnly = config.readOnly ?? false;\n }\n\n /** Read a boundary-relative file as UTF-8. Throws {@link FileNotFoundError}. */\n abstract readFile(path: string): Promise<string>;\n\n /**\n * Write UTF-8 content to a boundary-relative path (creating parents). Returns\n * the new {@link FileStat}. Throws {@link FilesystemReadOnlyError} on a\n * read-only backend and {@link StaleFileError} when `opts.expectedMtime`\n * mismatches (SE32).\n */\n abstract writeFile(path: string, content: string, opts?: WriteFileOptions): Promise<FileStat>;\n\n /** Structured metadata for a path. Throws {@link FileNotFoundError}. */\n abstract stat(path: string): Promise<FileStat>;\n\n /** Directory entry names (not recursive). Throws {@link FileNotFoundError}. */\n abstract list(path: string): Promise<string[]>;\n\n /** Derived — true iff `stat(path)` resolves (absent ⇒ false). */\n async exists(path: string): Promise<boolean> {\n try {\n await this.stat(path);\n return true;\n } catch (err) {\n if (err instanceof FileNotFoundError) return false;\n throw err;\n }\n }\n\n /** Throw {@link FilesystemReadOnlyError} when the backend is read-only. */\n protected assertWritable(): void {\n if (this._readOnly) {\n throw new FilesystemReadOnlyError(`Filesystem is read-only (basePath: ${this._basePath})`);\n }\n }\n\n get readOnly(): boolean {\n return this._readOnly;\n }\n\n get basePath(): string {\n return this._basePath;\n }\n}\n\n/**\n * A backend OR a per-request resolver of one. A resolver runs at tool-execution\n * time (the request scope), so multi-tenant / multi-role agents get a distinct\n * root or permission set per request without a shared mutable backend.\n *\n * @public\n */\nexport type FilesystemProvider<Ctx = unknown> =\n | FilesystemBackend\n | ((ctx: Ctx) => FilesystemBackend | Promise<FilesystemBackend>);\n\n/** Resolve a {@link FilesystemProvider} to a concrete backend for `ctx`. */\nexport async function resolveFilesystem<Ctx>(\n provider: FilesystemProvider<Ctx>,\n ctx: Ctx,\n): Promise<FilesystemBackend> {\n return provider instanceof FilesystemBackend ? provider : provider(ctx);\n}\n","/**\n * LocalFilesystem — a {@link FilesystemBackend} over the local process\n * filesystem (`node:fs/promises`), boundary-enforced against `basePath`.\n *\n * **This is NOT an isolation boundary** (same OS, same user). Its safety\n * affordances are path-boundary enforcement (traversal + symlink escape,\n * reusing the core `internal/security/path-guard` primitives) and the optional\n * `readOnly` flag. For untrusted code, run it inside a container/VM sandbox.\n *\n * The check-then-use gap between `assertNoSymlinkEscape` and the subsequent\n * `fs` call is a known TOCTOU: a local attacker could atomically swap an\n * in-boundary symlink after the check. Closing it needs `O_NOFOLLOW`, which\n * Node's `fs/promises` does not expose — accepted for same-user local contexts.\n *\n * SE31 (a peer framework Workspaces comparison). See ADR 0011.\n *\n * @public\n */\n\nimport {\n readFile as fsReadFile,\n stat as fsStat,\n writeFile as fsWriteFile,\n mkdir,\n readdir,\n} from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\nimport {\n assertNoSymlinkEscape,\n PathTraversalError,\n safePathJoin,\n} from \"../internal/security/path-guard.js\";\nimport {\n FileNotFoundError,\n type FileStat,\n FilesystemBackend,\n type FilesystemConfig,\n FilesystemError,\n FilesystemSecurityError,\n StaleFileError,\n type WriteFileOptions,\n} from \"./types.js\";\n\nexport class LocalFilesystem extends FilesystemBackend {\n constructor(config: FilesystemConfig = {}) {\n super(config);\n }\n\n async readFile(path: string): Promise<string> {\n const abs = this.resolve(path);\n try {\n return await fsReadFile(abs, \"utf-8\");\n } catch (err) {\n throw this.mapError(err, path);\n }\n }\n\n async writeFile(path: string, content: string, opts?: WriteFileOptions): Promise<FileStat> {\n // Security boundary FIRST (a traversal path on a read-only backend must\n // report the security error, not the read-only one — fail-clear).\n const abs = this.resolve(path);\n this.assertWritable();\n // SE32 — stale-write guard: if the caller passed the mtime it last read,\n // reject when the file changed underneath it (never a silent clobber).\n if (opts?.expectedMtime !== undefined) {\n await this.assertNotStale(path, abs, opts.expectedMtime);\n }\n try {\n await mkdir(dirname(abs), { recursive: true });\n await fsWriteFile(abs, content, \"utf-8\");\n } catch (err) {\n throw this.mapError(err, path);\n }\n return this.statAbs(abs, path);\n }\n\n async stat(path: string): Promise<FileStat> {\n const abs = this.resolve(path);\n return this.statAbs(abs, path);\n }\n\n async list(path: string): Promise<string[]> {\n const abs = this.resolve(path);\n try {\n return await readdir(abs);\n } catch (err) {\n throw this.mapError(err, path);\n }\n }\n\n private async statAbs(abs: string, relPath: string): Promise<FileStat> {\n try {\n const s = await fsStat(abs);\n return {\n size: s.size,\n mtimeMs: s.mtimeMs,\n isFile: s.isFile(),\n isDirectory: s.isDirectory(),\n };\n } catch (err) {\n throw this.mapError(err, relPath);\n }\n }\n\n /** SE32 — compare the on-disk mtime against the caller's expected value. */\n private async assertNotStale(relPath: string, abs: string, expectedMtime: number): Promise<void> {\n let current: number | undefined;\n try {\n current = (await fsStat(abs)).mtimeMs;\n } catch (err) {\n // A brand-new file (does not exist yet) cannot be stale — allow the write.\n if ((err as { code?: string }).code === \"ENOENT\") return;\n throw this.mapError(err, relPath);\n }\n if (current !== expectedMtime) {\n throw new StaleFileError(relPath, expectedMtime, current);\n }\n }\n\n /**\n * Resolve a boundary-relative path to an absolute one, rejecting lexical\n * traversal (`..`, absolute, NUL) and symlink escape — both reusing the core\n * path-guard primitives, remapped to {@link FilesystemSecurityError}.\n */\n private resolve(path: string): string {\n let abs: string;\n try {\n abs = safePathJoin(this._basePath, path);\n } catch (err) {\n if (err instanceof PathTraversalError) {\n throw new FilesystemSecurityError(`Path escapes basePath: ${path}`);\n }\n throw err;\n }\n try {\n assertNoSymlinkEscape(abs, this._basePath);\n } catch (err) {\n if (err instanceof PathTraversalError) {\n throw new FilesystemSecurityError(`Path escapes basePath via symlink: ${path}`);\n }\n throw err;\n }\n return abs;\n }\n\n private mapError(err: unknown, path: string): Error {\n if (\n err instanceof FilesystemSecurityError ||\n err instanceof FilesystemError ||\n err instanceof FileNotFoundError ||\n err instanceof StaleFileError\n ) {\n return err;\n }\n if ((err as { code?: string }).code === \"ENOENT\") return new FileNotFoundError(path);\n // ENOTDIR (a path component is a file), EACCES, ENOSPC, … — never leak a\n // raw untyped Node SystemError (Rule 8); wrap with the original as cause.\n return new FilesystemError(path, err);\n }\n}\n"]}
@@ -1,12 +1,13 @@
1
1
  'use strict';
2
2
 
3
- var chunkGH52NOCL_cjs = require('./chunk-GH52NOCL.cjs');
3
+ var chunkRWMNTFHZ_cjs = require('./chunk-RWMNTFHZ.cjs');
4
4
  require('./chunk-2RW7K6FN.cjs');
5
5
  require('./chunk-MUUQ2WFJ.cjs');
6
6
  require('./chunk-BV42CCRP.cjs');
7
7
  require('./chunk-YLQQX5W2.cjs');
8
8
  require('./chunk-NETYW4V3.cjs');
9
- require('./chunk-XA3TSBAH.cjs');
9
+ require('./chunk-XABN5HY6.cjs');
10
+ require('./chunk-VKJ7V7EB.cjs');
10
11
  require('./chunk-YULF6FPB.cjs');
11
12
  require('./chunk-ZHPET3LZ.cjs');
12
13
 
@@ -14,7 +15,7 @@ require('./chunk-ZHPET3LZ.cjs');
14
15
 
15
16
  Object.defineProperty(exports, "IndexManager", {
16
17
  enumerable: true,
17
- get: function () { return chunkGH52NOCL_cjs.IndexManager; }
18
+ get: function () { return chunkRWMNTFHZ_cjs.IndexManager; }
18
19
  });
19
- //# sourceMappingURL=index-manager-YFFEPISE.cjs.map
20
- //# sourceMappingURL=index-manager-YFFEPISE.cjs.map
20
+ //# sourceMappingURL=index-manager-34ELCOAP.cjs.map
21
+ //# sourceMappingURL=index-manager-34ELCOAP.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index-manager-YFFEPISE.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index-manager-34ELCOAP.cjs"}
@@ -0,0 +1,12 @@
1
+ export { IndexManager } from './chunk-E54KDYOE.js';
2
+ import './chunk-OXNYIMZZ.js';
3
+ import './chunk-FD2UT76F.js';
4
+ import './chunk-2WB6EIYW.js';
5
+ import './chunk-2XLKLVVR.js';
6
+ import './chunk-VQFSEKU5.js';
7
+ import './chunk-JGYYNDAZ.js';
8
+ import './chunk-RIAM53CP.js';
9
+ import './chunk-MRKSSN36.js';
10
+ import './chunk-PBML2FHN.js';
11
+ //# sourceMappingURL=index-manager-OMJVYS2U.js.map
12
+ //# sourceMappingURL=index-manager-OMJVYS2U.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index-manager-X5IPG2JL.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index-manager-OMJVYS2U.js"}
package/dist/index.cjs CHANGED
@@ -5,12 +5,12 @@ var chunkUJMEWGO6_cjs = require('./chunk-UJMEWGO6.cjs');
5
5
  var chunk57KX5WTP_cjs = require('./chunk-57KX5WTP.cjs');
6
6
  var chunkGC44RATP_cjs = require('./chunk-GC44RATP.cjs');
7
7
  require('./chunk-WIGJGFH4.cjs');
8
- var chunkJO76RWCA_cjs = require('./chunk-JO76RWCA.cjs');
8
+ var chunk72HEBGWN_cjs = require('./chunk-72HEBGWN.cjs');
9
9
  require('./chunk-RBQYHEZD.cjs');
10
10
  require('./chunk-PNVDQL5Y.cjs');
11
- var chunk74VVGK7P_cjs = require('./chunk-74VVGK7P.cjs');
12
- var chunkTSK4VVBW_cjs = require('./chunk-TSK4VVBW.cjs');
13
- require('./chunk-FAUKVJCC.cjs');
11
+ var chunkWUUSAMFC_cjs = require('./chunk-WUUSAMFC.cjs');
12
+ var chunkF7OBYH2X_cjs = require('./chunk-F7OBYH2X.cjs');
13
+ require('./chunk-UQHIEUDY.cjs');
14
14
  require('./chunk-BV2MWEMV.cjs');
15
15
  var chunkKCQUYQ3V_cjs = require('./chunk-KCQUYQ3V.cjs');
16
16
  require('./chunk-BUUUWQMB.cjs');
@@ -19,10 +19,10 @@ var chunkQFFNMJAS_cjs = require('./chunk-QFFNMJAS.cjs');
19
19
  require('./chunk-4JBHSLQO.cjs');
20
20
  require('./chunk-HLNLYLNN.cjs');
21
21
  require('./chunk-FZ4YMZA3.cjs');
22
- var chunkGH52NOCL_cjs = require('./chunk-GH52NOCL.cjs');
22
+ var chunkRWMNTFHZ_cjs = require('./chunk-RWMNTFHZ.cjs');
23
23
  require('./chunk-HECR7KF5.cjs');
24
24
  require('./chunk-BBZYXVLZ.cjs');
25
- require('./chunk-UU7MAO2D.cjs');
25
+ require('./chunk-OKLYRPKL.cjs');
26
26
  require('./chunk-6X2HUT4A.cjs');
27
27
  require('./chunk-7PESI6YD.cjs');
28
28
  require('./chunk-S4Q5OMIK.cjs');
@@ -49,13 +49,14 @@ var chunkVYHJZVL5_cjs = require('./chunk-VYHJZVL5.cjs');
49
49
  var chunkGLEKLAUW_cjs = require('./chunk-GLEKLAUW.cjs');
50
50
  require('./chunk-4JRRFRV4.cjs');
51
51
  require('./chunk-C6Y6CWYD.cjs');
52
- require('./chunk-64TJCXY5.cjs');
53
- require('./chunk-XA3TSBAH.cjs');
52
+ require('./chunk-3G6ZDZ6L.cjs');
53
+ require('./chunk-XABN5HY6.cjs');
54
+ require('./chunk-VKJ7V7EB.cjs');
54
55
  require('./chunk-BRHRQOJA.cjs');
55
56
  var chunkYULF6FPB_cjs = require('./chunk-YULF6FPB.cjs');
56
57
  var chunkZHPET3LZ_cjs = require('./chunk-ZHPET3LZ.cjs');
57
- var zod = require('zod');
58
58
  var crypto = require('crypto');
59
+ var zod = require('zod');
59
60
  var promises = require('fs/promises');
60
61
  var path = require('path');
61
62
  var fs = require('fs');
@@ -63,8 +64,8 @@ var fs = require('fs');
63
64
  // src/agent-factory.ts
64
65
  function createAgentFactory(common) {
65
66
  return {
66
- forSession: (agentId, overrides) => chunkTSK4VVBW_cjs.Agent.create(mergeAgentOptions(common, overrides, agentId)),
67
- getOrCreate: (agentId, overrides) => chunkTSK4VVBW_cjs.Agent.getOrCreate(agentId, mergeAgentOptions(common, overrides, agentId))
67
+ forSession: (agentId, overrides) => chunkF7OBYH2X_cjs.Agent.create(mergeAgentOptions(common, overrides, agentId)),
68
+ getOrCreate: (agentId, overrides) => chunkF7OBYH2X_cjs.Agent.getOrCreate(agentId, mergeAgentOptions(common, overrides, agentId))
68
69
  };
69
70
  }
70
71
  function mergeAgentOptions(common, overrides, agentId) {
@@ -103,6 +104,39 @@ var AgentFactory = class {
103
104
  }
104
105
  };
105
106
 
107
+ // src/approval-policy.ts
108
+ var BY_MODE = {
109
+ ask: { outcome: "ask", reason: "mode-ask" },
110
+ "never-ask": { outcome: "allow", reason: "mode-never-ask" },
111
+ "refuse-all": { outcome: "deny", reason: "mode-refuse-all" }
112
+ };
113
+ function decideApproval(input) {
114
+ const { tool } = input;
115
+ if ((input.denied ?? []).includes(tool)) {
116
+ return { outcome: "deny", reason: "explicitly-denied", tool };
117
+ }
118
+ if ((input.allowed ?? []).includes(tool)) {
119
+ return { outcome: "allow", reason: "explicitly-allowed", tool };
120
+ }
121
+ const fromMode = BY_MODE[input.mode];
122
+ return { outcome: fromMode.outcome, reason: fromMode.reason, tool };
123
+ }
124
+
125
+ // src/blast-radius.ts
126
+ function evaluateBlastRadius(input) {
127
+ const { scope, reversible } = input.action;
128
+ if (scope.length === 0) {
129
+ return { outcome: "refuse", reason: "scope-undeclared", scope };
130
+ }
131
+ if (!input.granted.includes(scope)) {
132
+ return { outcome: "refuse", reason: "scope-not-granted", scope };
133
+ }
134
+ if (!reversible && !(input.irreversibleAllowed ?? []).includes(scope)) {
135
+ return { outcome: "require-approval", reason: "irreversible", scope };
136
+ }
137
+ return { outcome: "allow", reason: "within-granted-scope", scope };
138
+ }
139
+
106
140
  // src/internal/budget/calendar-window.ts
107
141
  function startOfDayUtc(now = /* @__PURE__ */ new Date()) {
108
142
  return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
@@ -568,6 +602,18 @@ var Skill = class {
568
602
  return createSkill(spec);
569
603
  }
570
604
  };
605
+ function describeCredential(input) {
606
+ const secret = (input.value ?? "").trim();
607
+ if (secret.length === 0) {
608
+ return { provider: input.provider, present: false, source: input.source };
609
+ }
610
+ return {
611
+ provider: input.provider,
612
+ present: true,
613
+ source: input.source,
614
+ fingerprint: crypto.createHash("sha256").update(secret).digest("hex").slice(0, 8)
615
+ };
616
+ }
571
617
 
572
618
  // src/define-provider.ts
573
619
  function defineProvider(profile, opts) {
@@ -967,7 +1013,7 @@ function foldLayers(entries, accumulatingKeys = []) {
967
1013
  return combined;
968
1014
  }
969
1015
  function diaryPath(cwd) {
970
- return path.join(chunkGH52NOCL_cjs.memoryDir(cwd), "dream-diary.md");
1016
+ return path.join(chunkRWMNTFHZ_cjs.memoryDir(cwd), "dream-diary.md");
971
1017
  }
972
1018
  function renderDiaryEntry(entry) {
973
1019
  const stamp = new Date(entry.timestampMs).toISOString();
@@ -1114,7 +1160,7 @@ async function runInner(options) {
1114
1160
  const now = options.now ?? Date.now;
1115
1161
  const timestampMs = now();
1116
1162
  try {
1117
- const facts = await chunkGH52NOCL_cjs.readFactsFromMarkdown(options.cwd);
1163
+ const facts = await chunkRWMNTFHZ_cjs.readFactsFromMarkdown(options.cwd);
1118
1164
  if (facts.length === 0) {
1119
1165
  return emptyResult("skipped");
1120
1166
  }
@@ -1148,7 +1194,7 @@ async function runInner(options) {
1148
1194
  }
1149
1195
  async function writeConsolidatedNotes(cwd, clusters, timestampMs) {
1150
1196
  if (clusters.length === 0) return 0;
1151
- const notesDir = path.join(chunkGH52NOCL_cjs.memoryDir(cwd), "notes");
1197
+ const notesDir = path.join(chunkRWMNTFHZ_cjs.memoryDir(cwd), "notes");
1152
1198
  await promises.mkdir(notesDir, { recursive: true });
1153
1199
  const isoSlug = new Date(timestampMs).toISOString().replace(/[^\dT]/g, "-");
1154
1200
  const file = path.join(notesDir, `dreamed-${isoSlug}.md`);
@@ -1214,8 +1260,8 @@ var Memory = {
1214
1260
  openArgs.embedding = await resolveEmbedding(opts.embedding, peer.MEMORY_EMBEDDING_ADAPTERS);
1215
1261
  return await peer.IndexManager.open(openArgs);
1216
1262
  }
1217
- const { IndexManager } = await import('./index-manager-YFFEPISE.cjs');
1218
- openArgs.embedding = await resolveEmbedding(opts.embedding, chunkTSK4VVBW_cjs.MEMORY_EMBEDDING_ADAPTERS);
1263
+ const { IndexManager } = await import('./index-manager-34ELCOAP.cjs');
1264
+ openArgs.embedding = await resolveEmbedding(opts.embedding, chunkF7OBYH2X_cjs.MEMORY_EMBEDDING_ADAPTERS);
1219
1265
  return await IndexManager.open(openArgs);
1220
1266
  },
1221
1267
  /**
@@ -1226,7 +1272,7 @@ var Memory = {
1226
1272
  */
1227
1273
  async runDreamingSweep(opts) {
1228
1274
  const peer = await tryLoadSdkMemoryPeer();
1229
- const catalog = peer !== null ? peer.MEMORY_EMBEDDING_ADAPTERS : chunkTSK4VVBW_cjs.MEMORY_EMBEDDING_ADAPTERS;
1275
+ const catalog = peer !== null ? peer.MEMORY_EMBEDDING_ADAPTERS : chunkF7OBYH2X_cjs.MEMORY_EMBEDDING_ADAPTERS;
1230
1276
  const sweepArgs = await buildDreamingSweepArgs(opts, catalog);
1231
1277
  const result = peer !== null ? (
1232
1278
  // biome-ignore lint/suspicious/noExplicitAny: peer is dynamically loaded — structural compat ensured by sdk-memory
@@ -1292,9 +1338,9 @@ function extractRawId(id, expectedAdapterId) {
1292
1338
  return id.slice(prefix.length);
1293
1339
  }
1294
1340
  async function readAllSqliteFacts(cwd) {
1295
- const dbPath = chunkGH52NOCL_cjs.defaultIndexPath(cwd);
1341
+ const dbPath = chunkRWMNTFHZ_cjs.defaultIndexPath(cwd);
1296
1342
  if (!fs.existsSync(dbPath)) return [];
1297
- const db = await chunkGH52NOCL_cjs.openMemoryDb({ filePath: dbPath });
1343
+ const db = await chunkRWMNTFHZ_cjs.openMemoryDb({ filePath: dbPath });
1298
1344
  try {
1299
1345
  const stmt = db.prepare("SELECT id, path, source, start_line, end_line, text FROM chunks");
1300
1346
  const rows = stmt.all();
@@ -1313,7 +1359,7 @@ function nfcEqual(a, b) {
1313
1359
  }
1314
1360
  async function migrateSqliteToLance(opts) {
1315
1361
  const cwd = opts.cwd;
1316
- const finalPath = chunkGH52NOCL_cjs.lanceStoragePath(cwd);
1362
+ const finalPath = chunkRWMNTFHZ_cjs.lanceStoragePath(cwd);
1317
1363
  const newPath = path.join(cwd, ".theokit", "memory", "lance-new");
1318
1364
  const rawLog = opts.logger ?? ((m) => console.log(m));
1319
1365
  const log = (m) => rawLog(chunkZHPET3LZ_cjs.redactSecrets(m));
@@ -1357,7 +1403,7 @@ async function migrateSqliteToLance(opts) {
1357
1403
  };
1358
1404
  fs.mkdirSync(newPath, { recursive: true });
1359
1405
  log(`Writing Lance index to ${newPath} ...`);
1360
- const lance = await chunkGH52NOCL_cjs.LanceIndex.open({
1406
+ const lance = await chunkRWMNTFHZ_cjs.LanceIndex.open({
1361
1407
  cwd,
1362
1408
  embedding: placeholderEmbedding,
1363
1409
  storagePath: newPath
@@ -1571,6 +1617,60 @@ function loadProjectEnv(env = process.env, load = typeof process.loadEnvFile ===
1571
1617
  }
1572
1618
  }
1573
1619
 
1620
+ // src/reap-plan.ts
1621
+ var RetentionPolicyError = class extends chunkYULF6FPB_cjs.TheokitAgentError {
1622
+ name = "RetentionPolicyError";
1623
+ };
1624
+ function assertPolicy(retention) {
1625
+ const { maxAgeMs, keepLast } = retention;
1626
+ if (!Number.isFinite(maxAgeMs) || maxAgeMs < 0) {
1627
+ throw new RetentionPolicyError(
1628
+ `retention.maxAgeMs must be a non-negative number of milliseconds, got ${String(maxAgeMs)}`
1629
+ );
1630
+ }
1631
+ if (!Number.isInteger(keepLast) || keepLast < 0) {
1632
+ throw new RetentionPolicyError(
1633
+ `retention.keepLast must be a non-negative integer, got ${String(keepLast)}`
1634
+ );
1635
+ }
1636
+ }
1637
+ function classifyByOwnReason(input) {
1638
+ const keep = [];
1639
+ const atRisk = [];
1640
+ for (const artifact of input.artifacts) {
1641
+ if (artifact.live === "unknown") continue;
1642
+ if (artifact.live === true) {
1643
+ keep.push({ ...artifact, reason: "live" });
1644
+ continue;
1645
+ }
1646
+ if (input.nowMs - artifact.lastModifiedMs <= input.retention.maxAgeMs) {
1647
+ keep.push({ ...artifact, reason: "within-retention" });
1648
+ continue;
1649
+ }
1650
+ atRisk.push(artifact);
1651
+ }
1652
+ return { keep, atRisk };
1653
+ }
1654
+ function applyFloor(kept, atRisk, keepLast) {
1655
+ const shortfall = Math.max(0, keepLast - kept.length);
1656
+ const newestFirst = [...atRisk].sort((a, b) => b.lastModifiedMs - a.lastModifiedMs);
1657
+ const spared = new Set(newestFirst.slice(0, shortfall).map((a) => a.id));
1658
+ const rescued = [];
1659
+ const reap = [];
1660
+ for (const artifact of atRisk) {
1661
+ if (spared.has(artifact.id)) rescued.push({ ...artifact, reason: "keep-last" });
1662
+ else reap.push(artifact);
1663
+ }
1664
+ return { rescued, reap };
1665
+ }
1666
+ function planReaping(input) {
1667
+ assertPolicy(input.retention);
1668
+ const undetermined = input.artifacts.filter((a) => a.live === "unknown");
1669
+ const { keep, atRisk } = classifyByOwnReason(input);
1670
+ const { rescued, reap } = applyFloor(keep, atRisk, input.retention.keepLast);
1671
+ return { reap, keep: [...keep, ...rescued], undetermined };
1672
+ }
1673
+
1574
1674
  // src/schema-normalizer.ts
1575
1675
  function isJsonSchemaObject(s) {
1576
1676
  if (typeof s !== "object" || s === null) return false;
@@ -1701,6 +1801,28 @@ function applySecurityFloor(input) {
1701
1801
  return input.layers[input.override] ?? tightenOnly(input, baseline(input));
1702
1802
  }
1703
1803
 
1804
+ // src/session-guard.ts
1805
+ var LiveSessionError = class extends chunkYULF6FPB_cjs.TheokitAgentError {
1806
+ name = "LiveSessionError";
1807
+ sessionId;
1808
+ reason;
1809
+ constructor(sessionId, reason) {
1810
+ super(
1811
+ reason === "session-is-live" ? `refusing to destroy session ${sessionId}: it is live \u2014 another process is probably still appending to it. Switch to another session first.` : `refusing to destroy session ${sessionId}: the set of live sessions could not be determined, so this cannot be shown to be safe. Resolve that before deleting.`
1812
+ );
1813
+ this.sessionId = sessionId;
1814
+ this.reason = reason;
1815
+ }
1816
+ };
1817
+ function guardSessionDestruction(sessionId, live) {
1818
+ if (live === void 0) {
1819
+ throw new LiveSessionError(sessionId, "liveness-undetermined");
1820
+ }
1821
+ if (live.includes(sessionId)) {
1822
+ throw new LiveSessionError(sessionId, "session-is-live");
1823
+ }
1824
+ }
1825
+
1704
1826
  // src/session-scope.ts
1705
1827
  function scopedConversationId(scope, id) {
1706
1828
  return `${scope}__${id}`;
@@ -1714,7 +1836,7 @@ function isBuiltAgent(m) {
1714
1836
  return typeof m.send === "function";
1715
1837
  }
1716
1838
  async function materialize(def, index) {
1717
- const { Agent: Agent2 } = await import('./agent-JA4ILE5O.cjs');
1839
+ const { Agent: Agent2 } = await import('./agent-B2WU3JP6.cjs');
1718
1840
  return Agent2.create({
1719
1841
  // `AgentDefinition.model` admits the sentinel `'inherit'`, which is not a model id. Inheriting
1720
1842
  // here means "declare nothing and let the default apply" — forwarding the literal would create
@@ -1746,13 +1868,13 @@ function createSquad(options) {
1746
1868
  };
1747
1869
  }
1748
1870
  async function buildPipeline(agents, nome) {
1749
- let builder = chunkJO76RWCA_cjs.Workflow.create({ name: nome ?? "squad" });
1871
+ let builder = chunk72HEBGWN_cjs.Workflow.create({ name: nome ?? "squad" });
1750
1872
  for (let i = 0; i < agents.length; i++) {
1751
1873
  const member = agents[i];
1752
1874
  if (member === void 0) continue;
1753
1875
  const agent = isBuiltAgent(member) ? member : await materialize(member, i);
1754
1876
  const opts = i > 0 ? { origin: { kind: "peer", from: `agent-${i - 1}` } } : void 0;
1755
- builder = builder.then(chunkJO76RWCA_cjs.agentStep(`agent-${i}`, agent, (prev) => String(prev), opts));
1877
+ builder = builder.then(chunk72HEBGWN_cjs.agentStep(`agent-${i}`, agent, (prev) => String(prev), opts));
1756
1878
  }
1757
1879
  return builder.commit();
1758
1880
  }
@@ -1856,7 +1978,7 @@ var FIXTURE_USER = {
1856
1978
  };
1857
1979
  var FIXTURE_MODELS = [
1858
1980
  {
1859
- id: chunkTSK4VVBW_cjs.DEFAULT_AGENTIC_MODEL_ID,
1981
+ id: chunkF7OBYH2X_cjs.DEFAULT_AGENTIC_MODEL_ID,
1860
1982
  name: "Gemini 2.0 Flash",
1861
1983
  displayName: "Gemini 2.0 Flash",
1862
1984
  parameters: [
@@ -2059,7 +2181,7 @@ var Theokit = class {
2059
2181
  envVars: p.envVars
2060
2182
  }));
2061
2183
  },
2062
- embeddingAdapters: () => Object.entries(chunkTSK4VVBW_cjs.MEMORY_EMBEDDING_ADAPTERS).map(([id, adapter]) => ({
2184
+ embeddingAdapters: () => Object.entries(chunkF7OBYH2X_cjs.MEMORY_EMBEDDING_ADAPTERS).map(([id, adapter]) => ({
2063
2185
  id,
2064
2186
  transport: adapter.transport,
2065
2187
  defaultModel: adapter.defaultModel
@@ -2091,7 +2213,7 @@ function resolveLocalProviderBaseUrl(providerName, fallback) {
2091
2213
  return fallback;
2092
2214
  }
2093
2215
  async function executeCatalogRequest(request) {
2094
- const apiKey = chunkTSK4VVBW_cjs.resolveApiKey(request.apiKey);
2216
+ const apiKey = chunkF7OBYH2X_cjs.resolveApiKey(request.apiKey);
2095
2217
  if (apiKey === void 0) {
2096
2218
  throw new chunkYULF6FPB_cjs.AuthenticationError("Missing API key", { code: "missing_api_key" });
2097
2219
  }
@@ -2104,6 +2226,23 @@ async function executeCatalogRequest(request) {
2104
2226
  return chunkQFFNMJAS_cjs.httpRequest(request.path, { apiKey });
2105
2227
  }
2106
2228
 
2229
+ // src/tool-blast-radius.ts
2230
+ var DECLARED = /* @__PURE__ */ Symbol.for("@theokit/sdk.blastRadius");
2231
+ function withBlastRadius(tool, action) {
2232
+ return Object.defineProperty(tool, DECLARED, {
2233
+ value: action,
2234
+ // `enumerable: false` is defensive and NOT load-bearing — checked, not assumed. Flipping it to
2235
+ // true leaves every case green, because the symbol key already excludes this from `Object.keys`
2236
+ // and `JSON.stringify`. It stays because a future string-keyed variant would need it, and the
2237
+ // next reader should not have to discover that the flag has no test behind it.
2238
+ enumerable: false,
2239
+ configurable: true
2240
+ });
2241
+ }
2242
+ function describeAction(tool) {
2243
+ return tool[DECLARED];
2244
+ }
2245
+
2107
2246
  // src/trajectory-helpers.ts
2108
2247
  function toShareGptTrajectory(result, options) {
2109
2248
  if (!result.ok) return null;
@@ -2249,35 +2388,35 @@ Object.defineProperty(exports, "GenerateObjectError", {
2249
2388
  });
2250
2389
  Object.defineProperty(exports, "Cron", {
2251
2390
  enumerable: true,
2252
- get: function () { return chunk74VVGK7P_cjs.Cron; }
2391
+ get: function () { return chunkWUUSAMFC_cjs.Cron; }
2253
2392
  });
2254
2393
  Object.defineProperty(exports, "Agent", {
2255
2394
  enumerable: true,
2256
- get: function () { return chunkTSK4VVBW_cjs.Agent; }
2395
+ get: function () { return chunkF7OBYH2X_cjs.Agent; }
2257
2396
  });
2258
2397
  Object.defineProperty(exports, "AgentBuilder", {
2259
2398
  enumerable: true,
2260
- get: function () { return chunkTSK4VVBW_cjs.AgentBuilder; }
2399
+ get: function () { return chunkF7OBYH2X_cjs.AgentBuilder; }
2261
2400
  });
2262
2401
  Object.defineProperty(exports, "Tool", {
2263
2402
  enumerable: true,
2264
- get: function () { return chunkTSK4VVBW_cjs.Tool; }
2403
+ get: function () { return chunkF7OBYH2X_cjs.Tool; }
2265
2404
  });
2266
2405
  Object.defineProperty(exports, "ToolError", {
2267
2406
  enumerable: true,
2268
- get: function () { return chunkTSK4VVBW_cjs.ToolError; }
2407
+ get: function () { return chunkF7OBYH2X_cjs.ToolError; }
2269
2408
  });
2270
2409
  Object.defineProperty(exports, "UsageAccumulator", {
2271
2410
  enumerable: true,
2272
- get: function () { return chunkTSK4VVBW_cjs.UsageAccumulator; }
2411
+ get: function () { return chunkF7OBYH2X_cjs.UsageAccumulator; }
2273
2412
  });
2274
2413
  Object.defineProperty(exports, "computeCost", {
2275
2414
  enumerable: true,
2276
- get: function () { return chunkTSK4VVBW_cjs.computeCost; }
2415
+ get: function () { return chunkF7OBYH2X_cjs.computeCost; }
2277
2416
  });
2278
2417
  Object.defineProperty(exports, "getPricingEntry", {
2279
2418
  enumerable: true,
2280
- get: function () { return chunkTSK4VVBW_cjs.getPricingEntry; }
2419
+ get: function () { return chunkF7OBYH2X_cjs.getPricingEntry; }
2281
2420
  });
2282
2421
  Object.defineProperty(exports, "emitRunEvent", {
2283
2422
  enumerable: true,
@@ -2364,12 +2503,14 @@ exports.Budget = Budget;
2364
2503
  exports.EventBus = EventBus;
2365
2504
  exports.JobQueue = JobQueue;
2366
2505
  exports.LayerOrderError = LayerOrderError;
2506
+ exports.LiveSessionError = LiveSessionError;
2367
2507
  exports.Memory = Memory;
2368
2508
  exports.NoopMemoryProvider = NoopMemoryProvider;
2369
2509
  exports.PermissionEngine = PermissionEngine;
2370
2510
  exports.PermissionPlugin = PermissionPlugin;
2371
2511
  exports.Plugin = Plugin;
2372
2512
  exports.Provider = Provider;
2513
+ exports.RetentionPolicyError = RetentionPolicyError;
2373
2514
  exports.SOVEREIGN_ENV_KEYS = SOVEREIGN_ENV_KEYS;
2374
2515
  exports.Security = Security;
2375
2516
  exports.Skill = Skill;
@@ -2385,15 +2526,21 @@ exports.applySecurityFloor = applySecurityFloor;
2385
2526
  exports.auditEnvReachability = auditEnvReachability;
2386
2527
  exports.chargeAndCheckThresholds = chargeAndCheckThresholds;
2387
2528
  exports.createCounterBudgetTracker = createCounterBudgetTracker;
2529
+ exports.decideApproval = decideApproval;
2530
+ exports.describeAction = describeAction;
2531
+ exports.describeCredential = describeCredential;
2388
2532
  exports.estimateTokens = estimateTokens;
2533
+ exports.evaluateBlastRadius = evaluateBlastRadius;
2389
2534
  exports.extractRawId = extractRawId;
2390
2535
  exports.foldLayers = foldLayers;
2536
+ exports.guardSessionDestruction = guardSessionDestruction;
2391
2537
  exports.inferApiMode = inferApiMode;
2392
2538
  exports.loadProjectEnv = loadProjectEnv;
2393
2539
  exports.migrateSqliteToLance = migrateSqliteToLance2;
2394
2540
  exports.mkMemoryId = mkMemoryId;
2395
2541
  exports.normalizeSchema = normalizeSchema;
2396
2542
  exports.normalizeUsage = normalizeUsage;
2543
+ exports.planReaping = planReaping;
2397
2544
  exports.preflightCheck = preflightCheck;
2398
2545
  exports.recordWiring = recordWiring;
2399
2546
  exports.resolveTrustPosture = resolveTrustPosture;
@@ -2402,5 +2549,6 @@ exports.scopedConversationId = scopedConversationId;
2402
2549
  exports.sessionScopePrefix = sessionScopePrefix;
2403
2550
  exports.toShareGptTrajectory = toShareGptTrajectory;
2404
2551
  exports.verifyLayerOrdering = verifyLayerOrdering;
2552
+ exports.withBlastRadius = withBlastRadius;
2405
2553
  //# sourceMappingURL=index.cjs.map
2406
2554
  //# sourceMappingURL=index.cjs.map