cloison-runtime 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (316) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +313 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +47 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/config/index.d.ts +57 -0
  8. package/dist/config/index.d.ts.map +1 -0
  9. package/dist/config/index.js +27 -0
  10. package/dist/config/index.js.map +1 -0
  11. package/dist/credentials/index.d.ts +4 -0
  12. package/dist/credentials/index.d.ts.map +1 -0
  13. package/dist/credentials/index.js +3 -0
  14. package/dist/credentials/index.js.map +1 -0
  15. package/dist/credentials/proxy.d.ts +3 -0
  16. package/dist/credentials/proxy.d.ts.map +1 -0
  17. package/dist/credentials/proxy.js +11 -0
  18. package/dist/credentials/proxy.js.map +1 -0
  19. package/dist/credentials/store.d.ts +7 -0
  20. package/dist/credentials/store.d.ts.map +1 -0
  21. package/dist/credentials/store.js +115 -0
  22. package/dist/credentials/store.js.map +1 -0
  23. package/dist/credentials/types.d.ts +14 -0
  24. package/dist/credentials/types.d.ts.map +1 -0
  25. package/dist/credentials/types.js +2 -0
  26. package/dist/credentials/types.js.map +1 -0
  27. package/dist/hooks/index.d.ts +3 -0
  28. package/dist/hooks/index.d.ts.map +1 -0
  29. package/dist/hooks/index.js +2 -0
  30. package/dist/hooks/index.js.map +1 -0
  31. package/dist/hooks/runner.d.ts +7 -0
  32. package/dist/hooks/runner.d.ts.map +1 -0
  33. package/dist/hooks/runner.js +20 -0
  34. package/dist/hooks/runner.js.map +1 -0
  35. package/dist/hooks/types.d.ts +39 -0
  36. package/dist/hooks/types.d.ts.map +1 -0
  37. package/dist/hooks/types.js +2 -0
  38. package/dist/hooks/types.js.map +1 -0
  39. package/dist/index.d.ts +32 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +58 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/infra/env.d.ts +2 -0
  44. package/dist/infra/env.d.ts.map +1 -0
  45. package/dist/infra/env.js +6 -0
  46. package/dist/infra/env.js.map +1 -0
  47. package/dist/infra/warning-filter.d.ts +8 -0
  48. package/dist/infra/warning-filter.d.ts.map +1 -0
  49. package/dist/infra/warning-filter.js +66 -0
  50. package/dist/infra/warning-filter.js.map +1 -0
  51. package/dist/logging/subsystem.d.ts +29 -0
  52. package/dist/logging/subsystem.d.ts.map +1 -0
  53. package/dist/logging/subsystem.js +322 -0
  54. package/dist/logging/subsystem.js.map +1 -0
  55. package/dist/memory/embedding-batch.d.ts +38 -0
  56. package/dist/memory/embedding-batch.d.ts.map +1 -0
  57. package/dist/memory/embedding-batch.js +253 -0
  58. package/dist/memory/embedding-batch.js.map +1 -0
  59. package/dist/memory/embedding-cache.d.ts +16 -0
  60. package/dist/memory/embedding-cache.d.ts.map +1 -0
  61. package/dist/memory/embedding-cache.js +113 -0
  62. package/dist/memory/embedding-cache.js.map +1 -0
  63. package/dist/memory/embeddings-debug.d.ts +2 -0
  64. package/dist/memory/embeddings-debug.d.ts.map +1 -0
  65. package/dist/memory/embeddings-debug.js +12 -0
  66. package/dist/memory/embeddings-debug.js.map +1 -0
  67. package/dist/memory/embeddings.d.ts +17 -0
  68. package/dist/memory/embeddings.d.ts.map +1 -0
  69. package/dist/memory/embeddings.js +203 -0
  70. package/dist/memory/embeddings.js.map +1 -0
  71. package/dist/memory/file-indexer.d.ts +26 -0
  72. package/dist/memory/file-indexer.d.ts.map +1 -0
  73. package/dist/memory/file-indexer.js +260 -0
  74. package/dist/memory/file-indexer.js.map +1 -0
  75. package/dist/memory/fs-utils.d.ts +12 -0
  76. package/dist/memory/fs-utils.d.ts.map +1 -0
  77. package/dist/memory/fs-utils.js +24 -0
  78. package/dist/memory/fs-utils.js.map +1 -0
  79. package/dist/memory/hybrid.d.ts +46 -0
  80. package/dist/memory/hybrid.d.ts.map +1 -0
  81. package/dist/memory/hybrid.js +85 -0
  82. package/dist/memory/hybrid.js.map +1 -0
  83. package/dist/memory/index.d.ts +17 -0
  84. package/dist/memory/index.d.ts.map +1 -0
  85. package/dist/memory/index.js +15 -0
  86. package/dist/memory/index.js.map +1 -0
  87. package/dist/memory/internal.d.ts +39 -0
  88. package/dist/memory/internal.d.ts.map +1 -0
  89. package/dist/memory/internal.js +292 -0
  90. package/dist/memory/internal.js.map +1 -0
  91. package/dist/memory/manager-search.d.ts +61 -0
  92. package/dist/memory/manager-search.d.ts.map +1 -0
  93. package/dist/memory/manager-search.js +102 -0
  94. package/dist/memory/manager-search.js.map +1 -0
  95. package/dist/memory/mmr.d.ts +63 -0
  96. package/dist/memory/mmr.d.ts.map +1 -0
  97. package/dist/memory/mmr.js +165 -0
  98. package/dist/memory/mmr.js.map +1 -0
  99. package/dist/memory/query-expansion.d.ts +42 -0
  100. package/dist/memory/query-expansion.d.ts.map +1 -0
  101. package/dist/memory/query-expansion.js +776 -0
  102. package/dist/memory/query-expansion.js.map +1 -0
  103. package/dist/memory/session-indexer.d.ts +41 -0
  104. package/dist/memory/session-indexer.d.ts.map +1 -0
  105. package/dist/memory/session-indexer.js +367 -0
  106. package/dist/memory/session-indexer.js.map +1 -0
  107. package/dist/memory/simple-manager.d.ts +29 -0
  108. package/dist/memory/simple-manager.d.ts.map +1 -0
  109. package/dist/memory/simple-manager.js +216 -0
  110. package/dist/memory/simple-manager.js.map +1 -0
  111. package/dist/memory/sqlite.d.ts +2 -0
  112. package/dist/memory/sqlite.d.ts.map +1 -0
  113. package/dist/memory/sqlite.js +16 -0
  114. package/dist/memory/sqlite.js.map +1 -0
  115. package/dist/memory/ssrf.d.ts +18 -0
  116. package/dist/memory/ssrf.d.ts.map +1 -0
  117. package/dist/memory/ssrf.js +396 -0
  118. package/dist/memory/ssrf.js.map +1 -0
  119. package/dist/memory/temporal-decay.d.ts +26 -0
  120. package/dist/memory/temporal-decay.d.ts.map +1 -0
  121. package/dist/memory/temporal-decay.js +120 -0
  122. package/dist/memory/temporal-decay.js.map +1 -0
  123. package/dist/memory/types.d.ts +95 -0
  124. package/dist/memory/types.d.ts.map +1 -0
  125. package/dist/memory/types.js +2 -0
  126. package/dist/memory/types.js.map +1 -0
  127. package/dist/package.json +68 -0
  128. package/dist/platform/index.d.ts +3 -0
  129. package/dist/platform/index.d.ts.map +1 -0
  130. package/dist/platform/index.js +2 -0
  131. package/dist/platform/index.js.map +1 -0
  132. package/dist/platform/platform.d.ts +3 -0
  133. package/dist/platform/platform.d.ts.map +1 -0
  134. package/dist/platform/platform.js +91 -0
  135. package/dist/platform/platform.js.map +1 -0
  136. package/dist/platform/types.d.ts +18 -0
  137. package/dist/platform/types.d.ts.map +1 -0
  138. package/dist/platform/types.js +2 -0
  139. package/dist/platform/types.js.map +1 -0
  140. package/dist/runtime/agent.d.ts +36 -0
  141. package/dist/runtime/agent.d.ts.map +1 -0
  142. package/dist/runtime/agent.js +250 -0
  143. package/dist/runtime/agent.js.map +1 -0
  144. package/dist/runtime/api-key-rotation.d.ts +26 -0
  145. package/dist/runtime/api-key-rotation.d.ts.map +1 -0
  146. package/dist/runtime/api-key-rotation.js +174 -0
  147. package/dist/runtime/api-key-rotation.js.map +1 -0
  148. package/dist/runtime/context-guard.d.ts +32 -0
  149. package/dist/runtime/context-guard.d.ts.map +1 -0
  150. package/dist/runtime/context-guard.js +61 -0
  151. package/dist/runtime/context-guard.js.map +1 -0
  152. package/dist/runtime/failover-error.d.ts +62 -0
  153. package/dist/runtime/failover-error.d.ts.map +1 -0
  154. package/dist/runtime/failover-error.js +733 -0
  155. package/dist/runtime/failover-error.js.map +1 -0
  156. package/dist/runtime/failover-policy.d.ts +5 -0
  157. package/dist/runtime/failover-policy.d.ts.map +1 -0
  158. package/dist/runtime/failover-policy.js +18 -0
  159. package/dist/runtime/failover-policy.js.map +1 -0
  160. package/dist/runtime/index.d.ts +13 -0
  161. package/dist/runtime/index.d.ts.map +1 -0
  162. package/dist/runtime/index.js +13 -0
  163. package/dist/runtime/index.js.map +1 -0
  164. package/dist/runtime/memory-flush.d.ts +24 -0
  165. package/dist/runtime/memory-flush.d.ts.map +1 -0
  166. package/dist/runtime/memory-flush.js +64 -0
  167. package/dist/runtime/memory-flush.js.map +1 -0
  168. package/dist/runtime/memory-tools.d.ts +14 -0
  169. package/dist/runtime/memory-tools.d.ts.map +1 -0
  170. package/dist/runtime/memory-tools.js +58 -0
  171. package/dist/runtime/memory-tools.js.map +1 -0
  172. package/dist/runtime/model-fallback.d.ts +56 -0
  173. package/dist/runtime/model-fallback.d.ts.map +1 -0
  174. package/dist/runtime/model-fallback.js +301 -0
  175. package/dist/runtime/model-fallback.js.map +1 -0
  176. package/dist/runtime/model-fallback.types.d.ts +14 -0
  177. package/dist/runtime/model-fallback.types.d.ts.map +1 -0
  178. package/dist/runtime/model-fallback.types.js +3 -0
  179. package/dist/runtime/model-fallback.types.js.map +1 -0
  180. package/dist/runtime/retry.d.ts +24 -0
  181. package/dist/runtime/retry.d.ts.map +1 -0
  182. package/dist/runtime/retry.js +100 -0
  183. package/dist/runtime/retry.js.map +1 -0
  184. package/dist/runtime/session-pruning.d.ts +22 -0
  185. package/dist/runtime/session-pruning.d.ts.map +1 -0
  186. package/dist/runtime/session-pruning.js +118 -0
  187. package/dist/runtime/session-pruning.js.map +1 -0
  188. package/dist/runtime/stream-adapters.d.ts +11 -0
  189. package/dist/runtime/stream-adapters.d.ts.map +1 -0
  190. package/dist/runtime/stream-adapters.js +46 -0
  191. package/dist/runtime/stream-adapters.js.map +1 -0
  192. package/dist/runtime/subagent.d.ts +83 -0
  193. package/dist/runtime/subagent.d.ts.map +1 -0
  194. package/dist/runtime/subagent.js +190 -0
  195. package/dist/runtime/subagent.js.map +1 -0
  196. package/dist/runtime/tool-result-truncation.d.ts +25 -0
  197. package/dist/runtime/tool-result-truncation.d.ts.map +1 -0
  198. package/dist/runtime/tool-result-truncation.js +115 -0
  199. package/dist/runtime/tool-result-truncation.js.map +1 -0
  200. package/dist/sandbox/cgroup.d.ts +20 -0
  201. package/dist/sandbox/cgroup.d.ts.map +1 -0
  202. package/dist/sandbox/cgroup.js +82 -0
  203. package/dist/sandbox/cgroup.js.map +1 -0
  204. package/dist/sandbox/index.d.ts +12 -0
  205. package/dist/sandbox/index.d.ts.map +1 -0
  206. package/dist/sandbox/index.js +10 -0
  207. package/dist/sandbox/index.js.map +1 -0
  208. package/dist/sandbox/ipc.d.ts +26 -0
  209. package/dist/sandbox/ipc.d.ts.map +1 -0
  210. package/dist/sandbox/ipc.js +154 -0
  211. package/dist/sandbox/ipc.js.map +1 -0
  212. package/dist/sandbox/manager.d.ts +4 -0
  213. package/dist/sandbox/manager.d.ts.map +1 -0
  214. package/dist/sandbox/manager.js +251 -0
  215. package/dist/sandbox/manager.js.map +1 -0
  216. package/dist/sandbox/namespace.d.ts +12 -0
  217. package/dist/sandbox/namespace.d.ts.map +1 -0
  218. package/dist/sandbox/namespace.js +119 -0
  219. package/dist/sandbox/namespace.js.map +1 -0
  220. package/dist/sandbox/proxy-tools.d.ts +14 -0
  221. package/dist/sandbox/proxy-tools.d.ts.map +1 -0
  222. package/dist/sandbox/proxy-tools.js +63 -0
  223. package/dist/sandbox/proxy-tools.js.map +1 -0
  224. package/dist/sandbox/rootfs.d.ts +20 -0
  225. package/dist/sandbox/rootfs.d.ts.map +1 -0
  226. package/dist/sandbox/rootfs.js +247 -0
  227. package/dist/sandbox/rootfs.js.map +1 -0
  228. package/dist/sandbox/seccomp-apply.d.ts +9 -0
  229. package/dist/sandbox/seccomp-apply.d.ts.map +1 -0
  230. package/dist/sandbox/seccomp-apply.js +227 -0
  231. package/dist/sandbox/seccomp-apply.js.map +1 -0
  232. package/dist/sandbox/seccomp.d.ts +13 -0
  233. package/dist/sandbox/seccomp.d.ts.map +1 -0
  234. package/dist/sandbox/seccomp.js +120 -0
  235. package/dist/sandbox/seccomp.js.map +1 -0
  236. package/dist/sandbox/types.d.ts +66 -0
  237. package/dist/sandbox/types.d.ts.map +1 -0
  238. package/dist/sandbox/types.js +8 -0
  239. package/dist/sandbox/types.js.map +1 -0
  240. package/dist/sandbox/worker.d.ts +15 -0
  241. package/dist/sandbox/worker.d.ts.map +1 -0
  242. package/dist/sandbox/worker.js +151 -0
  243. package/dist/sandbox/worker.js.map +1 -0
  244. package/dist/sessions/index.d.ts +3 -0
  245. package/dist/sessions/index.d.ts.map +1 -0
  246. package/dist/sessions/index.js +3 -0
  247. package/dist/sessions/index.js.map +1 -0
  248. package/dist/sessions/store.d.ts +17 -0
  249. package/dist/sessions/store.d.ts.map +1 -0
  250. package/dist/sessions/store.js +70 -0
  251. package/dist/sessions/store.js.map +1 -0
  252. package/dist/sessions/transcript-events.d.ts +11 -0
  253. package/dist/sessions/transcript-events.d.ts.map +1 -0
  254. package/dist/sessions/transcript-events.js +40 -0
  255. package/dist/sessions/transcript-events.js.map +1 -0
  256. package/dist/shared/agent-session.d.ts +10 -0
  257. package/dist/shared/agent-session.d.ts.map +1 -0
  258. package/dist/shared/agent-session.js +33 -0
  259. package/dist/shared/agent-session.js.map +1 -0
  260. package/dist/shared/constants.d.ts +6 -0
  261. package/dist/shared/constants.d.ts.map +1 -0
  262. package/dist/shared/constants.js +17 -0
  263. package/dist/shared/constants.js.map +1 -0
  264. package/dist/shared/fs.d.ts +7 -0
  265. package/dist/shared/fs.d.ts.map +1 -0
  266. package/dist/shared/fs.js +14 -0
  267. package/dist/shared/fs.js.map +1 -0
  268. package/dist/shared/index.d.ts +4 -0
  269. package/dist/shared/index.d.ts.map +1 -0
  270. package/dist/shared/index.js +4 -0
  271. package/dist/shared/index.js.map +1 -0
  272. package/dist/skills/enablement.d.ts +10 -0
  273. package/dist/skills/enablement.d.ts.map +1 -0
  274. package/dist/skills/enablement.js +52 -0
  275. package/dist/skills/enablement.js.map +1 -0
  276. package/dist/skills/index.d.ts +4 -0
  277. package/dist/skills/index.d.ts.map +1 -0
  278. package/dist/skills/index.js +4 -0
  279. package/dist/skills/index.js.map +1 -0
  280. package/dist/skills/loader.d.ts +8 -0
  281. package/dist/skills/loader.d.ts.map +1 -0
  282. package/dist/skills/loader.js +8 -0
  283. package/dist/skills/loader.js.map +1 -0
  284. package/dist/skills/registry.d.ts +19 -0
  285. package/dist/skills/registry.d.ts.map +1 -0
  286. package/dist/skills/registry.js +106 -0
  287. package/dist/skills/registry.js.map +1 -0
  288. package/dist/utils/boolean.d.ts +6 -0
  289. package/dist/utils/boolean.d.ts.map +1 -0
  290. package/dist/utils/boolean.js +28 -0
  291. package/dist/utils/boolean.js.map +1 -0
  292. package/dist/utils/run-with-concurrency.d.ts +12 -0
  293. package/dist/utils/run-with-concurrency.d.ts.map +1 -0
  294. package/dist/utils/run-with-concurrency.js +40 -0
  295. package/dist/utils/run-with-concurrency.js.map +1 -0
  296. package/dist/utils.d.ts +3 -0
  297. package/dist/utils.d.ts.map +1 -0
  298. package/dist/utils.js +38 -0
  299. package/dist/utils.js.map +1 -0
  300. package/dist/workspace/index.d.ts +3 -0
  301. package/dist/workspace/index.d.ts.map +1 -0
  302. package/dist/workspace/index.js +2 -0
  303. package/dist/workspace/index.js.map +1 -0
  304. package/dist/workspace/runner.d.ts +19 -0
  305. package/dist/workspace/runner.d.ts.map +1 -0
  306. package/dist/workspace/runner.js +491 -0
  307. package/dist/workspace/runner.js.map +1 -0
  308. package/dist/workspace/types.d.ts +37 -0
  309. package/dist/workspace/types.d.ts.map +1 -0
  310. package/dist/workspace/types.js +2 -0
  311. package/dist/workspace/types.js.map +1 -0
  312. package/dist/workspace/workspace.d.ts +12 -0
  313. package/dist/workspace/workspace.d.ts.map +1 -0
  314. package/dist/workspace/workspace.js +85 -0
  315. package/dist/workspace/workspace.js.map +1 -0
  316. package/package.json +82 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Peter Steinberger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,313 @@
1
+ ![Cloison Runtime](docs/assets/hero-banner.png)
2
+
3
+ [![npm](https://img.shields.io/npm/v/cloison-runtime?style=flat-square&color=4F8CFF&labelColor=0A0F1C)](https://www.npmjs.com/package/cloison-runtime) ![MIT](https://img.shields.io/badge/license-MIT-4F8CFF?style=flat-square&labelColor=0A0F1C) ![node](https://img.shields.io/badge/node-%3E%3D22.12-18C6B3?style=flat-square&labelColor=0A0F1C&logo=node.js&logoColor=white) ![deps](https://img.shields.io/badge/runtime_deps-3-18C6B3?style=flat-square&labelColor=0A0F1C) ![tests](https://img.shields.io/badge/tests-279_passing-18C6B3?style=flat-square&labelColor=0A0F1C) ![isolation](https://img.shields.io/badge/sandbox-5_isolation_layers-7A5CFF?style=flat-square&labelColor=0A0F1C) ![crypto](https://img.shields.io/badge/crypto-AES--256--GCM-7A5CFF?style=flat-square&labelColor=0A0F1C)
4
+
5
+ **Run 1,000 AI agents on a single Linux box.**
6
+ Each in its own OS namespace. Each with private memory, encrypted credentials, and an isolated filesystem.
7
+ **No Docker. No cloud. One `npm install`.**
8
+
9
+ Built on battle-tested subsystems extracted from [OpenClaw](https://github.com/nicepkg/openclaw) — model fallback, error classification, API key rotation, SSRF protection, embedding pipeline, and more.
10
+
11
+ ---
12
+
13
+ ## Quick Start
14
+
15
+ ```bash
16
+ npm install cloison-runtime
17
+ ```
18
+
19
+ ```typescript
20
+ import { createPlatform } from "cloison-runtime";
21
+
22
+ const platform = createPlatform({
23
+ stateDir: "/var/cloison-runtime",
24
+ credentialPassphrase: process.env.CLOISON_CREDENTIAL_KEY,
25
+ });
26
+
27
+ const workspace = await platform.createWorkspace("user-42", {
28
+ provider: "anthropic",
29
+ model: "claude-sonnet-4-20250514",
30
+ });
31
+
32
+ const result = await workspace.run({
33
+ message: "Refactor the auth module to use JWT",
34
+ sessionId: "project-alpha",
35
+ });
36
+ ```
37
+
38
+ > **Requires:** Linux + Node.js 22.12+
39
+ >
40
+ > **macOS / Windows dev:**
41
+ >
42
+ > ```bash
43
+ > git clone https://github.com/tonga54/cloison-runtime.git && cd cloison-runtime
44
+ > docker compose run dev bash
45
+ > pnpm test # 279 tests, all green
46
+ > ```
47
+
48
+ ---
49
+
50
+ ## Use Cases
51
+
52
+ ![Use Cases](docs/assets/use-cases.png)
53
+
54
+ ### SaaS -- one agent per customer
55
+
56
+ Customer A's agent can never see Customer B's tokens, data, or conversation history.
57
+
58
+ ```typescript
59
+ app.post("/api/agent", async (req, res) => {
60
+ const ws = await platform.getWorkspace(req.org.id);
61
+ const result = await ws.run({
62
+ message: req.body.message,
63
+ sessionId: req.body.threadId,
64
+ });
65
+ res.json({ response: result.response });
66
+ });
67
+ ```
68
+
69
+ ### Teams -- per-team agents, per-team secrets
70
+
71
+ Different teams, different databases, different cloud accounts. No credential leaks.
72
+
73
+ ```typescript
74
+ const eng = await platform.createWorkspace("engineering");
75
+ const ops = await platform.createWorkspace("ops");
76
+
77
+ eng.skills.enable("github-pr");
78
+ ops.skills.enable("pagerduty");
79
+
80
+ await eng.credentials.store("github", { token: "ghp_eng..." });
81
+ await ops.credentials.store("pagerduty", { token: "pd_..." });
82
+ ```
83
+
84
+ ### CI/CD -- ephemeral agents, zero state leaks
85
+
86
+ Spin up per job, per PR, per deploy. Destroyed after.
87
+
88
+ ```typescript
89
+ const ws = await platform.createWorkspace(`deploy-${Date.now()}`);
90
+ await ws.credentials.store("k8s", { kubeconfig: "..." });
91
+ ws.skills.enable("kubectl");
92
+ const result = await ws.run({ message: "Roll out v2.3.1 to staging, run smoke tests" });
93
+ await platform.deleteWorkspace(ws.userId);
94
+ ```
95
+
96
+ ---
97
+
98
+ ## How It Works
99
+
100
+ ![Architecture](docs/assets/architecture.png)
101
+
102
+ When `workspace.run()` executes, Cloison spawns a **child process** with 5 layers of kernel isolation: user namespace, PID namespace, mount namespace (pivot_root), optional network namespace, and cgroups v2 resource limits. The agent **never runs in your application's process** and **cannot see anything outside its sandbox**.
103
+
104
+ > **[Read the full isolation architecture →](docs/isolation.md)**
105
+
106
+ ---
107
+
108
+ ## Single-User Mode
109
+
110
+ For prototyping or single-agent use. No platform needed.
111
+
112
+ ```typescript
113
+ import { createRuntime } from "cloison-runtime";
114
+
115
+ const runtime = await createRuntime({
116
+ provider: "anthropic",
117
+ model: "claude-sonnet-4-20250514",
118
+ });
119
+
120
+ const result = await runtime.run({
121
+ message: "Find all TODO comments and create a summary",
122
+ });
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Features
128
+
129
+ | Feature | What It Does | Docs |
130
+ |---------|-------------|------|
131
+ | **OS-level Isolation** | 5 layers: user, PID, mount, network namespaces + cgroups v2 | [docs/isolation.md](docs/isolation.md) |
132
+ | **Encrypted Credentials** | AES-256-GCM at rest, PBKDF2 key derivation, never exposed to agent | [docs/credentials.md](docs/credentials.md) |
133
+ | **Hybrid Memory** | Vector + FTS5 fusion, MMR diversity, temporal decay, 7-language query expansion | [docs/memory.md](docs/memory.md) |
134
+ | **Per-Workspace Skills** | Global registry, per-tenant enablement, credentials injected server-side | [docs/skills.md](docs/skills.md) |
135
+ | **Session Continuity** | Named sessions, JSONL transcripts, context pruning | [docs/sessions.md](docs/sessions.md) |
136
+ | **Model Fallback** | Automatic multi-model chains, error classification, cooldown tracking | [docs/fallback.md](docs/fallback.md) |
137
+ | **API Key Rotation** | Multi-key per provider, automatic rotation on rate limits | [docs/fallback.md](docs/fallback.md) |
138
+ | **Subagent Orchestration** | Parallel execution, depth limiting, registry | [docs/subagents.md](docs/subagents.md) |
139
+ | **Structured Logging** | JSON/pretty/compact, file output, subsystem tagging | [docs/logging.md](docs/logging.md) |
140
+ | **SSRF Protection** | DNS pinning, private IP blocking, hostname allowlists, fail-closed | [docs/memory.md](docs/memory.md) |
141
+ | **Embedding Pipeline** | Batch with retry, SQLite cache, 5 providers (including local Ollama) | [docs/memory.md](docs/memory.md) |
142
+
143
+ ---
144
+
145
+ ## Why Cloison Over Alternatives
146
+
147
+ | | Docker per user | E2B / Cloud | **Cloison Runtime** |
148
+ | -------------------------------- | ------------------ | -------------------- | -------------------------------------------- |
149
+ | **Isolation mechanism** | Container per user | Cloud VM per session | **Linux namespaces** |
150
+ | **Credential security** | DIY | Not built-in | **AES-256-GCM, never exposed to agent** |
151
+ | **Persistent memory** | DIY | DIY | **SQLite + vector embeddings per tenant** |
152
+ | **SSRF protection** | DIY | DIY | **DNS-validated, private-IP blocking** |
153
+ | **Model fallback** | DIY | DIY | **Automatic multi-model fallback chains** |
154
+ | **API key rotation** | DIY | DIY | **Multi-key with rate-limit rotation** |
155
+ | **Skills with secret injection** | DIY | DIY | **Credentials injected server-side** |
156
+ | **Infrastructure** | Docker daemon | Cloud API + billing | **Single npm package** |
157
+ | **Cold start** | ~2s | ~5-10s | **~50ms** |
158
+ | **Embeddable in your app** | No | No | **Yes — it's a library** |
159
+ | **License** | — | Proprietary | **MIT** |
160
+
161
+ ---
162
+
163
+ ## Provider Support
164
+
165
+ ### LLM Providers
166
+
167
+ Any provider supported by [pi-ai](https://github.com/nicepkg/pi-ai):
168
+
169
+ | Provider | Example Model |
170
+ |----------|---------------|
171
+ | **Anthropic** | `claude-sonnet-4-20250514` |
172
+ | **Google** | `gemini-2.5-flash` |
173
+ | **OpenAI** | `gpt-4o` |
174
+ | **Groq** | `llama-3.3-70b-versatile` |
175
+ | **Cerebras** | `llama-3.3-70b` |
176
+ | **Mistral** | `mistral-large-latest` |
177
+ | **xAI** | `grok-3` |
178
+
179
+ ### Embedding Providers
180
+
181
+ | Provider | Default Model | Local |
182
+ |----------|--------------|-------|
183
+ | **OpenAI** | `text-embedding-3-small` | |
184
+ | **Gemini** | `gemini-embedding-001` | |
185
+ | **Voyage** | `voyage-3-lite` | |
186
+ | **Mistral** | `mistral-embed` | |
187
+ | **Ollama** | `nomic-embed-text` | **Yes** |
188
+
189
+ ---
190
+
191
+ ## Lifecycle Hooks
192
+
193
+ 6 hook points for audit logging, billing, and custom logic:
194
+
195
+ ```typescript
196
+ workspace.hooks.register("before_tool_call", async ({ toolName, input }) => {
197
+ await auditLog.write({ tool: toolName, input, timestamp: Date.now() });
198
+ });
199
+
200
+ workspace.hooks.register("after_agent_end", async ({ sessionId, result }) => {
201
+ await billing.recordUsage(workspace.userId, sessionId);
202
+ });
203
+ ```
204
+
205
+ `session_start` · `session_end` · `before_agent_start` · `after_agent_end` · `before_tool_call` · `after_tool_call`
206
+
207
+ ---
208
+
209
+ ## Demos
210
+
211
+ 12 runnable demos covering every feature. 4 require an API key, 8 run fully local.
212
+
213
+ > **[See all demos →](docs/demos.md)**
214
+
215
+ Highlights:
216
+
217
+ - **[demo-workspace-real](demos/demo-workspace-real.ts)** — Full multi-tenant DevOps platform with 2 teams, skills, memory, credentials, and live agent execution
218
+ - **[demo-subagents](demos/demo-subagents.ts)** — Orchestrator delegates to specialist sub-agents
219
+ - **[demo-fallback](demos/demo-fallback.ts)** — Model fallback chains with simulated failures
220
+
221
+ ---
222
+
223
+ ## Architecture
224
+
225
+ ```
226
+ src/
227
+ ├── platform/ createPlatform() — workspace CRUD, skill registry
228
+ ├── workspace/ createWorkspace() — scoped memory, sessions, runner
229
+ │ └── runner.ts Out-of-process agent execution via sandbox + IPC
230
+ ├── sandbox/ Linux namespace sandbox — zero external deps
231
+ │ ├── namespace.ts unshare(2) + pivot_root
232
+ │ ├── cgroup.ts cgroups v2 resource limits (fail-closed)
233
+ │ ├── rootfs.ts Minimal rootfs with bind mounts
234
+ │ ├── ipc.ts Bidirectional JSON-RPC 2.0 over stdio
235
+ │ ├── seccomp.ts BPF syscall filter profiles
236
+ │ ├── proxy-tools.ts memory/skill tools proxied to host via IPC
237
+ │ └── worker.ts Agent entry point inside sandbox
238
+ ├── credentials/ AES-256-GCM encrypted store + credential proxy
239
+ ├── skills/ Global registry + per-workspace enablement
240
+ ├── runtime/ createRuntime() — single-user mode
241
+ │ ├── failover-error.ts Error classification (ported from OpenClaw)
242
+ │ ├── model-fallback.ts Fallback chains + cooldown tracking
243
+ │ ├── api-key-rotation.ts Per-provider key rotation
244
+ │ ├── subagent.ts Parallel execution + lifecycle + registry
245
+ │ └── ... context-guard, retry, session-pruning, memory-flush
246
+ ├── memory/ Hybrid search engine
247
+ │ ├── hybrid.ts Vector + FTS5 fusion scoring
248
+ │ ├── mmr.ts Maximal Marginal Relevance re-ranking
249
+ │ ├── embeddings.ts 5-provider embedding support
250
+ │ ├── ssrf.ts SSRF protection for HTTP calls
251
+ │ └── ... temporal-decay, query-expansion, cache, indexers
252
+ ├── hooks/ 6 lifecycle hook points
253
+ ├── logging/ Structured JSON logging with file output
254
+ ├── sessions/ File-based store with async locking
255
+ └── config/ Configuration loading
256
+ ```
257
+
258
+ **78 source files** · **3 runtime deps** · Sandbox, crypto, IPC, logging, and SSRF use **zero external deps** — all Node.js built-ins.
259
+
260
+ ---
261
+
262
+ ## State Directory
263
+
264
+ ```
265
+ <stateDir>/
266
+ ├── skills/ # Global skill catalog
267
+ │ └── <skill-id>/
268
+ │ ├── SKILL.md # LLM-readable skill description
269
+ │ └── execute.js # Runs with injected credentials
270
+ └── workspaces/
271
+ └── <userId>/
272
+ ├── config.json # Workspace config (no secrets)
273
+ ├── credentials.enc.json # AES-256-GCM encrypted credentials
274
+ ├── enabled-skills.json # Which skills this workspace can use
275
+ ├── sessions.json # Session index
276
+ ├── sessions/ # JSONL transcripts
277
+ └── memory/
278
+ └── memory.db # SQLite (vectors + FTS5)
279
+ ```
280
+
281
+ Every file is workspace-scoped. No shared state between tenants.
282
+
283
+ ---
284
+
285
+ ## Built on OpenClaw
286
+
287
+ Cloison Runtime stands on the shoulders of [OpenClaw](https://github.com/nicepkg/openclaw). Several production-critical subsystems were ported directly:
288
+
289
+ | Subsystem | Origin |
290
+ |-----------|--------|
291
+ | **Model fallback & error classification** | `src/agents/model-fallback.ts`, `failover-error.ts` |
292
+ | **API key rotation** | `src/agents/api-key-rotation.ts`, `live-auth-keys.ts` |
293
+ | **Context window guards** | `src/agents/context-window-guard.ts` |
294
+ | **Retry with backoff** | `src/infra/retry.ts` |
295
+ | **SSRF protection** | `src/infra/net/ssrf.ts`, `fetch-guard.ts` |
296
+ | **Embedding cache & batch** | `extensions/memory-core/` |
297
+ | **File & session indexers** | `extensions/memory-core/` |
298
+ | **Subagent orchestration** | `src/agents/subagent-*.ts` |
299
+ | **Structured logging** | `src/logging/logger.ts`, `subsystem.ts` |
300
+
301
+ OpenClaw solved these problems in production. We extracted, adapted, and integrated them into Cloison's multi-tenant architecture.
302
+
303
+ ---
304
+
305
+ ## Requirements
306
+
307
+ - **Linux** — bare metal, VM, or container with `--privileged`
308
+ - **Node.js 22.12+** — uses `node:sqlite` built-in
309
+ - **macOS / Windows** — `docker compose run dev` for development
310
+
311
+ ## License
312
+
313
+ [MIT](LICENSE)
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env node
2
+ import { createRuntime } from "./runtime/index.js";
3
+ async function main() {
4
+ const args = process.argv.slice(2);
5
+ function getFlag(flag) {
6
+ const i = args.indexOf(flag);
7
+ if (i === -1 || i + 1 >= args.length)
8
+ return undefined;
9
+ return args[i + 1];
10
+ }
11
+ const message = getFlag("--message") ?? getFlag("-m");
12
+ const sessionId = getFlag("--session");
13
+ const model = getFlag("--model");
14
+ const provider = getFlag("--provider");
15
+ const apiKey = getFlag("--api-key");
16
+ if (apiKey) {
17
+ process.stderr.write("Warning: --api-key is visible in process listings. " +
18
+ "Prefer setting the API key via environment variable (e.g. ANTHROPIC_API_KEY).\n");
19
+ }
20
+ const workspaceDir = getFlag("--workspace");
21
+ const systemPrompt = getFlag("--system-prompt");
22
+ if (!message) {
23
+ console.error("Usage: cloison-runtime --message <message> [--session <id>] [--model <model>] [--provider <provider>]");
24
+ process.exit(1);
25
+ }
26
+ const runtime = await createRuntime({
27
+ model,
28
+ provider,
29
+ apiKey,
30
+ workspaceDir,
31
+ });
32
+ const result = await runtime.run({
33
+ message,
34
+ sessionId,
35
+ model,
36
+ provider,
37
+ apiKey,
38
+ workspaceDir,
39
+ systemPrompt,
40
+ });
41
+ console.log(result.response);
42
+ }
43
+ main().catch((err) => {
44
+ console.error(err);
45
+ process.exit(1);
46
+ });
47
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,SAAS,OAAO,CAAC,IAAY;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QACvD,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACrB,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACpC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,qDAAqD;YACrD,iFAAiF,CAClF,CAAC;IACJ,CAAC;IACD,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5C,MAAM,YAAY,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAEhD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CACX,uGAAuG,CACxG,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,aAAa,CAAC;QAClC,KAAK;QACL,QAAQ;QACR,MAAM;QACN,YAAY;KACb,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC/B,OAAO;QACP,SAAS;QACT,KAAK;QACL,QAAQ;QACR,MAAM;QACN,YAAY;QACZ,YAAY;KACb,CAAC,CAAC;IAEH,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,57 @@
1
+ export interface AgentRuntimeConfig {
2
+ model?: string;
3
+ provider?: string;
4
+ apiKey?: string;
5
+ apiKeys?: string[];
6
+ configPath?: string;
7
+ stateDir?: string;
8
+ workspaceDir?: string;
9
+ systemPrompt?: string;
10
+ skills?: {
11
+ enabled?: boolean;
12
+ dirs?: string[];
13
+ };
14
+ memory?: {
15
+ enabled?: boolean;
16
+ dir?: string;
17
+ embeddingProvider?: {
18
+ provider: "openai" | "gemini" | "voyage" | "mistral" | "ollama";
19
+ apiKey?: string;
20
+ model?: string;
21
+ baseUrl?: string;
22
+ enableSsrf?: boolean;
23
+ };
24
+ enableEmbeddingCache?: boolean;
25
+ maxCacheEntries?: number;
26
+ fileIndexing?: {
27
+ enabled?: boolean;
28
+ watchPaths?: string[];
29
+ debounceMs?: number;
30
+ };
31
+ sessionIndexing?: {
32
+ enabled?: boolean;
33
+ deltaBytes?: number;
34
+ deltaMessages?: number;
35
+ };
36
+ };
37
+ hooks?: {
38
+ dirs?: string[];
39
+ };
40
+ fallbacks?: string[];
41
+ contextTokens?: number;
42
+ maxRetries?: number;
43
+ logging?: {
44
+ level?: "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "silent";
45
+ file?: string;
46
+ maxFileBytes?: number;
47
+ json?: boolean;
48
+ };
49
+ streamConfig?: Record<string, {
50
+ headers?: Record<string, string>;
51
+ baseUrl?: string;
52
+ }>;
53
+ }
54
+ export declare function getDefaultStateDir(): string;
55
+ export declare function loadConfig(configPath?: string): AgentRuntimeConfig;
56
+ export declare function resolveStateDir(config: AgentRuntimeConfig): string;
57
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAChD,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,iBAAiB,CAAC,EAAE;YAClB,QAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;YAChE,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,UAAU,CAAC,EAAE,OAAO,CAAC;SACtB,CAAC;QACF,oBAAoB,CAAC,EAAE,OAAO,CAAC;QAC/B,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,YAAY,CAAC,EAAE;YACb,OAAO,CAAC,EAAE,OAAO,CAAC;YAClB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;YACtB,UAAU,CAAC,EAAE,MAAM,CAAC;SACrB,CAAC;QACF,eAAe,CAAC,EAAE;YAChB,OAAO,CAAC,EAAE,OAAO,CAAC;YAClB,UAAU,CAAC,EAAE,MAAM,CAAC;YACpB,aAAa,CAAC,EAAE,MAAM,CAAC;SACxB,CAAC;KACH,CAAC;IACF,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;QAC3E,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,IAAI,CAAC,EAAE,OAAO,CAAC;KAChB,CAAC;IACF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAclE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CAMlE"}
@@ -0,0 +1,27 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import * as os from "node:os";
4
+ export function getDefaultStateDir() {
5
+ return path.join(os.homedir(), ".cloison-runtime");
6
+ }
7
+ export function loadConfig(configPath) {
8
+ const explicit = configPath ?? process.env["CLOISON_CONFIG_PATH"];
9
+ const resolved = explicit ?? path.join(getDefaultStateDir(), "cloison-runtime.json");
10
+ try {
11
+ const raw = fs.readFileSync(resolved, "utf-8");
12
+ return JSON.parse(raw);
13
+ }
14
+ catch (err) {
15
+ if (explicit) {
16
+ const msg = err instanceof Error ? err.message : String(err);
17
+ throw new Error(`Failed to load config from "${resolved}": ${msg}`);
18
+ }
19
+ return {};
20
+ }
21
+ }
22
+ export function resolveStateDir(config) {
23
+ return (config.stateDir ??
24
+ process.env["CLOISON_STATE_DIR"] ??
25
+ getDefaultStateDir());
26
+ }
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAmD9B,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,kBAAkB,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,UAAmB;IAC5C,MAAM,QAAQ,GAAG,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,sBAAsB,CAAC,CAAC;IAErF,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAuB,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,MAAM,GAAG,EAAE,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAA0B;IACxD,OAAO,CACL,MAAM,CAAC,QAAQ;QACf,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAChC,kBAAkB,EAAE,CACrB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { createCredentialStore, type CreateCredentialStoreOptions } from "./store.js";
2
+ export { createCredentialProxy } from "./proxy.js";
3
+ export type { CredentialStore, CredentialProxy, CredentialEntry } from "./types.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/credentials/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,KAAK,4BAA4B,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { createCredentialStore } from "./store.js";
2
+ export { createCredentialProxy } from "./proxy.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/credentials/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAqC,MAAM,YAAY,CAAC;AACtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CredentialStore, CredentialProxy } from "./types.js";
2
+ export declare function createCredentialProxy(store: CredentialStore): CredentialProxy;
3
+ //# sourceMappingURL=proxy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/credentials/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnE,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,eAAe,GACrB,eAAe,CAQjB"}
@@ -0,0 +1,11 @@
1
+ export function createCredentialProxy(store) {
2
+ return {
3
+ async injectCredentials(skillId, env) {
4
+ const creds = await store.resolve(skillId);
5
+ if (!creds)
6
+ return env;
7
+ return { ...env, ...creds };
8
+ },
9
+ };
10
+ }
11
+ //# sourceMappingURL=proxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/credentials/proxy.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,qBAAqB,CACnC,KAAsB;IAEtB,OAAO;QACL,KAAK,CAAC,iBAAiB,CAAC,OAAO,EAAE,GAAG;YAClC,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YAC3C,IAAI,CAAC,KAAK;gBAAE,OAAO,GAAG,CAAC;YACvB,OAAO,EAAE,GAAG,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC;QAC9B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { CredentialStore } from "./types.js";
2
+ export interface CreateCredentialStoreOptions {
3
+ workspaceDir: string;
4
+ passphrase?: string;
5
+ }
6
+ export declare function createCredentialStore(options: CreateCredentialStoreOptions): CredentialStore;
7
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/credentials/store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAmElD,MAAM,WAAW,4BAA4B;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,4BAA4B,GACpC,eAAe,CA6EjB"}
@@ -0,0 +1,115 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import * as crypto from "node:crypto";
4
+ import { atomicWriteFileSync } from "../shared/index.js";
5
+ let credentialLock = Promise.resolve();
6
+ function withCredentialLock(fn) {
7
+ const prev = credentialLock;
8
+ let release;
9
+ credentialLock = new Promise((r) => { release = r; });
10
+ return prev.then(fn).finally(() => release());
11
+ }
12
+ const ALGORITHM = "aes-256-gcm";
13
+ const KEY_LENGTH = 32;
14
+ const IV_LENGTH = 16;
15
+ const SALT_LENGTH = 32;
16
+ const TAG_LENGTH = 16;
17
+ const PBKDF2_ITERATIONS = 100_000;
18
+ function deriveKey(passphrase, salt) {
19
+ return crypto.pbkdf2Sync(passphrase, salt, PBKDF2_ITERATIONS, KEY_LENGTH, "sha512");
20
+ }
21
+ function encrypt(plaintext, passphrase) {
22
+ const salt = crypto.randomBytes(SALT_LENGTH);
23
+ const key = deriveKey(passphrase, salt);
24
+ const iv = crypto.randomBytes(IV_LENGTH);
25
+ const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
26
+ let ciphertext = cipher.update(plaintext, "utf-8", "base64");
27
+ ciphertext += cipher.final("base64");
28
+ const tag = cipher.getAuthTag();
29
+ return {
30
+ salt: salt.toString("base64"),
31
+ iv: iv.toString("base64"),
32
+ tag: tag.toString("base64"),
33
+ ciphertext,
34
+ };
35
+ }
36
+ function decrypt(payload, passphrase) {
37
+ const salt = Buffer.from(payload.salt, "base64");
38
+ const key = deriveKey(passphrase, salt);
39
+ const iv = Buffer.from(payload.iv, "base64");
40
+ const tag = Buffer.from(payload.tag, "base64");
41
+ const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
42
+ decipher.setAuthTag(tag);
43
+ let plaintext = decipher.update(payload.ciphertext, "base64", "utf-8");
44
+ plaintext += decipher.final("utf-8");
45
+ return plaintext;
46
+ }
47
+ export function createCredentialStore(options) {
48
+ const filePath = path.join(options.workspaceDir, "credentials.enc.json");
49
+ const passphrase = options.passphrase ??
50
+ process.env["CLOISON_CREDENTIAL_KEY"];
51
+ if (!passphrase) {
52
+ throw new Error("Credential store requires a passphrase: pass it explicitly or set CLOISON_CREDENTIAL_KEY");
53
+ }
54
+ const DANGEROUS_KEYS = new Set(["__proto__", "constructor", "prototype"]);
55
+ function validateSkillId(skillId) {
56
+ if (DANGEROUS_KEYS.has(skillId)) {
57
+ throw new Error(`Invalid skillId "${skillId}": reserved property name`);
58
+ }
59
+ }
60
+ function loadFile() {
61
+ try {
62
+ const raw = fs.readFileSync(filePath, "utf-8");
63
+ return JSON.parse(raw);
64
+ }
65
+ catch {
66
+ return { version: 1, credentials: {} };
67
+ }
68
+ }
69
+ function saveFile(file) {
70
+ atomicWriteFileSync(filePath, JSON.stringify(file, null, 2));
71
+ }
72
+ return {
73
+ async store(skillId, credentials) {
74
+ validateSkillId(skillId);
75
+ return withCredentialLock(async () => {
76
+ const file = loadFile();
77
+ const plaintext = JSON.stringify(credentials);
78
+ file.credentials[skillId] = encrypt(plaintext, passphrase);
79
+ saveFile(file);
80
+ });
81
+ },
82
+ async resolve(skillId) {
83
+ validateSkillId(skillId);
84
+ const file = loadFile();
85
+ const payload = file.credentials[skillId];
86
+ if (!payload)
87
+ return undefined;
88
+ try {
89
+ const plaintext = decrypt(payload, passphrase);
90
+ return JSON.parse(plaintext);
91
+ }
92
+ catch (err) {
93
+ process.stderr.write(`[credential-store] Failed to decrypt credentials for skill "${skillId}": ${err instanceof Error ? err.message : String(err)}. ` +
94
+ `This typically means the passphrase has changed since the credentials were stored.\n`);
95
+ return undefined;
96
+ }
97
+ },
98
+ async delete(skillId) {
99
+ validateSkillId(skillId);
100
+ return withCredentialLock(async () => {
101
+ const file = loadFile();
102
+ if (!(skillId in file.credentials))
103
+ return false;
104
+ delete file.credentials[skillId];
105
+ saveFile(file);
106
+ return true;
107
+ });
108
+ },
109
+ async list() {
110
+ const file = loadFile();
111
+ return Object.keys(file.credentials);
112
+ },
113
+ };
114
+ }
115
+ //# sourceMappingURL=store.js.map