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.
- package/LICENSE +21 -0
- package/README.md +313 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +47 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/index.d.ts +57 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +27 -0
- package/dist/config/index.js.map +1 -0
- package/dist/credentials/index.d.ts +4 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +3 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/proxy.d.ts +3 -0
- package/dist/credentials/proxy.d.ts.map +1 -0
- package/dist/credentials/proxy.js +11 -0
- package/dist/credentials/proxy.js.map +1 -0
- package/dist/credentials/store.d.ts +7 -0
- package/dist/credentials/store.d.ts.map +1 -0
- package/dist/credentials/store.js +115 -0
- package/dist/credentials/store.js.map +1 -0
- package/dist/credentials/types.d.ts +14 -0
- package/dist/credentials/types.d.ts.map +1 -0
- package/dist/credentials/types.js +2 -0
- package/dist/credentials/types.js.map +1 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/runner.d.ts +7 -0
- package/dist/hooks/runner.d.ts.map +1 -0
- package/dist/hooks/runner.js +20 -0
- package/dist/hooks/runner.js.map +1 -0
- package/dist/hooks/types.d.ts +39 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +2 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/infra/env.d.ts +2 -0
- package/dist/infra/env.d.ts.map +1 -0
- package/dist/infra/env.js +6 -0
- package/dist/infra/env.js.map +1 -0
- package/dist/infra/warning-filter.d.ts +8 -0
- package/dist/infra/warning-filter.d.ts.map +1 -0
- package/dist/infra/warning-filter.js +66 -0
- package/dist/infra/warning-filter.js.map +1 -0
- package/dist/logging/subsystem.d.ts +29 -0
- package/dist/logging/subsystem.d.ts.map +1 -0
- package/dist/logging/subsystem.js +322 -0
- package/dist/logging/subsystem.js.map +1 -0
- package/dist/memory/embedding-batch.d.ts +38 -0
- package/dist/memory/embedding-batch.d.ts.map +1 -0
- package/dist/memory/embedding-batch.js +253 -0
- package/dist/memory/embedding-batch.js.map +1 -0
- package/dist/memory/embedding-cache.d.ts +16 -0
- package/dist/memory/embedding-cache.d.ts.map +1 -0
- package/dist/memory/embedding-cache.js +113 -0
- package/dist/memory/embedding-cache.js.map +1 -0
- package/dist/memory/embeddings-debug.d.ts +2 -0
- package/dist/memory/embeddings-debug.d.ts.map +1 -0
- package/dist/memory/embeddings-debug.js +12 -0
- package/dist/memory/embeddings-debug.js.map +1 -0
- package/dist/memory/embeddings.d.ts +17 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +203 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/file-indexer.d.ts +26 -0
- package/dist/memory/file-indexer.d.ts.map +1 -0
- package/dist/memory/file-indexer.js +260 -0
- package/dist/memory/file-indexer.js.map +1 -0
- package/dist/memory/fs-utils.d.ts +12 -0
- package/dist/memory/fs-utils.d.ts.map +1 -0
- package/dist/memory/fs-utils.js +24 -0
- package/dist/memory/fs-utils.js.map +1 -0
- package/dist/memory/hybrid.d.ts +46 -0
- package/dist/memory/hybrid.d.ts.map +1 -0
- package/dist/memory/hybrid.js +85 -0
- package/dist/memory/hybrid.js.map +1 -0
- package/dist/memory/index.d.ts +17 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +15 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/internal.d.ts +39 -0
- package/dist/memory/internal.d.ts.map +1 -0
- package/dist/memory/internal.js +292 -0
- package/dist/memory/internal.js.map +1 -0
- package/dist/memory/manager-search.d.ts +61 -0
- package/dist/memory/manager-search.d.ts.map +1 -0
- package/dist/memory/manager-search.js +102 -0
- package/dist/memory/manager-search.js.map +1 -0
- package/dist/memory/mmr.d.ts +63 -0
- package/dist/memory/mmr.d.ts.map +1 -0
- package/dist/memory/mmr.js +165 -0
- package/dist/memory/mmr.js.map +1 -0
- package/dist/memory/query-expansion.d.ts +42 -0
- package/dist/memory/query-expansion.d.ts.map +1 -0
- package/dist/memory/query-expansion.js +776 -0
- package/dist/memory/query-expansion.js.map +1 -0
- package/dist/memory/session-indexer.d.ts +41 -0
- package/dist/memory/session-indexer.d.ts.map +1 -0
- package/dist/memory/session-indexer.js +367 -0
- package/dist/memory/session-indexer.js.map +1 -0
- package/dist/memory/simple-manager.d.ts +29 -0
- package/dist/memory/simple-manager.d.ts.map +1 -0
- package/dist/memory/simple-manager.js +216 -0
- package/dist/memory/simple-manager.js.map +1 -0
- package/dist/memory/sqlite.d.ts +2 -0
- package/dist/memory/sqlite.d.ts.map +1 -0
- package/dist/memory/sqlite.js +16 -0
- package/dist/memory/sqlite.js.map +1 -0
- package/dist/memory/ssrf.d.ts +18 -0
- package/dist/memory/ssrf.d.ts.map +1 -0
- package/dist/memory/ssrf.js +396 -0
- package/dist/memory/ssrf.js.map +1 -0
- package/dist/memory/temporal-decay.d.ts +26 -0
- package/dist/memory/temporal-decay.d.ts.map +1 -0
- package/dist/memory/temporal-decay.js +120 -0
- package/dist/memory/temporal-decay.js.map +1 -0
- package/dist/memory/types.d.ts +95 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +2 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/package.json +68 -0
- package/dist/platform/index.d.ts +3 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +2 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/platform.d.ts +3 -0
- package/dist/platform/platform.d.ts.map +1 -0
- package/dist/platform/platform.js +91 -0
- package/dist/platform/platform.js.map +1 -0
- package/dist/platform/types.d.ts +18 -0
- package/dist/platform/types.d.ts.map +1 -0
- package/dist/platform/types.js +2 -0
- package/dist/platform/types.js.map +1 -0
- package/dist/runtime/agent.d.ts +36 -0
- package/dist/runtime/agent.d.ts.map +1 -0
- package/dist/runtime/agent.js +250 -0
- package/dist/runtime/agent.js.map +1 -0
- package/dist/runtime/api-key-rotation.d.ts +26 -0
- package/dist/runtime/api-key-rotation.d.ts.map +1 -0
- package/dist/runtime/api-key-rotation.js +174 -0
- package/dist/runtime/api-key-rotation.js.map +1 -0
- package/dist/runtime/context-guard.d.ts +32 -0
- package/dist/runtime/context-guard.d.ts.map +1 -0
- package/dist/runtime/context-guard.js +61 -0
- package/dist/runtime/context-guard.js.map +1 -0
- package/dist/runtime/failover-error.d.ts +62 -0
- package/dist/runtime/failover-error.d.ts.map +1 -0
- package/dist/runtime/failover-error.js +733 -0
- package/dist/runtime/failover-error.js.map +1 -0
- package/dist/runtime/failover-policy.d.ts +5 -0
- package/dist/runtime/failover-policy.d.ts.map +1 -0
- package/dist/runtime/failover-policy.js +18 -0
- package/dist/runtime/failover-policy.js.map +1 -0
- package/dist/runtime/index.d.ts +13 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +13 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/memory-flush.d.ts +24 -0
- package/dist/runtime/memory-flush.d.ts.map +1 -0
- package/dist/runtime/memory-flush.js +64 -0
- package/dist/runtime/memory-flush.js.map +1 -0
- package/dist/runtime/memory-tools.d.ts +14 -0
- package/dist/runtime/memory-tools.d.ts.map +1 -0
- package/dist/runtime/memory-tools.js +58 -0
- package/dist/runtime/memory-tools.js.map +1 -0
- package/dist/runtime/model-fallback.d.ts +56 -0
- package/dist/runtime/model-fallback.d.ts.map +1 -0
- package/dist/runtime/model-fallback.js +301 -0
- package/dist/runtime/model-fallback.js.map +1 -0
- package/dist/runtime/model-fallback.types.d.ts +14 -0
- package/dist/runtime/model-fallback.types.d.ts.map +1 -0
- package/dist/runtime/model-fallback.types.js +3 -0
- package/dist/runtime/model-fallback.types.js.map +1 -0
- package/dist/runtime/retry.d.ts +24 -0
- package/dist/runtime/retry.d.ts.map +1 -0
- package/dist/runtime/retry.js +100 -0
- package/dist/runtime/retry.js.map +1 -0
- package/dist/runtime/session-pruning.d.ts +22 -0
- package/dist/runtime/session-pruning.d.ts.map +1 -0
- package/dist/runtime/session-pruning.js +118 -0
- package/dist/runtime/session-pruning.js.map +1 -0
- package/dist/runtime/stream-adapters.d.ts +11 -0
- package/dist/runtime/stream-adapters.d.ts.map +1 -0
- package/dist/runtime/stream-adapters.js +46 -0
- package/dist/runtime/stream-adapters.js.map +1 -0
- package/dist/runtime/subagent.d.ts +83 -0
- package/dist/runtime/subagent.d.ts.map +1 -0
- package/dist/runtime/subagent.js +190 -0
- package/dist/runtime/subagent.js.map +1 -0
- package/dist/runtime/tool-result-truncation.d.ts +25 -0
- package/dist/runtime/tool-result-truncation.d.ts.map +1 -0
- package/dist/runtime/tool-result-truncation.js +115 -0
- package/dist/runtime/tool-result-truncation.js.map +1 -0
- package/dist/sandbox/cgroup.d.ts +20 -0
- package/dist/sandbox/cgroup.d.ts.map +1 -0
- package/dist/sandbox/cgroup.js +82 -0
- package/dist/sandbox/cgroup.js.map +1 -0
- package/dist/sandbox/index.d.ts +12 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +10 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/ipc.d.ts +26 -0
- package/dist/sandbox/ipc.d.ts.map +1 -0
- package/dist/sandbox/ipc.js +154 -0
- package/dist/sandbox/ipc.js.map +1 -0
- package/dist/sandbox/manager.d.ts +4 -0
- package/dist/sandbox/manager.d.ts.map +1 -0
- package/dist/sandbox/manager.js +251 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/namespace.d.ts +12 -0
- package/dist/sandbox/namespace.d.ts.map +1 -0
- package/dist/sandbox/namespace.js +119 -0
- package/dist/sandbox/namespace.js.map +1 -0
- package/dist/sandbox/proxy-tools.d.ts +14 -0
- package/dist/sandbox/proxy-tools.d.ts.map +1 -0
- package/dist/sandbox/proxy-tools.js +63 -0
- package/dist/sandbox/proxy-tools.js.map +1 -0
- package/dist/sandbox/rootfs.d.ts +20 -0
- package/dist/sandbox/rootfs.d.ts.map +1 -0
- package/dist/sandbox/rootfs.js +247 -0
- package/dist/sandbox/rootfs.js.map +1 -0
- package/dist/sandbox/seccomp-apply.d.ts +9 -0
- package/dist/sandbox/seccomp-apply.d.ts.map +1 -0
- package/dist/sandbox/seccomp-apply.js +227 -0
- package/dist/sandbox/seccomp-apply.js.map +1 -0
- package/dist/sandbox/seccomp.d.ts +13 -0
- package/dist/sandbox/seccomp.d.ts.map +1 -0
- package/dist/sandbox/seccomp.js +120 -0
- package/dist/sandbox/seccomp.js.map +1 -0
- package/dist/sandbox/types.d.ts +66 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +8 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/sandbox/worker.d.ts +15 -0
- package/dist/sandbox/worker.d.ts.map +1 -0
- package/dist/sandbox/worker.js +151 -0
- package/dist/sandbox/worker.js.map +1 -0
- package/dist/sessions/index.d.ts +3 -0
- package/dist/sessions/index.d.ts.map +1 -0
- package/dist/sessions/index.js +3 -0
- package/dist/sessions/index.js.map +1 -0
- package/dist/sessions/store.d.ts +17 -0
- package/dist/sessions/store.d.ts.map +1 -0
- package/dist/sessions/store.js +70 -0
- package/dist/sessions/store.js.map +1 -0
- package/dist/sessions/transcript-events.d.ts +11 -0
- package/dist/sessions/transcript-events.d.ts.map +1 -0
- package/dist/sessions/transcript-events.js +40 -0
- package/dist/sessions/transcript-events.js.map +1 -0
- package/dist/shared/agent-session.d.ts +10 -0
- package/dist/shared/agent-session.d.ts.map +1 -0
- package/dist/shared/agent-session.js +33 -0
- package/dist/shared/agent-session.js.map +1 -0
- package/dist/shared/constants.d.ts +6 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +17 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/fs.d.ts +7 -0
- package/dist/shared/fs.d.ts.map +1 -0
- package/dist/shared/fs.js +14 -0
- package/dist/shared/fs.js.map +1 -0
- package/dist/shared/index.d.ts +4 -0
- package/dist/shared/index.d.ts.map +1 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/skills/enablement.d.ts +10 -0
- package/dist/skills/enablement.d.ts.map +1 -0
- package/dist/skills/enablement.js +52 -0
- package/dist/skills/enablement.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +4 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/loader.d.ts +8 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +8 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/registry.d.ts +19 -0
- package/dist/skills/registry.d.ts.map +1 -0
- package/dist/skills/registry.js +106 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/utils/boolean.d.ts +6 -0
- package/dist/utils/boolean.d.ts.map +1 -0
- package/dist/utils/boolean.js +28 -0
- package/dist/utils/boolean.js.map +1 -0
- package/dist/utils/run-with-concurrency.d.ts +12 -0
- package/dist/utils/run-with-concurrency.d.ts.map +1 -0
- package/dist/utils/run-with-concurrency.js +40 -0
- package/dist/utils/run-with-concurrency.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +38 -0
- package/dist/utils.js.map +1 -0
- package/dist/workspace/index.d.ts +3 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +2 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/runner.d.ts +19 -0
- package/dist/workspace/runner.d.ts.map +1 -0
- package/dist/workspace/runner.js +491 -0
- package/dist/workspace/runner.js.map +1 -0
- package/dist/workspace/types.d.ts +37 -0
- package/dist/workspace/types.d.ts.map +1 -0
- package/dist/workspace/types.js +2 -0
- package/dist/workspace/types.js.map +1 -0
- package/dist/workspace/workspace.d.ts +12 -0
- package/dist/workspace/workspace.d.ts.map +1 -0
- package/dist/workspace/workspace.js +85 -0
- package/dist/workspace/workspace.js.map +1 -0
- 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
|
+

|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/cloison-runtime)      
|
|
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
|
+

|
|
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
|
+

|
|
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 @@
|
|
|
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
|
package/dist/cli.js.map
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|