replicas-engine 0.1.702 → 0.1.704
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/dist/src/chunk-2RB7SIP3.js +10 -0
- package/dist/src/chunk-EC4MFY4M.js +551 -0
- package/dist/src/chunk-GDCMH7YA.js +23 -0
- package/dist/src/{chunk-UNES5UCP.js → chunk-WUJ4IALO.js} +42 -544
- package/dist/src/chunk-ZCBMGGAC.js +284 -0
- package/dist/src/command-protection-hook.js +50 -0
- package/dist/src/deepseek-command-protection-plugin.js +32 -0
- package/dist/src/headless-agent.js +6 -4
- package/dist/src/index.js +521 -818
- package/dist/src/post-tool-pr-hook.js +26 -0
- package/package.json +4 -1
- package/scripts/deepseek/replicas.cordis.patch.yml +4 -0
- package/scripts/opencode-command-protection-plugin.ts +88 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
notifyPostToolUse
|
|
4
|
+
} from "./chunk-GDCMH7YA.js";
|
|
5
|
+
import {
|
|
6
|
+
isRecord
|
|
7
|
+
} from "./chunk-2RB7SIP3.js";
|
|
8
|
+
import "./chunk-WUJ4IALO.js";
|
|
9
|
+
|
|
10
|
+
// src/post-tool-pr-hook.ts
|
|
11
|
+
async function main() {
|
|
12
|
+
let stdin = "";
|
|
13
|
+
for await (const chunk of process.stdin) stdin += chunk;
|
|
14
|
+
try {
|
|
15
|
+
const input = JSON.parse(stdin);
|
|
16
|
+
const record = isRecord(input) ? input : {};
|
|
17
|
+
const toolName = [record.tool_name, record.tool, record.name].find((value) => typeof value === "string") ?? "";
|
|
18
|
+
const toolInput = record.tool_input ?? record.arguments ?? record.args ?? ("command" in record ? { command: record.command } : record);
|
|
19
|
+
await notifyPostToolUse(toolName, toolInput);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
22
|
+
`);
|
|
23
|
+
}
|
|
24
|
+
process.stdout.write("{}\n");
|
|
25
|
+
}
|
|
26
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "replicas-engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.704",
|
|
4
4
|
"description": "Lightweight API server for Replicas workspaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"replicas-engine": "./dist/src/index.js",
|
|
9
9
|
"replicas-headless-agent": "./dist/src/headless-agent.js",
|
|
10
|
+
"replicas-command-protection-hook": "./dist/src/command-protection-hook.js",
|
|
11
|
+
"replicas-post-tool-pr-hook": "./dist/src/post-tool-pr-hook.js",
|
|
10
12
|
"replicas-engine-watchdog": "./scripts/engine-watchdog.sh"
|
|
11
13
|
},
|
|
12
14
|
"files": [
|
|
13
15
|
"dist",
|
|
14
16
|
"workspace-sdk",
|
|
15
17
|
"scripts/opencode",
|
|
18
|
+
"scripts/opencode-command-protection-plugin.ts",
|
|
16
19
|
"scripts/deepseek",
|
|
17
20
|
"scripts/engine-watchdog.sh",
|
|
18
21
|
"scripts/lockmem.c"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
|
|
3
|
+
interface PolicyResult {
|
|
4
|
+
allowed: boolean;
|
|
5
|
+
reason?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ToolExecuteBeforeInput {
|
|
9
|
+
tool: string;
|
|
10
|
+
callID: string;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ToolExecuteBeforeOutput {
|
|
14
|
+
args: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const toolInputs = new Map<string, unknown>();
|
|
18
|
+
|
|
19
|
+
function evaluate(tool: string, args: unknown, callId: string, cwd: string): Promise<PolicyResult> {
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
let settled = false;
|
|
22
|
+
let timeout: ReturnType<typeof setTimeout> | undefined;
|
|
23
|
+
const finish = (result: PolicyResult) => {
|
|
24
|
+
if (settled) return;
|
|
25
|
+
settled = true;
|
|
26
|
+
if (timeout) clearTimeout(timeout);
|
|
27
|
+
resolve(result);
|
|
28
|
+
};
|
|
29
|
+
const hookPath = process.env.REPLICAS_COMMAND_PROTECTION_HOOK_PATH;
|
|
30
|
+
const runtimePath = process.env.REPLICAS_COMMAND_PROTECTION_RUNTIME_PATH;
|
|
31
|
+
if (!hookPath || !runtimePath) {
|
|
32
|
+
finish({ allowed: false, reason: 'Replicas command protection runtime is missing.' });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const hookArgs = hookPath.endsWith('.ts') && !runtimePath.endsWith('/bun')
|
|
36
|
+
? ['--import', 'tsx', hookPath, 'opencode']
|
|
37
|
+
: [hookPath, 'opencode'];
|
|
38
|
+
const child = spawn(runtimePath, hookArgs, { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
39
|
+
let stdout = '';
|
|
40
|
+
let stderr = '';
|
|
41
|
+
timeout = setTimeout(() => {
|
|
42
|
+
child.kill('SIGTERM');
|
|
43
|
+
finish({ allowed: false, reason: 'Command protection failed closed: hook timed out' });
|
|
44
|
+
}, 30_000);
|
|
45
|
+
child.stdout.on('data', (chunk: Buffer) => { stdout = (stdout + chunk).slice(-16_384); });
|
|
46
|
+
child.stderr.on('data', (chunk: Buffer) => { stderr = (stderr + chunk).slice(-16_384); });
|
|
47
|
+
child.on('error', (error) => finish({ allowed: false, reason: `Command protection failed closed: ${error.message}` }));
|
|
48
|
+
child.on('exit', (code) => {
|
|
49
|
+
if (code !== 0) {
|
|
50
|
+
finish({ allowed: false, reason: `Command protection failed closed: ${stderr || `hook exited with code ${code}`}` });
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const result: unknown = JSON.parse(stdout);
|
|
55
|
+
finish(result && typeof result === 'object' && 'allowed' in result && typeof result.allowed === 'boolean'
|
|
56
|
+
? { allowed: result.allowed, ...('reason' in result && typeof result.reason === 'string' ? { reason: result.reason } : {}) }
|
|
57
|
+
: { allowed: false, reason: 'Command protection failed closed: invalid hook response' });
|
|
58
|
+
} catch {
|
|
59
|
+
finish({ allowed: false, reason: 'Command protection failed closed: invalid hook response' });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
child.stdin.end(JSON.stringify({ name: tool, arguments: args, call_id: callId, cwd }));
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const ReplicasCommandProtection = async ({ directory }: { directory: string }) => ({
|
|
67
|
+
'tool.execute.before': async (input: ToolExecuteBeforeInput, output: ToolExecuteBeforeOutput) => {
|
|
68
|
+
const result = await evaluate(input.tool, output.args, input.callID, directory);
|
|
69
|
+
if (!result.allowed) throw new Error(result.reason ?? 'Blocked by Replicas command protection.');
|
|
70
|
+
toolInputs.set(input.callID, output.args);
|
|
71
|
+
},
|
|
72
|
+
'tool.execute.after': async (input: ToolExecuteBeforeInput) => {
|
|
73
|
+
const args = toolInputs.get(input.callID);
|
|
74
|
+
toolInputs.delete(input.callID);
|
|
75
|
+
const hookPath = process.env.REPLICAS_POST_TOOL_PR_HOOK_PATH;
|
|
76
|
+
const runtimePath = process.env.REPLICAS_COMMAND_PROTECTION_RUNTIME_PATH;
|
|
77
|
+
if (!hookPath || !runtimePath) return;
|
|
78
|
+
const hookArgs = hookPath.endsWith('.ts') && !runtimePath.endsWith('/bun')
|
|
79
|
+
? ['--import', 'tsx', hookPath]
|
|
80
|
+
: [hookPath];
|
|
81
|
+
await new Promise<void>((resolve) => {
|
|
82
|
+
const child = spawn(runtimePath, hookArgs, { cwd: directory, stdio: ['pipe', 'ignore', 'ignore'] });
|
|
83
|
+
child.on('error', () => resolve());
|
|
84
|
+
child.on('exit', () => resolve());
|
|
85
|
+
child.stdin.end(JSON.stringify({ tool: input.tool, args }));
|
|
86
|
+
});
|
|
87
|
+
},
|
|
88
|
+
});
|