@swifty.js/swifty 0.0.35 → 0.0.37
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 +8 -8
- package/dist/{acp-A4KRKOHD.js → acp-R22FJPVN.js} +1 -1
- package/dist/{agent-VDWIGFIV.js → agent-WOWGQDBG.js} +1 -1
- package/dist/anthropic-3DXT42SN.js +4 -0
- package/dist/{chunk-4B4SGVJH.js → chunk-ENZ5LHRN.js} +23 -23
- package/dist/chunk-FOPUR6OB.js +610 -0
- package/dist/{chunk-IOLGXPUQ.js → chunk-LW273HD5.js} +1 -1
- package/dist/{chunk-TNF3EHFY.js → chunk-QBGGDF62.js} +1 -1
- package/dist/{chunk-TOM34LJB.js → chunk-R62BGTT4.js} +17 -17
- package/dist/chunk-S2VEXEVV.js +4 -0
- package/dist/{chunk-H56UQALW.js → chunk-VN7HK3YD.js} +1 -1
- package/dist/lib/{agent-TC4HSVMS.js → agent-ZSFK66FQ.js} +2 -2
- package/dist/lib/{anthropic-FKIGL7NL.js → anthropic-GD3ILYG6.js} +1 -1
- package/dist/lib/{chunk-S5VWPTME.js → chunk-5OJV33Y2.js} +37 -14
- package/dist/lib/{chunk-RUDYC7OS.js → chunk-BHSNJT6Z.js} +1 -1
- package/dist/lib/{chunk-LRN4MOQ3.js → chunk-GWZDEU27.js} +0 -5
- package/dist/lib/{chunk-ALQHMYOZ.js → chunk-LKFJIK6F.js} +0 -3
- package/dist/lib/{chunk-OJTISIYU.js → chunk-O35GIE35.js} +1 -1
- package/dist/lib/{chunk-6V7RW6HA.js → chunk-TD7Z6L4D.js} +10 -13
- package/dist/lib/index.d.ts +689 -563
- package/dist/lib/index.js +1153 -729
- package/dist/lib/{openai-ZWIYIBLC.js → openai-N6X7XUQJ.js} +1 -1
- package/dist/lib/{permissions-BW4QPZXV.js → permissions-77UJQITR.js} +1 -1
- package/dist/lib/{providers-ROWSB6ND.js → providers-WQ3UOLMF.js} +1 -1
- package/dist/lib/{tool-filter-QU4LOZII.js → tool-filter-S3ZZOXFD.js} +1 -1
- package/dist/main.js +154 -153
- package/dist/{openai-7LMX5HKW.js → openai-XMJVVTTX.js} +1 -1
- package/dist/{providers-2J4JJYQD.js → providers-NWLGMQOZ.js} +1 -1
- package/dist/{server-ZYK4L22D.js → server-TINTK5DM.js} +1 -1
- package/dist/{tool-filter-U5SSL3LR.js → tool-filter-QETBQPHL.js} +1 -1
- package/package.json +2 -2
- package/dist/anthropic-AR2Y4FBR.js +0 -4
- package/dist/chunk-F4FOFPKL.js +0 -611
- package/dist/chunk-UJGMTIYO.js +0 -4
package/dist/lib/index.js
CHANGED
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
ConversationManager,
|
|
11
11
|
FileHistory,
|
|
12
12
|
RecoveryState,
|
|
13
|
+
TOOL_RESULT_PREVIEW_CHARS,
|
|
13
14
|
agent_exports,
|
|
14
15
|
asImageMediaType,
|
|
16
|
+
buildPersistedOutputPreview,
|
|
15
17
|
captureTelemetryError,
|
|
16
18
|
compact_exports,
|
|
17
19
|
conversation_exports,
|
|
@@ -27,6 +29,7 @@ import {
|
|
|
27
29
|
loadSession,
|
|
28
30
|
maybeResizeAndDownsampleImage,
|
|
29
31
|
newSessionId,
|
|
32
|
+
persistLargeResult,
|
|
30
33
|
plan_file_exports,
|
|
31
34
|
plan_mode_exports,
|
|
32
35
|
prompts_exports,
|
|
@@ -37,25 +40,26 @@ import {
|
|
|
37
40
|
saveMessage,
|
|
38
41
|
session_exports,
|
|
39
42
|
shutdownTelemetry,
|
|
43
|
+
spillDir,
|
|
40
44
|
telemetry_exports,
|
|
41
45
|
tool_result_exports
|
|
42
|
-
} from "./chunk-
|
|
46
|
+
} from "./chunk-5OJV33Y2.js";
|
|
43
47
|
import {
|
|
44
48
|
version,
|
|
45
49
|
version_exports
|
|
46
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-O35GIE35.js";
|
|
47
51
|
import {
|
|
48
52
|
anthropic_exports,
|
|
49
53
|
decideAndApply,
|
|
50
54
|
strategy_exports
|
|
51
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-TD7Z6L4D.js";
|
|
52
56
|
import {
|
|
53
57
|
SKIP_DIRS,
|
|
54
58
|
types_exports
|
|
55
59
|
} from "./chunk-BQFVUVLI.js";
|
|
56
60
|
import {
|
|
57
61
|
openai_exports
|
|
58
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-LKFJIK6F.js";
|
|
59
63
|
import {
|
|
60
64
|
DEFAULT_CONTEXT_WINDOW,
|
|
61
65
|
DEFAULT_MAX_OUTPUT_TOKENS,
|
|
@@ -78,7 +82,7 @@ import {
|
|
|
78
82
|
PermissionChecker,
|
|
79
83
|
isSafeCommand,
|
|
80
84
|
permissions_exports
|
|
81
|
-
} from "./chunk-
|
|
85
|
+
} from "./chunk-BHSNJT6Z.js";
|
|
82
86
|
import {
|
|
83
87
|
MCPToolWrapper,
|
|
84
88
|
MCP_TOOL_PREFIX,
|
|
@@ -113,7 +117,7 @@ import {
|
|
|
113
117
|
filterToolsForAgent,
|
|
114
118
|
registry_exports,
|
|
115
119
|
tool_filter_exports
|
|
116
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-GWZDEU27.js";
|
|
117
121
|
import {
|
|
118
122
|
bwrap_exports
|
|
119
123
|
} from "./chunk-YIWNQ7OA.js";
|
|
@@ -347,9 +351,9 @@ __export(server_exports, {
|
|
|
347
351
|
RemoteServer: () => RemoteServer,
|
|
348
352
|
createRemoteAgent: () => createRemoteAgent
|
|
349
353
|
});
|
|
350
|
-
import { readFileSync as readFileSync16, existsSync as existsSync16, statSync as
|
|
354
|
+
import { readFileSync as readFileSync16, existsSync as existsSync16, statSync as statSync12 } from "fs";
|
|
351
355
|
import { createServer } from "http";
|
|
352
|
-
import { join as
|
|
356
|
+
import { join as join21, extname as extname2, normalize } from "path";
|
|
353
357
|
import { cwd } from "process";
|
|
354
358
|
import Koa from "koa";
|
|
355
359
|
import { WebSocketServer, WebSocket } from "ws";
|
|
@@ -1400,21 +1404,21 @@ __export(client_exports, {
|
|
|
1400
1404
|
async function createClient(config, systemPrompt) {
|
|
1401
1405
|
switch (config.protocol) {
|
|
1402
1406
|
case "anthropic": {
|
|
1403
|
-
const { AnthropicClient } = await import("./anthropic-
|
|
1407
|
+
const { AnthropicClient } = await import("./anthropic-GD3ILYG6.js");
|
|
1404
1408
|
return registerLlmClient(new AnthropicClient(config, systemPrompt), {
|
|
1405
1409
|
model: config.model,
|
|
1406
1410
|
protocol: config.protocol
|
|
1407
1411
|
});
|
|
1408
1412
|
}
|
|
1409
1413
|
case "openai": {
|
|
1410
|
-
const { OpenAIClient } = await import("./openai-
|
|
1414
|
+
const { OpenAIClient } = await import("./openai-N6X7XUQJ.js");
|
|
1411
1415
|
return registerLlmClient(new OpenAIClient(config, systemPrompt), {
|
|
1412
1416
|
model: config.model,
|
|
1413
1417
|
protocol: config.protocol
|
|
1414
1418
|
});
|
|
1415
1419
|
}
|
|
1416
1420
|
case "openai-compat": {
|
|
1417
|
-
const { OpenAICompatClient } = await import("./openai-
|
|
1421
|
+
const { OpenAICompatClient } = await import("./openai-N6X7XUQJ.js");
|
|
1418
1422
|
return registerLlmClient(new OpenAICompatClient(config, systemPrompt), {
|
|
1419
1423
|
model: config.model,
|
|
1420
1424
|
protocol: config.protocol
|
|
@@ -1927,11 +1931,14 @@ import { resolve as resolve4 } from "path";
|
|
|
1927
1931
|
// src/tools/descriptions.ts
|
|
1928
1932
|
var descriptions_exports = {};
|
|
1929
1933
|
__export(descriptions_exports, {
|
|
1934
|
+
BASH_BACKGROUND_DESCRIPTION: () => BASH_BACKGROUND_DESCRIPTION,
|
|
1930
1935
|
BASH_DESCRIPTION: () => BASH_DESCRIPTION,
|
|
1931
1936
|
EDIT_FILE_DESCRIPTION: () => EDIT_FILE_DESCRIPTION,
|
|
1932
1937
|
GLOB_DESCRIPTION: () => GLOB_DESCRIPTION,
|
|
1933
1938
|
GREP_DESCRIPTION: () => GREP_DESCRIPTION,
|
|
1939
|
+
JAVASCRIPT_BACKGROUND_DESCRIPTION: () => JAVASCRIPT_BACKGROUND_DESCRIPTION,
|
|
1934
1940
|
JAVASCRIPT_DESCRIPTION: () => JAVASCRIPT_DESCRIPTION,
|
|
1941
|
+
POWERSHELL_BACKGROUND_DESCRIPTION: () => POWERSHELL_BACKGROUND_DESCRIPTION,
|
|
1935
1942
|
POWERSHELL_DESCRIPTION: () => POWERSHELL_DESCRIPTION,
|
|
1936
1943
|
READ_FILE_DESCRIPTION: () => READ_FILE_DESCRIPTION,
|
|
1937
1944
|
WEB_FETCH_DESCRIPTION: () => WEB_FETCH_DESCRIPTION,
|
|
@@ -1943,15 +1950,18 @@ var BASH_DESCRIPTION = `Execute command in Bash; return stdout and stderr. Prefe
|
|
|
1943
1950
|
- Quote paths with spaces. To change directory, use cd "path" && command in the same call. Separate independent commands; chain dependent commands with &&, not ;.
|
|
1944
1951
|
- Prefer dedicated file/search tools over cat, head, tail, sed, awk, echo, or find. Scope searches to a directory, never the filesystem root. Diagnose failures rather than retrying in sleep loops.
|
|
1945
1952
|
${GIT_GUIDANCE}`;
|
|
1953
|
+
var BASH_BACKGROUND_DESCRIPTION = `- Set run_in_background to true to run the command in the background. The call returns a task ID immediately and the result arrives later as a task notification; do not poll or sleep waiting for it. Use this for long-running commands you do not need the result of right away. Use TaskStop with the task_id to kill a background command early. A foreground command that exceeds its timeout is moved to the background automatically instead of being killed, unless it is a bare sleep.`;
|
|
1946
1954
|
var POWERSHELL_DESCRIPTION = `Execute command in PowerShell; return stdout and stderr. Recommended on Windows (powershell.exe); uses pwsh elsewhere.
|
|
1947
1955
|
- timeout is in seconds: default 120, maximum 600. Each call starts a fresh, independent shell in the Agent's working directory; location, variables, and options do not persist.
|
|
1948
1956
|
- Quote paths with spaces; use Set-Location -LiteralPath "path" in the same call. Separate independent commands. For dependencies, check $LASTEXITCODE for native commands and use -ErrorAction Stop for cmdlets; ; does not stop on failure. Do not assume PowerShell 7 syntax.
|
|
1949
1957
|
- Prefer dedicated file/search tools over Get-Content, Select-String, or Write-Output. Scope recursion to a directory, not a drive root. Diagnose failures rather than retrying in Start-Sleep loops.
|
|
1950
1958
|
${GIT_GUIDANCE}`;
|
|
1959
|
+
var POWERSHELL_BACKGROUND_DESCRIPTION = `- Set run_in_background to true to run the command in the background. The call returns a task ID immediately and the result arrives later as a task notification; do not poll or Start-Sleep waiting for it. Use this for long-running commands you do not need the result of right away. Use TaskStop with the task_id to kill a background command early. A foreground command that exceeds its timeout is moved to the background automatically instead of being killed, unless it is a bare Start-Sleep.`;
|
|
1951
1960
|
var JAVASCRIPT_DESCRIPTION = `Execute JavaScript in a fresh isolated V8 context for pure computation.
|
|
1952
1961
|
- Provide a function body and use return to produce a JSON-compatible result. Optional input is available as globalThis.input.
|
|
1953
1962
|
- No filesystem, network, process, require, imports, timers, or host callbacks are available. Use Bash for Node.js or system operations.
|
|
1954
1963
|
- timeout_ms defaults to 1000 (max 10000); memory_limit_mb defaults to 64 (max 256). Requires Node.js 24 or newer.`;
|
|
1964
|
+
var JAVASCRIPT_BACKGROUND_DESCRIPTION = `- Set run_in_background to true to evaluate in the background. The call returns a task ID immediately and the result arrives later as a task notification; do not poll. timeout_ms still caps the evaluation (max 10000). Use TaskStop with the task_id to abort it early.`;
|
|
1955
1965
|
var READ_FILE_DESCRIPTION = `Read text with 1-based display line numbers, or images (png, jpg, jpeg, gif, webp) as visual content; not directories.
|
|
1956
1966
|
- file_path is absolute or relative to the Agent's working directory. offset skips lines (0-based, default 0); limit defaults to 2000 lines, with a 50KB text output cap. Displayed line 101 starts at offset=100. Follow continuation/readback instructions for partial output.
|
|
1957
1967
|
- Images ignore offset/limit. A successful read refreshes the file-state cache used by EditFile/WriteFile; re-read after an external-change error.`;
|
|
@@ -3178,7 +3188,9 @@ var MemoryManager = class {
|
|
|
3178
3188
|
return this.loadAll();
|
|
3179
3189
|
}
|
|
3180
3190
|
/**
|
|
3181
|
-
* Builds the memory index injected into the
|
|
3191
|
+
* Builds the memory index injected into the conversation as a
|
|
3192
|
+
* system-reminder message (not the system prompt, which stays
|
|
3193
|
+
* project-independent to preserve prompt caching).
|
|
3182
3194
|
*
|
|
3183
3195
|
* This content is re-sent to the model on every conversation turn, so each additional index line
|
|
3184
3196
|
* is a recurring cost. We therefore enforce both a line-count and a byte-size cap at the output
|
|
@@ -3268,8 +3280,9 @@ ${body}
|
|
|
3268
3280
|
// ── Feature 2: findRelevantMemories ────────────────────────────────
|
|
3269
3281
|
/**
|
|
3270
3282
|
* Scans all memory headers from both dirs, asks the LLM to select the
|
|
3271
|
-
* top 5 most relevant ones for the query, and returns
|
|
3272
|
-
*
|
|
3283
|
+
* top 5 most relevant ones for the query, and returns their paths (with
|
|
3284
|
+
* mtimes); the file contents are read later by renderReminder.
|
|
3285
|
+
* Best-effort: selector failures return an empty array.
|
|
3273
3286
|
*/
|
|
3274
3287
|
async findRelevantMemories(query, client, recentTools = [], alreadySurfaced = /* @__PURE__ */ new Set()) {
|
|
3275
3288
|
const allHeaders = [];
|
|
@@ -4543,27 +4556,37 @@ function parseAgentDefinition(content) {
|
|
|
4543
4556
|
// src/subagent/task-manager.ts
|
|
4544
4557
|
var task_manager_exports = {};
|
|
4545
4558
|
__export(task_manager_exports, {
|
|
4559
|
+
TaskFailure: () => TaskFailure,
|
|
4546
4560
|
TaskManager: () => TaskManager,
|
|
4547
4561
|
formatAgentTaskNotification: () => formatAgentTaskNotification
|
|
4548
4562
|
});
|
|
4563
|
+
var TaskFailure = class extends Error {
|
|
4564
|
+
constructor(output) {
|
|
4565
|
+
super("task failed");
|
|
4566
|
+
this.output = output;
|
|
4567
|
+
}
|
|
4568
|
+
output;
|
|
4569
|
+
};
|
|
4549
4570
|
var TaskManager = class {
|
|
4550
4571
|
tasks = /* @__PURE__ */ new Map();
|
|
4551
4572
|
notifiedTaskIds = /* @__PURE__ */ new Set();
|
|
4552
4573
|
listeners = /* @__PURE__ */ new Set();
|
|
4553
4574
|
nextId = 1;
|
|
4575
|
+
pendingTaskIds = /* @__PURE__ */ new Set();
|
|
4554
4576
|
create(name, runner, cancel, options = {}) {
|
|
4555
|
-
const id =
|
|
4577
|
+
const id = `${options.idPrefix ?? "agent"}-${String(this.nextId++)}`;
|
|
4556
4578
|
const task = {
|
|
4557
4579
|
id,
|
|
4558
4580
|
name,
|
|
4559
4581
|
...options.originToolCallId ? { originToolCallId: options.originToolCallId } : {},
|
|
4582
|
+
...options.kind ? { kind: options.kind } : {},
|
|
4560
4583
|
status: "running",
|
|
4561
4584
|
output: "",
|
|
4562
4585
|
cancel,
|
|
4563
4586
|
done: Promise.resolve()
|
|
4564
4587
|
};
|
|
4565
4588
|
this.tasks.set(id, task);
|
|
4566
|
-
this.
|
|
4589
|
+
this.pendingTaskIds.add(id);
|
|
4567
4590
|
task.done = Promise.resolve().then(() => runner(task)).then((output) => {
|
|
4568
4591
|
if (task.status === "running") {
|
|
4569
4592
|
task.status = "completed";
|
|
@@ -4573,10 +4596,17 @@ var TaskManager = class {
|
|
|
4573
4596
|
}).catch((error) => {
|
|
4574
4597
|
if (task.status === "running") {
|
|
4575
4598
|
task.status = "failed";
|
|
4576
|
-
task.output = `Error: ${asErrorString(error)}`;
|
|
4599
|
+
task.output = error instanceof TaskFailure ? error.output : `Error: ${asErrorString(error)}`;
|
|
4600
|
+
this.emitChange();
|
|
4601
|
+
} else if (task.status === "cancelled" && error instanceof TaskFailure) {
|
|
4602
|
+
task.output = error.output;
|
|
4577
4603
|
this.emitChange();
|
|
4578
4604
|
}
|
|
4605
|
+
}).finally(() => {
|
|
4606
|
+
this.pendingTaskIds.delete(id);
|
|
4607
|
+
this.emitChange();
|
|
4579
4608
|
});
|
|
4609
|
+
this.emitChange();
|
|
4580
4610
|
return task;
|
|
4581
4611
|
}
|
|
4582
4612
|
get(id) {
|
|
@@ -4614,25 +4644,32 @@ var TaskManager = class {
|
|
|
4614
4644
|
}
|
|
4615
4645
|
async stopAndWait(id) {
|
|
4616
4646
|
const task = this.tasks.get(id);
|
|
4617
|
-
if (!task
|
|
4647
|
+
if (!task) {
|
|
4618
4648
|
return false;
|
|
4619
4649
|
}
|
|
4650
|
+
const stopped = this.stop(id);
|
|
4620
4651
|
await task.done;
|
|
4621
|
-
return
|
|
4652
|
+
return stopped;
|
|
4622
4653
|
}
|
|
4623
4654
|
async stopAll() {
|
|
4624
|
-
const running = this.list().filter((task) => task.
|
|
4655
|
+
const running = this.list().filter((task) => this.pendingTaskIds.has(task.id));
|
|
4625
4656
|
for (const task of running) {
|
|
4626
4657
|
this.stop(task.id);
|
|
4627
4658
|
}
|
|
4628
4659
|
await Promise.allSettled(running.map((task) => task.done));
|
|
4629
4660
|
}
|
|
4630
|
-
|
|
4631
|
-
|
|
4661
|
+
/**
|
|
4662
|
+
* Wait for tasks to settle. An optional filter selects which tasks to wait
|
|
4663
|
+
* for (e.g. print-mode waits only for agent-kind tasks: shell/js tasks may
|
|
4664
|
+
* run indefinitely and are stopped, not awaited, at exit).
|
|
4665
|
+
*/
|
|
4666
|
+
async waitAll(filter) {
|
|
4667
|
+
const tasks = filter ? this.list().filter(filter) : this.list();
|
|
4668
|
+
await Promise.allSettled(tasks.map((task) => task.done));
|
|
4632
4669
|
}
|
|
4633
4670
|
drainNotifications() {
|
|
4634
4671
|
const completed = this.list().filter(
|
|
4635
|
-
(task) => task.status !== "running" && !this.notifiedTaskIds.has(task.id)
|
|
4672
|
+
(task) => task.status !== "running" && !this.pendingTaskIds.has(task.id) && !this.notifiedTaskIds.has(task.id)
|
|
4636
4673
|
);
|
|
4637
4674
|
for (const task of completed) {
|
|
4638
4675
|
this.notifiedTaskIds.add(task.id);
|
|
@@ -6129,7 +6166,7 @@ ${prompt}`;
|
|
|
6129
6166
|
permissionChecker: ctx.permissionChecker?.forWorkDir(worktree.path)
|
|
6130
6167
|
};
|
|
6131
6168
|
}
|
|
6132
|
-
const { cloneRegistryForFork } = await import("./tool-filter-
|
|
6169
|
+
const { cloneRegistryForFork } = await import("./tool-filter-S3ZZOXFD.js");
|
|
6133
6170
|
const forkedRegistry = cloneRegistryForFork(this.registry);
|
|
6134
6171
|
const snapshot = conversationSnapshot ?? this.conversation.fork();
|
|
6135
6172
|
const output = await this.forkHandler(
|
|
@@ -6218,6 +6255,7 @@ async function spawnSubagent(definition, prompt, parentClient, parentRegistry, p
|
|
|
6218
6255
|
const conversation = options.conversation ?? new ConversationManager();
|
|
6219
6256
|
conversation.addSystemReminder(buildSubagentInstructions(definition));
|
|
6220
6257
|
conversation.addUserMessage(prompt);
|
|
6258
|
+
const taskManager = options.backgroundTasks === false ? null : new TaskManager();
|
|
6221
6259
|
const agent2 = new Agent({
|
|
6222
6260
|
client,
|
|
6223
6261
|
registry,
|
|
@@ -6230,53 +6268,59 @@ async function spawnSubagent(definition, prompt, parentClient, parentRegistry, p
|
|
|
6230
6268
|
fileStateCache: new FileStateCache(),
|
|
6231
6269
|
instructions: loadInstructions(workDir),
|
|
6232
6270
|
contextWindow: getContextWindow(provider),
|
|
6233
|
-
maxOutput: getMaxOutputTokens(provider)
|
|
6271
|
+
maxOutput: getMaxOutputTokens(provider),
|
|
6272
|
+
taskManager,
|
|
6273
|
+
notificationFn: taskManager ? () => taskManager.drainNotifications().map(formatAgentTaskNotification) : void 0
|
|
6234
6274
|
});
|
|
6235
6275
|
let output = "";
|
|
6236
6276
|
let turn = 0;
|
|
6237
|
-
|
|
6238
|
-
|
|
6239
|
-
|
|
6240
|
-
|
|
6241
|
-
|
|
6242
|
-
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6277
|
+
try {
|
|
6278
|
+
for await (const event of agent2.run()) {
|
|
6279
|
+
switch (event.type) {
|
|
6280
|
+
case "stream_text":
|
|
6281
|
+
output += event.text;
|
|
6282
|
+
break;
|
|
6283
|
+
case "tool_use":
|
|
6284
|
+
onProgress?.({ lastTool: event.toolName });
|
|
6285
|
+
onEvent?.({
|
|
6286
|
+
type: "tool_use",
|
|
6287
|
+
toolId: event.toolId,
|
|
6288
|
+
toolName: event.toolName,
|
|
6289
|
+
args: event.args
|
|
6290
|
+
});
|
|
6291
|
+
break;
|
|
6292
|
+
case "tool_result":
|
|
6293
|
+
onEvent?.({
|
|
6294
|
+
type: "tool_result",
|
|
6295
|
+
toolId: event.toolId
|
|
6296
|
+
});
|
|
6297
|
+
break;
|
|
6298
|
+
case "usage":
|
|
6299
|
+
onEvent?.({
|
|
6300
|
+
type: "usage",
|
|
6301
|
+
usage: {
|
|
6302
|
+
inputTokens: event.usage.inputTokens,
|
|
6303
|
+
outputTokens: event.usage.outputTokens
|
|
6304
|
+
}
|
|
6305
|
+
});
|
|
6306
|
+
break;
|
|
6307
|
+
case "turn_complete":
|
|
6308
|
+
onProgress?.({ turn: ++turn });
|
|
6309
|
+
onEvent?.({ type: "turn_complete" });
|
|
6310
|
+
break;
|
|
6311
|
+
case "loop_complete":
|
|
6312
|
+
if (event.stopReason === "interrupted") {
|
|
6313
|
+
return `${output}${output ? "\n\n" : ""}${SUBAGENT_INTERRUPTED_MARKER}`;
|
|
6263
6314
|
}
|
|
6264
|
-
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
onEvent?.({ type: "turn_complete" });
|
|
6269
|
-
break;
|
|
6270
|
-
case "loop_complete":
|
|
6271
|
-
if (event.stopReason === "interrupted") {
|
|
6272
|
-
return `${output}${output ? "\n\n" : ""}${SUBAGENT_INTERRUPTED_MARKER}`;
|
|
6273
|
-
}
|
|
6274
|
-
return output || "[No output]";
|
|
6275
|
-
case "error":
|
|
6276
|
-
throw event.error;
|
|
6315
|
+
return output || "[No output]";
|
|
6316
|
+
case "error":
|
|
6317
|
+
throw event.error;
|
|
6318
|
+
}
|
|
6277
6319
|
}
|
|
6320
|
+
return output || "[No output]";
|
|
6321
|
+
} finally {
|
|
6322
|
+
await taskManager?.stopAll();
|
|
6278
6323
|
}
|
|
6279
|
-
return output || "[No output]";
|
|
6280
6324
|
}
|
|
6281
6325
|
|
|
6282
6326
|
// src/teams/coordinator.ts
|
|
@@ -7063,7 +7107,7 @@ var TaskStopTool = class {
|
|
|
7063
7107
|
teamManager;
|
|
7064
7108
|
taskManager;
|
|
7065
7109
|
name = "TaskStop";
|
|
7066
|
-
description = "Stop a running teammate or background Agent
|
|
7110
|
+
description = "Stop a running teammate or background task (Agent, Bash, PowerShell or JavaScript). Pass exactly one of teammate or task_id.";
|
|
7067
7111
|
category = "command";
|
|
7068
7112
|
schema() {
|
|
7069
7113
|
return {
|
|
@@ -7078,20 +7122,21 @@ var TaskStopTool = class {
|
|
|
7078
7122
|
},
|
|
7079
7123
|
task_id: {
|
|
7080
7124
|
type: "string",
|
|
7081
|
-
description: "ID of a background Agent
|
|
7125
|
+
description: "ID of a background task (Agent, Bash, PowerShell or JavaScript)"
|
|
7082
7126
|
}
|
|
7083
7127
|
}
|
|
7084
7128
|
}
|
|
7085
7129
|
};
|
|
7086
7130
|
}
|
|
7087
|
-
async execute(
|
|
7131
|
+
async execute(ctx, args) {
|
|
7088
7132
|
const name = strArg(args, "teammate", "");
|
|
7089
7133
|
const taskId = strArg(args, "task_id", "");
|
|
7090
7134
|
if (!name && !taskId || name && taskId) {
|
|
7091
7135
|
return { output: "Error: pass exactly one of teammate or task_id", isError: true };
|
|
7092
7136
|
}
|
|
7093
7137
|
if (taskId) {
|
|
7094
|
-
const
|
|
7138
|
+
const manager = ctx.taskManager?.get(taskId) ? ctx.taskManager : this.taskManager;
|
|
7139
|
+
const task = manager?.get(taskId);
|
|
7095
7140
|
if (!task) {
|
|
7096
7141
|
return { output: `Error: background task '${taskId}' not found`, isError: true };
|
|
7097
7142
|
}
|
|
@@ -7101,7 +7146,7 @@ var TaskStopTool = class {
|
|
|
7101
7146
|
isError: false
|
|
7102
7147
|
};
|
|
7103
7148
|
}
|
|
7104
|
-
await
|
|
7149
|
+
await manager?.stopAndWait(taskId);
|
|
7105
7150
|
return { output: `Background task '${taskId}' stopped.`, isError: false };
|
|
7106
7151
|
}
|
|
7107
7152
|
for (const team of this.teamManager.list()) {
|
|
@@ -7425,16 +7470,7 @@ ${prompt}` };
|
|
|
7425
7470
|
shutdown: shutdownRequest("lead", "member deactivated")
|
|
7426
7471
|
};
|
|
7427
7472
|
}
|
|
7428
|
-
/**
|
|
7429
|
-
* Sends the teammate's completed plan to the Lead, blocks until approval is received,
|
|
7430
|
-
* and returns the prompt to feed the model on the next turn.
|
|
7431
|
-
*
|
|
7432
|
-
* The teammate holds read-only permissions at this point, so no matter how long the
|
|
7433
|
-
* wait, no damage can occur — hence no timeout is set here. Rather than timing out and
|
|
7434
|
-
* autonomously modifying files, it is better to wait indefinitely and let the user
|
|
7435
|
-
* drive progress from the Lead side. Returns null when the teammate has been
|
|
7436
|
-
* deactivated; the caller should exit the main loop.
|
|
7437
|
-
*/
|
|
7473
|
+
/** Reads the teammate's plan file for review; returns a fallback note when empty or unreadable. */
|
|
7438
7474
|
readPlanForReview() {
|
|
7439
7475
|
try {
|
|
7440
7476
|
const text = readFileSync14(getOrCreatePlanPath(this.workDir), "utf-8");
|
|
@@ -7445,6 +7481,16 @@ ${prompt}` };
|
|
|
7445
7481
|
}
|
|
7446
7482
|
return "(Plan file is empty \u2014 the teammate may not have written the plan as expected)";
|
|
7447
7483
|
}
|
|
7484
|
+
/**
|
|
7485
|
+
* Sends the teammate's completed plan to the Lead, blocks until approval is received,
|
|
7486
|
+
* and returns the prompt to feed the model on the next turn.
|
|
7487
|
+
*
|
|
7488
|
+
* The teammate holds read-only permissions at this point, so no matter how long the
|
|
7489
|
+
* wait, no damage can occur — hence no timeout is set here. Rather than timing out and
|
|
7490
|
+
* autonomously modifying files, it is better to wait indefinitely and let the user
|
|
7491
|
+
* drive progress from the Lead side. Returns null when the teammate has been
|
|
7492
|
+
* deactivated; the caller should exit the main loop.
|
|
7493
|
+
*/
|
|
7448
7494
|
async runPlanApproval(member, plan) {
|
|
7449
7495
|
const req = planApprovalRequest(member.name, plan);
|
|
7450
7496
|
await this.leadMailbox.send(member.name, req.text, req);
|
|
@@ -8139,8 +8185,50 @@ __export(bash_exports, {
|
|
|
8139
8185
|
BashTool: () => BashTool
|
|
8140
8186
|
});
|
|
8141
8187
|
import { spawn as spawn2 } from "child_process";
|
|
8188
|
+
import { statSync as statSync10 } from "fs";
|
|
8189
|
+
|
|
8190
|
+
// src/tools/shell-background.ts
|
|
8191
|
+
var shell_background_exports = {};
|
|
8192
|
+
__export(shell_background_exports, {
|
|
8193
|
+
BACKGROUNDABLE_TOOL_NAMES: () => BACKGROUNDABLE_TOOL_NAMES,
|
|
8194
|
+
BACKGROUND_MAX_OUTPUT_BYTES: () => BACKGROUND_MAX_OUTPUT_BYTES,
|
|
8195
|
+
BACKGROUND_NOTIFICATION_CHARS: () => BACKGROUND_NOTIFICATION_CHARS,
|
|
8196
|
+
SIZE_WATCHDOG_INTERVAL_MS: () => SIZE_WATCHDOG_INTERVAL_MS,
|
|
8197
|
+
attachBackgroundTaskManager: () => attachBackgroundTaskManager,
|
|
8198
|
+
backgroundAllForegroundTasks: () => backgroundAllForegroundTasks,
|
|
8199
|
+
backgroundMessage: () => backgroundMessage,
|
|
8200
|
+
backgroundTaskName: () => backgroundTaskName,
|
|
8201
|
+
buildBackgroundBody: () => buildBackgroundBody,
|
|
8202
|
+
createShellOutputFile: () => createShellOutputFile,
|
|
8203
|
+
discardFd: () => discardFd,
|
|
8204
|
+
formatFinalResult: () => formatFinalResult,
|
|
8205
|
+
hasAnyForegroundTasks: () => hasAnyForegroundTasks,
|
|
8206
|
+
isAutobackgroundingAllowed: () => isAutobackgroundingAllowed,
|
|
8207
|
+
openOutputFd: () => openOutputFd,
|
|
8208
|
+
readOutputFile: () => readOutputFile,
|
|
8209
|
+
sliceUtf8Safe: () => sliceUtf8Safe,
|
|
8210
|
+
unlinkQuiet: () => unlinkQuiet
|
|
8211
|
+
});
|
|
8212
|
+
import { randomBytes as randomBytes3 } from "crypto";
|
|
8213
|
+
import {
|
|
8214
|
+
closeSync as closeSync2,
|
|
8215
|
+
constants as fsConstants,
|
|
8216
|
+
fstatSync,
|
|
8217
|
+
mkdirSync as mkdirSync12,
|
|
8218
|
+
openSync as openSync2,
|
|
8219
|
+
readSync,
|
|
8220
|
+
statSync as statSync9,
|
|
8221
|
+
unlinkSync as unlinkSync5
|
|
8222
|
+
} from "fs";
|
|
8223
|
+
import { tmpdir } from "os";
|
|
8224
|
+
import { join as join19 } from "path";
|
|
8142
8225
|
|
|
8143
8226
|
// src/tools/exit-code-hints.ts
|
|
8227
|
+
var exit_code_hints_exports = {};
|
|
8228
|
+
__export(exit_code_hints_exports, {
|
|
8229
|
+
exitCodeHint: () => exitCodeHint,
|
|
8230
|
+
extractBaseCmd: () => extractBaseCmd
|
|
8231
|
+
});
|
|
8144
8232
|
function extractBaseCmd(command) {
|
|
8145
8233
|
const lastSegment = command.split("|").pop()?.trim() ?? command;
|
|
8146
8234
|
const tokens = lastSegment.split(/\s+/);
|
|
@@ -8372,9 +8460,201 @@ function exitCodeHint(command, exitCode) {
|
|
|
8372
8460
|
return "";
|
|
8373
8461
|
}
|
|
8374
8462
|
|
|
8463
|
+
// src/tools/shell-background.ts
|
|
8464
|
+
var BACKGROUND_NOTIFICATION_CHARS = 3e4;
|
|
8465
|
+
var BACKGROUND_MAX_OUTPUT_BYTES = 5 * 1024 * 1024 * 1024;
|
|
8466
|
+
var SIZE_WATCHDOG_INTERVAL_MS = 500;
|
|
8467
|
+
function isAutobackgroundingAllowed(command, disallowed) {
|
|
8468
|
+
const first = /^\S+/.exec(command.trimStart())?.[0] ?? "";
|
|
8469
|
+
const base = first.replace(/^.*\//, "").replace(/^["']|["']$/g, "").toLowerCase();
|
|
8470
|
+
return !disallowed.has(base);
|
|
8471
|
+
}
|
|
8472
|
+
function backgroundTaskName(command) {
|
|
8473
|
+
const flat = command.replace(/\s+/g, " ").trim();
|
|
8474
|
+
return flat.length > 80 ? `${flat.slice(0, 77)}...` : flat;
|
|
8475
|
+
}
|
|
8476
|
+
function backgroundMessage(reason, taskId, timeout) {
|
|
8477
|
+
switch (reason) {
|
|
8478
|
+
case "explicit":
|
|
8479
|
+
return `Command running in background (task_id: ${taskId}). You will be notified when it completes; do not poll. Use TaskStop with task_id to kill it early.`;
|
|
8480
|
+
case "timeout":
|
|
8481
|
+
return `Command exceeded its ${String(timeout)}s timeout and was moved to the background (task_id: ${taskId}). It is still running \u2014 you will be notified when it completes.`;
|
|
8482
|
+
case "user":
|
|
8483
|
+
return `Command was manually backgrounded by the user (task_id: ${taskId}). It is still running \u2014 you will be notified when it completes.`;
|
|
8484
|
+
}
|
|
8485
|
+
}
|
|
8486
|
+
function sliceUtf8Safe(buf, maxBytes) {
|
|
8487
|
+
if (buf.length <= maxBytes) {
|
|
8488
|
+
return buf;
|
|
8489
|
+
}
|
|
8490
|
+
let end = maxBytes;
|
|
8491
|
+
while (end > 0 && (buf[end] & 192) === 128) {
|
|
8492
|
+
end--;
|
|
8493
|
+
}
|
|
8494
|
+
return buf.subarray(0, end);
|
|
8495
|
+
}
|
|
8496
|
+
function readOutputFile(path, maxBytes) {
|
|
8497
|
+
let fd;
|
|
8498
|
+
try {
|
|
8499
|
+
fd = openSync2(path, "r");
|
|
8500
|
+
} catch {
|
|
8501
|
+
return { text: "", size: 0, truncated: false };
|
|
8502
|
+
}
|
|
8503
|
+
try {
|
|
8504
|
+
const size = fstatSync(fd).size;
|
|
8505
|
+
const readLen = Math.min(size, maxBytes + 1);
|
|
8506
|
+
const buf = Buffer.alloc(readLen);
|
|
8507
|
+
let bytesRead = 0;
|
|
8508
|
+
while (bytesRead < readLen) {
|
|
8509
|
+
const count = readSync(fd, buf, bytesRead, readLen - bytesRead, bytesRead);
|
|
8510
|
+
if (count === 0) {
|
|
8511
|
+
break;
|
|
8512
|
+
}
|
|
8513
|
+
bytesRead += count;
|
|
8514
|
+
}
|
|
8515
|
+
return {
|
|
8516
|
+
text: sliceUtf8Safe(buf.subarray(0, bytesRead), maxBytes).toString("utf-8"),
|
|
8517
|
+
size,
|
|
8518
|
+
truncated: size > maxBytes
|
|
8519
|
+
};
|
|
8520
|
+
} finally {
|
|
8521
|
+
closeSync2(fd);
|
|
8522
|
+
}
|
|
8523
|
+
}
|
|
8524
|
+
function unlinkQuiet(path) {
|
|
8525
|
+
try {
|
|
8526
|
+
unlinkSync5(path);
|
|
8527
|
+
} catch {
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8530
|
+
function discardFd(fd) {
|
|
8531
|
+
try {
|
|
8532
|
+
closeSync2(fd);
|
|
8533
|
+
} catch {
|
|
8534
|
+
}
|
|
8535
|
+
}
|
|
8536
|
+
function openOutputFd(path) {
|
|
8537
|
+
const flags = process.platform === "win32" ? "w" : fsConstants.O_WRONLY | fsConstants.O_CREAT | fsConstants.O_APPEND | fsConstants.O_NOFOLLOW;
|
|
8538
|
+
return openSync2(path, flags, 384);
|
|
8539
|
+
}
|
|
8540
|
+
function createShellOutputFile(workDir, sessionId) {
|
|
8541
|
+
const fileName = `shell-${randomBytes3(8).toString("hex")}.output`;
|
|
8542
|
+
const candidates = [];
|
|
8543
|
+
try {
|
|
8544
|
+
const dir = spillDir(workDir, sessionId);
|
|
8545
|
+
mkdirSync12(dir, { recursive: true });
|
|
8546
|
+
candidates.push(join19(dir, fileName));
|
|
8547
|
+
} catch {
|
|
8548
|
+
}
|
|
8549
|
+
candidates.push(join19(tmpdir(), fileName));
|
|
8550
|
+
let lastError = new Error("no candidate output directory");
|
|
8551
|
+
for (const path of candidates) {
|
|
8552
|
+
try {
|
|
8553
|
+
return { path, fd: openOutputFd(path) };
|
|
8554
|
+
} catch (error) {
|
|
8555
|
+
lastError = error;
|
|
8556
|
+
}
|
|
8557
|
+
}
|
|
8558
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
8559
|
+
}
|
|
8560
|
+
function formatFinalResult(prompt, command, exit, merged, truncated, timeout) {
|
|
8561
|
+
if (exit.spawnError) {
|
|
8562
|
+
return {
|
|
8563
|
+
output: `Error executing command: ${exit.spawnError}`,
|
|
8564
|
+
isError: true
|
|
8565
|
+
};
|
|
8566
|
+
}
|
|
8567
|
+
if (exit.aborted || exit.timedOut) {
|
|
8568
|
+
const captured = merged || truncated ? formatShellOutput(prompt, command, merged, "", truncated) : "";
|
|
8569
|
+
const error = exit.aborted ? "Error: command interrupted" : `Error: command timed out after ${String(timeout)}s`;
|
|
8570
|
+
return {
|
|
8571
|
+
output: captured ? `${captured}
|
|
8572
|
+
${error}` : error,
|
|
8573
|
+
isError: true
|
|
8574
|
+
};
|
|
8575
|
+
}
|
|
8576
|
+
const exitCode = exit.code ?? 0;
|
|
8577
|
+
let output = formatShellOutput(prompt, command, merged, "", truncated);
|
|
8578
|
+
if (!truncated) {
|
|
8579
|
+
if (exitCode !== 0) {
|
|
8580
|
+
const hint = exitCodeHint(command, exitCode);
|
|
8581
|
+
output += hint ? `
|
|
8582
|
+
Exit code ${String(exitCode)} (${hint})` : `
|
|
8583
|
+
Exit code ${String(exitCode)}`;
|
|
8584
|
+
}
|
|
8585
|
+
if (exit.code === null) {
|
|
8586
|
+
output += `
|
|
8587
|
+
Process terminated${exit.signal ? ` by ${exit.signal}` : " unexpectedly"}`;
|
|
8588
|
+
}
|
|
8589
|
+
}
|
|
8590
|
+
return { output, isError: truncated || exitCode !== 0 || exit.code === null };
|
|
8591
|
+
}
|
|
8592
|
+
function buildBackgroundBody(prompt, command, exit, outputPath, timeout, annotate) {
|
|
8593
|
+
let size = 0;
|
|
8594
|
+
try {
|
|
8595
|
+
size = statSync9(outputPath).size;
|
|
8596
|
+
} catch {
|
|
8597
|
+
}
|
|
8598
|
+
let result;
|
|
8599
|
+
if (size <= BACKGROUND_NOTIFICATION_CHARS) {
|
|
8600
|
+
const read = readOutputFile(outputPath, MAX_SHELL_OUTPUT_BYTES);
|
|
8601
|
+
const merged = annotate ? annotate(read.text) : read.text;
|
|
8602
|
+
result = formatFinalResult(prompt, command, exit, merged, read.truncated, timeout);
|
|
8603
|
+
unlinkQuiet(outputPath);
|
|
8604
|
+
} else {
|
|
8605
|
+
const header = formatFinalResult(prompt, command, exit, "", false, timeout);
|
|
8606
|
+
const preview2 = readOutputFile(outputPath, TOOL_RESULT_PREVIEW_CHARS).text;
|
|
8607
|
+
result = {
|
|
8608
|
+
output: `${header.output}
|
|
8609
|
+
${buildPersistedOutputPreview(size, annotate ? annotate(preview2) : preview2, outputPath)}`,
|
|
8610
|
+
isError: header.isError
|
|
8611
|
+
};
|
|
8612
|
+
}
|
|
8613
|
+
if (exit.sizeKilled) {
|
|
8614
|
+
result.output += "\nBackground command killed: output file exceeded 5GB";
|
|
8615
|
+
result.isError = true;
|
|
8616
|
+
}
|
|
8617
|
+
return result;
|
|
8618
|
+
}
|
|
8619
|
+
var BACKGROUNDABLE_TOOL_NAMES = ["Bash", "PowerShell", "JavaScript"];
|
|
8620
|
+
function asBackgroundable(tool) {
|
|
8621
|
+
if (typeof tool === "object" && tool !== null && "taskManager" in tool && "backgroundForegroundTasks" in tool) {
|
|
8622
|
+
return tool;
|
|
8623
|
+
}
|
|
8624
|
+
return null;
|
|
8625
|
+
}
|
|
8626
|
+
function attachBackgroundTaskManager(registry, manager) {
|
|
8627
|
+
for (const name of BACKGROUNDABLE_TOOL_NAMES) {
|
|
8628
|
+
const tool = asBackgroundable(registry.get(name));
|
|
8629
|
+
if (tool) {
|
|
8630
|
+
tool.taskManager = manager;
|
|
8631
|
+
}
|
|
8632
|
+
}
|
|
8633
|
+
}
|
|
8634
|
+
function hasAnyForegroundTasks(registry) {
|
|
8635
|
+
for (const name of BACKGROUNDABLE_TOOL_NAMES) {
|
|
8636
|
+
const tool = asBackgroundable(registry.get(name));
|
|
8637
|
+
if (tool?.hasForegroundTasks()) {
|
|
8638
|
+
return true;
|
|
8639
|
+
}
|
|
8640
|
+
}
|
|
8641
|
+
return false;
|
|
8642
|
+
}
|
|
8643
|
+
function backgroundAllForegroundTasks(registry) {
|
|
8644
|
+
let count = 0;
|
|
8645
|
+
for (const name of BACKGROUNDABLE_TOOL_NAMES) {
|
|
8646
|
+
const tool = asBackgroundable(registry.get(name));
|
|
8647
|
+
if (tool) {
|
|
8648
|
+
count += tool.backgroundForegroundTasks();
|
|
8649
|
+
}
|
|
8650
|
+
}
|
|
8651
|
+
return count;
|
|
8652
|
+
}
|
|
8653
|
+
|
|
8375
8654
|
// src/tools/bash.ts
|
|
8376
8655
|
var MAX_TIMEOUT = 600;
|
|
8377
8656
|
var KILL_GRACE_MS = 3e3;
|
|
8657
|
+
var DISALLOWED_AUTO_BACKGROUND_COMMANDS = /* @__PURE__ */ new Set(["sleep"]);
|
|
8378
8658
|
var BashTool = class {
|
|
8379
8659
|
// Use a hardcoded string instead of BashTool.name.replace("Tool", "")
|
|
8380
8660
|
// because class names are not stable after minification — bundlers like
|
|
@@ -8390,6 +8670,18 @@ var BashTool = class {
|
|
|
8390
8670
|
denyWrite: [],
|
|
8391
8671
|
networkEnabled: true
|
|
8392
8672
|
};
|
|
8673
|
+
/**
|
|
8674
|
+
* Background task registry, injected by the host (UI / print mode / remote
|
|
8675
|
+
* server) — the same instance the Agent tool uses, so completion
|
|
8676
|
+
* notifications share one drain and TaskStop covers both. When null, Bash is
|
|
8677
|
+
* foreground-only: run_in_background disappears from the schema, timeouts
|
|
8678
|
+
* kill, and Ctrl+B is a no-op. Calls running inside a subagent loop carry
|
|
8679
|
+
* that loop's own manager in ctx.taskManager, which takes precedence.
|
|
8680
|
+
*/
|
|
8681
|
+
taskManager = null;
|
|
8682
|
+
/** Running foreground executions eligible for manual backgrounding (Ctrl+B). */
|
|
8683
|
+
foreground = /* @__PURE__ */ new Map();
|
|
8684
|
+
nextForegroundId = 1;
|
|
8393
8685
|
/**
|
|
8394
8686
|
* Read-only commands can run concurrently with other read-only tools;
|
|
8395
8687
|
* mutating commands must run exclusively.
|
|
@@ -8404,26 +8696,62 @@ var BashTool = class {
|
|
|
8404
8696
|
const command = args.command;
|
|
8405
8697
|
return typeof command === "string" && isSafeCommand(command);
|
|
8406
8698
|
}
|
|
8699
|
+
/**
|
|
8700
|
+
* The background subsystem needs a task manager and can be disabled
|
|
8701
|
+
* wholesale with SWIFTY_DISABLE_BACKGROUND_TASKS=1 (schema parameter
|
|
8702
|
+
* removed, timeouts kill, Ctrl+B becomes a no-op). Instance-level gate used
|
|
8703
|
+
* by the schema; execute() re-checks with the ctx-resolved manager.
|
|
8704
|
+
*/
|
|
8705
|
+
backgroundEnabled() {
|
|
8706
|
+
return this.taskManager !== null && process.env.SWIFTY_DISABLE_BACKGROUND_TASKS !== "1";
|
|
8707
|
+
}
|
|
8708
|
+
/** True while at least one foreground Bash command runs (gates the Ctrl+B handler). */
|
|
8709
|
+
hasForegroundTasks() {
|
|
8710
|
+
return this.foreground.size > 0;
|
|
8711
|
+
}
|
|
8712
|
+
/**
|
|
8713
|
+
* Move every running foreground Bash command to the background (Ctrl+B).
|
|
8714
|
+
* Returns how many commands were actually backgrounded.
|
|
8715
|
+
*/
|
|
8716
|
+
backgroundForegroundTasks() {
|
|
8717
|
+
let count = 0;
|
|
8718
|
+
for (const entry of [...this.foreground.values()]) {
|
|
8719
|
+
if (entry.background()) {
|
|
8720
|
+
count++;
|
|
8721
|
+
}
|
|
8722
|
+
}
|
|
8723
|
+
return count;
|
|
8724
|
+
}
|
|
8407
8725
|
schema() {
|
|
8408
|
-
const
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
type: "string",
|
|
8413
|
-
description: "Shell command to execute"
|
|
8414
|
-
},
|
|
8415
|
-
timeout: {
|
|
8416
|
-
type: "integer",
|
|
8417
|
-
description: "Timeout in seconds (max 600)",
|
|
8418
|
-
default: 120
|
|
8419
|
-
}
|
|
8726
|
+
const properties = {
|
|
8727
|
+
command: {
|
|
8728
|
+
type: "string",
|
|
8729
|
+
description: "Shell command to execute"
|
|
8420
8730
|
},
|
|
8421
|
-
|
|
8731
|
+
timeout: {
|
|
8732
|
+
type: "integer",
|
|
8733
|
+
description: "Timeout in seconds (max 600)",
|
|
8734
|
+
default: 120
|
|
8735
|
+
}
|
|
8422
8736
|
};
|
|
8737
|
+
let description = this.description;
|
|
8738
|
+
if (this.backgroundEnabled()) {
|
|
8739
|
+
properties.run_in_background = {
|
|
8740
|
+
type: "boolean",
|
|
8741
|
+
description: "Run the command in the background. Returns a task ID immediately; the result arrives later as a task notification.",
|
|
8742
|
+
default: false
|
|
8743
|
+
};
|
|
8744
|
+
description = `${this.description}
|
|
8745
|
+
${BASH_BACKGROUND_DESCRIPTION}`;
|
|
8746
|
+
}
|
|
8423
8747
|
return {
|
|
8424
8748
|
name: this.name,
|
|
8425
|
-
description
|
|
8426
|
-
input_schema:
|
|
8749
|
+
description,
|
|
8750
|
+
input_schema: {
|
|
8751
|
+
type: "object",
|
|
8752
|
+
properties,
|
|
8753
|
+
required: ["command"]
|
|
8754
|
+
}
|
|
8427
8755
|
};
|
|
8428
8756
|
}
|
|
8429
8757
|
async execute(ctx, args) {
|
|
@@ -8444,12 +8772,29 @@ var BashTool = class {
|
|
|
8444
8772
|
if (timeout > MAX_TIMEOUT) {
|
|
8445
8773
|
timeout = MAX_TIMEOUT;
|
|
8446
8774
|
}
|
|
8775
|
+
const manager = ctx.taskManager !== void 0 ? ctx.taskManager : this.taskManager;
|
|
8776
|
+
const backgroundAvailable = manager !== null && process.env.SWIFTY_DISABLE_BACKGROUND_TASKS !== "1";
|
|
8777
|
+
const runInBackground = boolArg(args, "run_in_background") && backgroundAvailable;
|
|
8778
|
+
let outputFile;
|
|
8779
|
+
try {
|
|
8780
|
+
outputFile = createShellOutputFile(ctx.workDir, ctx.sessionId ?? "");
|
|
8781
|
+
} catch (error) {
|
|
8782
|
+
return {
|
|
8783
|
+
output: `Error creating output file: ${asErrorString(error)}`,
|
|
8784
|
+
isError: true
|
|
8785
|
+
};
|
|
8786
|
+
}
|
|
8787
|
+
const discardOutputFile = () => {
|
|
8788
|
+
discardFd(outputFile.fd);
|
|
8789
|
+
unlinkQuiet(outputFile.path);
|
|
8790
|
+
};
|
|
8447
8791
|
let prepared = {
|
|
8448
8792
|
executable: "bash",
|
|
8449
8793
|
args: ["-c", command]
|
|
8450
8794
|
};
|
|
8451
8795
|
if (this.sandboxRequired || this.sandbox) {
|
|
8452
8796
|
if (!this.sandbox) {
|
|
8797
|
+
discardOutputFile();
|
|
8453
8798
|
return {
|
|
8454
8799
|
output: "Error: sandbox is enabled but unavailable; command was not executed",
|
|
8455
8800
|
isError: true
|
|
@@ -8457,17 +8802,28 @@ var BashTool = class {
|
|
|
8457
8802
|
}
|
|
8458
8803
|
try {
|
|
8459
8804
|
if (!await this.sandbox.available()) {
|
|
8805
|
+
discardOutputFile();
|
|
8460
8806
|
return {
|
|
8461
8807
|
output: `Error: ${this.sandbox.implementation} sandbox is unavailable; command was not executed`,
|
|
8462
8808
|
isError: true
|
|
8463
8809
|
};
|
|
8464
8810
|
}
|
|
8465
|
-
prepared = await this.sandbox.prepare(
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8811
|
+
prepared = await this.sandbox.prepare(
|
|
8812
|
+
command,
|
|
8813
|
+
{
|
|
8814
|
+
...this.sandboxConfig,
|
|
8815
|
+
// The child writes its output file directly; grant write access to
|
|
8816
|
+
// that path even under a strict allowWrite config.
|
|
8817
|
+
allowWrite: [...this.sandboxConfig.allowWrite, outputFile.path]
|
|
8818
|
+
},
|
|
8819
|
+
{
|
|
8820
|
+
cwd: ctx.workDir,
|
|
8821
|
+
abortSignal: ctx.abortSignal,
|
|
8822
|
+
commandId: ctx.toolCallId
|
|
8823
|
+
}
|
|
8824
|
+
);
|
|
8470
8825
|
} catch (error) {
|
|
8826
|
+
discardOutputFile();
|
|
8471
8827
|
return {
|
|
8472
8828
|
output: `Error preparing sandbox: ${asErrorString(error)}`,
|
|
8473
8829
|
isError: true
|
|
@@ -8475,6 +8831,7 @@ var BashTool = class {
|
|
|
8475
8831
|
}
|
|
8476
8832
|
}
|
|
8477
8833
|
if (ctx.abortSignal?.aborted) {
|
|
8834
|
+
discardOutputFile();
|
|
8478
8835
|
try {
|
|
8479
8836
|
await prepared.cleanup?.();
|
|
8480
8837
|
} catch {
|
|
@@ -8484,22 +8841,58 @@ var BashTool = class {
|
|
|
8484
8841
|
isError: true
|
|
8485
8842
|
};
|
|
8486
8843
|
}
|
|
8487
|
-
|
|
8488
|
-
|
|
8844
|
+
const handle = this.startCommand(ctx, prepared, command, timeout, outputFile, manager);
|
|
8845
|
+
if (runInBackground) {
|
|
8846
|
+
const taskId = handle.background("explicit");
|
|
8847
|
+
if (taskId !== null) {
|
|
8848
|
+
return {
|
|
8849
|
+
output: backgroundMessage("explicit", taskId, timeout),
|
|
8850
|
+
isError: false
|
|
8851
|
+
};
|
|
8852
|
+
}
|
|
8853
|
+
}
|
|
8854
|
+
return handle.result;
|
|
8855
|
+
}
|
|
8856
|
+
/**
|
|
8857
|
+
* Spawn the command with stdout+stderr writing directly into the output
|
|
8858
|
+
* file (ccb's file-descriptor mode): output never flows through JS, so
|
|
8859
|
+
* backgrounding is a bookkeeping switch — no re-spawn, no buffer handover.
|
|
8860
|
+
* The returned handle exposes the tool-call promise plus a background()
|
|
8861
|
+
* trigger that transitions the running command into a TaskManager task.
|
|
8862
|
+
*/
|
|
8863
|
+
startCommand(ctx, prepared, command, timeout, outputFile, manager) {
|
|
8864
|
+
let backgroundFn;
|
|
8865
|
+
const result = new Promise((resolve12) => {
|
|
8489
8866
|
let aborted = false;
|
|
8490
8867
|
let terminating = false;
|
|
8491
8868
|
let settled = false;
|
|
8869
|
+
let backgrounded = false;
|
|
8870
|
+
let sizeKilled = false;
|
|
8492
8871
|
let escalateTimer = null;
|
|
8493
|
-
|
|
8494
|
-
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
|
|
8872
|
+
let child;
|
|
8873
|
+
try {
|
|
8874
|
+
child = spawn2(prepared.executable, prepared.args, {
|
|
8875
|
+
cwd: ctx.workDir,
|
|
8876
|
+
detached: true,
|
|
8877
|
+
env: prepared.env,
|
|
8878
|
+
// stdout and stderr share one O_APPEND fd: each write lands on disk
|
|
8879
|
+
// atomically and the streams interleave chronologically.
|
|
8880
|
+
stdio: ["ignore", outputFile.fd, outputFile.fd]
|
|
8881
|
+
});
|
|
8882
|
+
} catch (error) {
|
|
8883
|
+
discardFd(outputFile.fd);
|
|
8884
|
+
unlinkQuiet(outputFile.path);
|
|
8885
|
+
resolve12({
|
|
8886
|
+
output: `Error executing command: ${asErrorString(error)}`,
|
|
8887
|
+
isError: true
|
|
8888
|
+
});
|
|
8889
|
+
return;
|
|
8890
|
+
}
|
|
8891
|
+
discardFd(outputFile.fd);
|
|
8892
|
+
let doneResolve;
|
|
8893
|
+
const done = new Promise((resolveDone) => {
|
|
8894
|
+
doneResolve = resolveDone;
|
|
8498
8895
|
});
|
|
8499
|
-
let stdout = "";
|
|
8500
|
-
let stderr = "";
|
|
8501
|
-
let total = 0;
|
|
8502
|
-
let outputTruncated = false;
|
|
8503
8896
|
const killTree = (signal) => {
|
|
8504
8897
|
if (typeof child.pid !== "number") {
|
|
8505
8898
|
return;
|
|
@@ -8521,41 +8914,35 @@ var BashTool = class {
|
|
|
8521
8914
|
killTree("SIGTERM");
|
|
8522
8915
|
escalateTimer = setTimeout(() => {
|
|
8523
8916
|
killTree("SIGKILL");
|
|
8524
|
-
child.stdout.destroy();
|
|
8525
|
-
child.stderr.destroy();
|
|
8526
8917
|
}, KILL_GRACE_MS);
|
|
8527
8918
|
escalateTimer.unref();
|
|
8528
8919
|
};
|
|
8529
|
-
const
|
|
8530
|
-
|
|
8920
|
+
const watchdog = setInterval(() => {
|
|
8921
|
+
let size = 0;
|
|
8922
|
+
try {
|
|
8923
|
+
size = statSync10(outputFile.path).size;
|
|
8924
|
+
} catch {
|
|
8531
8925
|
return;
|
|
8532
8926
|
}
|
|
8533
|
-
const
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
outputTruncated = true;
|
|
8927
|
+
const cap = backgrounded ? BACKGROUND_MAX_OUTPUT_BYTES : MAX_SHELL_OUTPUT_BYTES;
|
|
8928
|
+
if (size > cap) {
|
|
8929
|
+
sizeKilled = backgrounded;
|
|
8930
|
+
clearInterval(watchdog);
|
|
8538
8931
|
terminate();
|
|
8539
8932
|
}
|
|
8540
|
-
|
|
8541
|
-
|
|
8542
|
-
} else {
|
|
8543
|
-
stderr += piece;
|
|
8544
|
-
}
|
|
8545
|
-
};
|
|
8546
|
-
child.stdout.setEncoding("utf-8");
|
|
8547
|
-
child.stdout.on("data", (chunk) => {
|
|
8548
|
-
appendChunk(chunk, "stdout");
|
|
8549
|
-
});
|
|
8550
|
-
child.stderr.setEncoding("utf-8");
|
|
8551
|
-
child.stderr.on("data", (chunk) => {
|
|
8552
|
-
appendChunk(chunk, "stderr");
|
|
8553
|
-
});
|
|
8933
|
+
}, SIZE_WATCHDOG_INTERVAL_MS);
|
|
8934
|
+
watchdog.unref();
|
|
8554
8935
|
const onAbort = () => {
|
|
8555
8936
|
aborted = true;
|
|
8556
8937
|
terminate();
|
|
8557
8938
|
};
|
|
8939
|
+
const backgroundAvailableHere = manager !== null && process.env.SWIFTY_DISABLE_BACKGROUND_TASKS !== "1";
|
|
8940
|
+
const autoBackgroundAllowed = backgroundAvailableHere && isAutobackgroundingAllowed(command, DISALLOWED_AUTO_BACKGROUND_COMMANDS);
|
|
8941
|
+
let timedOut = false;
|
|
8558
8942
|
const timeoutTimer = setTimeout(() => {
|
|
8943
|
+
if (autoBackgroundAllowed && backgroundExecution("timeout") !== null) {
|
|
8944
|
+
return;
|
|
8945
|
+
}
|
|
8559
8946
|
timedOut = true;
|
|
8560
8947
|
terminate();
|
|
8561
8948
|
}, timeout * 1e3);
|
|
@@ -8564,14 +8951,17 @@ var BashTool = class {
|
|
|
8564
8951
|
if (ctx.abortSignal?.aborted) {
|
|
8565
8952
|
onAbort();
|
|
8566
8953
|
}
|
|
8954
|
+
const foregroundKey = `bash-${String(this.nextForegroundId++)}`;
|
|
8567
8955
|
const cleanup = () => {
|
|
8568
8956
|
clearTimeout(timeoutTimer);
|
|
8957
|
+
clearInterval(watchdog);
|
|
8569
8958
|
if (escalateTimer) {
|
|
8570
8959
|
clearTimeout(escalateTimer);
|
|
8571
8960
|
}
|
|
8572
8961
|
ctx.abortSignal?.removeEventListener("abort", onAbort);
|
|
8962
|
+
this.foreground.delete(foregroundKey);
|
|
8573
8963
|
};
|
|
8574
|
-
const settle = (
|
|
8964
|
+
const settle = (finalResult) => {
|
|
8575
8965
|
if (settled) {
|
|
8576
8966
|
return;
|
|
8577
8967
|
}
|
|
@@ -8582,54 +8972,105 @@ var BashTool = class {
|
|
|
8582
8972
|
};
|
|
8583
8973
|
void finalize().then(
|
|
8584
8974
|
() => {
|
|
8585
|
-
resolve12(
|
|
8975
|
+
resolve12(finalResult);
|
|
8586
8976
|
},
|
|
8587
8977
|
(error) => {
|
|
8588
8978
|
resolve12({
|
|
8589
|
-
output: `${
|
|
8979
|
+
output: `${finalResult.output}
|
|
8590
8980
|
Error cleaning up sandbox: ${asErrorString(error)}`,
|
|
8591
8981
|
isError: true
|
|
8592
8982
|
});
|
|
8593
8983
|
}
|
|
8594
8984
|
);
|
|
8595
8985
|
};
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
output: `Error executing command: ${error.message}`,
|
|
8599
|
-
isError: true
|
|
8600
|
-
});
|
|
8601
|
-
});
|
|
8602
|
-
child.on("close", (code, signal) => {
|
|
8603
|
-
stderr = prepared.annotateStderr?.(stderr) ?? stderr;
|
|
8604
|
-
if (aborted || timedOut) {
|
|
8605
|
-
const captured = stdout || stderr || outputTruncated ? formatShellOutput("$ ", command, stdout, stderr, outputTruncated) : "";
|
|
8606
|
-
const error = aborted ? "Error: command interrupted" : `Error: command timed out after ${String(timeout)}s`;
|
|
8607
|
-
settle({
|
|
8608
|
-
output: captured ? `${captured}
|
|
8609
|
-
${error}` : error,
|
|
8610
|
-
isError: true
|
|
8611
|
-
});
|
|
8986
|
+
const settleExit = (exit) => {
|
|
8987
|
+
if (backgrounded) {
|
|
8612
8988
|
return;
|
|
8613
8989
|
}
|
|
8614
|
-
const
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
Exit code ${String(exitCode)} (${hint})` : `
|
|
8624
|
-
Exit code ${String(exitCode)}`;
|
|
8990
|
+
const read = readOutputFile(outputFile.path, MAX_SHELL_OUTPUT_BYTES);
|
|
8991
|
+
const merged = prepared.annotateStderr?.(read.text) ?? read.text;
|
|
8992
|
+
const finalResult = formatFinalResult("$ ", command, exit, merged, read.truncated, timeout);
|
|
8993
|
+
unlinkQuiet(outputFile.path);
|
|
8994
|
+
settle(finalResult);
|
|
8995
|
+
};
|
|
8996
|
+
const backgroundExecution = (reason) => {
|
|
8997
|
+
if (backgrounded || settled || terminating || !manager || !backgroundAvailableHere) {
|
|
8998
|
+
return null;
|
|
8625
8999
|
}
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
9000
|
+
backgrounded = true;
|
|
9001
|
+
settled = true;
|
|
9002
|
+
clearTimeout(timeoutTimer);
|
|
9003
|
+
ctx.abortSignal?.removeEventListener("abort", onAbort);
|
|
9004
|
+
this.foreground.delete(foregroundKey);
|
|
9005
|
+
const task = manager.create(
|
|
9006
|
+
backgroundTaskName(command),
|
|
9007
|
+
async () => {
|
|
9008
|
+
const exit = await done;
|
|
9009
|
+
try {
|
|
9010
|
+
await prepared.cleanup?.();
|
|
9011
|
+
} catch {
|
|
9012
|
+
}
|
|
9013
|
+
const annotate = prepared.annotateStderr ? (text) => prepared.annotateStderr?.(text) ?? text : void 0;
|
|
9014
|
+
const body = buildBackgroundBody(
|
|
9015
|
+
"$ ",
|
|
9016
|
+
command,
|
|
9017
|
+
exit,
|
|
9018
|
+
outputFile.path,
|
|
9019
|
+
timeout,
|
|
9020
|
+
annotate
|
|
9021
|
+
);
|
|
9022
|
+
if (body.isError) {
|
|
9023
|
+
throw new TaskFailure(body.output);
|
|
9024
|
+
}
|
|
9025
|
+
return body.output;
|
|
9026
|
+
},
|
|
9027
|
+
() => {
|
|
9028
|
+
killTree("SIGKILL");
|
|
9029
|
+
},
|
|
9030
|
+
{ originToolCallId: ctx.toolCallId, idPrefix: "bash", kind: "shell" }
|
|
9031
|
+
);
|
|
9032
|
+
resolve12({
|
|
9033
|
+
output: backgroundMessage(reason, task.id, timeout),
|
|
9034
|
+
isError: false
|
|
9035
|
+
});
|
|
9036
|
+
return task.id;
|
|
9037
|
+
};
|
|
9038
|
+
if (backgroundAvailableHere) {
|
|
9039
|
+
this.foreground.set(foregroundKey, {
|
|
9040
|
+
background: () => backgroundExecution("user") !== null
|
|
9041
|
+
});
|
|
9042
|
+
}
|
|
9043
|
+
const stopTimers = () => {
|
|
9044
|
+
clearInterval(watchdog);
|
|
9045
|
+
if (escalateTimer) {
|
|
9046
|
+
clearTimeout(escalateTimer);
|
|
8629
9047
|
}
|
|
8630
|
-
|
|
9048
|
+
};
|
|
9049
|
+
child.on("error", (error) => {
|
|
9050
|
+
stopTimers();
|
|
9051
|
+
const exit = {
|
|
9052
|
+
code: null,
|
|
9053
|
+
signal: null,
|
|
9054
|
+
aborted,
|
|
9055
|
+
timedOut,
|
|
9056
|
+
sizeKilled,
|
|
9057
|
+
spawnError: error.message
|
|
9058
|
+
};
|
|
9059
|
+
doneResolve?.(exit);
|
|
9060
|
+
settleExit(exit);
|
|
8631
9061
|
});
|
|
9062
|
+
child.on("close", (code, signal) => {
|
|
9063
|
+
stopTimers();
|
|
9064
|
+
const exit = { code, signal, aborted, timedOut, sizeKilled };
|
|
9065
|
+
doneResolve?.(exit);
|
|
9066
|
+
settleExit(exit);
|
|
9067
|
+
});
|
|
9068
|
+
backgroundFn = backgroundExecution;
|
|
8632
9069
|
});
|
|
9070
|
+
return {
|
|
9071
|
+
result,
|
|
9072
|
+
background: (reason) => backgroundFn?.(reason) ?? null
|
|
9073
|
+
};
|
|
8633
9074
|
}
|
|
8634
9075
|
};
|
|
8635
9076
|
|
|
@@ -8640,8 +9081,8 @@ __export(computer_use_exports, {
|
|
|
8640
9081
|
});
|
|
8641
9082
|
import { spawn as spawn3 } from "child_process";
|
|
8642
9083
|
import { mkdtemp, readFile as readFile4, rm, writeFile as writeFile2 } from "fs/promises";
|
|
8643
|
-
import { tmpdir } from "os";
|
|
8644
|
-
import { join as
|
|
9084
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
9085
|
+
import { join as join20 } from "path";
|
|
8645
9086
|
import { setTimeout as delay } from "timers/promises";
|
|
8646
9087
|
import sharp from "sharp";
|
|
8647
9088
|
import { safeParse as safeParse2, z as z14 } from "zod";
|
|
@@ -9359,22 +9800,6 @@ var ComputerUseTool = class {
|
|
|
9359
9800
|
isConcurrencySafe(_args) {
|
|
9360
9801
|
return false;
|
|
9361
9802
|
}
|
|
9362
|
-
providerSchema(protocol) {
|
|
9363
|
-
if (protocol === "anthropic") {
|
|
9364
|
-
return {
|
|
9365
|
-
type: "computer_20251124",
|
|
9366
|
-
name: "computer",
|
|
9367
|
-
display_width_px: this.displayWidthPx,
|
|
9368
|
-
display_height_px: this.displayHeightPx,
|
|
9369
|
-
...this.displayNumber !== void 0 ? { display_number: this.displayNumber } : {},
|
|
9370
|
-
...this.enableZoom ? { enable_zoom: true } : {}
|
|
9371
|
-
};
|
|
9372
|
-
}
|
|
9373
|
-
if (protocol === "openai") {
|
|
9374
|
-
return { type: "computer" };
|
|
9375
|
-
}
|
|
9376
|
-
return void 0;
|
|
9377
|
-
}
|
|
9378
9803
|
schema() {
|
|
9379
9804
|
return {
|
|
9380
9805
|
name: this.name,
|
|
@@ -9718,9 +10143,9 @@ var ComputerUseTool = class {
|
|
|
9718
10143
|
}
|
|
9719
10144
|
}
|
|
9720
10145
|
async compileMacHelper(signal) {
|
|
9721
|
-
const directory = await mkdtemp(
|
|
9722
|
-
const sourcePath =
|
|
9723
|
-
const executablePath =
|
|
10146
|
+
const directory = await mkdtemp(join20(tmpdir2(), "swifty-computer-helper-"));
|
|
10147
|
+
const sourcePath = join20(directory, "main.swift");
|
|
10148
|
+
const executablePath = join20(directory, "computer-helper");
|
|
9724
10149
|
try {
|
|
9725
10150
|
await writeFile2(sourcePath, MACOS_SNIPPET, "utf8");
|
|
9726
10151
|
const result = await this.run(
|
|
@@ -9937,8 +10362,8 @@ var ComputerUseTool = class {
|
|
|
9937
10362
|
return { output, contentBlocks: [imageBlock], isError: false };
|
|
9938
10363
|
}
|
|
9939
10364
|
async captureScreenshot(signal) {
|
|
9940
|
-
const directory = await mkdtemp(
|
|
9941
|
-
const screenshotPath =
|
|
10365
|
+
const directory = await mkdtemp(join20(tmpdir2(), "swifty-computer-"));
|
|
10366
|
+
const screenshotPath = join20(directory, "screenshot.png");
|
|
9942
10367
|
try {
|
|
9943
10368
|
switch (this.platform) {
|
|
9944
10369
|
case "darwin": {
|
|
@@ -10215,8 +10640,10 @@ __export(powershell_exports, {
|
|
|
10215
10640
|
PowerShellTool: () => PowerShellTool
|
|
10216
10641
|
});
|
|
10217
10642
|
import { execFile as execFile2, spawn as spawn4 } from "child_process";
|
|
10643
|
+
import { statSync as statSync11 } from "fs";
|
|
10218
10644
|
var MAX_TIMEOUT2 = 600;
|
|
10219
10645
|
var KILL_GRACE_MS2 = 3e3;
|
|
10646
|
+
var DISALLOWED_AUTO_BACKGROUND_COMMANDS2 = /* @__PURE__ */ new Set(["start-sleep", "sleep"]);
|
|
10220
10647
|
var PowerShellTool = class {
|
|
10221
10648
|
// Use a hardcoded string instead of PowerShellTool.name.replace("Tool", "")
|
|
10222
10649
|
// because class names are not stable after minification — bundlers like
|
|
@@ -10224,57 +10651,130 @@ var PowerShellTool = class {
|
|
|
10224
10651
|
name = "PowerShell";
|
|
10225
10652
|
description = POWERSHELL_DESCRIPTION;
|
|
10226
10653
|
category = "command";
|
|
10654
|
+
/**
|
|
10655
|
+
* Background task registry, injected by the host — same contract as
|
|
10656
|
+
* BashTool.taskManager (schema gating, timeout auto-background, Ctrl+B).
|
|
10657
|
+
* Calls running inside a subagent loop carry that loop's own manager in
|
|
10658
|
+
* ctx.taskManager, which takes precedence.
|
|
10659
|
+
*/
|
|
10660
|
+
taskManager = null;
|
|
10661
|
+
/** Running foreground executions eligible for manual backgrounding (Ctrl+B). */
|
|
10662
|
+
foreground = /* @__PURE__ */ new Map();
|
|
10663
|
+
nextForegroundId = 1;
|
|
10664
|
+
/** Instance-level background gate; see BashTool.backgroundEnabled. */
|
|
10665
|
+
backgroundEnabled() {
|
|
10666
|
+
return this.taskManager !== null && process.env.SWIFTY_DISABLE_BACKGROUND_TASKS !== "1";
|
|
10667
|
+
}
|
|
10668
|
+
/** True while at least one foreground PowerShell command runs. */
|
|
10669
|
+
hasForegroundTasks() {
|
|
10670
|
+
return this.foreground.size > 0;
|
|
10671
|
+
}
|
|
10672
|
+
/** Move every running foreground command to the background (Ctrl+B). */
|
|
10673
|
+
backgroundForegroundTasks() {
|
|
10674
|
+
let count = 0;
|
|
10675
|
+
for (const entry of [...this.foreground.values()]) {
|
|
10676
|
+
if (entry.background()) {
|
|
10677
|
+
count++;
|
|
10678
|
+
}
|
|
10679
|
+
}
|
|
10680
|
+
return count;
|
|
10681
|
+
}
|
|
10227
10682
|
schema() {
|
|
10228
|
-
const
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
type: "string",
|
|
10233
|
-
description: "PowerShell command to execute"
|
|
10234
|
-
},
|
|
10235
|
-
timeout: {
|
|
10236
|
-
type: "integer",
|
|
10237
|
-
description: "Timeout in seconds (max 600)",
|
|
10238
|
-
default: 120
|
|
10239
|
-
}
|
|
10683
|
+
const properties = {
|
|
10684
|
+
command: {
|
|
10685
|
+
type: "string",
|
|
10686
|
+
description: "PowerShell command to execute"
|
|
10240
10687
|
},
|
|
10241
|
-
|
|
10688
|
+
timeout: {
|
|
10689
|
+
type: "integer",
|
|
10690
|
+
description: "Timeout in seconds (max 600)",
|
|
10691
|
+
default: 120
|
|
10692
|
+
}
|
|
10242
10693
|
};
|
|
10694
|
+
let description = this.description;
|
|
10695
|
+
if (this.backgroundEnabled()) {
|
|
10696
|
+
properties.run_in_background = {
|
|
10697
|
+
type: "boolean",
|
|
10698
|
+
description: "Run the command in the background. Returns a task ID immediately; the result arrives later as a task notification.",
|
|
10699
|
+
default: false
|
|
10700
|
+
};
|
|
10701
|
+
description = `${this.description}
|
|
10702
|
+
${POWERSHELL_BACKGROUND_DESCRIPTION}`;
|
|
10703
|
+
}
|
|
10243
10704
|
return {
|
|
10244
10705
|
name: this.name,
|
|
10245
|
-
description
|
|
10246
|
-
input_schema:
|
|
10706
|
+
description,
|
|
10707
|
+
input_schema: {
|
|
10708
|
+
type: "object",
|
|
10709
|
+
properties,
|
|
10710
|
+
required: ["command"]
|
|
10711
|
+
}
|
|
10247
10712
|
};
|
|
10248
10713
|
}
|
|
10249
|
-
execute(ctx, args) {
|
|
10714
|
+
async execute(ctx, args) {
|
|
10250
10715
|
const command = strArg(args, "command");
|
|
10251
10716
|
if (!command) {
|
|
10252
|
-
return
|
|
10717
|
+
return {
|
|
10253
10718
|
output: "Error: command is required",
|
|
10254
10719
|
isError: true
|
|
10255
|
-
}
|
|
10720
|
+
};
|
|
10256
10721
|
}
|
|
10257
10722
|
let timeout = intArg(args, "timeout", 120);
|
|
10258
10723
|
if (!Number.isFinite(timeout) || timeout <= 0) {
|
|
10259
|
-
return
|
|
10724
|
+
return {
|
|
10260
10725
|
output: "Error: timeout must be a finite number greater than 0 seconds",
|
|
10261
10726
|
isError: true
|
|
10262
|
-
}
|
|
10727
|
+
};
|
|
10263
10728
|
}
|
|
10264
10729
|
if (timeout > MAX_TIMEOUT2) {
|
|
10265
10730
|
timeout = MAX_TIMEOUT2;
|
|
10266
10731
|
}
|
|
10732
|
+
const manager = ctx.taskManager !== void 0 ? ctx.taskManager : this.taskManager;
|
|
10733
|
+
const backgroundAvailable = manager !== null && process.env.SWIFTY_DISABLE_BACKGROUND_TASKS !== "1";
|
|
10734
|
+
const runInBackground = boolArg(args, "run_in_background") && backgroundAvailable;
|
|
10267
10735
|
const shell = process.platform === "win32" ? "powershell.exe" : "pwsh";
|
|
10736
|
+
let outputFile;
|
|
10737
|
+
try {
|
|
10738
|
+
outputFile = createShellOutputFile(ctx.workDir, ctx.sessionId ?? "");
|
|
10739
|
+
} catch (error) {
|
|
10740
|
+
return {
|
|
10741
|
+
output: `Error creating output file: ${asErrorString(error)}`,
|
|
10742
|
+
isError: true
|
|
10743
|
+
};
|
|
10744
|
+
}
|
|
10268
10745
|
if (ctx.abortSignal?.aborted) {
|
|
10269
|
-
|
|
10746
|
+
discardFd(outputFile.fd);
|
|
10747
|
+
unlinkQuiet(outputFile.path);
|
|
10748
|
+
return {
|
|
10270
10749
|
output: "Error: command interrupted",
|
|
10271
10750
|
isError: true
|
|
10272
|
-
}
|
|
10751
|
+
};
|
|
10273
10752
|
}
|
|
10274
|
-
|
|
10275
|
-
|
|
10753
|
+
const handle = this.startCommand(ctx, shell, command, timeout, outputFile, manager);
|
|
10754
|
+
if (runInBackground) {
|
|
10755
|
+
const taskId = handle.background("explicit");
|
|
10756
|
+
if (taskId !== null) {
|
|
10757
|
+
return {
|
|
10758
|
+
output: backgroundMessage("explicit", taskId, timeout),
|
|
10759
|
+
isError: false
|
|
10760
|
+
};
|
|
10761
|
+
}
|
|
10762
|
+
}
|
|
10763
|
+
return handle.result;
|
|
10764
|
+
}
|
|
10765
|
+
/**
|
|
10766
|
+
* Spawn PowerShell with stdout+stderr writing directly into the output file
|
|
10767
|
+
* (fd mode, shared with BashTool): output never flows through JS, so
|
|
10768
|
+
* backgrounding is a bookkeeping switch — no re-spawn, no buffer handover.
|
|
10769
|
+
*/
|
|
10770
|
+
startCommand(ctx, shell, command, timeout, outputFile, manager) {
|
|
10771
|
+
let backgroundFn;
|
|
10772
|
+
const result = new Promise((resolve12) => {
|
|
10276
10773
|
let aborted = false;
|
|
10277
10774
|
let terminating = false;
|
|
10775
|
+
let settled = false;
|
|
10776
|
+
let backgrounded = false;
|
|
10777
|
+
let sizeKilled = false;
|
|
10278
10778
|
let escalateTimer = null;
|
|
10279
10779
|
const shellCommand = process.platform === "win32" ? "try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\n" + command : command;
|
|
10280
10780
|
const shellArgs = process.platform === "win32" ? [
|
|
@@ -10285,17 +10785,31 @@ var PowerShellTool = class {
|
|
|
10285
10785
|
"-Command",
|
|
10286
10786
|
shellCommand
|
|
10287
10787
|
] : ["-NoProfile", "-NonInteractive", "-Command", shellCommand];
|
|
10288
|
-
|
|
10289
|
-
|
|
10290
|
-
|
|
10291
|
-
|
|
10292
|
-
|
|
10293
|
-
|
|
10788
|
+
let child;
|
|
10789
|
+
try {
|
|
10790
|
+
child = spawn4(shell, shellArgs, {
|
|
10791
|
+
cwd: ctx.workDir,
|
|
10792
|
+
// Only POSIX needs its own process group for kill(-pid); the Windows
|
|
10793
|
+
// tree kill goes through taskkill and needs no new group.
|
|
10794
|
+
detached: process.platform !== "win32",
|
|
10795
|
+
// stdout and stderr share one O_APPEND fd: each write lands on disk
|
|
10796
|
+
// atomically and the streams interleave chronologically.
|
|
10797
|
+
stdio: ["ignore", outputFile.fd, outputFile.fd]
|
|
10798
|
+
});
|
|
10799
|
+
} catch (error) {
|
|
10800
|
+
discardFd(outputFile.fd);
|
|
10801
|
+
unlinkQuiet(outputFile.path);
|
|
10802
|
+
resolve12({
|
|
10803
|
+
output: `Error executing command: ${asErrorString(error)}`,
|
|
10804
|
+
isError: true
|
|
10805
|
+
});
|
|
10806
|
+
return;
|
|
10807
|
+
}
|
|
10808
|
+
discardFd(outputFile.fd);
|
|
10809
|
+
let doneResolve;
|
|
10810
|
+
const done = new Promise((resolveDone) => {
|
|
10811
|
+
doneResolve = resolveDone;
|
|
10294
10812
|
});
|
|
10295
|
-
let stdout = "";
|
|
10296
|
-
let stderr = "";
|
|
10297
|
-
let total = 0;
|
|
10298
|
-
let outputTruncated = false;
|
|
10299
10813
|
const alreadyExited = () => child.exitCode !== null || child.signalCode !== null;
|
|
10300
10814
|
const killTree = (signal) => {
|
|
10301
10815
|
if (typeof child.pid !== "number") {
|
|
@@ -10333,41 +10847,35 @@ var PowerShellTool = class {
|
|
|
10333
10847
|
killTree("SIGTERM");
|
|
10334
10848
|
escalateTimer = setTimeout(() => {
|
|
10335
10849
|
killTree("SIGKILL");
|
|
10336
|
-
child.stdout.destroy();
|
|
10337
|
-
child.stderr.destroy();
|
|
10338
10850
|
}, KILL_GRACE_MS2);
|
|
10339
10851
|
escalateTimer.unref();
|
|
10340
10852
|
};
|
|
10341
|
-
const
|
|
10342
|
-
|
|
10853
|
+
const watchdog = setInterval(() => {
|
|
10854
|
+
let size = 0;
|
|
10855
|
+
try {
|
|
10856
|
+
size = statSync11(outputFile.path).size;
|
|
10857
|
+
} catch {
|
|
10343
10858
|
return;
|
|
10344
10859
|
}
|
|
10345
|
-
const
|
|
10346
|
-
|
|
10347
|
-
|
|
10348
|
-
|
|
10349
|
-
outputTruncated = true;
|
|
10860
|
+
const cap = backgrounded ? BACKGROUND_MAX_OUTPUT_BYTES : MAX_SHELL_OUTPUT_BYTES;
|
|
10861
|
+
if (size > cap) {
|
|
10862
|
+
sizeKilled = backgrounded;
|
|
10863
|
+
clearInterval(watchdog);
|
|
10350
10864
|
terminate();
|
|
10351
10865
|
}
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
} else {
|
|
10355
|
-
stderr += piece;
|
|
10356
|
-
}
|
|
10357
|
-
};
|
|
10358
|
-
child.stdout.setEncoding("utf-8");
|
|
10359
|
-
child.stdout.on("data", (chunk) => {
|
|
10360
|
-
appendChunk(chunk, "stdout");
|
|
10361
|
-
});
|
|
10362
|
-
child.stderr.setEncoding("utf-8");
|
|
10363
|
-
child.stderr.on("data", (chunk) => {
|
|
10364
|
-
appendChunk(chunk, "stderr");
|
|
10365
|
-
});
|
|
10866
|
+
}, SIZE_WATCHDOG_INTERVAL_MS);
|
|
10867
|
+
watchdog.unref();
|
|
10366
10868
|
const onAbort = () => {
|
|
10367
10869
|
aborted = true;
|
|
10368
10870
|
terminate();
|
|
10369
10871
|
};
|
|
10872
|
+
const backgroundAvailableHere = manager !== null && process.env.SWIFTY_DISABLE_BACKGROUND_TASKS !== "1";
|
|
10873
|
+
const autoBackgroundAllowed = backgroundAvailableHere && isAutobackgroundingAllowed(command, DISALLOWED_AUTO_BACKGROUND_COMMANDS2);
|
|
10874
|
+
let timedOut = false;
|
|
10370
10875
|
const timeoutTimer = setTimeout(() => {
|
|
10876
|
+
if (autoBackgroundAllowed && backgroundExecution("timeout") !== null) {
|
|
10877
|
+
return;
|
|
10878
|
+
}
|
|
10371
10879
|
timedOut = true;
|
|
10372
10880
|
terminate();
|
|
10373
10881
|
}, timeout * 1e3);
|
|
@@ -10376,60 +10884,107 @@ var PowerShellTool = class {
|
|
|
10376
10884
|
if (ctx.abortSignal?.aborted) {
|
|
10377
10885
|
onAbort();
|
|
10378
10886
|
}
|
|
10887
|
+
const foregroundKey = `ps-${String(this.nextForegroundId++)}`;
|
|
10379
10888
|
const cleanup = () => {
|
|
10380
10889
|
clearTimeout(timeoutTimer);
|
|
10890
|
+
clearInterval(watchdog);
|
|
10381
10891
|
if (escalateTimer) {
|
|
10382
10892
|
clearTimeout(escalateTimer);
|
|
10383
10893
|
}
|
|
10384
10894
|
ctx.abortSignal?.removeEventListener("abort", onAbort);
|
|
10895
|
+
this.foreground.delete(foregroundKey);
|
|
10385
10896
|
};
|
|
10386
|
-
|
|
10387
|
-
|
|
10388
|
-
const hint = strArg(asRecord(err), "code") === "ENOENT" && process.platform !== "win32" ? " (pwsh is required on macOS/Linux \u2014 install PowerShell Core)" : "";
|
|
10389
|
-
resolve12({
|
|
10390
|
-
output: `Error executing command: ${err.message}${hint}`,
|
|
10391
|
-
isError: true
|
|
10392
|
-
});
|
|
10393
|
-
});
|
|
10394
|
-
child.on("close", (code, signal) => {
|
|
10395
|
-
cleanup();
|
|
10396
|
-
if (aborted) {
|
|
10397
|
-
const captured = stdout || stderr || outputTruncated ? formatShellOutput("PS> ", command, stdout, stderr, outputTruncated) : "";
|
|
10398
|
-
resolve12({
|
|
10399
|
-
output: captured ? `${captured}
|
|
10400
|
-
Error: command interrupted` : "Error: command interrupted",
|
|
10401
|
-
isError: true
|
|
10402
|
-
});
|
|
10403
|
-
return;
|
|
10404
|
-
}
|
|
10405
|
-
if (timedOut) {
|
|
10406
|
-
const captured = stdout || stderr || outputTruncated ? formatShellOutput("PS> ", command, stdout, stderr, outputTruncated) : "";
|
|
10407
|
-
resolve12({
|
|
10408
|
-
output: captured ? `${captured}
|
|
10409
|
-
Error: command timed out after ${String(timeout)}s` : `Error: command timed out after ${String(timeout)}s`,
|
|
10410
|
-
isError: true
|
|
10411
|
-
});
|
|
10897
|
+
const settle = (finalResult) => {
|
|
10898
|
+
if (settled) {
|
|
10412
10899
|
return;
|
|
10413
10900
|
}
|
|
10414
|
-
|
|
10415
|
-
|
|
10416
|
-
|
|
10417
|
-
|
|
10901
|
+
settled = true;
|
|
10902
|
+
cleanup();
|
|
10903
|
+
resolve12(finalResult);
|
|
10904
|
+
};
|
|
10905
|
+
const settleExit = (exit) => {
|
|
10906
|
+
if (backgrounded) {
|
|
10418
10907
|
return;
|
|
10419
10908
|
}
|
|
10420
|
-
|
|
10421
|
-
|
|
10422
|
-
|
|
10423
|
-
|
|
10424
|
-
|
|
10909
|
+
const read = readOutputFile(outputFile.path, MAX_SHELL_OUTPUT_BYTES);
|
|
10910
|
+
const finalResult = formatFinalResult(
|
|
10911
|
+
"PS> ",
|
|
10912
|
+
command,
|
|
10913
|
+
exit,
|
|
10914
|
+
read.text,
|
|
10915
|
+
read.truncated,
|
|
10916
|
+
timeout
|
|
10917
|
+
);
|
|
10918
|
+
unlinkQuiet(outputFile.path);
|
|
10919
|
+
settle(finalResult);
|
|
10920
|
+
};
|
|
10921
|
+
const backgroundExecution = (reason) => {
|
|
10922
|
+
if (backgrounded || settled || terminating || !manager || !backgroundAvailableHere) {
|
|
10923
|
+
return null;
|
|
10425
10924
|
}
|
|
10426
|
-
|
|
10427
|
-
|
|
10428
|
-
|
|
10925
|
+
backgrounded = true;
|
|
10926
|
+
settled = true;
|
|
10927
|
+
clearTimeout(timeoutTimer);
|
|
10928
|
+
ctx.abortSignal?.removeEventListener("abort", onAbort);
|
|
10929
|
+
this.foreground.delete(foregroundKey);
|
|
10930
|
+
const task = manager.create(
|
|
10931
|
+
backgroundTaskName(command),
|
|
10932
|
+
async () => {
|
|
10933
|
+
const exit = await done;
|
|
10934
|
+
const body = buildBackgroundBody("PS> ", command, exit, outputFile.path, timeout);
|
|
10935
|
+
if (body.isError) {
|
|
10936
|
+
throw new TaskFailure(body.output);
|
|
10937
|
+
}
|
|
10938
|
+
return body.output;
|
|
10939
|
+
},
|
|
10940
|
+
() => {
|
|
10941
|
+
killTree("SIGKILL");
|
|
10942
|
+
},
|
|
10943
|
+
{ originToolCallId: ctx.toolCallId, idPrefix: "ps", kind: "shell" }
|
|
10944
|
+
);
|
|
10945
|
+
resolve12({
|
|
10946
|
+
output: backgroundMessage(reason, task.id, timeout),
|
|
10947
|
+
isError: false
|
|
10948
|
+
});
|
|
10949
|
+
return task.id;
|
|
10950
|
+
};
|
|
10951
|
+
if (backgroundAvailableHere) {
|
|
10952
|
+
this.foreground.set(foregroundKey, {
|
|
10953
|
+
background: () => backgroundExecution("user") !== null
|
|
10954
|
+
});
|
|
10955
|
+
}
|
|
10956
|
+
const stopTimers = () => {
|
|
10957
|
+
clearInterval(watchdog);
|
|
10958
|
+
if (escalateTimer) {
|
|
10959
|
+
clearTimeout(escalateTimer);
|
|
10429
10960
|
}
|
|
10430
|
-
|
|
10961
|
+
};
|
|
10962
|
+
child.on("error", (err) => {
|
|
10963
|
+
stopTimers();
|
|
10964
|
+
const hint = strArg(asRecord(err), "code") === "ENOENT" && process.platform !== "win32" ? " (pwsh is required on macOS/Linux \u2014 install PowerShell Core)" : "";
|
|
10965
|
+
const exit = {
|
|
10966
|
+
code: null,
|
|
10967
|
+
signal: null,
|
|
10968
|
+
aborted,
|
|
10969
|
+
timedOut,
|
|
10970
|
+
sizeKilled,
|
|
10971
|
+
spawnError: `${err.message}${hint}`
|
|
10972
|
+
};
|
|
10973
|
+
doneResolve?.(exit);
|
|
10974
|
+
settleExit(exit);
|
|
10975
|
+
});
|
|
10976
|
+
child.on("close", (code, signal) => {
|
|
10977
|
+
stopTimers();
|
|
10978
|
+
const exit = { code, signal, aborted, timedOut, sizeKilled };
|
|
10979
|
+
doneResolve?.(exit);
|
|
10980
|
+
settleExit(exit);
|
|
10431
10981
|
});
|
|
10982
|
+
backgroundFn = backgroundExecution;
|
|
10432
10983
|
});
|
|
10984
|
+
return {
|
|
10985
|
+
result,
|
|
10986
|
+
background: (reason) => backgroundFn?.(reason) ?? null
|
|
10987
|
+
};
|
|
10433
10988
|
}
|
|
10434
10989
|
};
|
|
10435
10990
|
|
|
@@ -10621,7 +11176,7 @@ var AskUserResponseSchema = z15.object({
|
|
|
10621
11176
|
id: z15.string(),
|
|
10622
11177
|
answers: z15.record(z15.string(), z15.string())
|
|
10623
11178
|
});
|
|
10624
|
-
var FE_DIST =
|
|
11179
|
+
var FE_DIST = join21(import.meta.dirname, "fe", "dist");
|
|
10625
11180
|
var MIME_TYPES = {
|
|
10626
11181
|
".html": "text/html; charset=utf-8",
|
|
10627
11182
|
".js": "application/javascript; charset=utf-8",
|
|
@@ -10634,11 +11189,11 @@ var MIME_TYPES = {
|
|
|
10634
11189
|
};
|
|
10635
11190
|
function serveStatic(path) {
|
|
10636
11191
|
const cleanPath = normalize(path).replace(/^(\.\.[/\\])+/, "");
|
|
10637
|
-
const fullPath =
|
|
11192
|
+
const fullPath = join21(FE_DIST, cleanPath);
|
|
10638
11193
|
if (!fullPath.startsWith(FE_DIST)) {
|
|
10639
11194
|
return null;
|
|
10640
11195
|
}
|
|
10641
|
-
if (!existsSync16(fullPath) || !
|
|
11196
|
+
if (!existsSync16(fullPath) || !statSync12(fullPath).isFile()) {
|
|
10642
11197
|
return null;
|
|
10643
11198
|
}
|
|
10644
11199
|
const body = readFileSync16(fullPath);
|
|
@@ -10814,31 +11369,38 @@ async function createRemoteAgent(opts) {
|
|
|
10814
11369
|
if (!client) {
|
|
10815
11370
|
throw new Error("no llm client (provider not initialized)");
|
|
10816
11371
|
}
|
|
10817
|
-
const { PermissionChecker: PC } = await import("./permissions-
|
|
10818
|
-
const { Agent: AgentClass } = await import("./agent-
|
|
11372
|
+
const { PermissionChecker: PC } = await import("./permissions-77UJQITR.js");
|
|
11373
|
+
const { Agent: AgentClass } = await import("./agent-ZSFK66FQ.js");
|
|
10819
11374
|
const subConv = new ConversationManager();
|
|
10820
11375
|
subConv.addUserMessage(prompt);
|
|
11376
|
+
const taskManager = new TaskManager();
|
|
10821
11377
|
const subAgent = new AgentClass({
|
|
10822
11378
|
client,
|
|
10823
11379
|
registry: filterToolsForAgent(registry, void 0, void 0, false),
|
|
10824
11380
|
checker: new PC(workDir, "acceptEdits"),
|
|
10825
11381
|
conversation: subConv,
|
|
10826
11382
|
workDir,
|
|
10827
|
-
maxIterations: 200
|
|
11383
|
+
maxIterations: 200,
|
|
11384
|
+
taskManager,
|
|
11385
|
+
notificationFn: () => taskManager.drainNotifications().map(formatAgentTaskNotification)
|
|
10828
11386
|
});
|
|
10829
11387
|
let output = "";
|
|
10830
|
-
|
|
10831
|
-
|
|
10832
|
-
|
|
10833
|
-
|
|
10834
|
-
|
|
10835
|
-
|
|
10836
|
-
|
|
10837
|
-
|
|
10838
|
-
|
|
11388
|
+
try {
|
|
11389
|
+
for await (const event of subAgent.run()) {
|
|
11390
|
+
switch (event.type) {
|
|
11391
|
+
case "stream_text":
|
|
11392
|
+
output += event.text;
|
|
11393
|
+
break;
|
|
11394
|
+
case "loop_complete":
|
|
11395
|
+
return output || "[No output]";
|
|
11396
|
+
case "error":
|
|
11397
|
+
throw event.error;
|
|
11398
|
+
}
|
|
10839
11399
|
}
|
|
11400
|
+
return output || "[No output]";
|
|
11401
|
+
} finally {
|
|
11402
|
+
await taskManager.stopAll();
|
|
10840
11403
|
}
|
|
10841
|
-
return output || "[No output]";
|
|
10842
11404
|
}
|
|
10843
11405
|
};
|
|
10844
11406
|
registry.register(new LoadSkillTool(catalog, skillHost, skillForkHost));
|
|
@@ -10856,10 +11418,12 @@ async function createRemoteAgent(opts) {
|
|
|
10856
11418
|
onEvent,
|
|
10857
11419
|
void 0,
|
|
10858
11420
|
teamChecker,
|
|
10859
|
-
|
|
11421
|
+
// Teammates stay purely foreground: see SubagentRunOptions.backgroundTasks.
|
|
11422
|
+
{ abortSignal, backgroundTasks: false }
|
|
10860
11423
|
);
|
|
10861
11424
|
const teamManager = new TeamManager(workDir);
|
|
10862
11425
|
const backgroundTaskManager = new TaskManager();
|
|
11426
|
+
attachBackgroundTaskManager(registry, backgroundTaskManager);
|
|
10863
11427
|
registry.register(new TeamCreateTool(teamManager));
|
|
10864
11428
|
registry.register(new SendMessageTool(teamManager));
|
|
10865
11429
|
registry.register(new TeamDeleteTool(teamManager));
|
|
@@ -10898,6 +11462,7 @@ async function createRemoteAgent(opts) {
|
|
|
10898
11462
|
const forkClient = modelOverride ? await createClient({ ...provider, model: resolvedModel }, forkSystemPrompt) : client;
|
|
10899
11463
|
const checker = context?.permissionChecker ?? new PermissionChecker(forkWorkDir, "acceptEdits");
|
|
10900
11464
|
forkConv.addUserMessage(prompt);
|
|
11465
|
+
const forkTaskManager = new TaskManager();
|
|
10901
11466
|
const agent2 = new Agent({
|
|
10902
11467
|
client: forkClient,
|
|
10903
11468
|
registry: forkRegistry,
|
|
@@ -10909,23 +11474,29 @@ async function createRemoteAgent(opts) {
|
|
|
10909
11474
|
onPermissionRequest: context?.onPermissionRequest,
|
|
10910
11475
|
fileStateCache: new FileStateCache(),
|
|
10911
11476
|
instructions,
|
|
10912
|
-
memoryContent: memReminder
|
|
11477
|
+
memoryContent: memReminder,
|
|
11478
|
+
taskManager: forkTaskManager,
|
|
11479
|
+
notificationFn: () => forkTaskManager.drainNotifications().map(formatAgentTaskNotification)
|
|
10913
11480
|
});
|
|
10914
11481
|
let output = "";
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
10918
|
-
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
|
|
10923
|
-
|
|
11482
|
+
try {
|
|
11483
|
+
for await (const event of agent2.run()) {
|
|
11484
|
+
switch (event.type) {
|
|
11485
|
+
case "stream_text":
|
|
11486
|
+
output += event.text;
|
|
11487
|
+
break;
|
|
11488
|
+
case "loop_complete":
|
|
11489
|
+
return output || "[No output]";
|
|
11490
|
+
case "error":
|
|
11491
|
+
return output ? `${output}
|
|
10924
11492
|
|
|
10925
11493
|
[Error: ${event.error.message}]` : `Error: ${event.error.message}`;
|
|
11494
|
+
}
|
|
10926
11495
|
}
|
|
11496
|
+
return output || "[No output]";
|
|
11497
|
+
} finally {
|
|
11498
|
+
await forkTaskManager.stopAll();
|
|
10927
11499
|
}
|
|
10928
|
-
return output || "[No output]";
|
|
10929
11500
|
},
|
|
10930
11501
|
backgroundTaskManager
|
|
10931
11502
|
);
|
|
@@ -12423,6 +12994,7 @@ __export(javascript_exports, {
|
|
|
12423
12994
|
evaluateJavaScript: () => evaluateJavaScript,
|
|
12424
12995
|
isolatedVmSupported: () => isolatedVmSupported
|
|
12425
12996
|
});
|
|
12997
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
12426
12998
|
import { z as z16 } from "zod";
|
|
12427
12999
|
var DEFAULT_TIMEOUT_MS = 1e3;
|
|
12428
13000
|
var MAX_TIMEOUT_MS = 1e4;
|
|
@@ -12435,7 +13007,10 @@ var JavaScriptArgumentsSchema = z16.object({
|
|
|
12435
13007
|
code: z16.string().min(1),
|
|
12436
13008
|
input: z16.json().optional(),
|
|
12437
13009
|
timeout_ms: z16.number().int().min(1).max(MAX_TIMEOUT_MS).default(DEFAULT_TIMEOUT_MS),
|
|
12438
|
-
memory_limit_mb: z16.number().int().min(8).max(MAX_MEMORY_LIMIT_MB).default(DEFAULT_MEMORY_LIMIT_MB)
|
|
13010
|
+
memory_limit_mb: z16.number().int().min(8).max(MAX_MEMORY_LIMIT_MB).default(DEFAULT_MEMORY_LIMIT_MB),
|
|
13011
|
+
// Accepted even when backgrounding is unavailable (then simply ignored):
|
|
13012
|
+
// the JSON schema gates what the model sees per host.
|
|
13013
|
+
run_in_background: z16.boolean().optional()
|
|
12439
13014
|
});
|
|
12440
13015
|
var JavaScriptEvaluationOptionsSchema = z16.object({
|
|
12441
13016
|
input: z16.json().optional(),
|
|
@@ -12471,14 +13046,22 @@ async function runJavaScript(code, input, timeoutMs, memoryLimitMb, abortSignal)
|
|
|
12471
13046
|
}
|
|
12472
13047
|
abortSignal?.throwIfAborted();
|
|
12473
13048
|
const module = await import("isolated-vm");
|
|
13049
|
+
abortSignal?.throwIfAborted();
|
|
12474
13050
|
const ivm = module.default;
|
|
12475
13051
|
const isolate = new ivm.Isolate({ memoryLimit: memoryLimitMb });
|
|
12476
13052
|
const context = await isolate.createContext();
|
|
12477
13053
|
const onAbort = () => {
|
|
12478
|
-
isolate.
|
|
13054
|
+
if (!isolate.isDisposed) {
|
|
13055
|
+
isolate.dispose();
|
|
13056
|
+
}
|
|
12479
13057
|
};
|
|
12480
13058
|
abortSignal?.addEventListener("abort", onAbort, { once: true });
|
|
13059
|
+
let wallTimer;
|
|
12481
13060
|
try {
|
|
13061
|
+
if (abortSignal?.aborted) {
|
|
13062
|
+
onAbort();
|
|
13063
|
+
abortSignal.throwIfAborted();
|
|
13064
|
+
}
|
|
12482
13065
|
await context.global.set("input", input ?? null, { copy: true });
|
|
12483
13066
|
const source = `
|
|
12484
13067
|
(async () => {
|
|
@@ -12523,12 +13106,19 @@ ${code}
|
|
|
12523
13106
|
return __payload;
|
|
12524
13107
|
})()
|
|
12525
13108
|
`;
|
|
12526
|
-
const
|
|
13109
|
+
const evaluation = context.eval(source, {
|
|
12527
13110
|
timeout: timeoutMs,
|
|
12528
13111
|
promise: true,
|
|
12529
13112
|
copy: true,
|
|
12530
13113
|
filename: "swifty-sandbox.js"
|
|
12531
13114
|
});
|
|
13115
|
+
const deadline = new Promise((_, reject) => {
|
|
13116
|
+
wallTimer = setTimeout(() => {
|
|
13117
|
+
reject(new Error(`JavaScript evaluation timed out after ${String(timeoutMs)}ms`));
|
|
13118
|
+
onAbort();
|
|
13119
|
+
}, timeoutMs);
|
|
13120
|
+
});
|
|
13121
|
+
const raw = await Promise.race([evaluation, deadline]);
|
|
12532
13122
|
if (typeof raw !== "string") {
|
|
12533
13123
|
throw new Error("JavaScript sandbox returned an invalid result");
|
|
12534
13124
|
}
|
|
@@ -12538,6 +13128,7 @@ ${code}
|
|
|
12538
13128
|
const decoded = JSON.parse(raw);
|
|
12539
13129
|
return JavaScriptEvaluationSchema.parse(decoded);
|
|
12540
13130
|
} finally {
|
|
13131
|
+
clearTimeout(wallTimer);
|
|
12541
13132
|
abortSignal?.removeEventListener("abort", onAbort);
|
|
12542
13133
|
try {
|
|
12543
13134
|
context.release();
|
|
@@ -12548,37 +13139,94 @@ ${code}
|
|
|
12548
13139
|
}
|
|
12549
13140
|
}
|
|
12550
13141
|
}
|
|
13142
|
+
function formatEvaluation(result) {
|
|
13143
|
+
const sections = [];
|
|
13144
|
+
if (result.logs.length > 0) {
|
|
13145
|
+
sections.push(`Console:
|
|
13146
|
+
${result.logs.join("\n")}`);
|
|
13147
|
+
}
|
|
13148
|
+
if (result.logsTruncated) {
|
|
13149
|
+
sections.push("Console output truncated");
|
|
13150
|
+
}
|
|
13151
|
+
sections.push(`Result:
|
|
13152
|
+
${JSON.stringify(result.value, null, 2)}`);
|
|
13153
|
+
return sections.join("\n\n");
|
|
13154
|
+
}
|
|
13155
|
+
function jsBackgroundMessage(reason, taskId) {
|
|
13156
|
+
return reason === "user" ? `JavaScript evaluation was manually backgrounded by the user (task_id: ${taskId}). It is still running \u2014 you will be notified when it completes.` : `JavaScript running in background (task_id: ${taskId}). You will be notified when it completes; do not poll. Use TaskStop with task_id to abort it early.`;
|
|
13157
|
+
}
|
|
12551
13158
|
var JavaScriptTool = class {
|
|
12552
13159
|
name = "JavaScript";
|
|
12553
13160
|
description = JAVASCRIPT_DESCRIPTION;
|
|
12554
13161
|
category = "command";
|
|
13162
|
+
/**
|
|
13163
|
+
* Background task registry, injected by the host — same contract as
|
|
13164
|
+
* BashTool.taskManager. Unlike the shell tools there is no timeout
|
|
13165
|
+
* auto-background: timeout_ms is the isolate's hard safety cap — V8 kills a
|
|
13166
|
+
* synchronous script at the cap, and a wall-clock deadline disposes the
|
|
13167
|
+
* isolate when an evaluation is suspended on a promise — so nothing is left
|
|
13168
|
+
* to keep running.
|
|
13169
|
+
*/
|
|
13170
|
+
taskManager = null;
|
|
13171
|
+
/** Running foreground evaluations eligible for manual backgrounding (Ctrl+B). */
|
|
13172
|
+
foreground = /* @__PURE__ */ new Map();
|
|
13173
|
+
nextForegroundId = 1;
|
|
13174
|
+
/** Instance-level background gate; see BashTool.backgroundEnabled. */
|
|
13175
|
+
backgroundEnabled() {
|
|
13176
|
+
return this.taskManager !== null && process.env.SWIFTY_DISABLE_BACKGROUND_TASKS !== "1";
|
|
13177
|
+
}
|
|
13178
|
+
/** True while at least one foreground evaluation runs. */
|
|
13179
|
+
hasForegroundTasks() {
|
|
13180
|
+
return this.foreground.size > 0;
|
|
13181
|
+
}
|
|
13182
|
+
/** Move every running foreground evaluation to the background (Ctrl+B). */
|
|
13183
|
+
backgroundForegroundTasks() {
|
|
13184
|
+
let count = 0;
|
|
13185
|
+
for (const entry of [...this.foreground.values()]) {
|
|
13186
|
+
if (entry.background()) {
|
|
13187
|
+
count++;
|
|
13188
|
+
}
|
|
13189
|
+
}
|
|
13190
|
+
return count;
|
|
13191
|
+
}
|
|
12555
13192
|
schema() {
|
|
13193
|
+
const properties = {
|
|
13194
|
+
code: {
|
|
13195
|
+
type: "string",
|
|
13196
|
+
description: "JavaScript function body to execute; use return to produce a result"
|
|
13197
|
+
},
|
|
13198
|
+
input: {
|
|
13199
|
+
description: "Optional JSON-compatible value exposed as globalThis.input"
|
|
13200
|
+
},
|
|
13201
|
+
timeout_ms: {
|
|
13202
|
+
type: "integer",
|
|
13203
|
+
minimum: 1,
|
|
13204
|
+
maximum: MAX_TIMEOUT_MS,
|
|
13205
|
+
default: DEFAULT_TIMEOUT_MS
|
|
13206
|
+
},
|
|
13207
|
+
memory_limit_mb: {
|
|
13208
|
+
type: "integer",
|
|
13209
|
+
minimum: 8,
|
|
13210
|
+
maximum: MAX_MEMORY_LIMIT_MB,
|
|
13211
|
+
default: DEFAULT_MEMORY_LIMIT_MB
|
|
13212
|
+
}
|
|
13213
|
+
};
|
|
13214
|
+
let description = this.description;
|
|
13215
|
+
if (this.backgroundEnabled()) {
|
|
13216
|
+
properties.run_in_background = {
|
|
13217
|
+
type: "boolean",
|
|
13218
|
+
description: "Run the evaluation in the background. Returns a task ID immediately; the result arrives later as a task notification.",
|
|
13219
|
+
default: false
|
|
13220
|
+
};
|
|
13221
|
+
description = `${this.description}
|
|
13222
|
+
${JAVASCRIPT_BACKGROUND_DESCRIPTION}`;
|
|
13223
|
+
}
|
|
12556
13224
|
return {
|
|
12557
13225
|
name: this.name,
|
|
12558
|
-
description
|
|
13226
|
+
description,
|
|
12559
13227
|
input_schema: {
|
|
12560
13228
|
type: "object",
|
|
12561
|
-
properties
|
|
12562
|
-
code: {
|
|
12563
|
-
type: "string",
|
|
12564
|
-
description: "JavaScript function body to execute; use return to produce a result"
|
|
12565
|
-
},
|
|
12566
|
-
input: {
|
|
12567
|
-
description: "Optional JSON-compatible value exposed as globalThis.input"
|
|
12568
|
-
},
|
|
12569
|
-
timeout_ms: {
|
|
12570
|
-
type: "integer",
|
|
12571
|
-
minimum: 1,
|
|
12572
|
-
maximum: MAX_TIMEOUT_MS,
|
|
12573
|
-
default: DEFAULT_TIMEOUT_MS
|
|
12574
|
-
},
|
|
12575
|
-
memory_limit_mb: {
|
|
12576
|
-
type: "integer",
|
|
12577
|
-
minimum: 8,
|
|
12578
|
-
maximum: MAX_MEMORY_LIMIT_MB,
|
|
12579
|
-
default: DEFAULT_MEMORY_LIMIT_MB
|
|
12580
|
-
}
|
|
12581
|
-
},
|
|
13229
|
+
properties,
|
|
12582
13230
|
required: ["code"],
|
|
12583
13231
|
additionalProperties: false
|
|
12584
13232
|
}
|
|
@@ -12589,32 +13237,128 @@ var JavaScriptTool = class {
|
|
|
12589
13237
|
if (!parsed.success) {
|
|
12590
13238
|
return { output: `Error: ${parsed.error.message}`, isError: true };
|
|
12591
13239
|
}
|
|
12592
|
-
|
|
12593
|
-
|
|
12594
|
-
|
|
12595
|
-
|
|
12596
|
-
|
|
12597
|
-
|
|
12598
|
-
|
|
12599
|
-
|
|
12600
|
-
|
|
12601
|
-
|
|
12602
|
-
|
|
12603
|
-
${result.logs.join("\n")}`);
|
|
12604
|
-
}
|
|
12605
|
-
if (result.logsTruncated) {
|
|
12606
|
-
sections.push("Console output truncated");
|
|
13240
|
+
const manager = ctx.taskManager !== void 0 ? ctx.taskManager : this.taskManager;
|
|
13241
|
+
const backgroundAvailable = manager !== null && process.env.SWIFTY_DISABLE_BACKGROUND_TASKS !== "1";
|
|
13242
|
+
const runInBackground = parsed.data.run_in_background === true && backgroundAvailable;
|
|
13243
|
+
const handle = this.startEvaluation(ctx, parsed.data, manager, backgroundAvailable);
|
|
13244
|
+
if (runInBackground) {
|
|
13245
|
+
const taskId = handle.background("explicit");
|
|
13246
|
+
if (taskId !== null) {
|
|
13247
|
+
return {
|
|
13248
|
+
output: jsBackgroundMessage("explicit", taskId),
|
|
13249
|
+
isError: false
|
|
13250
|
+
};
|
|
12607
13251
|
}
|
|
12608
|
-
sections.push(`Result:
|
|
12609
|
-
${JSON.stringify(result.value, null, 2)}`);
|
|
12610
|
-
return { output: sections.join("\n\n"), isError: false };
|
|
12611
|
-
} catch (error) {
|
|
12612
|
-
return { output: `Error executing JavaScript: ${asErrorString(error)}`, isError: true };
|
|
12613
13252
|
}
|
|
13253
|
+
return handle.result;
|
|
13254
|
+
}
|
|
13255
|
+
/**
|
|
13256
|
+
* Start the isolated evaluation. The returned handle mirrors the shell
|
|
13257
|
+
* tools: background() transitions the pending evaluation into a TaskManager
|
|
13258
|
+
* task — the isolate keeps running on its own thread, the tool call
|
|
13259
|
+
* resolves immediately, and completion arrives as a task notification.
|
|
13260
|
+
* While foreground, the caller's abort signal (Esc) disposes the isolate;
|
|
13261
|
+
* once backgrounded, only TaskStop or session shutdown can abort it.
|
|
13262
|
+
*/
|
|
13263
|
+
startEvaluation(ctx, data, manager, backgroundAvailable) {
|
|
13264
|
+
let backgroundFn;
|
|
13265
|
+
const result = new Promise((resolve12) => {
|
|
13266
|
+
let settled = false;
|
|
13267
|
+
let backgrounded = false;
|
|
13268
|
+
const controller = new AbortController();
|
|
13269
|
+
const onCallerAbort = () => {
|
|
13270
|
+
controller.abort();
|
|
13271
|
+
};
|
|
13272
|
+
if (ctx.abortSignal?.aborted) {
|
|
13273
|
+
resolve12({ output: "Error: command interrupted", isError: true });
|
|
13274
|
+
return;
|
|
13275
|
+
}
|
|
13276
|
+
ctx.abortSignal?.addEventListener("abort", onCallerAbort, { once: true });
|
|
13277
|
+
const evalPromise = runJavaScript(
|
|
13278
|
+
data.code,
|
|
13279
|
+
data.input,
|
|
13280
|
+
data.timeout_ms,
|
|
13281
|
+
data.memory_limit_mb,
|
|
13282
|
+
controller.signal
|
|
13283
|
+
);
|
|
13284
|
+
const foregroundKey = `js-${String(this.nextForegroundId++)}`;
|
|
13285
|
+
const settle = (finalResult) => {
|
|
13286
|
+
if (settled) {
|
|
13287
|
+
return;
|
|
13288
|
+
}
|
|
13289
|
+
settled = true;
|
|
13290
|
+
ctx.abortSignal?.removeEventListener("abort", onCallerAbort);
|
|
13291
|
+
this.foreground.delete(foregroundKey);
|
|
13292
|
+
resolve12(finalResult);
|
|
13293
|
+
};
|
|
13294
|
+
const backgroundExecution = (reason) => {
|
|
13295
|
+
if (backgrounded || settled || controller.signal.aborted || !manager || !backgroundAvailable) {
|
|
13296
|
+
return null;
|
|
13297
|
+
}
|
|
13298
|
+
backgrounded = true;
|
|
13299
|
+
settled = true;
|
|
13300
|
+
ctx.abortSignal?.removeEventListener("abort", onCallerAbort);
|
|
13301
|
+
this.foreground.delete(foregroundKey);
|
|
13302
|
+
const task = manager.create(
|
|
13303
|
+
backgroundTaskName(data.code),
|
|
13304
|
+
async (backgroundTask) => {
|
|
13305
|
+
const cap = (text) => text.length > BACKGROUND_NOTIFICATION_CHARS ? persistLargeResult(
|
|
13306
|
+
ctx.workDir,
|
|
13307
|
+
ctx.sessionId ?? "",
|
|
13308
|
+
`${backgroundTask.id}-${randomBytes4(4).toString("hex")}`,
|
|
13309
|
+
text
|
|
13310
|
+
) : text;
|
|
13311
|
+
try {
|
|
13312
|
+
const evaluation = await evalPromise;
|
|
13313
|
+
return cap(formatEvaluation(evaluation));
|
|
13314
|
+
} catch (error) {
|
|
13315
|
+
if (backgroundTask.status === "cancelled") {
|
|
13316
|
+
throw error;
|
|
13317
|
+
}
|
|
13318
|
+
throw new TaskFailure(cap(`Error executing JavaScript: ${asErrorString(error)}`));
|
|
13319
|
+
}
|
|
13320
|
+
},
|
|
13321
|
+
() => {
|
|
13322
|
+
controller.abort();
|
|
13323
|
+
},
|
|
13324
|
+
{ originToolCallId: ctx.toolCallId, idPrefix: "js", kind: "js" }
|
|
13325
|
+
);
|
|
13326
|
+
resolve12({
|
|
13327
|
+
output: jsBackgroundMessage(reason, task.id),
|
|
13328
|
+
isError: false
|
|
13329
|
+
});
|
|
13330
|
+
return task.id;
|
|
13331
|
+
};
|
|
13332
|
+
if (backgroundAvailable) {
|
|
13333
|
+
this.foreground.set(foregroundKey, {
|
|
13334
|
+
background: () => backgroundExecution("user") !== null
|
|
13335
|
+
});
|
|
13336
|
+
}
|
|
13337
|
+
evalPromise.then(
|
|
13338
|
+
(evaluation) => {
|
|
13339
|
+
settle({ output: formatEvaluation(evaluation), isError: false });
|
|
13340
|
+
},
|
|
13341
|
+
(error) => {
|
|
13342
|
+
settle({
|
|
13343
|
+
output: `Error executing JavaScript: ${asErrorString(error)}`,
|
|
13344
|
+
isError: true
|
|
13345
|
+
});
|
|
13346
|
+
}
|
|
13347
|
+
);
|
|
13348
|
+
backgroundFn = backgroundExecution;
|
|
13349
|
+
});
|
|
13350
|
+
return {
|
|
13351
|
+
result,
|
|
13352
|
+
background: (reason) => backgroundFn?.(reason) ?? null
|
|
13353
|
+
};
|
|
12614
13354
|
}
|
|
12615
13355
|
};
|
|
12616
13356
|
|
|
12617
13357
|
// src/tools/web-fetch.ts
|
|
13358
|
+
var web_fetch_exports = {};
|
|
13359
|
+
__export(web_fetch_exports, {
|
|
13360
|
+
WebFetchTool: () => WebFetchTool
|
|
13361
|
+
});
|
|
12618
13362
|
var log27 = createChildLogger({ module: "tools" });
|
|
12619
13363
|
var MAX_CONTENT_BYTES = 10 * 1024 * 1024;
|
|
12620
13364
|
var FETCH_TIMEOUT_MS = 6e4;
|
|
@@ -13615,8 +14359,8 @@ __export(manager_exports3, {
|
|
|
13615
14359
|
CodeReviewManager: () => CodeReviewManager,
|
|
13616
14360
|
createDefaultCodeReviewTeam: () => createDefaultCodeReviewTeam
|
|
13617
14361
|
});
|
|
13618
|
-
import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, existsSync as existsSync18, mkdirSync as
|
|
13619
|
-
import { join as
|
|
14362
|
+
import { readFileSync as readFileSync17, writeFileSync as writeFileSync11, existsSync as existsSync18, mkdirSync as mkdirSync13 } from "fs";
|
|
14363
|
+
import { join as join22 } from "path";
|
|
13620
14364
|
import z17 from "zod";
|
|
13621
14365
|
var log30 = createChildLogger({ module: "code-review" });
|
|
13622
14366
|
var CodeReviewMemberSchema = z17.object({
|
|
@@ -13639,7 +14383,7 @@ var CodeReviewManager = class {
|
|
|
13639
14383
|
workDir;
|
|
13640
14384
|
constructor(workDir, teamManager) {
|
|
13641
14385
|
this.workDir = workDir;
|
|
13642
|
-
this.configPath =
|
|
14386
|
+
this.configPath = join22(workDir, ".swifty", "code-review-teams.json");
|
|
13643
14387
|
this.teamManager = teamManager;
|
|
13644
14388
|
this.loadTeams();
|
|
13645
14389
|
}
|
|
@@ -13658,9 +14402,9 @@ var CodeReviewManager = class {
|
|
|
13658
14402
|
}
|
|
13659
14403
|
}
|
|
13660
14404
|
saveTeams() {
|
|
13661
|
-
const dir =
|
|
14405
|
+
const dir = join22(this.workDir, ".swifty");
|
|
13662
14406
|
if (!existsSync18(dir)) {
|
|
13663
|
-
|
|
14407
|
+
mkdirSync13(dir, { recursive: true });
|
|
13664
14408
|
}
|
|
13665
14409
|
const teams = [...this.teams.values()];
|
|
13666
14410
|
writeFileSync11(this.configPath, JSON.stringify(teams, null, 2));
|
|
@@ -13806,8 +14550,8 @@ var usage_tracker_exports = {};
|
|
|
13806
14550
|
__export(usage_tracker_exports, {
|
|
13807
14551
|
CommandUsageTracker: () => CommandUsageTracker
|
|
13808
14552
|
});
|
|
13809
|
-
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as
|
|
13810
|
-
import { join as
|
|
14553
|
+
import { readFileSync as readFileSync18, writeFileSync as writeFileSync12, mkdirSync as mkdirSync14, existsSync as existsSync19 } from "fs";
|
|
14554
|
+
import { join as join23, dirname as dirname9 } from "path";
|
|
13811
14555
|
import { safeParse as safeParse3, z as z18 } from "zod";
|
|
13812
14556
|
var log31 = createChildLogger({ module: "commands" });
|
|
13813
14557
|
var UsageEntrySchema = z18.object({
|
|
@@ -13818,10 +14562,10 @@ var CommandUsageTracker = class {
|
|
|
13818
14562
|
usage = /* @__PURE__ */ new Map();
|
|
13819
14563
|
filePath;
|
|
13820
14564
|
constructor(workDir) {
|
|
13821
|
-
const dir =
|
|
13822
|
-
this.filePath =
|
|
14565
|
+
const dir = join23(workDir, ".swifty");
|
|
14566
|
+
this.filePath = join23(dir, "command_usage.json");
|
|
13823
14567
|
if (!existsSync19(dir)) {
|
|
13824
|
-
|
|
14568
|
+
mkdirSync14(dir, { recursive: true });
|
|
13825
14569
|
}
|
|
13826
14570
|
this.load();
|
|
13827
14571
|
}
|
|
@@ -13862,7 +14606,7 @@ var CommandUsageTracker = class {
|
|
|
13862
14606
|
}
|
|
13863
14607
|
save() {
|
|
13864
14608
|
try {
|
|
13865
|
-
|
|
14609
|
+
mkdirSync14(dirname9(this.filePath), { recursive: true });
|
|
13866
14610
|
writeFileSync12(this.filePath, JSON.stringify(Object.fromEntries(this.usage), null, 2));
|
|
13867
14611
|
} catch (err) {
|
|
13868
14612
|
log31.error({ err }, "commands operation failed");
|
|
@@ -13885,15 +14629,15 @@ __export(history_exports, {
|
|
|
13885
14629
|
append: () => append,
|
|
13886
14630
|
load: () => load
|
|
13887
14631
|
});
|
|
13888
|
-
import { readFileSync as readFileSync19, writeFileSync as writeFileSync13, mkdirSync as
|
|
13889
|
-
import { join as
|
|
14632
|
+
import { readFileSync as readFileSync19, writeFileSync as writeFileSync13, mkdirSync as mkdirSync15, existsSync as existsSync20 } from "fs";
|
|
14633
|
+
import { join as join24 } from "path";
|
|
13890
14634
|
import { parse as parse8, z as z19 } from "zod";
|
|
13891
14635
|
var log32 = createChildLogger({ module: "history" });
|
|
13892
14636
|
var MAX_HISTORY_ENTRIES = 200;
|
|
13893
14637
|
var FILENAME = "prompt_history.jsonl";
|
|
13894
14638
|
var JSONLSchema = z19.looseObject({ text: z19.string() });
|
|
13895
14639
|
function load(dir) {
|
|
13896
|
-
const filePath =
|
|
14640
|
+
const filePath = join24(dir, FILENAME);
|
|
13897
14641
|
if (!existsSync20(filePath)) {
|
|
13898
14642
|
return [];
|
|
13899
14643
|
}
|
|
@@ -13915,8 +14659,8 @@ function load(dir) {
|
|
|
13915
14659
|
}
|
|
13916
14660
|
}
|
|
13917
14661
|
function append(dir, text) {
|
|
13918
|
-
const filePath =
|
|
13919
|
-
|
|
14662
|
+
const filePath = join24(dir, FILENAME);
|
|
14663
|
+
mkdirSync15(dir, { recursive: true });
|
|
13920
14664
|
const entries = load(dir);
|
|
13921
14665
|
if (entries.length === 0 || entries[entries.length - 1] !== text) {
|
|
13922
14666
|
entries.push(text);
|
|
@@ -14132,17 +14876,17 @@ __export(install_tool_exports, {
|
|
|
14132
14876
|
});
|
|
14133
14877
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
14134
14878
|
import {
|
|
14135
|
-
mkdirSync as
|
|
14879
|
+
mkdirSync as mkdirSync16,
|
|
14136
14880
|
writeFileSync as writeFileSync14,
|
|
14137
14881
|
readFileSync as readFileSync20,
|
|
14138
14882
|
lstatSync,
|
|
14139
14883
|
realpathSync,
|
|
14140
|
-
openSync as
|
|
14141
|
-
closeSync as
|
|
14884
|
+
openSync as openSync3,
|
|
14885
|
+
closeSync as closeSync3,
|
|
14142
14886
|
renameSync as renameSync2,
|
|
14143
14887
|
rmSync as rmSync2
|
|
14144
14888
|
} from "fs";
|
|
14145
|
-
import { join as
|
|
14889
|
+
import { join as join25, resolve as resolve10 } from "path";
|
|
14146
14890
|
import yaml7 from "js-yaml";
|
|
14147
14891
|
var log33 = createChildLogger({ module: "skills" });
|
|
14148
14892
|
var InstallSkillTool = class {
|
|
@@ -14234,28 +14978,28 @@ ${parsed.body}
|
|
|
14234
14978
|
ctx.abortSignal?.throwIfAborted();
|
|
14235
14979
|
let dir = realpathSync(this.workDir);
|
|
14236
14980
|
for (const segment of [".agents", "skills", name]) {
|
|
14237
|
-
dir =
|
|
14981
|
+
dir = join25(dir, segment);
|
|
14238
14982
|
const stat4 = lstatSync(dir, { throwIfNoEntry: false });
|
|
14239
14983
|
if (stat4) {
|
|
14240
14984
|
if (stat4.isSymbolicLink() || !stat4.isDirectory()) {
|
|
14241
14985
|
throw new Error(`Installation directory must be a real directory: ${dir}`);
|
|
14242
14986
|
}
|
|
14243
14987
|
} else {
|
|
14244
|
-
|
|
14988
|
+
mkdirSync16(dir);
|
|
14245
14989
|
}
|
|
14246
14990
|
}
|
|
14247
|
-
const destination =
|
|
14991
|
+
const destination = join25(dir, "SKILL.md");
|
|
14248
14992
|
const stat3 = lstatSync(destination, { throwIfNoEntry: false });
|
|
14249
14993
|
if (stat3 && (stat3.isSymbolicLink() || !stat3.isFile())) {
|
|
14250
14994
|
throw new Error(`Installation target must be a regular file: ${destination}`);
|
|
14251
14995
|
}
|
|
14252
|
-
const temporary =
|
|
14253
|
-
const fd =
|
|
14996
|
+
const temporary = join25(dir, `.SKILL-${randomUUID2()}.tmp`);
|
|
14997
|
+
const fd = openSync3(temporary, "wx", stat3?.mode ?? 438);
|
|
14254
14998
|
try {
|
|
14255
14999
|
try {
|
|
14256
15000
|
writeFileSync14(fd, content, "utf-8");
|
|
14257
15001
|
} finally {
|
|
14258
|
-
|
|
15002
|
+
closeSync3(fd);
|
|
14259
15003
|
}
|
|
14260
15004
|
renameSync2(temporary, destination);
|
|
14261
15005
|
} finally {
|
|
@@ -14298,6 +15042,7 @@ __export(tools_exports3, {
|
|
|
14298
15042
|
Diff: () => diff_exports,
|
|
14299
15043
|
EditFile: () => edit_file_exports,
|
|
14300
15044
|
EnterWorktree: () => enter_worktree_exports,
|
|
15045
|
+
ExitCodeHints: () => exit_code_hints_exports,
|
|
14301
15046
|
ExitPlanMode: () => exit_plan_mode_exports,
|
|
14302
15047
|
ExitWorktree: () => exit_worktree_exports,
|
|
14303
15048
|
FileMutationQueue: () => file_mutation_queue_exports,
|
|
@@ -14310,11 +15055,13 @@ __export(tools_exports3, {
|
|
|
14310
15055
|
PowerShell: () => powershell_exports,
|
|
14311
15056
|
ReadFile: () => read_file_exports,
|
|
14312
15057
|
Registry: () => registry_exports,
|
|
15058
|
+
ShellBackground: () => shell_background_exports,
|
|
14313
15059
|
ShellOutput: () => shell_output_exports,
|
|
14314
15060
|
Snippets: () => snippets_exports,
|
|
14315
15061
|
SyntheticOutput: () => synthetic_output_exports,
|
|
14316
15062
|
ToolSearch: () => tool_search_exports,
|
|
14317
15063
|
Types: () => types_exports,
|
|
15064
|
+
WebFetchTool: () => web_fetch_exports,
|
|
14318
15065
|
WriteFile: () => write_file_exports
|
|
14319
15066
|
});
|
|
14320
15067
|
|
|
@@ -14327,262 +15074,13 @@ function isDiffTool(toolName) {
|
|
|
14327
15074
|
return toolName === "EditFile";
|
|
14328
15075
|
}
|
|
14329
15076
|
|
|
14330
|
-
// src/
|
|
14331
|
-
var
|
|
14332
|
-
__export(
|
|
14333
|
-
|
|
14334
|
-
|
|
14335
|
-
|
|
14336
|
-
UseTeammateStates: () => use_teammate_states_exports
|
|
14337
|
-
});
|
|
14338
|
-
|
|
14339
|
-
// src/ui/styles.ts
|
|
14340
|
-
var styles_exports = {};
|
|
14341
|
-
__export(styles_exports, {
|
|
14342
|
-
DARK_THEME: () => DARK_THEME,
|
|
14343
|
-
ICONS: () => ICONS,
|
|
14344
|
-
LIGHT_THEME: () => LIGHT_THEME,
|
|
14345
|
-
THEME: () => THEME,
|
|
14346
|
-
activityStatusColor: () => activityStatusColor,
|
|
14347
|
-
setThemeMode: () => setThemeMode,
|
|
14348
|
-
thinkingLevelColor: () => thinkingLevelColor
|
|
14349
|
-
});
|
|
14350
|
-
var DARK_THEME = {
|
|
14351
|
-
accent: "#8abeb7",
|
|
14352
|
-
bashMode: "#b5bd68",
|
|
14353
|
-
border: "#5f87ff",
|
|
14354
|
-
borderAccent: "#00d7ff",
|
|
14355
|
-
borderMuted: "#505050",
|
|
14356
|
-
customMessageBg: "#2d2838",
|
|
14357
|
-
customMessageLabel: "#9575cd",
|
|
14358
|
-
dim: "#666666",
|
|
14359
|
-
error: "#cc6666",
|
|
14360
|
-
mdCode: "#8abeb7",
|
|
14361
|
-
mdCodeBlock: "#b5bd68",
|
|
14362
|
-
mdCodeBlockBorder: "#808080",
|
|
14363
|
-
mdHeading: "#f0c674",
|
|
14364
|
-
mdHr: "#808080",
|
|
14365
|
-
mdLink: "#81a2be",
|
|
14366
|
-
mdLinkUrl: "#666666",
|
|
14367
|
-
mdListBullet: "#8abeb7",
|
|
14368
|
-
mdQuote: "#808080",
|
|
14369
|
-
mdQuoteBorder: "#808080",
|
|
14370
|
-
muted: "#808080",
|
|
14371
|
-
searchMatchBg: "#3a3a4a",
|
|
14372
|
-
searchMatchText: "#d4d4d4",
|
|
14373
|
-
selectedBg: "#3a3a4a",
|
|
14374
|
-
success: "#b5bd68",
|
|
14375
|
-
syntaxComment: "#6A9955",
|
|
14376
|
-
syntaxFunction: "#DCDCAA",
|
|
14377
|
-
syntaxKeyword: "#569CD6",
|
|
14378
|
-
syntaxNumber: "#B5CEA8",
|
|
14379
|
-
syntaxOperator: "#D4D4D4",
|
|
14380
|
-
syntaxPunctuation: "#D4D4D4",
|
|
14381
|
-
syntaxString: "#CE9178",
|
|
14382
|
-
syntaxType: "#4EC9B0",
|
|
14383
|
-
syntaxVariable: "#9CDCFE",
|
|
14384
|
-
text: "#d4d4d4",
|
|
14385
|
-
thinking: "#808080",
|
|
14386
|
-
thinkingText: "#808080",
|
|
14387
|
-
thinkingHigh: "#b294bb",
|
|
14388
|
-
thinkingLow: "#5f87af",
|
|
14389
|
-
thinkingMax: "#ff5fff",
|
|
14390
|
-
thinkingMedium: "#81a2be",
|
|
14391
|
-
thinkingMinimal: "#6e6e6e",
|
|
14392
|
-
thinkingOff: "#505050",
|
|
14393
|
-
thinkingXHigh: "#d183e8",
|
|
14394
|
-
toolDiffAdded: "#b5bd68",
|
|
14395
|
-
toolDiffContext: "#808080",
|
|
14396
|
-
toolDiffRemoved: "#cc6666",
|
|
14397
|
-
toolErrorBg: "#3c2828",
|
|
14398
|
-
toolOutput: "#808080",
|
|
14399
|
-
toolPendingBg: "#282832",
|
|
14400
|
-
toolSuccessBg: "#283228",
|
|
14401
|
-
toolTitle: "#d4d4d4",
|
|
14402
|
-
customMessageText: "#d4d4d4",
|
|
14403
|
-
userMessageText: "#d4d4d4",
|
|
14404
|
-
userMessageBg: "#343541",
|
|
14405
|
-
warning: "#ffff00"
|
|
14406
|
-
};
|
|
14407
|
-
var LIGHT_THEME = {
|
|
14408
|
-
accent: "#5a8080",
|
|
14409
|
-
bashMode: "#588458",
|
|
14410
|
-
border: "#547da7",
|
|
14411
|
-
borderAccent: "#5a8080",
|
|
14412
|
-
borderMuted: "#b0b0b0",
|
|
14413
|
-
customMessageBg: "#ede7f6",
|
|
14414
|
-
customMessageLabel: "#7e57c2",
|
|
14415
|
-
dim: "#767676",
|
|
14416
|
-
error: "#aa5555",
|
|
14417
|
-
mdCode: "#5a8080",
|
|
14418
|
-
mdCodeBlock: "#588458",
|
|
14419
|
-
mdCodeBlockBorder: "#6c6c6c",
|
|
14420
|
-
mdHeading: "#9a7326",
|
|
14421
|
-
mdHr: "#6c6c6c",
|
|
14422
|
-
mdLink: "#547da7",
|
|
14423
|
-
mdLinkUrl: "#767676",
|
|
14424
|
-
mdListBullet: "#588458",
|
|
14425
|
-
mdQuote: "#6c6c6c",
|
|
14426
|
-
mdQuoteBorder: "#6c6c6c",
|
|
14427
|
-
muted: "#6c6c6c",
|
|
14428
|
-
searchMatchBg: "#d0d0e0",
|
|
14429
|
-
searchMatchText: "#1f2328",
|
|
14430
|
-
selectedBg: "#d0d0e0",
|
|
14431
|
-
success: "#588458",
|
|
14432
|
-
syntaxComment: "#008000",
|
|
14433
|
-
syntaxFunction: "#795E26",
|
|
14434
|
-
syntaxKeyword: "#0000FF",
|
|
14435
|
-
syntaxNumber: "#098658",
|
|
14436
|
-
syntaxOperator: "#000000",
|
|
14437
|
-
syntaxPunctuation: "#000000",
|
|
14438
|
-
syntaxString: "#A31515",
|
|
14439
|
-
syntaxType: "#267F99",
|
|
14440
|
-
syntaxVariable: "#001080",
|
|
14441
|
-
text: "#1f2328",
|
|
14442
|
-
thinking: "#6c6c6c",
|
|
14443
|
-
thinkingText: "#6c6c6c",
|
|
14444
|
-
thinkingHigh: "#875f87",
|
|
14445
|
-
thinkingLow: "#547da7",
|
|
14446
|
-
thinkingMax: "#af005f",
|
|
14447
|
-
thinkingMedium: "#5a8080",
|
|
14448
|
-
thinkingMinimal: "#767676",
|
|
14449
|
-
thinkingOff: "#b0b0b0",
|
|
14450
|
-
thinkingXHigh: "#8b008b",
|
|
14451
|
-
toolDiffAdded: "#588458",
|
|
14452
|
-
toolDiffContext: "#6c6c6c",
|
|
14453
|
-
toolDiffRemoved: "#aa5555",
|
|
14454
|
-
toolErrorBg: "#f0e8e8",
|
|
14455
|
-
toolOutput: "#6c6c6c",
|
|
14456
|
-
toolPendingBg: "#e8e8f0",
|
|
14457
|
-
toolSuccessBg: "#e8f0e8",
|
|
14458
|
-
toolTitle: "#1f2328",
|
|
14459
|
-
customMessageText: "#1f2328",
|
|
14460
|
-
userMessageText: "#1f2328",
|
|
14461
|
-
userMessageBg: "#e8e8e8",
|
|
14462
|
-
warning: "#9a7326"
|
|
14463
|
-
};
|
|
14464
|
-
var THEME = { ...DARK_THEME };
|
|
14465
|
-
function setThemeMode(mode) {
|
|
14466
|
-
Object.assign(THEME, mode === "light" ? LIGHT_THEME : DARK_THEME);
|
|
14467
|
-
}
|
|
14468
|
-
function thinkingLevelColor(level) {
|
|
14469
|
-
switch (level) {
|
|
14470
|
-
case "off":
|
|
14471
|
-
return THEME.thinkingOff;
|
|
14472
|
-
case "minimal":
|
|
14473
|
-
return THEME.thinkingMinimal;
|
|
14474
|
-
case "low":
|
|
14475
|
-
return THEME.thinkingLow;
|
|
14476
|
-
case "medium":
|
|
14477
|
-
return THEME.thinkingMedium;
|
|
14478
|
-
case "high":
|
|
14479
|
-
return THEME.thinkingHigh;
|
|
14480
|
-
case "xhigh":
|
|
14481
|
-
return THEME.thinkingXHigh;
|
|
14482
|
-
case "max":
|
|
14483
|
-
return THEME.thinkingMax;
|
|
14484
|
-
}
|
|
14485
|
-
}
|
|
14486
|
-
function activityStatusColor(status) {
|
|
14487
|
-
switch (status) {
|
|
14488
|
-
case "working":
|
|
14489
|
-
return THEME.thinkingHigh;
|
|
14490
|
-
case "retry":
|
|
14491
|
-
return THEME.warning;
|
|
14492
|
-
case "compacting":
|
|
14493
|
-
return THEME.accent;
|
|
14494
|
-
case "error":
|
|
14495
|
-
return THEME.error;
|
|
14496
|
-
case "idle":
|
|
14497
|
-
return THEME.borderMuted;
|
|
14498
|
-
}
|
|
14499
|
-
}
|
|
14500
|
-
var ICONS = {
|
|
14501
|
-
active: "\u25C9",
|
|
14502
|
-
arrow: "\u2192",
|
|
14503
|
-
branch: "\u251C\u2500",
|
|
14504
|
-
collapsed: "\u229E",
|
|
14505
|
-
expanded: "\u229F",
|
|
14506
|
-
inactive: "\u25CB",
|
|
14507
|
-
lastBranch: "\u2514\u2500",
|
|
14508
|
-
prompt: ">",
|
|
14509
|
-
success: "\u2713",
|
|
14510
|
-
tree: "\u2502"
|
|
14511
|
-
};
|
|
14512
|
-
|
|
14513
|
-
// src/ui/use-follow-up-queue.ts
|
|
14514
|
-
var use_follow_up_queue_exports = {};
|
|
14515
|
-
__export(use_follow_up_queue_exports, {
|
|
14516
|
-
useFollowUpQueue: () => useFollowUpQueue
|
|
14517
|
-
});
|
|
14518
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
14519
|
-
function useFollowUpQueue({ blocked, send, onError }) {
|
|
14520
|
-
const pending = useRef([]);
|
|
14521
|
-
const active = useRef(false);
|
|
14522
|
-
const mounted = useRef(true);
|
|
14523
|
-
const callbacks = useRef({ send, onError });
|
|
14524
|
-
callbacks.current = { send, onError };
|
|
14525
|
-
const [messages, setMessages] = useState([]);
|
|
14526
|
-
const [processing, setProcessing] = useState(false);
|
|
14527
|
-
const [paused, setPaused] = useState(false);
|
|
14528
|
-
useEffect(() => {
|
|
14529
|
-
mounted.current = true;
|
|
14530
|
-
return () => {
|
|
14531
|
-
mounted.current = false;
|
|
14532
|
-
};
|
|
14533
|
-
}, []);
|
|
14534
|
-
const enqueue = useCallback((message) => {
|
|
14535
|
-
if (!message.trim()) {
|
|
14536
|
-
return;
|
|
14537
|
-
}
|
|
14538
|
-
pending.current = [...pending.current, message];
|
|
14539
|
-
setMessages(pending.current);
|
|
14540
|
-
setPaused(false);
|
|
14541
|
-
}, []);
|
|
14542
|
-
const takeLast = useCallback(() => {
|
|
14543
|
-
const message = pending.current.at(-1);
|
|
14544
|
-
if (message === void 0) {
|
|
14545
|
-
return void 0;
|
|
14546
|
-
}
|
|
14547
|
-
pending.current = pending.current.slice(0, -1);
|
|
14548
|
-
setMessages(pending.current);
|
|
14549
|
-
return message;
|
|
14550
|
-
}, []);
|
|
14551
|
-
useEffect(() => {
|
|
14552
|
-
if (blocked || paused || active.current || pending.current.length === 0) {
|
|
14553
|
-
return;
|
|
14554
|
-
}
|
|
14555
|
-
const next = pending.current[0];
|
|
14556
|
-
pending.current = pending.current.slice(1);
|
|
14557
|
-
active.current = true;
|
|
14558
|
-
setMessages(pending.current);
|
|
14559
|
-
setProcessing(true);
|
|
14560
|
-
void (async () => {
|
|
14561
|
-
try {
|
|
14562
|
-
await callbacks.current.send(next);
|
|
14563
|
-
} catch (error) {
|
|
14564
|
-
if (mounted.current) {
|
|
14565
|
-
setPaused(true);
|
|
14566
|
-
callbacks.current.onError(error);
|
|
14567
|
-
}
|
|
14568
|
-
} finally {
|
|
14569
|
-
active.current = false;
|
|
14570
|
-
if (mounted.current) {
|
|
14571
|
-
setProcessing(false);
|
|
14572
|
-
}
|
|
14573
|
-
}
|
|
14574
|
-
})();
|
|
14575
|
-
}, [blocked, messages, paused, processing]);
|
|
14576
|
-
return { messages, enqueue, takeLast, processing, paused };
|
|
14577
|
-
}
|
|
14578
|
-
|
|
14579
|
-
// src/ui/use-ide-input.ts
|
|
14580
|
-
var use_ide_input_exports = {};
|
|
14581
|
-
__export(use_ide_input_exports, {
|
|
14582
|
-
useIdeInput: () => useIdeInput
|
|
15077
|
+
// src/vscode/index.ts
|
|
15078
|
+
var vscode_exports = {};
|
|
15079
|
+
__export(vscode_exports, {
|
|
15080
|
+
IdeClient: () => ide_client_exports,
|
|
15081
|
+
Lockfile: () => lockfile_exports,
|
|
15082
|
+
WsTransport: () => ws_transport_exports
|
|
14583
15083
|
});
|
|
14584
|
-
import { relative as relative4 } from "path";
|
|
14585
|
-
import { useEffect as useEffect2, useRef as useRef2 } from "react";
|
|
14586
15084
|
|
|
14587
15085
|
// src/vscode/ide-client.ts
|
|
14588
15086
|
var ide_client_exports = {};
|
|
@@ -14600,7 +15098,7 @@ __export(lockfile_exports, {
|
|
|
14600
15098
|
});
|
|
14601
15099
|
import { readdir as readdir2, readFile as readFile5 } from "fs/promises";
|
|
14602
15100
|
import { homedir as homedir10 } from "os";
|
|
14603
|
-
import { join as
|
|
15101
|
+
import { join as join26, resolve as resolve11, sep as sep2 } from "path";
|
|
14604
15102
|
import { z as z21 } from "zod";
|
|
14605
15103
|
var log34 = createChildLogger({ module: "vscode" });
|
|
14606
15104
|
var LockfileSchema = z21.object({
|
|
@@ -14611,8 +15109,8 @@ var LockfileSchema = z21.object({
|
|
|
14611
15109
|
authToken: z21.string().optional()
|
|
14612
15110
|
});
|
|
14613
15111
|
function ideLockDir() {
|
|
14614
|
-
const configDir = process.env.CLAUDE_CONFIG_DIR ??
|
|
14615
|
-
return
|
|
15112
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR ?? join26(homedir10(), ".claude");
|
|
15113
|
+
return join26(configDir, "ide");
|
|
14616
15114
|
}
|
|
14617
15115
|
function cwdInWorkspace(cwd2, workspaceFolders) {
|
|
14618
15116
|
const normalizedCwd = cwd2.normalize("NFC");
|
|
@@ -14630,7 +15128,7 @@ async function readLockfile(dir, filename) {
|
|
|
14630
15128
|
return null;
|
|
14631
15129
|
}
|
|
14632
15130
|
try {
|
|
14633
|
-
const content = await readFile5(
|
|
15131
|
+
const content = await readFile5(join26(dir, filename), "utf-8");
|
|
14634
15132
|
const parsed = LockfileSchema.parse(JSON.parse(content));
|
|
14635
15133
|
if (parsed.transport !== "ws") {
|
|
14636
15134
|
return null;
|
|
@@ -14847,81 +15345,6 @@ async function connectToIde(opts) {
|
|
|
14847
15345
|
};
|
|
14848
15346
|
}
|
|
14849
15347
|
|
|
14850
|
-
// src/ui/use-ide-input.ts
|
|
14851
|
-
function useIdeInput(workDir) {
|
|
14852
|
-
const insertInputTextRef = useRef2(null);
|
|
14853
|
-
const clearInputRef = useRef2(null);
|
|
14854
|
-
useEffect2(() => {
|
|
14855
|
-
let connection = null;
|
|
14856
|
-
let cancelled = false;
|
|
14857
|
-
const controller = new AbortController();
|
|
14858
|
-
void connectToIde({
|
|
14859
|
-
cwd: workDir,
|
|
14860
|
-
signal: controller.signal,
|
|
14861
|
-
onAtMentioned: ({ filePath, lineStart, lineEnd }) => {
|
|
14862
|
-
const rel = relative4(workDir, filePath);
|
|
14863
|
-
const shown = rel && !rel.startsWith("..") ? rel : filePath;
|
|
14864
|
-
let mention = `@${shown}`;
|
|
14865
|
-
if (lineStart !== void 0) {
|
|
14866
|
-
mention += `#L${String(lineStart)}`;
|
|
14867
|
-
if (lineEnd !== void 0 && lineEnd !== lineStart) {
|
|
14868
|
-
mention += `-${String(lineEnd)}`;
|
|
14869
|
-
}
|
|
14870
|
-
}
|
|
14871
|
-
insertInputTextRef.current?.(mention + " ");
|
|
14872
|
-
}
|
|
14873
|
-
}).then((connected) => {
|
|
14874
|
-
if (!connected) {
|
|
14875
|
-
return;
|
|
14876
|
-
}
|
|
14877
|
-
if (cancelled) {
|
|
14878
|
-
void connected.close();
|
|
14879
|
-
return;
|
|
14880
|
-
}
|
|
14881
|
-
connection = connected;
|
|
14882
|
-
});
|
|
14883
|
-
return () => {
|
|
14884
|
-
cancelled = true;
|
|
14885
|
-
controller.abort();
|
|
14886
|
-
void connection?.close();
|
|
14887
|
-
};
|
|
14888
|
-
}, [workDir]);
|
|
14889
|
-
return { insertInputTextRef, clearInputRef };
|
|
14890
|
-
}
|
|
14891
|
-
|
|
14892
|
-
// src/ui/use-teammate-states.ts
|
|
14893
|
-
var use_teammate_states_exports = {};
|
|
14894
|
-
__export(use_teammate_states_exports, {
|
|
14895
|
-
useTeammateStates: () => useTeammateStates
|
|
14896
|
-
});
|
|
14897
|
-
import { useEffect as useEffect3, useState as useState2 } from "react";
|
|
14898
|
-
function useTeammateStates(manager) {
|
|
14899
|
-
const [states, setStates] = useState2([]);
|
|
14900
|
-
useEffect3(() => {
|
|
14901
|
-
let signature = "";
|
|
14902
|
-
const timer = setInterval(() => {
|
|
14903
|
-
const next = manager.getAllTeammateStates();
|
|
14904
|
-
const nextSignature = JSON.stringify(next);
|
|
14905
|
-
if (nextSignature !== signature) {
|
|
14906
|
-
signature = nextSignature;
|
|
14907
|
-
setStates(next);
|
|
14908
|
-
}
|
|
14909
|
-
}, 500);
|
|
14910
|
-
return () => {
|
|
14911
|
-
clearInterval(timer);
|
|
14912
|
-
};
|
|
14913
|
-
}, [manager]);
|
|
14914
|
-
return states;
|
|
14915
|
-
}
|
|
14916
|
-
|
|
14917
|
-
// src/vscode/index.ts
|
|
14918
|
-
var vscode_exports = {};
|
|
14919
|
-
__export(vscode_exports, {
|
|
14920
|
-
IdeClient: () => ide_client_exports,
|
|
14921
|
-
Lockfile: () => lockfile_exports,
|
|
14922
|
-
WsTransport: () => ws_transport_exports
|
|
14923
|
-
});
|
|
14924
|
-
|
|
14925
15348
|
// src/print-mode.ts
|
|
14926
15349
|
var print_mode_exports = {};
|
|
14927
15350
|
__export(print_mode_exports, {
|
|
@@ -14975,6 +15398,7 @@ async function runPrintMode(args) {
|
|
|
14975
15398
|
registry.register(new ToolSearchTool(registry));
|
|
14976
15399
|
const teamManager = new TeamManager(workDir);
|
|
14977
15400
|
const backgroundTaskManager = new TaskManager();
|
|
15401
|
+
attachBackgroundTaskManager(registry, backgroundTaskManager);
|
|
14978
15402
|
registry.register(new TeamCreateTool(teamManager));
|
|
14979
15403
|
registry.register(new SendMessageTool(teamManager));
|
|
14980
15404
|
registry.register(new TeamDeleteTool(teamManager));
|
|
@@ -15036,7 +15460,8 @@ async function runPrintMode(args) {
|
|
|
15036
15460
|
onEvent,
|
|
15037
15461
|
void 0,
|
|
15038
15462
|
teamChecker,
|
|
15039
|
-
|
|
15463
|
+
// Teammates stay purely foreground: see SubagentRunOptions.backgroundTasks.
|
|
15464
|
+
{ abortSignal, backgroundTasks: false }
|
|
15040
15465
|
),
|
|
15041
15466
|
provider.base_url
|
|
15042
15467
|
);
|
|
@@ -15124,7 +15549,7 @@ Error: ${event.error.message}`);
|
|
|
15124
15549
|
break;
|
|
15125
15550
|
}
|
|
15126
15551
|
}
|
|
15127
|
-
await backgroundTaskManager.waitAll();
|
|
15552
|
+
await backgroundTaskManager.waitAll((task) => (task.kind ?? "agent") === "agent");
|
|
15128
15553
|
const backgroundNotifications = backgroundTaskManager.drainNotifications();
|
|
15129
15554
|
const durationMs = Date.now() - startTime;
|
|
15130
15555
|
if (args.outputFormat === "text" && resultText && !resultText.endsWith("\n")) {
|
|
@@ -15217,13 +15642,13 @@ __export(recover_exports, {
|
|
|
15217
15642
|
recordExit: () => recordExit,
|
|
15218
15643
|
recover: () => recover
|
|
15219
15644
|
});
|
|
15220
|
-
import { appendFileSync, mkdirSync as
|
|
15221
|
-
import { join as
|
|
15645
|
+
import { appendFileSync, mkdirSync as mkdirSync17 } from "fs";
|
|
15646
|
+
import { join as join27 } from "path";
|
|
15222
15647
|
var LOG_DIR = ".swifty";
|
|
15223
|
-
var LOG_PATH =
|
|
15648
|
+
var LOG_PATH = join27(LOG_DIR, "crash.log");
|
|
15224
15649
|
function record(text) {
|
|
15225
15650
|
try {
|
|
15226
|
-
|
|
15651
|
+
mkdirSync17(LOG_DIR, { recursive: true });
|
|
15227
15652
|
appendFileSync(LOG_PATH, `[${(/* @__PURE__ */ new Date()).toISOString()}] ${text}
|
|
15228
15653
|
`, "utf8");
|
|
15229
15654
|
} catch {
|
|
@@ -15303,7 +15728,7 @@ __export(teammate_exports, {
|
|
|
15303
15728
|
parseTeammateFlags: () => parseTeammateFlags,
|
|
15304
15729
|
runTeammate: () => runTeammate
|
|
15305
15730
|
});
|
|
15306
|
-
import { basename as basename6, dirname as dirname10, join as
|
|
15731
|
+
import { basename as basename6, dirname as dirname10, join as join28 } from "path";
|
|
15307
15732
|
function parseTeammateFlags(args) {
|
|
15308
15733
|
if (!args.includes("--teammate")) {
|
|
15309
15734
|
return null;
|
|
@@ -15399,7 +15824,7 @@ async function runTeammate(args) {
|
|
|
15399
15824
|
initLogger({
|
|
15400
15825
|
sessionId: `teammate-${safeMemberName}-${Date.now().toString(36)}`,
|
|
15401
15826
|
mode: "teammate",
|
|
15402
|
-
logDir:
|
|
15827
|
+
logDir: join28(dirname10(args.teamDir), "logs"),
|
|
15403
15828
|
skipCleanup: true
|
|
15404
15829
|
});
|
|
15405
15830
|
process.on("exit", closeLogger);
|
|
@@ -15538,7 +15963,6 @@ export {
|
|
|
15538
15963
|
todo_exports as Todo,
|
|
15539
15964
|
tool_result_exports as ToolResult,
|
|
15540
15965
|
tools_exports3 as Tools,
|
|
15541
|
-
ui_exports as UI,
|
|
15542
15966
|
utils_exports as Utils,
|
|
15543
15967
|
vscode_exports as VSCode,
|
|
15544
15968
|
version_exports as Version,
|