@kafca/agentdock 0.1.61 → 0.1.62

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 (127) hide show
  1. package/README.md +18 -0
  2. package/dist/renderer/assets/AutomationList-BgJgAdVO.js +16 -0
  3. package/dist/renderer/assets/{Badge-BLI4LHse.js → Badge-Bq2hPVcR.js} +1 -1
  4. package/dist/renderer/assets/{Card-DJeLDdL3.js → Card-BPJNSZce.js} +1 -1
  5. package/dist/renderer/assets/{Config-D1awc81A.js → Config-aSFqlI88.js} +2 -2
  6. package/dist/renderer/assets/Dashboard-D3ezFmb7.js +36 -0
  7. package/dist/renderer/assets/{EmptyState-CkI1RwPX.js → EmptyState-DK496gBq.js} +1 -1
  8. package/dist/renderer/assets/{HighlightedMarkdown-BUhDlhgW.js → HighlightedMarkdown-Ckre5jNv.js} +1 -1
  9. package/dist/renderer/assets/{Input-DHYrn-Ne.js → Input-C5C1d0ba.js} +1 -1
  10. package/dist/renderer/assets/{KnowledgeDetail-Bij-Xo90.js → KnowledgeDetail-N8Ey1ikc.js} +2 -2
  11. package/dist/renderer/assets/{KnowledgeHome-DmPZ2IlI.js → KnowledgeHome-9aF8nJEf.js} +2 -2
  12. package/dist/renderer/assets/{Logs-ISY99heA.js → Logs-sgAdwEeS.js} +2 -2
  13. package/dist/renderer/assets/{Modal-DAQfz0ot.js → Modal-BB10hTRc.js} +3 -3
  14. package/dist/renderer/assets/{Page-Dw43UYDT.js → Page-DfC319Ck.js} +1 -1
  15. package/dist/renderer/assets/{Select-DzmN5OGQ.js → Select-RHJBmNER.js} +1 -1
  16. package/dist/renderer/assets/{ThreadChat-B5CWqqMK.js → ThreadChat-BU1zCdr4.js} +3 -3
  17. package/dist/renderer/assets/{Workspace-C5g9LBj9.js → Workspace-BoZCz7S8.js} +1 -1
  18. package/dist/renderer/assets/{arrow-left-BLXh56Ip.js → arrow-left-D2V1eZSD.js} +1 -1
  19. package/dist/renderer/assets/{book-open-DhPGbc-7.js → book-open-DUcBn7Bb.js} +1 -1
  20. package/dist/renderer/assets/{channels-DfQrmuYO.js → channels-DMhDSlf2.js} +2 -2
  21. package/dist/renderer/assets/{chevron-down-CEFtpPDc.js → chevron-down-Ca2FQDB7.js} +1 -1
  22. package/dist/renderer/assets/en-Bnr4nMzg.js +1 -0
  23. package/dist/renderer/assets/es-B1GIFh3i.js +1 -0
  24. package/dist/renderer/assets/{index-BIKL3fTP.css → index-B6WcpkJF.css} +1 -1
  25. package/dist/renderer/assets/{index-CYhDUAR_.js → index-BlnvlekJ.js} +1 -1
  26. package/dist/renderer/assets/index-DRJ5wgw_.js +162 -0
  27. package/dist/renderer/assets/ja-CDWPWqEW.js +1 -0
  28. package/dist/renderer/assets/{knowledge-uHRQ80sR.js → knowledge-D1-k56eY.js} +1 -1
  29. package/dist/renderer/assets/{pencil-BD2Y31YC.js → pencil-BhWdv_86.js} +1 -1
  30. package/dist/renderer/assets/{plus-DDcldp_c.js → plus-BacLMlK3.js} +1 -1
  31. package/dist/renderer/assets/{save-CMW_cZI9.js → save-Bpoxbzau.js} +1 -1
  32. package/dist/renderer/assets/{search-BM-0CvJr.js → search-BVJcpdFX.js} +1 -1
  33. package/dist/renderer/assets/{shield-check-DaMB0FKG.js → shield-check-C2cw_Ip6.js} +1 -1
  34. package/dist/renderer/assets/{threads-DZgt9tWj.js → threads-DOsBQBg_.js} +1 -1
  35. package/dist/renderer/assets/{trash-2-DTXVbC5y.js → trash-2-Bs3rEm3g.js} +1 -1
  36. package/dist/renderer/assets/zh-MSddxMDX.js +1 -0
  37. package/dist/renderer/assets/zh-TW-C_LNWX0o.js +1 -0
  38. package/dist/renderer/index.html +2 -2
  39. package/dist-electron/electron/managed-skills/agent-browser/SKILL.md +41 -0
  40. package/dist-electron/electron/managed-skills/agent-browser/references/authentication.md +83 -0
  41. package/dist-electron/electron/managed-skills/agent-browser/references/commands.md +50 -0
  42. package/dist-electron/electron/managed-skills/agent-browser/references/profiling.md +20 -0
  43. package/dist-electron/electron/managed-skills/agent-browser/references/proxy-support.md +18 -0
  44. package/dist-electron/electron/managed-skills/agent-browser/references/session-management.md +17 -0
  45. package/dist-electron/electron/managed-skills/agent-browser/references/snapshot-refs.md +17 -0
  46. package/dist-electron/electron/managed-skills/agent-browser/references/video-recording.md +21 -0
  47. package/dist-electron/electron/managed-skills/agent-browser/templates/authenticated-session.sh +11 -0
  48. package/dist-electron/electron/managed-skills/agent-browser/templates/capture-workflow.sh +12 -0
  49. package/dist-electron/electron/managed-skills/agent-browser/templates/form-automation.sh +10 -0
  50. package/dist-electron/electron/managed-skills/condition-trigger/SKILL.md +21 -0
  51. package/dist-electron/electron/managed-skills/condition-trigger/scripts/register-condition-trigger.sh +106 -0
  52. package/dist-electron/electron/managed-skills/knowledge-base/SKILL.md +13 -0
  53. package/dist-electron/electron/managed-skills/knowledge-base/scripts/search-knowledge.sh +80 -0
  54. package/dist-electron/packages/contracts/src/automations.js +211 -0
  55. package/dist-electron/packages/contracts/src/index.js +1 -0
  56. package/dist-electron/packages/core-sdk/src/automations.js +87 -0
  57. package/dist-electron/packages/core-sdk/src/client.js +101 -0
  58. package/dist-electron/packages/core-sdk/src/index.js +2 -1
  59. package/dist-electron/services/local-ai-core/src/acp/store/automation-script-store.js +415 -0
  60. package/dist-electron/services/local-ai-core/src/acp/store/automation-store.js +829 -0
  61. package/dist-electron/services/local-ai-core/src/acp/store/local-core-acp-store.js +158 -0
  62. package/dist-electron/services/local-ai-core/src/acp/store/schema.js +81 -0
  63. package/dist-electron/services/local-ai-core/src/automation/automation-action-executor.js +144 -0
  64. package/dist-electron/services/local-ai-core/src/automation/automation-condition-engine.js +79 -0
  65. package/dist-electron/services/local-ai-core/src/automation/automation-conversation-executor.js +39 -73
  66. package/dist-electron/services/local-ai-core/src/automation/automation-monitor-service.js +695 -260
  67. package/dist-electron/services/local-ai-core/src/automation/automation-script-service.js +507 -0
  68. package/dist-electron/services/local-ai-core/src/automation/automation-service.js +1019 -0
  69. package/dist-electron/services/local-ai-core/src/automation/automation-trigger-engine.js +141 -0
  70. package/dist-electron/services/local-ai-core/src/automation/condition-evaluator.js +60 -17
  71. package/dist-electron/services/local-ai-core/src/automation/legacy-automation-mappers.js +286 -0
  72. package/dist-electron/services/local-ai-core/src/automation/scripts/anthropic-sandbox-runner.js +792 -0
  73. package/dist-electron/services/local-ai-core/src/automation/scripts/sandbox-runner.js +2 -0
  74. package/dist-electron/services/local-ai-core/src/automation/scripts/script-package.js +475 -0
  75. package/dist-electron/services/local-ai-core/src/automation/scripts/script-protocol-runner.js +266 -0
  76. package/dist-electron/services/local-ai-core/src/automation/scripts/secret-resolver.js +37 -0
  77. package/dist-electron/services/local-ai-core/src/channel/weixin/inbound-poller.js +1 -2
  78. package/dist-electron/services/local-ai-core/src/channel/weixin/transport.js +9 -8
  79. package/dist-electron/services/local-ai-core/src/cli/lac.js +229 -0
  80. package/dist-electron/services/local-ai-core/src/kernel/bootstrap.js +21 -0
  81. package/dist-electron/services/local-ai-core/src/runtime/deployment-diagnostics.js +76 -0
  82. package/dist-electron/services/local-ai-core/src/runtime/handlers/automations-handler.js +322 -0
  83. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +20 -0
  84. package/dist-electron/services/local-ai-core/src/runtime/managed-skill-catalog.js +37 -0
  85. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +14 -4
  86. package/dist-electron/services/local-ai-core/src/runtime/server-routes.js +75 -0
  87. package/dist-electron/services/local-ai-core/src/runtime/server.js +21 -0
  88. package/dist-electron/services/local-ai-core/src/runtime/standalone.js +1 -0
  89. package/dist-electron/services/local-ai-core/src/scheduler/cron.js +151 -39
  90. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-conversation-executor.js +2 -4
  91. package/dist-electron/services/local-ai-core/src/scheduler/scheduled-job-application-service.js +64 -12
  92. package/dist-electron/services/local-ai-core/src/scheduler/scheduler-service.js +71 -4
  93. package/dist-electron/services/local-ai-core/src/scheduler/thread-resolution.js +10 -0
  94. package/dist-electron/services/local-ai-core/src/thread/agent-message-policy.js +16 -1
  95. package/dist-electron/src/pages/Automation/automation-page-model.js +76 -0
  96. package/dist-electron/tests/contracts/agent-message-policy.test.js +32 -0
  97. package/dist-electron/tests/contracts/architecture-docs.test.js +30 -0
  98. package/dist-electron/tests/contracts/automation-contracts.test.js +154 -0
  99. package/dist-electron/tests/contracts/automation-renderer-model.test.js +47 -0
  100. package/dist-electron/tests/electron/automation-action-executor.test.js +75 -0
  101. package/dist-electron/tests/electron/automation-compatibility.test.js +463 -0
  102. package/dist-electron/tests/electron/automation-deployment.test.js +66 -0
  103. package/dist-electron/tests/electron/automation-engine.test.js +264 -0
  104. package/dist-electron/tests/electron/automation-monitor.test.js +1333 -0
  105. package/dist-electron/tests/electron/automation-sandbox-runner.test.js +333 -0
  106. package/dist-electron/tests/electron/automation-script-approval.test.js +553 -0
  107. package/dist-electron/tests/electron/automation-script-package.test.js +499 -0
  108. package/dist-electron/tests/electron/automation-script-runner.test.js +120 -0
  109. package/dist-electron/tests/electron/automation-service.test.js +1078 -0
  110. package/dist-electron/tests/electron/automation-store.test.js +593 -0
  111. package/dist-electron/tests/electron/condition-trigger-skill.test.js +93 -0
  112. package/dist-electron/tests/electron/core-client.test.js +99 -0
  113. package/dist-electron/tests/electron/lac-cli.test.js +110 -0
  114. package/dist-electron/tests/electron/workspace-task-store.test.js +25 -0
  115. package/dist-electron/tests/integration/automation-routes.test.js +186 -0
  116. package/dist-electron/tests/integration/automation-sandbox-runtime.test.js +92 -0
  117. package/package.json +4 -3
  118. package/dist/renderer/assets/CronList-CupZoNwW.js +0 -1
  119. package/dist/renderer/assets/Dashboard-nLZnOtcs.js +0 -41
  120. package/dist/renderer/assets/MonitorList-BlX82rXF.js +0 -1
  121. package/dist/renderer/assets/en-CmAr_0e6.js +0 -1
  122. package/dist/renderer/assets/es-Cs9x52ca.js +0 -1
  123. package/dist/renderer/assets/index-Dd00oqgY.js +0 -167
  124. package/dist/renderer/assets/ja-DtvtBRTW.js +0 -1
  125. package/dist/renderer/assets/play-DBJ8wsSy.js +0 -6
  126. package/dist/renderer/assets/zh-CcJ9vBZj.js +0 -1
  127. package/dist/renderer/assets/zh-TW-elI72AC1.js +0 -1
@@ -0,0 +1,333 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_test_1 = __importDefault(require("node:test"));
7
+ const strict_1 = __importDefault(require("node:assert/strict"));
8
+ const node_fs_1 = require("node:fs");
9
+ const node_os_1 = require("node:os");
10
+ const node_path_1 = require("node:path");
11
+ const anthropic_sandbox_runner_js_1 = require("../../services/local-ai-core/src/automation/scripts/anthropic-sandbox-runner.js");
12
+ class FakeManager {
13
+ config;
14
+ initialized = 0;
15
+ wrapped = [];
16
+ wrappedArgv = [];
17
+ dependencyErrors = [];
18
+ dependencyWarnings = [];
19
+ supported = true;
20
+ initializeError;
21
+ resetCalls = 0;
22
+ wrappedCommandOverride;
23
+ async initialize(config) {
24
+ this.initialized += 1;
25
+ this.config = config;
26
+ if (this.initializeError)
27
+ throw this.initializeError;
28
+ }
29
+ async wrapWithSandbox(command) {
30
+ this.wrapped.push(command);
31
+ return command;
32
+ }
33
+ async wrapWithSandboxArgv(command) {
34
+ this.wrappedArgv.push(command);
35
+ return { argv: ['/bin/sh', '-c', this.wrappedCommandOverride || command], env: { ...process.env } };
36
+ }
37
+ isSupportedPlatform() { return this.supported; }
38
+ isSandboxingEnabled() { return this.initialized > 0; }
39
+ checkDependencies() { return { errors: this.dependencyErrors, warnings: this.dependencyWarnings }; }
40
+ async reset() { this.resetCalls += 1; }
41
+ cleanupAfterCommand() { }
42
+ }
43
+ function input(root, overrides = {}) {
44
+ return {
45
+ command: 'printf sandbox-ok',
46
+ cwd: root,
47
+ packagePath: (0, node_path_1.join)(root, 'package'),
48
+ tempDir: (0, node_path_1.join)(root, 'tmp'),
49
+ tempRoot: root,
50
+ network: 'none',
51
+ ...overrides,
52
+ };
53
+ }
54
+ (0, node_test_1.default)('builds read-only package and temp-only write policy', () => {
55
+ const root = '/workspace/automation';
56
+ const config = (0, anthropic_sandbox_runner_js_1.buildSandboxRuntimeConfig)(input(root, {
57
+ allowedReadDirs: ['/workspace/automation/fixtures'],
58
+ denyRead: ['/workspace/automation/secret.txt'],
59
+ }));
60
+ strict_1.default.deepEqual(config.filesystem.allowWrite, ['/workspace/automation/tmp']);
61
+ strict_1.default.ok(config.filesystem.denyWrite.includes('/workspace/automation/package'));
62
+ strict_1.default.ok(config.filesystem.allowRead?.includes('/workspace/automation/package'));
63
+ strict_1.default.ok(config.filesystem.allowRead?.includes('/workspace/automation/fixtures'));
64
+ strict_1.default.ok(config.filesystem.denyRead.includes('/workspace/automation/secret.txt'));
65
+ strict_1.default.ok(config.filesystem.denyWrite.includes('/tmp/claude'));
66
+ strict_1.default.ok(config.filesystem.denyWrite.some((path) => path.endsWith('/.npm/_logs')));
67
+ });
68
+ (0, node_test_1.default)('rejects temp paths outside a controlled temporary root and explicit package denies win', () => {
69
+ const root = '/workspace/automation';
70
+ strict_1.default.throws(() => (0, anthropic_sandbox_runner_js_1.buildSandboxRuntimeConfig)(input(root, {
71
+ tempRoot: root,
72
+ tempDir: '/tmp',
73
+ })), /tempDir must be inside/);
74
+ const config = (0, anthropic_sandbox_runner_js_1.buildSandboxRuntimeConfig)(input(root, {
75
+ denyRead: [(0, node_path_1.join)(root, 'package', 'secret.txt')],
76
+ }));
77
+ strict_1.default.ok(!config.filesystem.allowRead?.some((path) => path === (0, node_path_1.join)(root, 'package')));
78
+ });
79
+ (0, node_test_1.default)('generates callback-gated public egress with explicit private/local denies', () => {
80
+ const config = (0, anthropic_sandbox_runner_js_1.buildSandboxRuntimeConfig)(input('/workspace/automation', {
81
+ network: 'public',
82
+ }));
83
+ strict_1.default.deepEqual(config.network.allowedDomains, []);
84
+ strict_1.default.equal(config.network.strictAllowlist, false);
85
+ for (const host of ['localhost', '127.0.0.1', '::1', '169.254.169.254']) {
86
+ strict_1.default.ok(config.network.deniedDomains.includes(host));
87
+ }
88
+ strict_1.default.ok(anthropic_sandbox_runner_js_1.PRIVATE_NETWORK_DENY_HOSTS.every((host) => config.network.deniedDomains.includes(host)));
89
+ });
90
+ (0, node_test_1.default)('generates restricted egress only from manifest domains', () => {
91
+ const config = (0, anthropic_sandbox_runner_js_1.buildSandboxRuntimeConfig)(input('/workspace/automation', {
92
+ network: 'restricted',
93
+ allowedDomains: ['api.example.com', '*.vendor.example'],
94
+ }));
95
+ strict_1.default.deepEqual(config.network.allowedDomains, []);
96
+ strict_1.default.equal(config.network.strictAllowlist, false);
97
+ strict_1.default.ok(config.network.deniedDomains.includes('localhost'));
98
+ });
99
+ (0, node_test_1.default)('private-address policy rejects numeric ranges and mapped IPv6 forms', async () => {
100
+ strict_1.default.equal(await (0, anthropic_sandbox_runner_js_1.isPrivateNetworkAddress)('10.0.0.2'), true);
101
+ strict_1.default.equal(await (0, anthropic_sandbox_runner_js_1.isPrivateNetworkAddress)('192.168.1.2'), true);
102
+ strict_1.default.equal(await (0, anthropic_sandbox_runner_js_1.isPrivateNetworkAddress)('::ffff:10.1.2.3'), true);
103
+ strict_1.default.equal(await (0, anthropic_sandbox_runner_js_1.isPrivateNetworkAddress)('::ffff:a01:203'), true);
104
+ strict_1.default.equal(await (0, anthropic_sandbox_runner_js_1.isPrivateNetworkAddress)('127.0.0.3'), true);
105
+ });
106
+ (0, node_test_1.default)('probe fails unverified Linux isolation capabilities when dependencies block behavioral proof', async () => {
107
+ const manager = new FakeManager();
108
+ manager.dependencyErrors = [
109
+ 'ripgrep (rg) not found',
110
+ 'bubblewrap (bwrap) not installed',
111
+ 'socat not installed',
112
+ ];
113
+ manager.dependencyWarnings = ['seccomp not available - unix socket access not restricted'];
114
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({
115
+ platform: 'linux',
116
+ manager,
117
+ appArmorUsernsRestricted: true,
118
+ });
119
+ const result = await runner.probe();
120
+ strict_1.default.equal(result.available, false);
121
+ strict_1.default.equal(result.platform, 'linux');
122
+ strict_1.default.deepEqual(result.missing, ['bwrap', 'socat', 'rg', 'seccomp', 'network.namespace', 'apparmor.userns']);
123
+ strict_1.default.deepEqual(result.unverified, ['seccomp', 'network.namespace', 'apparmor.userns']);
124
+ strict_1.default.equal(manager.initialized, 0);
125
+ });
126
+ (0, node_test_1.default)('a successful wrapped Linux probe overrides the restrictive AppArmor sysctl context', async () => {
127
+ const manager = new FakeManager();
128
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({
129
+ platform: 'linux',
130
+ manager,
131
+ appArmorUsernsRestricted: true,
132
+ });
133
+ const result = await runner.probe();
134
+ strict_1.default.equal(result.available, true);
135
+ strict_1.default.deepEqual(result.missing, []);
136
+ strict_1.default.deepEqual(manager.wrappedArgv, ['true']);
137
+ });
138
+ (0, node_test_1.default)('disabling behavioral initialization cannot produce green Linux isolation capabilities', async () => {
139
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({
140
+ platform: 'linux',
141
+ manager: new FakeManager(),
142
+ probeInitialization: false,
143
+ });
144
+ const result = await runner.probe();
145
+ strict_1.default.equal(result.available, false);
146
+ strict_1.default.deepEqual(result.missing, ['seccomp', 'network.namespace', 'sandbox_runtime', 'apparmor.userns']);
147
+ strict_1.default.deepEqual(result.unverified, ['seccomp', 'network.namespace', 'apparmor.userns']);
148
+ });
149
+ (0, node_test_1.default)('wrapped Linux probe classifies actual AppArmor, network namespace, and seccomp failures independently', async () => {
150
+ const cases = [
151
+ {
152
+ stderr: 'bwrap: Creating new namespace failed: Operation not permitted',
153
+ restricted: true,
154
+ expected: ['seccomp', 'network.namespace', 'apparmor.userns'],
155
+ unverified: ['seccomp', 'network.namespace'],
156
+ },
157
+ {
158
+ stderr: 'bwrap: unshare-net: network namespace operation not permitted',
159
+ restricted: false,
160
+ expected: ['seccomp', 'network.namespace'],
161
+ unverified: ['seccomp'],
162
+ },
163
+ {
164
+ stderr: 'apply-seccomp: seccomp filter installation failed',
165
+ restricted: false,
166
+ expected: ['seccomp'],
167
+ unverified: [],
168
+ },
169
+ ];
170
+ for (const item of cases) {
171
+ const manager = new FakeManager();
172
+ manager.wrappedCommandOverride = `printf '%s' '${item.stderr}' >&2; exit 1`;
173
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({
174
+ platform: 'linux',
175
+ manager,
176
+ appArmorUsernsRestricted: item.restricted,
177
+ });
178
+ const result = await runner.probe();
179
+ strict_1.default.equal(result.available, false);
180
+ strict_1.default.deepEqual(result.missing, item.expected);
181
+ strict_1.default.deepEqual(result.unverified || [], item.unverified);
182
+ strict_1.default.equal(manager.resetCalls, 1);
183
+ }
184
+ });
185
+ (0, node_test_1.default)('probe reports macOS sandbox-exec and ripgrep capabilities', async () => {
186
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({
187
+ platform: 'macos',
188
+ manager: new FakeManager(),
189
+ commandExists: (command) => command === 'sandbox-exec' || command === 'rg',
190
+ });
191
+ const result = await runner.probe();
192
+ strict_1.default.equal(result.available, true);
193
+ strict_1.default.deepEqual(result.missing, []);
194
+ });
195
+ (0, node_test_1.default)('probe reports missing macOS ripgrep independently', async () => {
196
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({
197
+ platform: 'macos',
198
+ manager: new FakeManager(),
199
+ commandExists: (command) => command === 'sandbox-exec',
200
+ });
201
+ const result = await runner.probe();
202
+ strict_1.default.equal(result.available, false);
203
+ strict_1.default.deepEqual(result.missing, ['rg']);
204
+ });
205
+ (0, node_test_1.default)('Windows probes and runs fail closed with sandbox_unavailable', async () => {
206
+ const manager = new FakeManager();
207
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: 'win32', manager });
208
+ const probe = await runner.probe();
209
+ strict_1.default.equal(probe.available, false);
210
+ strict_1.default.deepEqual(probe.missing, ['sandbox_unavailable']);
211
+ await strict_1.default.rejects(runner.run(input('/workspace/automation')), (error) => error instanceof Error && error.message.includes('sandbox_unavailable'));
212
+ strict_1.default.equal(manager.initialized, 0);
213
+ });
214
+ (0, node_test_1.default)('keeps wrapped shell command private to adapter and returns only execution result', async () => {
215
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'automation-sandbox-runner-'));
216
+ try {
217
+ const manager = new FakeManager();
218
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager, tempRoot: root });
219
+ const result = await runner.run({ ...input(root), env: { PATH: (0, node_path_1.join)(root, 'fake-bin') }, allowedEnv: ['PATH'] });
220
+ strict_1.default.equal(result.exitCode, 0);
221
+ strict_1.default.equal(result.stdout, 'sandbox-ok');
222
+ strict_1.default.deepEqual(Object.keys(result).sort(), ['exitCode', 'signal', 'stderr', 'stdout']);
223
+ strict_1.default.deepEqual(manager.wrappedArgv, ['true', 'printf sandbox-ok']);
224
+ }
225
+ finally {
226
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
227
+ }
228
+ });
229
+ (0, node_test_1.default)('enforces streamed output ceilings before buffering unbounded output', async () => {
230
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'automation-sandbox-runner-'));
231
+ try {
232
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager: new FakeManager(), tempRoot: root });
233
+ const result = await runner.run({ ...input(root, { command: 'yes output', stdoutBytes: 64, timeoutMs: 5_000 }) });
234
+ strict_1.default.equal(result.outputLimitExceeded, 'stdout');
235
+ strict_1.default.ok(Buffer.byteLength(result.stdout, 'utf8') <= 64);
236
+ }
237
+ finally {
238
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
239
+ }
240
+ });
241
+ (0, node_test_1.default)('stream truncation respects UTF-8 byte limits without replacement characters', async () => {
242
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'automation-sandbox-runner-'));
243
+ try {
244
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager: new FakeManager(), tempRoot: root });
245
+ const result = await runner.run({ ...input(root, { command: "printf '€€'", stdoutBytes: 4, timeoutMs: 5_000 }) });
246
+ strict_1.default.equal(result.outputLimitExceeded, 'stdout');
247
+ strict_1.default.ok(Buffer.byteLength(result.stdout, 'utf8') <= 4);
248
+ strict_1.default.ok(!result.stdout.includes('\uFFFD'));
249
+ }
250
+ finally {
251
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
252
+ }
253
+ });
254
+ (0, node_test_1.default)('stream truncation preserves a complete replacement character before overflow', async () => {
255
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'automation-sandbox-runner-'));
256
+ try {
257
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager: new FakeManager(), tempRoot: root });
258
+ const result = await runner.run({ ...input(root, { command: "printf '�€'", stdoutBytes: 5, timeoutMs: 5_000 }) });
259
+ strict_1.default.equal(result.stdout, '�');
260
+ strict_1.default.equal(Buffer.byteLength(result.stdout, 'utf8'), 3);
261
+ }
262
+ finally {
263
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
264
+ }
265
+ });
266
+ (0, node_test_1.default)('timeout terminates the sandbox command process group', { skip: process.platform === 'win32' }, async () => {
267
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'automation-sandbox-runner-'));
268
+ try {
269
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager: new FakeManager(), tempRoot: root });
270
+ const started = Date.now();
271
+ const result = await runner.run({ ...input(root, { command: 'sleep 3 & wait', timeoutMs: 50 }) });
272
+ strict_1.default.ok(Date.now() - started < 2_000);
273
+ strict_1.default.notEqual(result.exitCode, 0);
274
+ }
275
+ finally {
276
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
277
+ }
278
+ });
279
+ (0, node_test_1.default)('serializes process-global SandboxManager operations across runners', async () => {
280
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'automation-sandbox-lock-'));
281
+ try {
282
+ const manager = new FakeManager();
283
+ const first = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager, tempRoot: root });
284
+ const second = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager, tempRoot: root });
285
+ const [left, right] = await Promise.all([
286
+ first.run(input(root)),
287
+ second.run(input(root)),
288
+ ]);
289
+ strict_1.default.equal(left.exitCode, 0);
290
+ strict_1.default.equal(right.exitCode, 0);
291
+ strict_1.default.equal(manager.resetCalls >= 4, true);
292
+ }
293
+ finally {
294
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
295
+ }
296
+ });
297
+ (0, node_test_1.default)('sanitizes loader/startup/proxy environment variables while preserving approved data', async () => {
298
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'automation-sandbox-env-'));
299
+ try {
300
+ const manager = new FakeManager();
301
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager, tempRoot: root });
302
+ const result = await runner.run({
303
+ ...input(root),
304
+ command: 'printf "%s-%s" "$TOKEN" "$BASH_ENV"',
305
+ env: { TOKEN: 'approved', BASH_ENV: '/tmp/evil', HTTP_PROXY: 'http://evil' },
306
+ allowedEnv: ['TOKEN', 'BASH_ENV', 'HTTP_PROXY'],
307
+ });
308
+ strict_1.default.equal(result.exitCode, 0);
309
+ strict_1.default.equal(result.stdout, 'approved-');
310
+ }
311
+ finally {
312
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
313
+ }
314
+ });
315
+ (0, node_test_1.default)('keeps an explicit empty environment allowlist empty', async () => {
316
+ const root = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'automation-sandbox-empty-env-'));
317
+ try {
318
+ const manager = new FakeManager();
319
+ const runner = new anthropic_sandbox_runner_js_1.AnthropicSandboxRunner({ platform: process.platform, manager, tempRoot: root });
320
+ const result = await runner.run({
321
+ ...input(root),
322
+ command: 'printf "%s" "$TOKEN"',
323
+ env: { TOKEN: 'must-not-pass' },
324
+ allowedEnv: [],
325
+ manifest: { env: ['TOKEN'] },
326
+ });
327
+ strict_1.default.equal(result.exitCode, 0);
328
+ strict_1.default.equal(result.stdout, '');
329
+ }
330
+ finally {
331
+ (0, node_fs_1.rmSync)(root, { recursive: true, force: true });
332
+ }
333
+ });