termyte 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/README.md +50 -0
- package/dist/__tests__/command-sandbox.test.d.ts +2 -0
- package/dist/__tests__/command-sandbox.test.d.ts.map +1 -0
- package/dist/__tests__/command-sandbox.test.js +18 -0
- package/dist/__tests__/command-sandbox.test.js.map +1 -0
- package/dist/__tests__/contract.test.d.ts +2 -0
- package/dist/__tests__/contract.test.d.ts.map +1 -0
- package/dist/__tests__/contract.test.js +70 -0
- package/dist/__tests__/contract.test.js.map +1 -0
- package/dist/__tests__/offline.test.d.ts +2 -0
- package/dist/__tests__/offline.test.d.ts.map +1 -0
- package/dist/__tests__/offline.test.js +22 -0
- package/dist/__tests__/offline.test.js.map +1 -0
- package/dist/cache.d.ts +26 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +81 -0
- package/dist/cache.js.map +1 -0
- package/dist/client.d.ts +9 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +32 -0
- package/dist/client.js.map +1 -0
- package/dist/cloud-client.d.ts +11 -0
- package/dist/cloud-client.d.ts.map +1 -0
- package/dist/cloud-client.js +89 -0
- package/dist/cloud-client.js.map +1 -0
- package/dist/executor.d.ts +20 -0
- package/dist/executor.d.ts.map +1 -0
- package/dist/executor.js +93 -0
- package/dist/executor.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +383 -0
- package/dist/index.js.map +1 -0
- package/dist/policy.d.ts +6 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +24 -0
- package/dist/policy.js.map +1 -0
- package/dist/sanitizer.d.ts +28 -0
- package/dist/sanitizer.d.ts.map +1 -0
- package/dist/sanitizer.js +112 -0
- package/dist/sanitizer.js.map +1 -0
- package/package.json +49 -0
- package/proto/kernel.proto +101 -0
package/README.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Termyte — Terminal Governance for Coding Agents
|
|
2
|
+
|
|
3
|
+
Termyte is a lightweight, terminal-first governance runtime designed to protect your codebase from catastrophic agent actions (like `rm -rf /` or accidental database drops).
|
|
4
|
+
|
|
5
|
+
It provides a secure "Split-Plane" architecture where your coding agent (Claude Code, Cursor, etc.) proposes actions, and Termyte evaluates them against a deterministic sandbox and an LLM judge before execution.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Causal Guard**: Deterministic command analysis for high-risk operations.
|
|
10
|
+
- **Agent Ledger**: Every action, verdict, and outcome is recorded in a secure, immutable ledger.
|
|
11
|
+
- **Zero-Friction Auth**: Device-based identification (no API keys to manage).
|
|
12
|
+
- **Terminal First**: View governance events directly in your terminal with `npx termyte log`.
|
|
13
|
+
|
|
14
|
+
## Getting Started
|
|
15
|
+
|
|
16
|
+
### 1. Initialize Termyte
|
|
17
|
+
Run this to generate your unique device ID and setup local config:
|
|
18
|
+
```bash
|
|
19
|
+
npx termyte init
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. Configure your Agent
|
|
23
|
+
Add Termyte as an MCP server to your favorite tool.
|
|
24
|
+
|
|
25
|
+
#### Claude Code config:
|
|
26
|
+
Add the following to your `claude_desktop_config.json`:
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"termyte": {
|
|
31
|
+
"command": "npx",
|
|
32
|
+
"args": ["-y", "termyte"],
|
|
33
|
+
"env": {
|
|
34
|
+
"TERMYTE_API_URL": "https://mcp.causalos.xyz"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. Usage
|
|
42
|
+
Once configured, Termyte will automatically intercept sensitive tool calls. You can monitor the activity:
|
|
43
|
+
```bash
|
|
44
|
+
npx termyte log
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## How it Works
|
|
48
|
+
1. **Prepare**: The agent calls `causal_guard` with the proposed command.
|
|
49
|
+
2. **Judge**: Termyte evaluates the risk level and historical context.
|
|
50
|
+
3. **Commit**: After the agent executes the tool, it records the success/failure to the ledger.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-sandbox.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/command-sandbox.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { nativeExec, tokenize } from "../executor.js";
|
|
3
|
+
describe("Command Execution Sandbox", () => {
|
|
4
|
+
it("should tokenize commands correctly", () => {
|
|
5
|
+
expect(tokenize('ls -la "/path/with spaces"')).toEqual(['ls', '-la', '/path/with spaces']);
|
|
6
|
+
});
|
|
7
|
+
it("ALLOW-01: 'node -v' should execute successfully", async () => {
|
|
8
|
+
const result = await nativeExec("node -v");
|
|
9
|
+
expect(result.exit_code).toBe(0);
|
|
10
|
+
expect(result.stdout).toMatch(/v\d+\.\d+\.\d+/);
|
|
11
|
+
});
|
|
12
|
+
it("ALLOW-02: 'git --version' should pass validation", async () => {
|
|
13
|
+
const result = await nativeExec("git --version");
|
|
14
|
+
expect(result.exit_code).toBe(0);
|
|
15
|
+
expect(result.stdout).toContain("git version");
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=command-sandbox.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-sandbox.test.js","sourceRoot":"","sources":["../../src/__tests__/command-sandbox.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAEtD,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAC/F,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,eAAe,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/contract.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import { CloudKernelClient } from "../cloud-client.js";
|
|
4
|
+
let server;
|
|
5
|
+
let baseUrl = "";
|
|
6
|
+
const requests = [];
|
|
7
|
+
describe("Cloud contract", () => {
|
|
8
|
+
beforeAll(async () => {
|
|
9
|
+
server = http.createServer((req, res) => {
|
|
10
|
+
const chunks = [];
|
|
11
|
+
req.on("data", (d) => chunks.push(d));
|
|
12
|
+
req.on("end", () => {
|
|
13
|
+
const body = chunks.length ? JSON.parse(Buffer.concat(chunks).toString("utf-8")) : {};
|
|
14
|
+
requests.push({ url: req.url || "", body, method: req.method });
|
|
15
|
+
res.setHeader("content-type", "application/json");
|
|
16
|
+
if ((req.url || "").startsWith("/v1/governance/prepare")) {
|
|
17
|
+
res.end(JSON.stringify({ verdict: "ALLOW", reason: "ok", tool_call_id: "tc_1" }));
|
|
18
|
+
}
|
|
19
|
+
else if ((req.url || "").startsWith("/v1/governance/commit")) {
|
|
20
|
+
res.end(JSON.stringify({ status: "success" }));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
res.end(JSON.stringify({ ok: true }));
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
await new Promise((resolve) => {
|
|
28
|
+
server.listen(0, "127.0.0.1", () => resolve());
|
|
29
|
+
});
|
|
30
|
+
const addr = server.address();
|
|
31
|
+
if (addr && typeof addr === "object") {
|
|
32
|
+
baseUrl = `http://127.0.0.1:${addr.port}`;
|
|
33
|
+
}
|
|
34
|
+
// Mock environment variables
|
|
35
|
+
process.env.TERMYTE_API_URL = baseUrl;
|
|
36
|
+
process.env.TERMYTE_DEVICE_ID = "test-device-id";
|
|
37
|
+
});
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
requests.length = 0;
|
|
40
|
+
});
|
|
41
|
+
afterAll(async () => {
|
|
42
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
43
|
+
});
|
|
44
|
+
it("prepareToolCall calls /v1/governance/prepare with correct payload", async () => {
|
|
45
|
+
const client = new CloudKernelClient();
|
|
46
|
+
const payload = { command: "ls" };
|
|
47
|
+
await client.prepareToolCall("session-1", "execute", payload);
|
|
48
|
+
expect(requests[0]?.url).toBe("/v1/governance/prepare");
|
|
49
|
+
expect(requests[0]?.method).toBe("POST");
|
|
50
|
+
expect(requests[0]?.body).toMatchObject({
|
|
51
|
+
session_id: "session-1",
|
|
52
|
+
tool_name: "execute",
|
|
53
|
+
payload_json: payload,
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
it("commitToolCall calls /v1/governance/commit with correct payload", async () => {
|
|
57
|
+
const client = new CloudKernelClient();
|
|
58
|
+
const outcome = { stdout: "ok" };
|
|
59
|
+
await client.commitToolCall("tc_1", outcome, true, 0);
|
|
60
|
+
expect(requests[0]?.url).toBe("/v1/governance/commit");
|
|
61
|
+
expect(requests[0]?.method).toBe("POST");
|
|
62
|
+
expect(requests[0]?.body).toMatchObject({
|
|
63
|
+
tool_call_id: "tc_1",
|
|
64
|
+
outcome_json: outcome,
|
|
65
|
+
success: true,
|
|
66
|
+
exit_code: 0
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
//# sourceMappingURL=contract.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.test.js","sourceRoot":"","sources":["../../src/__tests__/contract.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/offline.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { KernelClient } from "../client.js";
|
|
3
|
+
describe("Offline Resilience", () => {
|
|
4
|
+
let client;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
client = new KernelClient();
|
|
7
|
+
// Mock cloudClient to throw error (simulating network down)
|
|
8
|
+
vi.spyOn(client.cloudClient, 'prepareToolCall').mockRejectedValue(new Error("Network Down"));
|
|
9
|
+
vi.spyOn(client.cloudClient, 'commitToolCall').mockRejectedValue(new Error("Network Down"));
|
|
10
|
+
});
|
|
11
|
+
it("should implement fail-closed in KernelClient for prepareToolCall", async () => {
|
|
12
|
+
// Based on the current client.ts implementation, it fails closed (BLOCK)
|
|
13
|
+
const verdict = await client.prepareToolCall("s1", "execute", { command: "ls" });
|
|
14
|
+
expect(verdict.verdict).toBe("BLOCK");
|
|
15
|
+
expect(verdict.reason).toContain("Governance runtime unreachable");
|
|
16
|
+
});
|
|
17
|
+
it("should handle failed commit gracefully", async () => {
|
|
18
|
+
const result = await client.commitToolCall("tc1", { stdout: "" }, true, 0);
|
|
19
|
+
expect(result.status).toBe("local_only");
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=offline.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offline.test.js","sourceRoot":"","sources":["../../src/__tests__/offline.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAChC,IAAI,MAAoB,CAAC;IAEzB,UAAU,CAAC,GAAG,EAAE;QACZ,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC5B,4DAA4D;QAC5D,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;QAC7F,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC,iBAAiB,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;IAChG,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kEAAkE,EAAE,KAAK,IAAI,EAAE;QAC9E,yEAAyE;QACzE,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QACjF,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gCAAgC,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3E,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface Verdict {
|
|
2
|
+
recommendation: 'PROCEED' | 'CAUTION' | 'ABORT';
|
|
3
|
+
reason: string;
|
|
4
|
+
confidence: number;
|
|
5
|
+
risk_score: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class HotCache {
|
|
8
|
+
private static allowCache;
|
|
9
|
+
private static blockCache;
|
|
10
|
+
/**
|
|
11
|
+
* Retrieves a cached verdict for a given action fingerprint.
|
|
12
|
+
*/
|
|
13
|
+
static get(fingerprint: string): Verdict | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Stores a verdict in the local hot cache.
|
|
16
|
+
*/
|
|
17
|
+
static set(fingerprint: string, verdict: Verdict): void;
|
|
18
|
+
/**
|
|
19
|
+
* Batch updates the cache from a cloud sync payload.
|
|
20
|
+
*/
|
|
21
|
+
static updateFromSync(data: Record<string, Verdict>): void;
|
|
22
|
+
private static getCachePath;
|
|
23
|
+
static saveToDisk(): void;
|
|
24
|
+
static loadFromDisk(): void;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,OAAO;IACpB,cAAc,EAAE,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,QAAQ;IACjB,OAAO,CAAC,MAAM,CAAC,UAAU,CAGtB;IACH,OAAO,CAAC,MAAM,CAAC,UAAU,CAGtB;IAEH;;OAEG;WACW,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAI3D;;OAEG;WACW,GAAG,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAQ9D;;OAEG;WACW,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAMjE,OAAO,CAAC,MAAM,CAAC,YAAY;WAQb,UAAU,IAAI,IAAI;WAoBlB,YAAY,IAAI,IAAI;CAcrC"}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { LRUCache } from 'lru-cache';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
export class HotCache {
|
|
6
|
+
static allowCache = new LRUCache({
|
|
7
|
+
max: 500,
|
|
8
|
+
ttl: 1000 * 60 * 60, // 1 hour
|
|
9
|
+
});
|
|
10
|
+
static blockCache = new LRUCache({
|
|
11
|
+
max: 1000,
|
|
12
|
+
ttl: 1000 * 60 * 60 * 24 * 7, // 7 days
|
|
13
|
+
});
|
|
14
|
+
/**
|
|
15
|
+
* Retrieves a cached verdict for a given action fingerprint.
|
|
16
|
+
*/
|
|
17
|
+
static get(fingerprint) {
|
|
18
|
+
return this.blockCache.get(fingerprint) || this.allowCache.get(fingerprint);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Stores a verdict in the local hot cache.
|
|
22
|
+
*/
|
|
23
|
+
static set(fingerprint, verdict) {
|
|
24
|
+
if (verdict.recommendation === 'ABORT') {
|
|
25
|
+
this.blockCache.set(fingerprint, verdict);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
this.allowCache.set(fingerprint, verdict);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Batch updates the cache from a cloud sync payload.
|
|
32
|
+
*/
|
|
33
|
+
static updateFromSync(data) {
|
|
34
|
+
for (const [fingerprint, verdict] of Object.entries(data)) {
|
|
35
|
+
this.set(fingerprint, verdict);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
static getCachePath() {
|
|
39
|
+
const dir = path.join(os.homedir(), '.termyte');
|
|
40
|
+
if (!fs.existsSync(dir)) {
|
|
41
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
42
|
+
}
|
|
43
|
+
return path.join(dir, 'governance_cache.json');
|
|
44
|
+
}
|
|
45
|
+
static saveToDisk() {
|
|
46
|
+
try {
|
|
47
|
+
const data = {};
|
|
48
|
+
// @ts-ignore - access internal cache entries for serialization
|
|
49
|
+
for (const [key, value] of this.allowCache.dump()) {
|
|
50
|
+
data[key] = value;
|
|
51
|
+
}
|
|
52
|
+
// @ts-ignore - access internal cache entries for serialization
|
|
53
|
+
for (const [key, value] of this.blockCache.dump()) {
|
|
54
|
+
data[key] = value;
|
|
55
|
+
}
|
|
56
|
+
const p = this.getCachePath();
|
|
57
|
+
const tempPath = `${p}.tmp`;
|
|
58
|
+
fs.writeFileSync(tempPath, JSON.stringify(data, null, 2));
|
|
59
|
+
fs.renameSync(tempPath, p);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
console.error('[HotCache] Failed to save to disk:', err);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
static loadFromDisk() {
|
|
66
|
+
try {
|
|
67
|
+
const cachePath = this.getCachePath();
|
|
68
|
+
if (fs.existsSync(cachePath)) {
|
|
69
|
+
const data = JSON.parse(fs.readFileSync(cachePath, 'utf8'));
|
|
70
|
+
for (const [key, val] of Object.entries(data)) {
|
|
71
|
+
this.set(key, val);
|
|
72
|
+
}
|
|
73
|
+
console.error(`[HotCache] Loaded ${Object.keys(data).length} patterns from disk.`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error('[HotCache] Failed to load from disk:', err);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CloudKernelClient } from './cloud-client.js';
|
|
2
|
+
export declare class KernelClient {
|
|
3
|
+
cloudClient: CloudKernelClient;
|
|
4
|
+
constructor();
|
|
5
|
+
prepareToolCall(session_id: string, tool_name: string, payload: any): Promise<any>;
|
|
6
|
+
commitToolCall(tool_call_id: string, outcome: any, success: boolean, exitCode?: number): Promise<any>;
|
|
7
|
+
}
|
|
8
|
+
export declare const kernel: KernelClient;
|
|
9
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,qBAAa,YAAY;IAChB,WAAW,EAAE,iBAAiB,CAAC;;IAMhC,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,GAAG,GACX,OAAO,CAAC,GAAG,CAAC;IAaT,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;CAS5G;AAED,eAAO,MAAM,MAAM,cAAqB,CAAC"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CloudKernelClient } from './cloud-client.js';
|
|
2
|
+
export class KernelClient {
|
|
3
|
+
cloudClient;
|
|
4
|
+
constructor() {
|
|
5
|
+
this.cloudClient = new CloudKernelClient();
|
|
6
|
+
}
|
|
7
|
+
async prepareToolCall(session_id, tool_name, payload) {
|
|
8
|
+
try {
|
|
9
|
+
return await this.cloudClient.prepareToolCall(session_id, tool_name, payload);
|
|
10
|
+
}
|
|
11
|
+
catch (err) {
|
|
12
|
+
console.error(`[KernelClient] Governance failure: ${err.message}. Failing closed.`);
|
|
13
|
+
return {
|
|
14
|
+
verdict: "BLOCK",
|
|
15
|
+
reason: "Governance runtime unreachable. Action blocked for safety.",
|
|
16
|
+
source: "failsafe"
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async commitToolCall(tool_call_id, outcome, success, exitCode) {
|
|
21
|
+
try {
|
|
22
|
+
return await this.cloudClient.commitToolCall(tool_call_id, outcome, success, exitCode);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
// Log locally if cloud is down, but don't crash
|
|
26
|
+
console.error(`[KernelClient] Failed to commit outcome: ${err}`);
|
|
27
|
+
return { status: "local_only" };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export const kernel = new KernelClient();
|
|
32
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEtD,MAAM,OAAO,YAAY;IAChB,WAAW,CAAoB;IAEtC;QACE,IAAI,CAAC,WAAW,GAAG,IAAI,iBAAiB,EAAE,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,eAAe,CACnB,UAAkB,EAClB,SAAiB,EACjB,OAAY;QAEZ,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,eAAe,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAChF,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,CAAC,KAAK,CAAC,sCAAsC,GAAG,CAAC,OAAO,mBAAmB,CAAC,CAAC;YACpF,OAAO;gBACH,OAAO,EAAE,OAAO;gBAChB,MAAM,EAAE,4DAA4D;gBACpE,MAAM,EAAE,UAAU;aACrB,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,YAAoB,EAAE,OAAY,EAAE,OAAgB,EAAE,QAAiB;QAC1F,IAAI,CAAC;YACD,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,cAAc,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAC3F,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACX,gDAAgD;YAChD,OAAO,CAAC,KAAK,CAAC,4CAA4C,GAAG,EAAE,CAAC,CAAC;YACjE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC;QACpC,CAAC;IACH,CAAC;CACF;AAED,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class CloudKernelClient {
|
|
2
|
+
private deviceId;
|
|
3
|
+
private baseURL;
|
|
4
|
+
constructor();
|
|
5
|
+
getDeviceId(): Promise<string>;
|
|
6
|
+
private request;
|
|
7
|
+
prepareToolCall(session_id: string, tool_name: string, payload: any): Promise<any>;
|
|
8
|
+
commitToolCall(tool_call_id: string, outcome: any, success: boolean, exitCode?: number): Promise<any>;
|
|
9
|
+
getMetrics(): Promise<any>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=cloud-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-client.d.ts","sourceRoot":"","sources":["../src/cloud-client.ts"],"names":[],"mappings":"AAKA,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,OAAO,CAAS;;IAMlB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC;YAoBtB,OAAO;IAwCf,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG;IAQnE,cAAc,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM;IAStF,UAAU;CAGnB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as os from 'os';
|
|
4
|
+
import * as https from 'https';
|
|
5
|
+
export class CloudKernelClient {
|
|
6
|
+
deviceId = null;
|
|
7
|
+
baseURL;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.baseURL = process.env.TERMYTE_API_URL || 'https://mcp.causalos.xyz';
|
|
10
|
+
}
|
|
11
|
+
async getDeviceId() {
|
|
12
|
+
if (this.deviceId)
|
|
13
|
+
return this.deviceId;
|
|
14
|
+
if (process.env.TERMYTE_DEVICE_ID) {
|
|
15
|
+
this.deviceId = process.env.TERMYTE_DEVICE_ID;
|
|
16
|
+
return this.deviceId;
|
|
17
|
+
}
|
|
18
|
+
const configPath = path.join(os.homedir(), '.termyte', 'config.json');
|
|
19
|
+
try {
|
|
20
|
+
const config = JSON.parse(await fs.readFile(configPath, 'utf-8'));
|
|
21
|
+
if (config.device_id) {
|
|
22
|
+
this.deviceId = config.device_id;
|
|
23
|
+
return this.deviceId;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (e) { }
|
|
27
|
+
throw new Error("TERMYTE_DEVICE_ID not found. Run 'npx termyte init' first.");
|
|
28
|
+
}
|
|
29
|
+
async request(method, endpoint, body) {
|
|
30
|
+
const url = new URL(endpoint, this.baseURL);
|
|
31
|
+
const deviceId = await this.getDeviceId();
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const options = {
|
|
34
|
+
method,
|
|
35
|
+
hostname: url.hostname,
|
|
36
|
+
path: url.pathname,
|
|
37
|
+
headers: {
|
|
38
|
+
'Content-Type': 'application/json',
|
|
39
|
+
'x-termyte-device-id': deviceId
|
|
40
|
+
},
|
|
41
|
+
timeout: 10000
|
|
42
|
+
};
|
|
43
|
+
const req = https.request(options, (res) => {
|
|
44
|
+
let data = '';
|
|
45
|
+
res.on('data', (chunk) => data += chunk);
|
|
46
|
+
res.on('end', () => {
|
|
47
|
+
try {
|
|
48
|
+
const parsed = JSON.parse(data);
|
|
49
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
50
|
+
reject(new Error(parsed.message || `Server error: ${res.statusCode}`));
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
resolve(parsed);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
if (res.statusCode === 204)
|
|
58
|
+
resolve({});
|
|
59
|
+
else
|
|
60
|
+
reject(new Error('Invalid JSON response'));
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
req.on('error', reject);
|
|
65
|
+
if (body)
|
|
66
|
+
req.write(JSON.stringify(body));
|
|
67
|
+
req.end();
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
async prepareToolCall(session_id, tool_name, payload) {
|
|
71
|
+
return this.request('POST', '/v1/governance/prepare', {
|
|
72
|
+
session_id,
|
|
73
|
+
tool_name,
|
|
74
|
+
payload_json: payload,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
async commitToolCall(tool_call_id, outcome, success, exitCode) {
|
|
78
|
+
return this.request('POST', '/v1/governance/commit', {
|
|
79
|
+
tool_call_id,
|
|
80
|
+
outcome_json: outcome,
|
|
81
|
+
success,
|
|
82
|
+
exit_code: exitCode
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async getMetrics() {
|
|
86
|
+
return this.request('GET', '/metrics');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=cloud-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-client.js","sourceRoot":"","sources":["../src/cloud-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ExecutionResult {
|
|
2
|
+
stdout: string;
|
|
3
|
+
stderr: string;
|
|
4
|
+
exit_code: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Tokenize a command string into a binary and its arguments.
|
|
8
|
+
* Handles single/double quotes and backslash escaping.
|
|
9
|
+
*/
|
|
10
|
+
export declare function tokenize(command: string): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Ensures batch commands on Windows are invoked with .cmd extension.
|
|
13
|
+
*/
|
|
14
|
+
export declare function resolveWindowsVerb(verb: string): string;
|
|
15
|
+
/**
|
|
16
|
+
* Execute a command natively after it has passed Termyte Governance.
|
|
17
|
+
* Uses execFile (not exec) to prevent shell injection at the OS level.
|
|
18
|
+
*/
|
|
19
|
+
export declare function nativeExec(rawCommand: string, timeoutMs?: number): Promise<ExecutionResult>;
|
|
20
|
+
//# sourceMappingURL=executor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAqClD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOvD;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,eAAe,CAAC,CAyBjG"}
|
package/dist/executor.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { execFile } from "child_process";
|
|
2
|
+
import { promisify } from "util";
|
|
3
|
+
const execFileAsync = promisify(execFile);
|
|
4
|
+
/**
|
|
5
|
+
* Tokenize a command string into a binary and its arguments.
|
|
6
|
+
* Handles single/double quotes and backslash escaping.
|
|
7
|
+
*/
|
|
8
|
+
export function tokenize(command) {
|
|
9
|
+
const tokens = [];
|
|
10
|
+
let current = "";
|
|
11
|
+
let inSingleQuote = false;
|
|
12
|
+
let inDoubleQuote = false;
|
|
13
|
+
let escaping = false;
|
|
14
|
+
for (let i = 0; i < command.length; i++) {
|
|
15
|
+
const ch = command[i];
|
|
16
|
+
if (escaping) {
|
|
17
|
+
current += ch;
|
|
18
|
+
escaping = false;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
if (ch === "\\") {
|
|
22
|
+
escaping = true;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (ch === "'" && !inSingleQuote && !inDoubleQuote) {
|
|
26
|
+
inSingleQuote = true;
|
|
27
|
+
}
|
|
28
|
+
else if (ch === "'" && inSingleQuote && !inDoubleQuote) {
|
|
29
|
+
inSingleQuote = false;
|
|
30
|
+
}
|
|
31
|
+
else if (ch === "\"" && !inSingleQuote && !inDoubleQuote) {
|
|
32
|
+
inDoubleQuote = true;
|
|
33
|
+
}
|
|
34
|
+
else if (ch === "\"" && inDoubleQuote && !inSingleQuote) {
|
|
35
|
+
inDoubleQuote = false;
|
|
36
|
+
}
|
|
37
|
+
else if (ch === " " && !inSingleQuote && !inDoubleQuote) {
|
|
38
|
+
if (current.length > 0) {
|
|
39
|
+
tokens.push(current);
|
|
40
|
+
current = "";
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
current += ch;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (current.length > 0)
|
|
48
|
+
tokens.push(current);
|
|
49
|
+
return tokens;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Ensures batch commands on Windows are invoked with .cmd extension.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveWindowsVerb(verb) {
|
|
55
|
+
if (process.platform !== "win32")
|
|
56
|
+
return verb;
|
|
57
|
+
const batchCommands = ["npm", "npx", "yarn", "pnpm", "tsc", "cargo"];
|
|
58
|
+
if (batchCommands.includes(verb.toLowerCase())) {
|
|
59
|
+
return `${verb}.cmd`;
|
|
60
|
+
}
|
|
61
|
+
return verb;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Execute a command natively after it has passed Termyte Governance.
|
|
65
|
+
* Uses execFile (not exec) to prevent shell injection at the OS level.
|
|
66
|
+
*/
|
|
67
|
+
export async function nativeExec(rawCommand, timeoutMs = 30_000) {
|
|
68
|
+
const tokens = tokenize(rawCommand.trim());
|
|
69
|
+
const rawVerbToken = tokens[0];
|
|
70
|
+
if (!rawVerbToken)
|
|
71
|
+
throw new Error("Empty command");
|
|
72
|
+
// Extract verb (strip path) and resolve Windows extension
|
|
73
|
+
const rawVerb = rawVerbToken.replace(/^.*[\\\/]/, "");
|
|
74
|
+
const verb = resolveWindowsVerb(rawVerb);
|
|
75
|
+
const args = tokens.slice(1);
|
|
76
|
+
try {
|
|
77
|
+
const { stdout, stderr } = await execFileAsync(verb, args, {
|
|
78
|
+
timeout: timeoutMs,
|
|
79
|
+
maxBuffer: 10 * 1024 * 1024, // 10 MB max output
|
|
80
|
+
windowsHide: true,
|
|
81
|
+
shell: false,
|
|
82
|
+
});
|
|
83
|
+
return { stdout, stderr, exit_code: 0 };
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
return {
|
|
87
|
+
stdout: err.stdout ?? "",
|
|
88
|
+
stderr: err.stderr ?? err.message,
|
|
89
|
+
exit_code: err.code ?? 1,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../src/executor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|