replicas-engine 0.1.702 → 0.1.703

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/package.json CHANGED
@@ -1,18 +1,20 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.702",
3
+ "version": "0.1.703",
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",
10
11
  "replicas-engine-watchdog": "./scripts/engine-watchdog.sh"
11
12
  },
12
13
  "files": [
13
14
  "dist",
14
15
  "workspace-sdk",
15
16
  "scripts/opencode",
17
+ "scripts/opencode-command-protection-plugin.ts",
16
18
  "scripts/deepseek",
17
19
  "scripts/engine-watchdog.sh",
18
20
  "scripts/lockmem.c"
@@ -16,3 +16,7 @@
16
16
  contextWindow: 262144
17
17
  - id: moonshotai/kimi-k2.6
18
18
  contextWindow: 262144
19
+
20
+ - insert:
21
+ - id: replicas-command-protection
22
+ name: __REPLICAS_DSH_COMMAND_PROTECTION_PLUGIN__
@@ -0,0 +1,69 @@
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
+ function evaluate(tool: string, args: unknown, callId: string, cwd: string): Promise<PolicyResult> {
18
+ return new Promise((resolve) => {
19
+ let settled = false;
20
+ let timeout: ReturnType<typeof setTimeout> | undefined;
21
+ const finish = (result: PolicyResult) => {
22
+ if (settled) return;
23
+ settled = true;
24
+ if (timeout) clearTimeout(timeout);
25
+ resolve(result);
26
+ };
27
+ const hookPath = process.env.REPLICAS_COMMAND_PROTECTION_HOOK_PATH;
28
+ const runtimePath = process.env.REPLICAS_COMMAND_PROTECTION_RUNTIME_PATH;
29
+ if (!hookPath || !runtimePath) {
30
+ finish({ allowed: false, reason: 'Replicas command protection runtime is missing.' });
31
+ return;
32
+ }
33
+ const hookArgs = hookPath.endsWith('.ts') && !runtimePath.endsWith('/bun')
34
+ ? ['--import', 'tsx', hookPath, 'opencode']
35
+ : [hookPath, 'opencode'];
36
+ const child = spawn(runtimePath, hookArgs, { cwd, stdio: ['pipe', 'pipe', 'pipe'] });
37
+ let stdout = '';
38
+ let stderr = '';
39
+ timeout = setTimeout(() => {
40
+ child.kill('SIGTERM');
41
+ finish({ allowed: false, reason: 'Command protection failed closed: hook timed out' });
42
+ }, 30_000);
43
+ child.stdout.on('data', (chunk: Buffer) => { stdout = (stdout + chunk).slice(-16_384); });
44
+ child.stderr.on('data', (chunk: Buffer) => { stderr = (stderr + chunk).slice(-16_384); });
45
+ child.on('error', (error) => finish({ allowed: false, reason: `Command protection failed closed: ${error.message}` }));
46
+ child.on('exit', (code) => {
47
+ if (code !== 0) {
48
+ finish({ allowed: false, reason: `Command protection failed closed: ${stderr || `hook exited with code ${code}`}` });
49
+ return;
50
+ }
51
+ try {
52
+ const result: unknown = JSON.parse(stdout);
53
+ finish(result && typeof result === 'object' && 'allowed' in result && typeof result.allowed === 'boolean'
54
+ ? { allowed: result.allowed, ...('reason' in result && typeof result.reason === 'string' ? { reason: result.reason } : {}) }
55
+ : { allowed: false, reason: 'Command protection failed closed: invalid hook response' });
56
+ } catch {
57
+ finish({ allowed: false, reason: 'Command protection failed closed: invalid hook response' });
58
+ }
59
+ });
60
+ child.stdin.end(JSON.stringify({ name: tool, arguments: args, call_id: callId, cwd }));
61
+ });
62
+ }
63
+
64
+ export const ReplicasCommandProtection = async ({ directory }: { directory: string }) => ({
65
+ 'tool.execute.before': async (input: ToolExecuteBeforeInput, output: ToolExecuteBeforeOutput) => {
66
+ const result = await evaluate(input.tool, output.args, input.callID, directory);
67
+ if (!result.allowed) throw new Error(result.reason ?? 'Blocked by Replicas command protection.');
68
+ },
69
+ });