skimpyclaw 0.3.14 → 0.4.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 +47 -37
- package/dist/__tests__/adapter-types.test.d.ts +4 -0
- package/dist/__tests__/adapter-types.test.js +63 -0
- package/dist/__tests__/anthropic-adapter.test.d.ts +4 -0
- package/dist/__tests__/anthropic-adapter.test.js +264 -0
- package/dist/__tests__/api.test.js +0 -1
- package/dist/__tests__/cli.integration.test.js +2 -4
- package/dist/__tests__/cli.test.js +0 -1
- package/dist/__tests__/code-agents-notifications.test.js +137 -0
- package/dist/__tests__/code-agents-parser.test.js +19 -1
- package/dist/__tests__/code-agents-preflight.test.js +3 -28
- package/dist/__tests__/code-agents-utils.test.js +34 -9
- package/dist/__tests__/code-agents-worktrees.test.js +116 -0
- package/dist/__tests__/codex-adapter.test.js +184 -0
- package/dist/__tests__/codex-auth.test.js +66 -0
- package/dist/__tests__/codex-provider-gating.test.js +35 -0
- package/dist/__tests__/codex-unified-loop.test.js +111 -0
- package/dist/__tests__/config-security.test.js +127 -0
- package/dist/__tests__/config.test.js +23 -0
- package/dist/__tests__/context-manager.test.js +243 -164
- package/dist/__tests__/cron-run.test.js +250 -0
- package/dist/__tests__/cron.test.js +12 -38
- package/dist/__tests__/digests.test.js +67 -0
- package/dist/__tests__/discord-attachments.test.js +211 -0
- package/dist/__tests__/discord-docs.test.d.ts +1 -0
- package/dist/__tests__/discord-docs.test.js +27 -0
- package/dist/__tests__/discord-thread-agents.test.d.ts +1 -0
- package/dist/__tests__/discord-thread-agents.test.js +115 -0
- package/dist/__tests__/discord-thread-context.test.d.ts +1 -0
- package/dist/__tests__/discord-thread-context.test.js +42 -0
- package/dist/__tests__/doctor.formatters.test.js +4 -4
- package/dist/__tests__/doctor.index.test.js +1 -1
- package/dist/__tests__/doctor.runner.test.js +3 -15
- package/dist/__tests__/env-sanitizer.test.d.ts +1 -0
- package/dist/__tests__/env-sanitizer.test.js +45 -0
- package/dist/__tests__/exec-approval.test.js +61 -0
- package/dist/__tests__/fetch-tool.test.d.ts +1 -0
- package/dist/__tests__/fetch-tool.test.js +85 -0
- package/dist/__tests__/gateway-status-auth.test.d.ts +1 -0
- package/dist/__tests__/gateway-status-auth.test.js +72 -0
- package/dist/__tests__/heartbeat.test.js +3 -3
- package/dist/__tests__/interactive-sessions.test.d.ts +1 -0
- package/dist/__tests__/interactive-sessions.test.js +96 -0
- package/dist/__tests__/langfuse.test.js +6 -18
- package/dist/__tests__/model-selection.test.js +3 -4
- package/dist/__tests__/providers-init.test.js +2 -8
- package/dist/__tests__/providers-routing.test.js +1 -1
- package/dist/__tests__/providers-utils.test.js +13 -3
- package/dist/__tests__/sessions.test.js +14 -10
- package/dist/__tests__/setup.test.js +12 -29
- package/dist/__tests__/skills.test.js +10 -7
- package/dist/__tests__/stream-formatter.test.d.ts +1 -0
- package/dist/__tests__/stream-formatter.test.js +114 -0
- package/dist/__tests__/token-efficiency.test.js +131 -15
- package/dist/__tests__/tool-loop.test.d.ts +4 -0
- package/dist/__tests__/tool-loop.test.js +505 -0
- package/dist/__tests__/tools.test.js +101 -276
- package/dist/__tests__/utils.test.d.ts +1 -0
- package/dist/__tests__/utils.test.js +14 -0
- package/dist/__tests__/voice.test.js +21 -0
- package/dist/agent.js +35 -4
- package/dist/api.js +113 -37
- package/dist/channels/discord/attachments.d.ts +50 -0
- package/dist/channels/discord/attachments.js +137 -0
- package/dist/channels/discord/delegation.d.ts +5 -0
- package/dist/channels/discord/delegation.js +136 -0
- package/dist/channels/discord/handlers.js +694 -7
- package/dist/channels/discord/index.d.ts +16 -1
- package/dist/channels/discord/index.js +64 -1
- package/dist/channels/discord/thread-agents.d.ts +54 -0
- package/dist/channels/discord/thread-agents.js +323 -0
- package/dist/channels/discord/threads.d.ts +58 -0
- package/dist/channels/discord/threads.js +192 -0
- package/dist/channels/discord/types.js +4 -2
- package/dist/channels/discord/utils.d.ts +16 -0
- package/dist/channels/discord/utils.js +86 -6
- package/dist/channels/telegram/index.d.ts +1 -1
- package/dist/channels/telegram/types.js +1 -1
- package/dist/channels/telegram/utils.js +9 -3
- package/dist/channels.d.ts +1 -1
- package/dist/cli.js +20 -400
- package/dist/code-agents/executor.d.ts +1 -1
- package/dist/code-agents/executor.js +101 -45
- package/dist/code-agents/index.d.ts +2 -7
- package/dist/code-agents/index.js +111 -80
- package/dist/code-agents/interactive-resume.d.ts +6 -0
- package/dist/code-agents/interactive-resume.js +98 -0
- package/dist/code-agents/interactive-sessions.d.ts +20 -0
- package/dist/code-agents/interactive-sessions.js +132 -0
- package/dist/code-agents/parser.js +5 -1
- package/dist/code-agents/registry.d.ts +7 -1
- package/dist/code-agents/registry.js +11 -23
- package/dist/code-agents/stream-formatter.d.ts +8 -0
- package/dist/code-agents/stream-formatter.js +92 -0
- package/dist/code-agents/types.d.ts +16 -24
- package/dist/code-agents/utils.d.ts +35 -11
- package/dist/code-agents/utils.js +349 -95
- package/dist/code-agents/worktrees.d.ts +37 -0
- package/dist/code-agents/worktrees.js +116 -0
- package/dist/config.d.ts +2 -4
- package/dist/config.js +123 -23
- package/dist/cron.d.ts +1 -6
- package/dist/cron.js +175 -82
- package/dist/dashboard/assets/index-B345aOO-.js +65 -0
- package/dist/dashboard/assets/index-ZWK4dalJ.css +1 -0
- package/dist/dashboard/index.html +2 -2
- package/dist/digests.d.ts +1 -0
- package/dist/digests.js +132 -42
- package/dist/doctor/checks.d.ts +0 -3
- package/dist/doctor/checks.js +1 -108
- package/dist/doctor/runner.js +1 -4
- package/dist/env-sanitizer.d.ts +2 -0
- package/dist/env-sanitizer.js +61 -0
- package/dist/exec-approval.d.ts +11 -1
- package/dist/exec-approval.js +17 -4
- package/dist/gateway.d.ts +3 -1
- package/dist/gateway.js +17 -7
- package/dist/heartbeat.js +1 -6
- package/dist/langfuse.js +3 -29
- package/dist/model-selection.js +3 -1
- package/dist/providers/adapter.d.ts +118 -0
- package/dist/providers/adapter.js +6 -0
- package/dist/providers/adapters/anthropic-adapter.d.ts +22 -0
- package/dist/providers/adapters/anthropic-adapter.js +204 -0
- package/dist/providers/adapters/codex-adapter.d.ts +26 -0
- package/dist/providers/adapters/codex-adapter.js +203 -0
- package/dist/providers/anthropic.d.ts +1 -0
- package/dist/providers/anthropic.js +10 -272
- package/dist/providers/codex.d.ts +21 -0
- package/dist/providers/codex.js +149 -330
- package/dist/providers/content.d.ts +1 -1
- package/dist/providers/content.js +2 -2
- package/dist/providers/context-manager.d.ts +18 -6
- package/dist/providers/context-manager.js +199 -223
- package/dist/providers/index.d.ts +9 -1
- package/dist/providers/index.js +73 -64
- package/dist/providers/loop-utils.d.ts +20 -0
- package/dist/providers/loop-utils.js +30 -0
- package/dist/providers/tool-loop.d.ts +12 -0
- package/dist/providers/tool-loop.js +251 -0
- package/dist/providers/utils.d.ts +19 -3
- package/dist/providers/utils.js +100 -29
- package/dist/secure-store.d.ts +8 -0
- package/dist/secure-store.js +80 -0
- package/dist/service.js +3 -28
- package/dist/sessions.d.ts +3 -0
- package/dist/sessions.js +147 -18
- package/dist/setup-templates.js +13 -25
- package/dist/setup.d.ts +10 -6
- package/dist/setup.js +84 -292
- package/dist/skills.js +3 -11
- package/dist/tools/agent-delegation.d.ts +19 -0
- package/dist/tools/agent-delegation.js +49 -0
- package/dist/tools/bash-tool.js +89 -34
- package/dist/tools/definitions.d.ts +199 -302
- package/dist/tools/definitions.js +70 -123
- package/dist/tools/execute-context.d.ts +13 -4
- package/dist/tools/fetch-tool.js +109 -13
- package/dist/tools/file-tools.js +7 -1
- package/dist/tools.d.ts +7 -7
- package/dist/tools.js +133 -151
- package/dist/types.d.ts +37 -30
- package/dist/utils.js +4 -6
- package/dist/voice.d.ts +1 -1
- package/dist/voice.js +17 -4
- package/package.json +33 -23
- package/templates/TOOLS.md +0 -27
- package/dist/__tests__/audit.test.js +0 -122
- package/dist/__tests__/code-agents-orchestrator.test.js +0 -216
- package/dist/__tests__/code-agents-sandbox.test.js +0 -163
- package/dist/__tests__/orchestrator.test.js +0 -425
- package/dist/__tests__/sandbox-bridge.test.js +0 -116
- package/dist/__tests__/sandbox-manager.test.js +0 -144
- package/dist/__tests__/sandbox-mount-security.test.js +0 -139
- package/dist/__tests__/sandbox-runtime.test.js +0 -176
- package/dist/__tests__/subagent.test.js +0 -240
- package/dist/__tests__/telegram.test.js +0 -42
- package/dist/code-agents/orchestrator.d.ts +0 -29
- package/dist/code-agents/orchestrator.js +0 -694
- package/dist/code-agents/worktree.d.ts +0 -40
- package/dist/code-agents/worktree.js +0 -215
- package/dist/dashboard/assets/index-BoTHPby4.js +0 -65
- package/dist/dashboard/assets/index-D4mufvBg.css +0 -1
- package/dist/dashboard.d.ts +0 -8
- package/dist/dashboard.js +0 -4071
- package/dist/discord.d.ts +0 -8
- package/dist/discord.js +0 -792
- package/dist/mcp-context-a8c.d.ts +0 -13
- package/dist/mcp-context-a8c.js +0 -34
- package/dist/orchestrator.d.ts +0 -15
- package/dist/orchestrator.js +0 -676
- package/dist/providers/openai.d.ts +0 -10
- package/dist/providers/openai.js +0 -355
- package/dist/sandbox/bridge.d.ts +0 -5
- package/dist/sandbox/bridge.js +0 -63
- package/dist/sandbox/index.d.ts +0 -5
- package/dist/sandbox/index.js +0 -4
- package/dist/sandbox/manager.d.ts +0 -7
- package/dist/sandbox/manager.js +0 -100
- package/dist/sandbox/mount-security.d.ts +0 -12
- package/dist/sandbox/mount-security.js +0 -122
- package/dist/sandbox/runtime.d.ts +0 -39
- package/dist/sandbox/runtime.js +0 -192
- package/dist/sandbox-utils.d.ts +0 -6
- package/dist/sandbox-utils.js +0 -36
- package/dist/subagent.d.ts +0 -19
- package/dist/subagent.js +0 -407
- package/dist/telegram.d.ts +0 -2
- package/dist/telegram.js +0 -11
- package/dist/tools/browser-tool.d.ts +0 -3
- package/dist/tools/browser-tool.js +0 -266
- package/sandbox/Dockerfile +0 -40
- /package/dist/__tests__/{audit.test.d.ts → code-agents-notifications.test.d.ts} +0 -0
- /package/dist/__tests__/{code-agents-orchestrator.test.d.ts → code-agents-worktrees.test.d.ts} +0 -0
- /package/dist/__tests__/{code-agents-sandbox.test.d.ts → codex-adapter.test.d.ts} +0 -0
- /package/dist/__tests__/{orchestrator.test.d.ts → codex-auth.test.d.ts} +0 -0
- /package/dist/__tests__/{sandbox-bridge.test.d.ts → codex-provider-gating.test.d.ts} +0 -0
- /package/dist/__tests__/{sandbox-manager.test.d.ts → codex-unified-loop.test.d.ts} +0 -0
- /package/dist/__tests__/{sandbox-mount-security.test.d.ts → config-security.test.d.ts} +0 -0
- /package/dist/__tests__/{sandbox-runtime.test.d.ts → cron-run.test.d.ts} +0 -0
- /package/dist/__tests__/{subagent.test.d.ts → digests.test.d.ts} +0 -0
- /package/dist/__tests__/{telegram.test.d.ts → discord-attachments.test.d.ts} +0 -0
package/dist/cli.js
CHANGED
|
@@ -8,9 +8,8 @@ import { loadConfig, loadRawConfig, getConfigPath, saveConfig, resolveAllowedPat
|
|
|
8
8
|
import { startRuntime } from './service.js';
|
|
9
9
|
import { runSetup, renderGatewayPlist } from './setup.js';
|
|
10
10
|
import { runDoctor as runDoctorCommand } from './doctor/index.js';
|
|
11
|
-
import {
|
|
11
|
+
import { getToolDefinitions, BUILTIN_TOOL_DEFINITIONS } from './tools.js';
|
|
12
12
|
import { formatModelSelectionError, getModelSelectionUsage, resolveModelSelection } from './model-selection.js';
|
|
13
|
-
import { detectSandboxRuntime, isSandboxRuntimeRunning, sandboxNetworkExists, defaultSandboxNetwork, sandboxImageExists, } from './sandbox-utils.js';
|
|
14
13
|
const APP_NAME = 'skimpyclaw';
|
|
15
14
|
const DEFAULT_PORT = 18790;
|
|
16
15
|
const LAUNCHD_LABEL = 'com.skimpyclaw.gateway';
|
|
@@ -39,18 +38,12 @@ Commands:
|
|
|
39
38
|
cron list List cron jobs from gateway status
|
|
40
39
|
cron run <id> Trigger cron job by id
|
|
41
40
|
doctor [--json] Run preflight checks
|
|
42
|
-
browser <action> ... Run browser tool action (open/click/type/select/hover/scroll/waitFor/evaluate/getText/screenshot/wait/close)
|
|
43
|
-
browser login [url] Open real Chrome (no automation) for manual login. Cookies persist for agent use.
|
|
44
41
|
tools list List available tools (built-in + MCP)
|
|
45
42
|
tools install <name> Add MCP server (--command <cmd> [--args ...] or --url <url>)
|
|
46
43
|
tools remove <name> Remove MCP server
|
|
47
44
|
agents List coding agents (active + recent)
|
|
48
45
|
agents <id> Show details for a coding agent (with live output)
|
|
49
46
|
agents <id> --follow Follow live output for an agent
|
|
50
|
-
sandbox status Show active sandbox containers
|
|
51
|
-
sandbox prune Force-prune all sandbox containers
|
|
52
|
-
sandbox init Auto-setup sandbox runtime/image/config (supports --profile)
|
|
53
|
-
sandbox doctor Sandbox-specific diagnostics and hints
|
|
54
47
|
help Show this help
|
|
55
48
|
`);
|
|
56
49
|
}
|
|
@@ -106,9 +99,7 @@ function getCliToolConfig(config) {
|
|
|
106
99
|
if (config.channels.telegram.tools) {
|
|
107
100
|
return {
|
|
108
101
|
...config.channels.telegram.tools,
|
|
109
|
-
allowedPaths: config.channels.telegram.tools.allowedPaths
|
|
110
|
-
? config.channels.telegram.tools.allowedPaths
|
|
111
|
-
: resolveAllowedPaths(config),
|
|
102
|
+
allowedPaths: resolveAllowedPaths(config, config.channels.telegram.tools.allowedPaths),
|
|
112
103
|
};
|
|
113
104
|
}
|
|
114
105
|
return {
|
|
@@ -249,10 +240,18 @@ function daemonStatus() {
|
|
|
249
240
|
async function requestGateway(path, init, port) {
|
|
250
241
|
const cfgPort = port ?? loadConfig().gateway.port;
|
|
251
242
|
const url = `http://127.0.0.1:${cfgPort}${path}`;
|
|
243
|
+
let dashboardToken = '';
|
|
244
|
+
try {
|
|
245
|
+
dashboardToken = String(loadConfig()?.dashboard?.token || '');
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
// best effort
|
|
249
|
+
}
|
|
252
250
|
const res = await fetch(url, {
|
|
253
251
|
...init,
|
|
254
252
|
headers: {
|
|
255
253
|
'content-type': 'application/json',
|
|
254
|
+
...(dashboardToken ? { authorization: `Bearer ${dashboardToken}` } : {}),
|
|
256
255
|
...(init?.headers || {}),
|
|
257
256
|
},
|
|
258
257
|
signal: AbortSignal.timeout(5000),
|
|
@@ -291,12 +290,12 @@ async function commandStatus() {
|
|
|
291
290
|
let port = DEFAULT_PORT;
|
|
292
291
|
let dashboardToken = '';
|
|
293
292
|
try {
|
|
294
|
-
const
|
|
295
|
-
const
|
|
296
|
-
if (Number.isFinite(
|
|
297
|
-
port =
|
|
293
|
+
const cfg = loadConfig();
|
|
294
|
+
const cfgPort = Number(cfg?.gateway?.port);
|
|
295
|
+
if (Number.isFinite(cfgPort) && cfgPort > 0) {
|
|
296
|
+
port = cfgPort;
|
|
298
297
|
}
|
|
299
|
-
dashboardToken = String(
|
|
298
|
+
dashboardToken = String(cfg?.dashboard?.token || '');
|
|
300
299
|
}
|
|
301
300
|
catch {
|
|
302
301
|
// Keep default when config does not exist yet.
|
|
@@ -499,159 +498,6 @@ async function commandCron(args) {
|
|
|
499
498
|
console.error('Usage: skimpyclaw cron <list|run>');
|
|
500
499
|
return 1;
|
|
501
500
|
}
|
|
502
|
-
async function commandBrowserLogin(args, config) {
|
|
503
|
-
const url = args[0] || 'about:blank';
|
|
504
|
-
const toolConfig = getCliToolConfig(config);
|
|
505
|
-
const profileDir = toolConfig.browser?.profileDir || join(homedir(), '.skimpyclaw', 'browser-profile');
|
|
506
|
-
const executablePath = toolConfig.browser?.executablePath || '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
|
507
|
-
if (!existsSync(profileDir)) {
|
|
508
|
-
mkdirSync(profileDir, { recursive: true });
|
|
509
|
-
}
|
|
510
|
-
console.log(`Opening Chrome for login (profile: ${profileDir})`);
|
|
511
|
-
console.log('Log in manually, then close the browser window when done.');
|
|
512
|
-
console.log('Cookies will persist for agent use.');
|
|
513
|
-
const chromeArgs = [
|
|
514
|
-
`--user-data-dir=${profileDir}`,
|
|
515
|
-
'--no-first-run',
|
|
516
|
-
'--no-default-browser-check',
|
|
517
|
-
url,
|
|
518
|
-
];
|
|
519
|
-
const child = spawn(executablePath, chromeArgs, {
|
|
520
|
-
stdio: 'ignore',
|
|
521
|
-
detached: false,
|
|
522
|
-
});
|
|
523
|
-
return new Promise((resolve) => {
|
|
524
|
-
child.on('exit', (code) => {
|
|
525
|
-
console.log('Browser closed. Login session saved.');
|
|
526
|
-
resolve(code ?? 0);
|
|
527
|
-
});
|
|
528
|
-
child.on('error', (err) => {
|
|
529
|
-
console.error(`Failed to launch Chrome: ${err.message}`);
|
|
530
|
-
resolve(1);
|
|
531
|
-
});
|
|
532
|
-
});
|
|
533
|
-
}
|
|
534
|
-
async function commandBrowser(args) {
|
|
535
|
-
const action = args[0];
|
|
536
|
-
if (!action) {
|
|
537
|
-
console.error('Usage: skimpyclaw browser <open|click|type|select|hover|scroll|waitFor|evaluate|getText|screenshot|wait|close|login> ...');
|
|
538
|
-
return 1;
|
|
539
|
-
}
|
|
540
|
-
const config = loadConfig();
|
|
541
|
-
if (action.toLowerCase() === 'login') {
|
|
542
|
-
return commandBrowserLogin(args.slice(1), config);
|
|
543
|
-
}
|
|
544
|
-
const toolConfig = getCliToolConfig(config);
|
|
545
|
-
if (!toolConfig.browser?.enabled) {
|
|
546
|
-
console.error('Browser tool is disabled. Enable tools.browser.enabled in config.');
|
|
547
|
-
return 1;
|
|
548
|
-
}
|
|
549
|
-
const normalizedAction = action.toLowerCase();
|
|
550
|
-
const input = { action: normalizedAction };
|
|
551
|
-
if (normalizedAction === 'open') {
|
|
552
|
-
input.url = args[1];
|
|
553
|
-
if (!input.url) {
|
|
554
|
-
console.error('Usage: skimpyclaw browser open <url>');
|
|
555
|
-
return 1;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
else if (normalizedAction === 'click') {
|
|
559
|
-
input.selector = args[1];
|
|
560
|
-
if (!input.selector) {
|
|
561
|
-
console.error('Usage: skimpyclaw browser click <selector>');
|
|
562
|
-
return 1;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
else if (normalizedAction === 'type') {
|
|
566
|
-
input.selector = args[1];
|
|
567
|
-
input.text = args.slice(2).join(' ');
|
|
568
|
-
if (!input.selector || !input.text) {
|
|
569
|
-
console.error('Usage: skimpyclaw browser type <selector> <text>');
|
|
570
|
-
return 1;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
else if (normalizedAction === 'waitfor') {
|
|
574
|
-
input.selector = args[1];
|
|
575
|
-
if (hasFlag(args, '--text')) {
|
|
576
|
-
const idx = args.indexOf('--text');
|
|
577
|
-
input.text = args[idx + 1];
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
else if (normalizedAction === 'screenshot') {
|
|
581
|
-
input.file_path = args[1];
|
|
582
|
-
}
|
|
583
|
-
else if (normalizedAction === 'wait') {
|
|
584
|
-
const idx = args.indexOf('--ms');
|
|
585
|
-
if (idx !== -1)
|
|
586
|
-
input.timeMs = Number(args[idx + 1]);
|
|
587
|
-
}
|
|
588
|
-
else if (normalizedAction === 'evaluate') {
|
|
589
|
-
const scriptIdx = args.indexOf('--script');
|
|
590
|
-
if (scriptIdx !== -1) {
|
|
591
|
-
input.script = args.slice(scriptIdx + 1).join(' ');
|
|
592
|
-
}
|
|
593
|
-
else {
|
|
594
|
-
input.script = args[1];
|
|
595
|
-
}
|
|
596
|
-
if (!input.script) {
|
|
597
|
-
console.error('Usage: skimpyclaw browser evaluate --script "document.title"');
|
|
598
|
-
return 1;
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
else if (normalizedAction === 'gettext') {
|
|
602
|
-
input.selector = args[1]; // optional
|
|
603
|
-
}
|
|
604
|
-
else if (normalizedAction === 'scroll') {
|
|
605
|
-
if (args[1] && !args[1].startsWith('--')) {
|
|
606
|
-
input.selector = args[1]; // scrollIntoView target
|
|
607
|
-
}
|
|
608
|
-
const dirIdx = args.indexOf('--direction');
|
|
609
|
-
if (dirIdx !== -1)
|
|
610
|
-
input.direction = args[dirIdx + 1];
|
|
611
|
-
const amtIdx = args.indexOf('--amount');
|
|
612
|
-
if (amtIdx !== -1)
|
|
613
|
-
input.amount = Number(args[amtIdx + 1]);
|
|
614
|
-
}
|
|
615
|
-
else if (normalizedAction === 'select') {
|
|
616
|
-
input.selector = args[1];
|
|
617
|
-
input.text = args[2];
|
|
618
|
-
if (!input.selector || !input.text) {
|
|
619
|
-
console.error('Usage: skimpyclaw browser select <selector> <value>');
|
|
620
|
-
return 1;
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
else if (normalizedAction === 'hover') {
|
|
624
|
-
input.selector = args[1];
|
|
625
|
-
if (!input.selector) {
|
|
626
|
-
console.error('Usage: skimpyclaw browser hover <selector>');
|
|
627
|
-
return 1;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
if (hasFlag(args, '--headful'))
|
|
631
|
-
input.headless = false;
|
|
632
|
-
if (hasFlag(args, '--headless'))
|
|
633
|
-
input.headless = true;
|
|
634
|
-
const browserIdx = args.indexOf('--browser');
|
|
635
|
-
if (browserIdx !== -1)
|
|
636
|
-
input.type = args[browserIdx + 1];
|
|
637
|
-
const slowIdx = args.indexOf('--slowmo');
|
|
638
|
-
if (slowIdx !== -1)
|
|
639
|
-
input.slowMoMs = Number(args[slowIdx + 1]);
|
|
640
|
-
const uaIdx = args.indexOf('--user-agent');
|
|
641
|
-
if (uaIdx !== -1)
|
|
642
|
-
input.userAgent = args[uaIdx + 1];
|
|
643
|
-
const exeIdx = args.indexOf('--executable');
|
|
644
|
-
if (exeIdx !== -1)
|
|
645
|
-
input.executablePath = args[exeIdx + 1];
|
|
646
|
-
const wIdx = args.indexOf('--width');
|
|
647
|
-
const hIdx = args.indexOf('--height');
|
|
648
|
-
if (wIdx !== -1 && hIdx !== -1) {
|
|
649
|
-
input.viewport = { width: Number(args[wIdx + 1]), height: Number(args[hIdx + 1]) };
|
|
650
|
-
}
|
|
651
|
-
const result = await executeTool('Browser', input, toolConfig);
|
|
652
|
-
console.log(result);
|
|
653
|
-
return result.startsWith('Error') ? 1 : 0;
|
|
654
|
-
}
|
|
655
501
|
async function commandTools(args) {
|
|
656
502
|
const sub = args[0];
|
|
657
503
|
if (sub === 'list' || !sub) {
|
|
@@ -659,20 +505,11 @@ async function commandTools(args) {
|
|
|
659
505
|
const toolConfig = getCliToolConfig(config);
|
|
660
506
|
const tools = await getToolDefinitions(toolConfig);
|
|
661
507
|
// Group tools
|
|
662
|
-
const builtinNames = new Set(BUILTIN_TOOL_DEFINITIONS.map(t => t.name));
|
|
663
|
-
const browserName = BROWSER_TOOL_DEFINITION.name;
|
|
508
|
+
const builtinNames = new Set([...BUILTIN_TOOL_DEFINITIONS.map(t => t.name), 'Fetch']);
|
|
664
509
|
console.log('Built-in tools:');
|
|
665
510
|
for (const t of tools.filter(t => builtinNames.has(t.name))) {
|
|
666
511
|
console.log(` ${t.name.padEnd(20)} ${(t.description || '').split('\n')[0]}`);
|
|
667
512
|
}
|
|
668
|
-
const browser = tools.find(t => t.name === browserName);
|
|
669
|
-
if (browser) {
|
|
670
|
-
console.log('\nBrowser tool:');
|
|
671
|
-
console.log(` ${browser.name.padEnd(20)} ${(browser.description || '').split('\n')[0]}`);
|
|
672
|
-
}
|
|
673
|
-
else {
|
|
674
|
-
console.log('\nBrowser tool: disabled');
|
|
675
|
-
}
|
|
676
513
|
const mcpTools = tools.filter(t => t.name.startsWith('mcp__'));
|
|
677
514
|
if (mcpTools.length > 0) {
|
|
678
515
|
// Group by server
|
|
@@ -765,44 +602,6 @@ async function commandTools(args) {
|
|
|
765
602
|
console.error('Usage: skimpyclaw tools <list|install|remove>');
|
|
766
603
|
return 1;
|
|
767
604
|
}
|
|
768
|
-
const SANDBOX_CLI_BY_PROFILE = {
|
|
769
|
-
minimal: ['bash', 'curl', 'git', 'gh', 'jq', 'python3', 'rg', 'pnpm'],
|
|
770
|
-
dev: ['bash', 'curl', 'git', 'gh', 'jq', 'python3', 'rg', 'pnpm', 'gcc', 'g++', 'make'],
|
|
771
|
-
full: ['bash', 'curl', 'git', 'gh', 'jq', 'python3', 'rg', 'pnpm', 'gcc', 'g++', 'make', 'pip3', 'sqlite3'],
|
|
772
|
-
};
|
|
773
|
-
function resolveSandboxDir() {
|
|
774
|
-
// 1. Check CWD (user is in repo root)
|
|
775
|
-
const cwdSandbox = join(process.cwd(), 'sandbox');
|
|
776
|
-
if (existsSync(join(cwdSandbox, 'Dockerfile'))) {
|
|
777
|
-
return cwdSandbox;
|
|
778
|
-
}
|
|
779
|
-
// 2. Check relative to package root (global/npm install)
|
|
780
|
-
const thisFile = fileURLToPath(import.meta.url);
|
|
781
|
-
const pkgRoot = join(thisFile, '..', '..'); // dist/src/cli.js -> repo root
|
|
782
|
-
const pkgSandbox = join(pkgRoot, 'sandbox');
|
|
783
|
-
if (existsSync(join(pkgSandbox, 'Dockerfile'))) {
|
|
784
|
-
return pkgSandbox;
|
|
785
|
-
}
|
|
786
|
-
return null;
|
|
787
|
-
}
|
|
788
|
-
function parseSandboxOption(args, flag) {
|
|
789
|
-
return parseOption(args, flag, '') || undefined;
|
|
790
|
-
}
|
|
791
|
-
function runSandboxImageCheck(runtime, image, network, cmd) {
|
|
792
|
-
const result = spawnSync(runtime, ['run', '--rm', '--network', network, image, 'sh', '-lc', cmd], { encoding: 'utf-8' });
|
|
793
|
-
if (result.status === 0) {
|
|
794
|
-
return { ok: true, detail: (result.stdout || '').trim() || 'ok' };
|
|
795
|
-
}
|
|
796
|
-
const detail = `${(result.stderr || '').trim()} ${(result.stdout || '').trim()}`.trim() || `exit ${result.status ?? 1}`;
|
|
797
|
-
return { ok: false, detail };
|
|
798
|
-
}
|
|
799
|
-
function printSandboxCheck(ok, name, detail, hint) {
|
|
800
|
-
const prefix = ok ? '✓' : '✗';
|
|
801
|
-
console.log(`${prefix} ${name}: ${detail}`);
|
|
802
|
-
if (!ok && hint) {
|
|
803
|
-
console.log(` → ${hint}`);
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
605
|
async function commandAgents(args) {
|
|
807
606
|
const { getAllCodeAgents, getCodeAgent, restoreCodeAgentTasks } = await import('./code-agents/index.js');
|
|
808
607
|
// Restore tasks from disk so we can see them
|
|
@@ -829,24 +628,6 @@ async function commandAgents(args) {
|
|
|
829
628
|
console.log(`Model: ${agent.model}`);
|
|
830
629
|
console.log(`Workdir: ${agent.workdir}`);
|
|
831
630
|
console.log(`Task: ${agent.task.slice(0, 200)}${agent.task.length > 200 ? '...' : ''}`);
|
|
832
|
-
// Show children for team coordinator
|
|
833
|
-
if (agent.childTaskIds && agent.childTaskIds.length > 0) {
|
|
834
|
-
console.log(`\n\x1b[1mChildren:\x1b[0m`);
|
|
835
|
-
for (const childId of agent.childTaskIds) {
|
|
836
|
-
const child = getCodeAgent(childId);
|
|
837
|
-
if (!child)
|
|
838
|
-
continue;
|
|
839
|
-
const cElapsed = child.durationSeconds != null
|
|
840
|
-
? child.durationSeconds
|
|
841
|
-
: Math.round((Date.now() - new Date(child.startedAt).getTime()) / 1000);
|
|
842
|
-
const cStr = cElapsed < 60 ? `${cElapsed}s` : `${Math.floor(cElapsed / 60)}m${cElapsed % 60}s`;
|
|
843
|
-
const waveLabel = child.wave != null ? ` [wave ${child.wave + 1}]` : '';
|
|
844
|
-
const icon = child.status === 'completed' ? '✅' : child.status === 'failed' ? '❌' : child.status === 'running' ? '🔄' : child.status === 'pending' ? '⏳' : '❓';
|
|
845
|
-
console.log(` ${icon} ${child.id} ${child.status} (${cStr})${waveLabel}`);
|
|
846
|
-
const subtask = (child.subtask || child.task).slice(0, 120);
|
|
847
|
-
console.log(` ${subtask}${(child.subtask || child.task).length > 120 ? '...' : ''}`);
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
631
|
// Show live output
|
|
851
632
|
if (agent.liveOutput) {
|
|
852
633
|
console.log(`\n\x1b[1mLive Output:\x1b[0m`);
|
|
@@ -895,8 +676,7 @@ async function commandAgents(args) {
|
|
|
895
676
|
const elapsed = Math.round((Date.now() - new Date(a.startedAt).getTime()) / 1000);
|
|
896
677
|
const elapsedStr = elapsed < 60 ? `${elapsed}s` : `${Math.floor(elapsed / 60)}m${elapsed % 60}s`;
|
|
897
678
|
const taskPreview = a.task.slice(0, 80) + (a.task.length > 80 ? '...' : '');
|
|
898
|
-
|
|
899
|
-
console.log(` ${a.id}: \x1b[33m${a.status}\x1b[0m ${a.agent} (${elapsedStr})${children} — ${taskPreview}`);
|
|
679
|
+
console.log(` ${a.id}: \x1b[33m${a.status}\x1b[0m ${a.agent} (${elapsedStr})${taskPreview ? ` — ${taskPreview}` : ''}`);
|
|
900
680
|
}
|
|
901
681
|
}
|
|
902
682
|
if (finished.length > 0) {
|
|
@@ -912,165 +692,8 @@ async function commandAgents(args) {
|
|
|
912
692
|
}
|
|
913
693
|
return 0;
|
|
914
694
|
}
|
|
915
|
-
async function
|
|
916
|
-
|
|
917
|
-
if (sub === 'status') {
|
|
918
|
-
const rt = detectSandboxRuntime();
|
|
919
|
-
if (!rt) {
|
|
920
|
-
console.log('No container runtime found (install Docker or Apple Containers).');
|
|
921
|
-
return 1;
|
|
922
|
-
}
|
|
923
|
-
const result = spawnSync(rt, ['ps', '--format', '{{.Names}}'], { encoding: 'utf-8' });
|
|
924
|
-
const lines = (result.stdout || '').trim().split('\n').filter(Boolean);
|
|
925
|
-
const containers = lines.filter((line) => line.includes('skimpyclaw-sbx'));
|
|
926
|
-
if (containers.length === 0) {
|
|
927
|
-
console.log('No active sandbox containers.');
|
|
928
|
-
}
|
|
929
|
-
else {
|
|
930
|
-
console.log(`Active sandbox containers (${containers.length}):`);
|
|
931
|
-
containers.forEach((c) => console.log(` ${c}`));
|
|
932
|
-
}
|
|
933
|
-
return 0;
|
|
934
|
-
}
|
|
935
|
-
if (sub === 'prune') {
|
|
936
|
-
const { cleanupOrphans } = await import('./sandbox/index.js');
|
|
937
|
-
const count = await cleanupOrphans();
|
|
938
|
-
console.log(`Pruned ${count} sandbox container(s).`);
|
|
939
|
-
return 0;
|
|
940
|
-
}
|
|
941
|
-
if (sub === 'init') {
|
|
942
|
-
const runtimeFlag = parseSandboxOption(args, '--runtime');
|
|
943
|
-
const profileFlag = parseSandboxOption(args, '--profile') || 'minimal';
|
|
944
|
-
const imageFlag = parseSandboxOption(args, '--image');
|
|
945
|
-
const networkFlag = parseSandboxOption(args, '--network');
|
|
946
|
-
const validProfiles = ['minimal', 'dev', 'full'];
|
|
947
|
-
if (!validProfiles.includes(profileFlag)) {
|
|
948
|
-
console.error(`Invalid profile "${profileFlag}". Use one of: minimal, dev, full`);
|
|
949
|
-
return 1;
|
|
950
|
-
}
|
|
951
|
-
const profile = profileFlag;
|
|
952
|
-
const runtime = detectSandboxRuntime(runtimeFlag);
|
|
953
|
-
if (!runtime) {
|
|
954
|
-
console.error('No supported runtime found. Install Apple Containers or Docker.');
|
|
955
|
-
return 1;
|
|
956
|
-
}
|
|
957
|
-
const network = networkFlag || defaultSandboxNetwork(runtime);
|
|
958
|
-
const image = imageFlag || 'skimpyclaw-sandbox:latest';
|
|
959
|
-
if (!isSandboxRuntimeRunning(runtime)) {
|
|
960
|
-
const hint = runtime === 'container' ? 'Run: container system start' : 'Start Docker Desktop (or run `docker info`).';
|
|
961
|
-
console.error(`Runtime "${runtime}" is not running.`);
|
|
962
|
-
console.error(hint);
|
|
963
|
-
return 1;
|
|
964
|
-
}
|
|
965
|
-
if (!sandboxNetworkExists(runtime, network)) {
|
|
966
|
-
const hint = runtime === 'container'
|
|
967
|
-
? 'Create/list networks with `container network ls`.'
|
|
968
|
-
: 'Create/list networks with `docker network ls`.';
|
|
969
|
-
console.error(`Sandbox network "${network}" not found for runtime "${runtime}".`);
|
|
970
|
-
console.error(hint);
|
|
971
|
-
return 1;
|
|
972
|
-
}
|
|
973
|
-
const sandboxDir = resolveSandboxDir();
|
|
974
|
-
if (!sandboxDir) {
|
|
975
|
-
console.error('Could not find sandbox/Dockerfile from current directory.');
|
|
976
|
-
console.error('Run from repo root (contains ./sandbox) or build image manually.');
|
|
977
|
-
return 1;
|
|
978
|
-
}
|
|
979
|
-
console.log(`Building sandbox image "${image}" (runtime=${runtime}, profile=${profile})...`);
|
|
980
|
-
const build = spawnSync(runtime, ['build', '--build-arg', `SKIMPY_PROFILE=${profile}`, '-t', image, sandboxDir], { stdio: 'inherit' });
|
|
981
|
-
if (build.status !== 0) {
|
|
982
|
-
console.error('Sandbox image build failed.');
|
|
983
|
-
return 1;
|
|
984
|
-
}
|
|
985
|
-
const raw = loadRawConfig();
|
|
986
|
-
const sandbox = raw.sandbox ?? {};
|
|
987
|
-
sandbox.enabled = true;
|
|
988
|
-
sandbox.runtime = runtime;
|
|
989
|
-
sandbox.network = network;
|
|
990
|
-
sandbox.image = image;
|
|
991
|
-
raw.sandbox = sandbox;
|
|
992
|
-
saveConfig(raw);
|
|
993
|
-
console.log('Updated config: sandbox.enabled=true');
|
|
994
|
-
console.log(`Updated config: sandbox.runtime="${runtime}"`);
|
|
995
|
-
console.log(`Updated config: sandbox.network="${network}"`);
|
|
996
|
-
console.log(`Updated config: sandbox.image="${image}"`);
|
|
997
|
-
const required = SANDBOX_CLI_BY_PROFILE[profile];
|
|
998
|
-
const checkCmd = `for c in ${required.join(' ')}; do command -v "$c" >/dev/null || { echo "missing:$c"; exit 1; }; done; echo cli-ok`;
|
|
999
|
-
const cliCheck = runSandboxImageCheck(runtime, image, network, checkCmd);
|
|
1000
|
-
const netCheck = runSandboxImageCheck(runtime, image, network, 'curl -fsS --max-time 8 https://example.com >/dev/null && echo net-ok');
|
|
1001
|
-
const hostCheck = runSandboxImageCheck(runtime, image, network, 'hostname');
|
|
1002
|
-
printSandboxCheck(hostCheck.ok, 'sandbox_hostname', hostCheck.detail);
|
|
1003
|
-
printSandboxCheck(cliCheck.ok, 'sandbox_tools', cliCheck.detail, 'Rebuild image or choose a lighter profile.');
|
|
1004
|
-
printSandboxCheck(netCheck.ok, 'sandbox_network_egress', netCheck.detail, 'Try a different sandbox.network or check runtime DNS/network settings.');
|
|
1005
|
-
if (!hostCheck.ok || !cliCheck.ok || !netCheck.ok) {
|
|
1006
|
-
return 1;
|
|
1007
|
-
}
|
|
1008
|
-
console.log('\nSandbox init complete. Restart Skimpy to apply runtime config.');
|
|
1009
|
-
return 0;
|
|
1010
|
-
}
|
|
1011
|
-
if (sub === 'doctor') {
|
|
1012
|
-
const config = loadConfig();
|
|
1013
|
-
const runtime = detectSandboxRuntime(config.sandbox?.runtime);
|
|
1014
|
-
const image = config.sandbox?.image || 'skimpyclaw-sandbox:latest';
|
|
1015
|
-
const network = config.sandbox?.network || (runtime ? defaultSandboxNetwork(runtime) : 'unknown');
|
|
1016
|
-
const profileFlag = parseSandboxOption(args, '--profile') || 'minimal';
|
|
1017
|
-
const profile = (['minimal', 'dev', 'full'].includes(profileFlag) ? profileFlag : 'minimal');
|
|
1018
|
-
let failed = false;
|
|
1019
|
-
printSandboxCheck(config.sandbox?.enabled === true, 'sandbox_enabled', config.sandbox?.enabled ? 'enabled' : 'disabled', 'Run: skimpyclaw sandbox init');
|
|
1020
|
-
if (!config.sandbox?.enabled)
|
|
1021
|
-
failed = true;
|
|
1022
|
-
printSandboxCheck(!!runtime, 'runtime_detected', runtime || 'none', 'Install Docker or Apple Containers.');
|
|
1023
|
-
if (!runtime)
|
|
1024
|
-
return 1;
|
|
1025
|
-
printSandboxCheck(isSandboxRuntimeRunning(runtime), 'runtime_running', runtime, runtime === 'container' ? 'Run: container system start' : 'Start Docker Desktop.');
|
|
1026
|
-
if (!isSandboxRuntimeRunning(runtime))
|
|
1027
|
-
failed = true;
|
|
1028
|
-
const networkOk = sandboxNetworkExists(runtime, network);
|
|
1029
|
-
printSandboxCheck(networkOk, 'network_exists', network, `Use "${runtime === 'container' ? 'container' : 'docker'} network ls" and update sandbox.network.`);
|
|
1030
|
-
if (!networkOk)
|
|
1031
|
-
failed = true;
|
|
1032
|
-
const imageOk = sandboxImageExists(runtime, image);
|
|
1033
|
-
printSandboxCheck(imageOk, 'image_exists', image, `Build image: ${runtime} build -t ${image} sandbox/`);
|
|
1034
|
-
if (!imageOk)
|
|
1035
|
-
failed = true;
|
|
1036
|
-
if (imageOk && networkOk) {
|
|
1037
|
-
const required = SANDBOX_CLI_BY_PROFILE[profile];
|
|
1038
|
-
const checkCmd = `for c in ${required.join(' ')}; do command -v "$c" >/dev/null || { echo "missing:$c"; exit 1; }; done; echo cli-ok`;
|
|
1039
|
-
const cliCheck = runSandboxImageCheck(runtime, image, network, checkCmd);
|
|
1040
|
-
printSandboxCheck(cliCheck.ok, 'image_toolchain', cliCheck.detail, 'Rebuild with: skimpyclaw sandbox init --profile dev');
|
|
1041
|
-
if (!cliCheck.ok)
|
|
1042
|
-
failed = true;
|
|
1043
|
-
const netCheck = runSandboxImageCheck(runtime, image, network, 'curl -fsS --max-time 8 https://api.duckduckgo.com/?q=skimpyclaw&format=json >/dev/null && echo net-ok');
|
|
1044
|
-
printSandboxCheck(netCheck.ok, 'network_egress', netCheck.detail, 'Some sources may timeout; verify DNS/network in runtime.');
|
|
1045
|
-
if (!netCheck.ok)
|
|
1046
|
-
failed = true;
|
|
1047
|
-
}
|
|
1048
|
-
return failed ? 1 : 0;
|
|
1049
|
-
}
|
|
1050
|
-
console.log(`Usage: skimpyclaw sandbox <command>
|
|
1051
|
-
|
|
1052
|
-
Commands:
|
|
1053
|
-
init Build sandbox image and enable in config
|
|
1054
|
-
status List active sandbox containers
|
|
1055
|
-
prune Remove orphaned sandbox containers
|
|
1056
|
-
doctor Run targeted sandbox diagnostics
|
|
1057
|
-
|
|
1058
|
-
Init options:
|
|
1059
|
-
--runtime <container|docker> Container runtime (default: auto-detect)
|
|
1060
|
-
--profile <minimal|dev|full> Package set (default: minimal)
|
|
1061
|
-
--image <name> Image name (default: skimpyclaw-sandbox:latest)
|
|
1062
|
-
--network <name> Network name (default: auto per runtime)
|
|
1063
|
-
|
|
1064
|
-
Profiles:
|
|
1065
|
-
minimal bash, curl, git, gh, jq, python3, ripgrep, pnpm
|
|
1066
|
-
dev minimal + gcc, g++, make
|
|
1067
|
-
full dev + pip3, sqlite3, unzip, less
|
|
1068
|
-
|
|
1069
|
-
Which runtime?
|
|
1070
|
-
Apple Containers (macOS 26+) — lighter, faster startup, no daemon.
|
|
1071
|
-
Docker — cross-platform, use if you already run Docker.
|
|
1072
|
-
Auto-detect prefers Apple Containers, falls back to Docker.
|
|
1073
|
-
`);
|
|
695
|
+
async function commandSandboxRemoved() {
|
|
696
|
+
console.error("The sandbox subsystem has been removed. Use exec-approval for command safety.");
|
|
1074
697
|
return 1;
|
|
1075
698
|
}
|
|
1076
699
|
export async function runCli(argv = process.argv.slice(2)) {
|
|
@@ -1141,9 +764,6 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
1141
764
|
console.log(result.output);
|
|
1142
765
|
return result.exitCode;
|
|
1143
766
|
}
|
|
1144
|
-
if (command === 'browser') {
|
|
1145
|
-
return await commandBrowser(args);
|
|
1146
|
-
}
|
|
1147
767
|
if (command === 'tools') {
|
|
1148
768
|
return await commandTools(args);
|
|
1149
769
|
}
|
|
@@ -1151,7 +771,7 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
1151
771
|
return await commandAgents(args);
|
|
1152
772
|
}
|
|
1153
773
|
if (command === 'sandbox') {
|
|
1154
|
-
return await
|
|
774
|
+
return await commandSandboxRemoved();
|
|
1155
775
|
}
|
|
1156
776
|
console.error(`Unknown command: ${command}`);
|
|
1157
777
|
printHelp();
|
|
@@ -20,7 +20,7 @@ export declare function detectPackageManager(workdir: string): PackageManager;
|
|
|
20
20
|
* 4. Empty string (skip validation) if no scripts found
|
|
21
21
|
*/
|
|
22
22
|
export declare function buildValidationCommand(workdir: string, validationCommands?: Record<string, string>): string;
|
|
23
|
-
/** Run build/test validation.
|
|
23
|
+
/** Run build/test validation. */
|
|
24
24
|
export declare function runValidation(workdir: string, validationCommands?: Record<string, string>): Promise<ValidationResult>;
|
|
25
25
|
/** Background execution of a coding agent. Updates task status throughout. */
|
|
26
26
|
export declare function runCodeAgentBackground(id: string, agent: string, task: string, workdir: string, validate: boolean, input: Record<string, any>, startedAt: Date, options?: CodeAgentBackgroundOptions): Promise<void>;
|