llm-party-cli 0.7.1 → 0.10.1
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 +91 -29
- package/dist/index.js +1451 -700
- package/package.json +2 -3
- package/prompts/artifacts.md +81 -68
- package/prompts/base.md +101 -195
- package/prompts/obsidian.md +30 -102
package/dist/index.js
CHANGED
|
@@ -3284,7 +3284,7 @@ var require_main = __commonJS((exports) => {
|
|
|
3284
3284
|
});
|
|
3285
3285
|
|
|
3286
3286
|
// src/index.ts
|
|
3287
|
-
import { readFile as
|
|
3287
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
3288
3288
|
import path11 from "path";
|
|
3289
3289
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3290
3290
|
|
|
@@ -36264,43 +36264,6 @@ function Show(props) {
|
|
|
36264
36264
|
return props.fallback;
|
|
36265
36265
|
}, undefined, undefined);
|
|
36266
36266
|
}
|
|
36267
|
-
function Switch(props) {
|
|
36268
|
-
const chs = children(() => props.children);
|
|
36269
|
-
const switchFunc = createMemo(() => {
|
|
36270
|
-
const ch = chs();
|
|
36271
|
-
const mps = Array.isArray(ch) ? ch : [ch];
|
|
36272
|
-
let func = () => {
|
|
36273
|
-
return;
|
|
36274
|
-
};
|
|
36275
|
-
for (let i = 0;i < mps.length; i++) {
|
|
36276
|
-
const index = i;
|
|
36277
|
-
const mp = mps[i];
|
|
36278
|
-
const prevFunc = func;
|
|
36279
|
-
const conditionValue = createMemo(() => prevFunc() ? undefined : mp.when, undefined, undefined);
|
|
36280
|
-
const condition = mp.keyed ? conditionValue : createMemo(conditionValue, undefined, {
|
|
36281
|
-
equals: (a, b2) => !a === !b2
|
|
36282
|
-
});
|
|
36283
|
-
func = () => prevFunc() || (condition() ? [index, conditionValue, mp] : undefined);
|
|
36284
|
-
}
|
|
36285
|
-
return func;
|
|
36286
|
-
});
|
|
36287
|
-
return createMemo(() => {
|
|
36288
|
-
const sel = switchFunc()();
|
|
36289
|
-
if (!sel)
|
|
36290
|
-
return props.fallback;
|
|
36291
|
-
const [index, conditionValue, mp] = sel;
|
|
36292
|
-
const child = mp.children;
|
|
36293
|
-
const fn = typeof child === "function" && child.length > 0;
|
|
36294
|
-
return fn ? untrack(() => child(mp.keyed ? conditionValue() : () => {
|
|
36295
|
-
if (untrack(switchFunc)()?.[0] !== index)
|
|
36296
|
-
throw narrowedError("Match");
|
|
36297
|
-
return conditionValue();
|
|
36298
|
-
})) : child;
|
|
36299
|
-
}, undefined, undefined);
|
|
36300
|
-
}
|
|
36301
|
-
function Match(props) {
|
|
36302
|
-
return props;
|
|
36303
|
-
}
|
|
36304
36267
|
|
|
36305
36268
|
// node_modules/entities/dist/esm/decode-codepoint.js
|
|
36306
36269
|
var _a;
|
|
@@ -37551,8 +37514,11 @@ var render = async (node, rendererOrConfig = {}) => {
|
|
|
37551
37514
|
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
37552
37515
|
|
|
37553
37516
|
// src/adapters/base.ts
|
|
37554
|
-
function formatTranscript(messages) {
|
|
37555
|
-
return messages.map((m2) =>
|
|
37517
|
+
function formatTranscript(messages, agentName, humanName) {
|
|
37518
|
+
return messages.map((m2) => {
|
|
37519
|
+
const role = m2.from === agentName ? "you" : m2.from === humanName ? "user" : "agent";
|
|
37520
|
+
return `${m2.from} (${role}):: ${m2.text}`;
|
|
37521
|
+
}).join(`
|
|
37556
37522
|
|
|
37557
37523
|
`);
|
|
37558
37524
|
}
|
|
@@ -37561,13 +37527,15 @@ function formatTranscript(messages) {
|
|
|
37561
37527
|
class ClaudeBaseAdapter {
|
|
37562
37528
|
name;
|
|
37563
37529
|
model;
|
|
37530
|
+
humanName;
|
|
37564
37531
|
systemPrompt = "";
|
|
37565
37532
|
sessionId = "";
|
|
37566
37533
|
runtimeEnv = {};
|
|
37567
37534
|
claudeExecutable;
|
|
37568
|
-
constructor(name, model) {
|
|
37535
|
+
constructor(name, model, humanName) {
|
|
37569
37536
|
this.name = name;
|
|
37570
37537
|
this.model = model;
|
|
37538
|
+
this.humanName = humanName;
|
|
37571
37539
|
}
|
|
37572
37540
|
async init(config) {
|
|
37573
37541
|
this.systemPrompt = config.resolvedPrompt ?? "";
|
|
@@ -37575,15 +37543,23 @@ class ClaudeBaseAdapter {
|
|
|
37575
37543
|
this.claudeExecutable = config.executablePath ?? process.env.CLAUDE_CODE_EXECUTABLE;
|
|
37576
37544
|
}
|
|
37577
37545
|
async buildEnv(config) {
|
|
37578
|
-
|
|
37579
|
-
|
|
37580
|
-
|
|
37581
|
-
|
|
37582
|
-
|
|
37583
|
-
|
|
37584
|
-
|
|
37546
|
+
const configEnv = config.env ?? {};
|
|
37547
|
+
const mapped = {};
|
|
37548
|
+
if (configEnv.AUTH_URL) {
|
|
37549
|
+
mapped.ANTHROPIC_BASE_URL = configEnv.AUTH_URL;
|
|
37550
|
+
}
|
|
37551
|
+
if (configEnv.AUTH_TOKEN) {
|
|
37552
|
+
mapped.ANTHROPIC_AUTH_TOKEN = configEnv.AUTH_TOKEN;
|
|
37553
|
+
}
|
|
37554
|
+
if (configEnv.AUTH_URL || configEnv.AUTH_TOKEN) {
|
|
37555
|
+
mapped.ANTHROPIC_DEFAULT_HAIKU_MODEL = this.model;
|
|
37556
|
+
mapped.ANTHROPIC_DEFAULT_SONNET_MODEL = this.model;
|
|
37557
|
+
mapped.ANTHROPIC_DEFAULT_OPUS_MODEL = this.model;
|
|
37558
|
+
}
|
|
37559
|
+
return { ...process.env, ...mapped, ...configEnv };
|
|
37585
37560
|
}
|
|
37586
|
-
async
|
|
37561
|
+
async* stream(messages, signal) {
|
|
37562
|
+
const transcript = formatTranscript(messages, this.name, this.humanName);
|
|
37587
37563
|
const executableOpt = this.claudeExecutable ? { pathToClaudeCodeExecutable: this.claudeExecutable } : {};
|
|
37588
37564
|
const options = {
|
|
37589
37565
|
cwd: process.cwd(),
|
|
@@ -37597,24 +37573,69 @@ class ClaudeBaseAdapter {
|
|
|
37597
37573
|
...this.sessionId ? { resume: this.sessionId } : {},
|
|
37598
37574
|
...executableOpt
|
|
37599
37575
|
};
|
|
37576
|
+
yield { type: "activity", activity: "thinking" };
|
|
37600
37577
|
try {
|
|
37601
37578
|
for await (const message of query({ prompt: transcript, options })) {
|
|
37602
37579
|
if (signal?.aborted) {
|
|
37603
|
-
|
|
37580
|
+
yield { type: "error", message: `[Aborted] ${this.name} was cancelled` };
|
|
37581
|
+
return;
|
|
37604
37582
|
}
|
|
37605
|
-
if (message
|
|
37583
|
+
if (!message || typeof message !== "object")
|
|
37584
|
+
continue;
|
|
37585
|
+
if ("type" in message && "subtype" in message && "session_id" in message && message.type === "system" && message.subtype === "init" && typeof message.session_id === "string") {
|
|
37606
37586
|
this.sessionId = message.session_id;
|
|
37607
37587
|
}
|
|
37608
|
-
if (message &&
|
|
37588
|
+
if ("type" in message && message.type === "assistant" && "message" in message) {
|
|
37589
|
+
const msg = message.message;
|
|
37590
|
+
const blocks = msg?.content;
|
|
37591
|
+
if (Array.isArray(blocks)) {
|
|
37592
|
+
for (const block of blocks) {
|
|
37593
|
+
if (block.type === "tool_use" && block.name) {
|
|
37594
|
+
const toolName = String(block.name).toLowerCase();
|
|
37595
|
+
if (toolName === "read" || toolName === "glob") {
|
|
37596
|
+
yield { type: "activity", activity: "reading", detail: block.name };
|
|
37597
|
+
} else if (toolName === "write" || toolName === "edit") {
|
|
37598
|
+
yield { type: "activity", activity: "writing", detail: block.name };
|
|
37599
|
+
} else if (toolName === "bash") {
|
|
37600
|
+
yield { type: "activity", activity: "running", detail: "shell" };
|
|
37601
|
+
} else if (toolName === "grep" || toolName === "search" || toolName === "websearch") {
|
|
37602
|
+
yield { type: "activity", activity: "searching", detail: block.name };
|
|
37603
|
+
} else {
|
|
37604
|
+
yield { type: "activity", activity: "thinking", detail: block.name };
|
|
37605
|
+
}
|
|
37606
|
+
} else if (block.type === "thinking") {
|
|
37607
|
+
yield { type: "activity", activity: "thinking" };
|
|
37608
|
+
}
|
|
37609
|
+
}
|
|
37610
|
+
}
|
|
37611
|
+
}
|
|
37612
|
+
if ("type" in message && message.type === "user") {
|
|
37613
|
+
yield { type: "activity", activity: "thinking" };
|
|
37614
|
+
}
|
|
37615
|
+
if ("result" in message) {
|
|
37609
37616
|
const result = message.result;
|
|
37610
|
-
|
|
37617
|
+
const text = typeof result === "string" && result.length > 0 ? result : `[No text response from ${this.name}]`;
|
|
37618
|
+
yield { type: "activity", activity: "idle" };
|
|
37619
|
+
yield { type: "response", text };
|
|
37620
|
+
return;
|
|
37611
37621
|
}
|
|
37612
37622
|
}
|
|
37613
37623
|
} catch (err) {
|
|
37614
37624
|
console.log(`[${this.name}] SDK error:`, err);
|
|
37615
|
-
|
|
37625
|
+
yield { type: "error", message: err instanceof Error ? err.message : String(err) };
|
|
37626
|
+
return;
|
|
37616
37627
|
}
|
|
37617
|
-
|
|
37628
|
+
yield { type: "activity", activity: "idle" };
|
|
37629
|
+
yield { type: "response", text: `[No text response from ${this.name}]` };
|
|
37630
|
+
}
|
|
37631
|
+
async destroy() {
|
|
37632
|
+
return;
|
|
37633
|
+
}
|
|
37634
|
+
getSdkSessionId() {
|
|
37635
|
+
return this.sessionId;
|
|
37636
|
+
}
|
|
37637
|
+
setSdkSessionId(id) {
|
|
37638
|
+
this.sessionId = id;
|
|
37618
37639
|
}
|
|
37619
37640
|
}
|
|
37620
37641
|
|
|
@@ -38061,11 +38082,15 @@ class CodexAdapter {
|
|
|
38061
38082
|
name;
|
|
38062
38083
|
provider = "codex";
|
|
38063
38084
|
model;
|
|
38085
|
+
humanName;
|
|
38064
38086
|
codex;
|
|
38065
38087
|
thread;
|
|
38066
|
-
|
|
38088
|
+
threadId = "";
|
|
38089
|
+
threadOptions = {};
|
|
38090
|
+
constructor(name, model, humanName) {
|
|
38067
38091
|
this.name = name;
|
|
38068
38092
|
this.model = model;
|
|
38093
|
+
this.humanName = humanName;
|
|
38069
38094
|
}
|
|
38070
38095
|
async init(config) {
|
|
38071
38096
|
const cliPath = config.executablePath ?? process.env.CODEX_CLI_EXECUTABLE;
|
|
@@ -38075,31 +38100,84 @@ class CodexAdapter {
|
|
|
38075
38100
|
...config.env?.OPENAI_API_KEY ? { apiKey: config.env.OPENAI_API_KEY } : {},
|
|
38076
38101
|
...systemPrompt ? { config: { developer_instructions: systemPrompt } } : {}
|
|
38077
38102
|
});
|
|
38078
|
-
this.
|
|
38103
|
+
this.threadOptions = {
|
|
38079
38104
|
model: this.model,
|
|
38080
38105
|
sandboxMode: "danger-full-access",
|
|
38081
38106
|
workingDirectory: process.cwd(),
|
|
38082
38107
|
approvalPolicy: "never",
|
|
38083
38108
|
skipGitRepoCheck: true
|
|
38084
|
-
}
|
|
38109
|
+
};
|
|
38110
|
+
if (this.threadId) {
|
|
38111
|
+
try {
|
|
38112
|
+
this.thread = this.codex.resumeThread(this.threadId, this.threadOptions);
|
|
38113
|
+
return;
|
|
38114
|
+
} catch (err) {
|
|
38115
|
+
console.error(`[${this.name}] resumeThread failed, starting fresh:`, err);
|
|
38116
|
+
this.threadId = "";
|
|
38117
|
+
}
|
|
38118
|
+
}
|
|
38119
|
+
this.thread = this.codex.startThread(this.threadOptions);
|
|
38120
|
+
this.threadId = this.thread.id ?? "";
|
|
38085
38121
|
}
|
|
38086
|
-
async
|
|
38122
|
+
async* stream(messages, signal) {
|
|
38087
38123
|
if (!this.thread) {
|
|
38088
|
-
|
|
38124
|
+
yield { type: "error", message: "[Codex thread not initialized]" };
|
|
38125
|
+
return;
|
|
38089
38126
|
}
|
|
38090
38127
|
if (signal?.aborted) {
|
|
38091
|
-
|
|
38128
|
+
yield { type: "error", message: "[Aborted] Codex was cancelled" };
|
|
38129
|
+
return;
|
|
38092
38130
|
}
|
|
38093
|
-
|
|
38094
|
-
|
|
38095
|
-
|
|
38131
|
+
yield { type: "activity", activity: "thinking" };
|
|
38132
|
+
try {
|
|
38133
|
+
const result = await this.thread.runStreamed(formatTranscript(messages, this.name, this.humanName));
|
|
38134
|
+
let lastAgentMessage = "";
|
|
38135
|
+
for await (const event of result.events) {
|
|
38136
|
+
if (signal?.aborted) {
|
|
38137
|
+
yield { type: "error", message: "[Aborted] Codex was cancelled" };
|
|
38138
|
+
return;
|
|
38139
|
+
}
|
|
38140
|
+
if (event.type === "item.started" || event.type === "item.updated") {
|
|
38141
|
+
const item = event.item;
|
|
38142
|
+
if (item.type === "command_execution") {
|
|
38143
|
+
yield { type: "activity", activity: "running", detail: item.command };
|
|
38144
|
+
} else if (item.type === "file_change") {
|
|
38145
|
+
yield { type: "activity", activity: "writing", detail: "file changes" };
|
|
38146
|
+
} else if (item.type === "reasoning") {
|
|
38147
|
+
yield { type: "activity", activity: "thinking", detail: "reasoning" };
|
|
38148
|
+
} else if (item.type === "web_search") {
|
|
38149
|
+
yield { type: "activity", activity: "searching", detail: item.query };
|
|
38150
|
+
} else if (item.type === "mcp_tool_call") {
|
|
38151
|
+
yield { type: "activity", activity: "running", detail: `${item.server}:${item.tool}` };
|
|
38152
|
+
}
|
|
38153
|
+
}
|
|
38154
|
+
if (event.type === "item.completed") {
|
|
38155
|
+
const item = event.item;
|
|
38156
|
+
if (item.type === "agent_message" && typeof item.text === "string") {
|
|
38157
|
+
lastAgentMessage = item.text;
|
|
38158
|
+
}
|
|
38159
|
+
}
|
|
38160
|
+
}
|
|
38161
|
+
const text = lastAgentMessage.length > 0 ? lastAgentMessage : `[No text response from ${this.name}]`;
|
|
38162
|
+
if (!this.threadId && this.thread?.id) {
|
|
38163
|
+
this.threadId = this.thread.id;
|
|
38164
|
+
}
|
|
38165
|
+
yield { type: "activity", activity: "idle" };
|
|
38166
|
+
yield { type: "response", text };
|
|
38167
|
+
} catch (err) {
|
|
38168
|
+
yield { type: "error", message: err instanceof Error ? err.message : String(err) };
|
|
38096
38169
|
}
|
|
38097
|
-
return "[No text response from Codex]";
|
|
38098
38170
|
}
|
|
38099
38171
|
async destroy() {
|
|
38100
38172
|
this.thread = undefined;
|
|
38101
38173
|
this.codex = undefined;
|
|
38102
38174
|
}
|
|
38175
|
+
getSdkSessionId() {
|
|
38176
|
+
return this.threadId;
|
|
38177
|
+
}
|
|
38178
|
+
setSdkSessionId(id) {
|
|
38179
|
+
this.threadId = id;
|
|
38180
|
+
}
|
|
38103
38181
|
}
|
|
38104
38182
|
|
|
38105
38183
|
// node_modules/@github/copilot-sdk/dist/client.js
|
|
@@ -39276,14 +39354,17 @@ class CopilotAdapter {
|
|
|
39276
39354
|
name;
|
|
39277
39355
|
provider = "copilot";
|
|
39278
39356
|
model;
|
|
39357
|
+
humanName;
|
|
39279
39358
|
client;
|
|
39280
39359
|
session;
|
|
39281
39360
|
systemPrompt = "";
|
|
39282
39361
|
cliPath;
|
|
39283
39362
|
timeout = 600000;
|
|
39284
|
-
|
|
39363
|
+
copilotSessionId = "";
|
|
39364
|
+
constructor(name, model, humanName) {
|
|
39285
39365
|
this.name = name;
|
|
39286
39366
|
this.model = model;
|
|
39367
|
+
this.humanName = humanName;
|
|
39287
39368
|
}
|
|
39288
39369
|
async init(config) {
|
|
39289
39370
|
this.systemPrompt = config.resolvedPrompt ?? "";
|
|
@@ -39293,123 +39374,186 @@ class CopilotAdapter {
|
|
|
39293
39374
|
}
|
|
39294
39375
|
await this.createSession();
|
|
39295
39376
|
}
|
|
39296
|
-
async
|
|
39377
|
+
async* stream(messages, signal) {
|
|
39297
39378
|
if (!this.session) {
|
|
39298
|
-
|
|
39379
|
+
yield { type: "error", message: "[Copilot session not initialized]" };
|
|
39380
|
+
return;
|
|
39299
39381
|
}
|
|
39300
39382
|
if (signal?.aborted) {
|
|
39301
|
-
|
|
39383
|
+
yield { type: "error", message: "[Aborted] Copilot was cancelled" };
|
|
39384
|
+
return;
|
|
39302
39385
|
}
|
|
39303
|
-
|
|
39386
|
+
yield { type: "activity", activity: "thinking" };
|
|
39387
|
+
const transcript = formatTranscript(messages, this.name, this.humanName);
|
|
39388
|
+
const eventQueue = [];
|
|
39389
|
+
let resolve4 = null;
|
|
39390
|
+
let done = false;
|
|
39391
|
+
const push = (event) => {
|
|
39392
|
+
eventQueue.push(event);
|
|
39393
|
+
if (resolve4) {
|
|
39394
|
+
resolve4();
|
|
39395
|
+
resolve4 = null;
|
|
39396
|
+
}
|
|
39397
|
+
};
|
|
39398
|
+
const waitForEvent = () => {
|
|
39399
|
+
if (eventQueue.length > 0 || done)
|
|
39400
|
+
return Promise.resolve();
|
|
39401
|
+
return new Promise((r) => {
|
|
39402
|
+
resolve4 = r;
|
|
39403
|
+
});
|
|
39404
|
+
};
|
|
39405
|
+
const timer = setTimeout(() => {
|
|
39406
|
+
push({ type: "error", message: `[Timeout] ${this.name} exceeded ${Math.floor(this.timeout / 1000)}s` });
|
|
39407
|
+
done = true;
|
|
39408
|
+
}, this.timeout);
|
|
39409
|
+
const unsubscribe = this.session.on((event) => {
|
|
39410
|
+
if (signal?.aborted) {
|
|
39411
|
+
push({ type: "error", message: `[Aborted] ${this.name} was cancelled` });
|
|
39412
|
+
done = true;
|
|
39413
|
+
return;
|
|
39414
|
+
}
|
|
39415
|
+
if (event.type === "tool.execution_start") {
|
|
39416
|
+
const toolName = String(event.data?.toolName ?? "").toLowerCase();
|
|
39417
|
+
if (toolName === "view" || toolName === "read" || toolName === "report_intent") {
|
|
39418
|
+
push({ type: "activity", activity: "reading", detail: event.data?.toolName });
|
|
39419
|
+
} else if (toolName === "create" || toolName === "edit" || toolName === "write") {
|
|
39420
|
+
push({ type: "activity", activity: "writing", detail: event.data?.toolName });
|
|
39421
|
+
} else if (toolName === "run" || toolName === "bash" || toolName === "shell") {
|
|
39422
|
+
push({ type: "activity", activity: "running", detail: event.data?.toolName });
|
|
39423
|
+
} else if (toolName === "search" || toolName === "grep" || toolName === "find") {
|
|
39424
|
+
push({ type: "activity", activity: "searching", detail: event.data?.toolName });
|
|
39425
|
+
} else {
|
|
39426
|
+
push({ type: "activity", activity: "thinking", detail: event.data?.toolName });
|
|
39427
|
+
}
|
|
39428
|
+
}
|
|
39429
|
+
if (event.type === "tool.execution_complete") {
|
|
39430
|
+
push({ type: "activity", activity: "thinking" });
|
|
39431
|
+
}
|
|
39432
|
+
if (event.type === "assistant.turn_start") {
|
|
39433
|
+
push({ type: "activity", activity: "thinking" });
|
|
39434
|
+
}
|
|
39435
|
+
if (event.type === "assistant.message") {
|
|
39436
|
+
const content = event.data?.content;
|
|
39437
|
+
if (typeof content === "string" && content.length > 0) {
|
|
39438
|
+
push({ type: "activity", activity: "idle" });
|
|
39439
|
+
push({ type: "response", text: content });
|
|
39440
|
+
done = true;
|
|
39441
|
+
}
|
|
39442
|
+
}
|
|
39443
|
+
if (event.type === "session.error") {
|
|
39444
|
+
push({ type: "error", message: event.data?.message ?? "Unknown Copilot error" });
|
|
39445
|
+
done = true;
|
|
39446
|
+
}
|
|
39447
|
+
});
|
|
39448
|
+
const sendSession = async () => {
|
|
39449
|
+
try {
|
|
39450
|
+
await this.session.send({ prompt: transcript });
|
|
39451
|
+
} catch (err) {
|
|
39452
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
39453
|
+
if (message.includes("Session not found")) {
|
|
39454
|
+
await this.createSession();
|
|
39455
|
+
try {
|
|
39456
|
+
await this.session.send({ prompt: transcript });
|
|
39457
|
+
} catch (retryErr) {
|
|
39458
|
+
push({ type: "error", message: retryErr instanceof Error ? retryErr.message : String(retryErr) });
|
|
39459
|
+
done = true;
|
|
39460
|
+
}
|
|
39461
|
+
} else {
|
|
39462
|
+
push({ type: "error", message });
|
|
39463
|
+
done = true;
|
|
39464
|
+
}
|
|
39465
|
+
}
|
|
39466
|
+
};
|
|
39467
|
+
sendSession();
|
|
39304
39468
|
try {
|
|
39305
|
-
|
|
39306
|
-
|
|
39307
|
-
|
|
39308
|
-
|
|
39309
|
-
|
|
39310
|
-
|
|
39469
|
+
while (!done || eventQueue.length > 0) {
|
|
39470
|
+
await waitForEvent();
|
|
39471
|
+
while (eventQueue.length > 0) {
|
|
39472
|
+
const event = eventQueue.shift();
|
|
39473
|
+
yield event;
|
|
39474
|
+
if (event.type === "response" || event.type === "error") {
|
|
39475
|
+
clearTimeout(timer);
|
|
39476
|
+
unsubscribe?.();
|
|
39477
|
+
return;
|
|
39478
|
+
}
|
|
39479
|
+
}
|
|
39311
39480
|
}
|
|
39312
|
-
|
|
39481
|
+
} finally {
|
|
39482
|
+
clearTimeout(timer);
|
|
39483
|
+
unsubscribe?.();
|
|
39313
39484
|
}
|
|
39485
|
+
yield { type: "activity", activity: "idle" };
|
|
39486
|
+
yield { type: "response", text: `[No text response from ${this.name}]` };
|
|
39314
39487
|
}
|
|
39315
39488
|
async destroy() {
|
|
39316
39489
|
if (this.session) {
|
|
39317
|
-
|
|
39490
|
+
try {
|
|
39491
|
+
await this.session.disconnect();
|
|
39492
|
+
} catch (err) {
|
|
39493
|
+
console.error(`[${this.name}] disconnect:`, err);
|
|
39494
|
+
}
|
|
39318
39495
|
}
|
|
39319
39496
|
if (this.client) {
|
|
39320
|
-
|
|
39497
|
+
try {
|
|
39498
|
+
await this.client.stop();
|
|
39499
|
+
} catch (err) {
|
|
39500
|
+
console.error(`[${this.name}] stop:`, err);
|
|
39501
|
+
}
|
|
39321
39502
|
}
|
|
39322
39503
|
}
|
|
39504
|
+
getSdkSessionId() {
|
|
39505
|
+
return this.copilotSessionId;
|
|
39506
|
+
}
|
|
39507
|
+
setSdkSessionId(id) {
|
|
39508
|
+
this.copilotSessionId = id;
|
|
39509
|
+
}
|
|
39323
39510
|
async createSession() {
|
|
39324
39511
|
if (this.session) {
|
|
39325
39512
|
try {
|
|
39326
39513
|
await this.session.disconnect();
|
|
39327
|
-
} catch {
|
|
39514
|
+
} catch (err) {
|
|
39515
|
+
console.error(`[${this.name}] stale session disconnect:`, err);
|
|
39516
|
+
}
|
|
39328
39517
|
}
|
|
39329
39518
|
if (this.client) {
|
|
39330
39519
|
try {
|
|
39331
39520
|
await this.client.stop();
|
|
39332
|
-
} catch {
|
|
39521
|
+
} catch (err) {
|
|
39522
|
+
console.error(`[${this.name}] stale client stop:`, err);
|
|
39523
|
+
}
|
|
39333
39524
|
}
|
|
39334
39525
|
process.env.NODE_NO_WARNINGS = "1";
|
|
39335
39526
|
this.client = new CopilotClient({
|
|
39336
39527
|
...this.cliPath ? { cliPath: this.cliPath } : {}
|
|
39337
39528
|
});
|
|
39338
39529
|
await this.client.start();
|
|
39530
|
+
if (this.copilotSessionId) {
|
|
39531
|
+
try {
|
|
39532
|
+
this.session = await this.client.resumeSession(this.copilotSessionId, {
|
|
39533
|
+
model: this.model,
|
|
39534
|
+
systemMessage: { content: this.systemPrompt },
|
|
39535
|
+
onPermissionRequest: approveAll
|
|
39536
|
+
});
|
|
39537
|
+
return;
|
|
39538
|
+
} catch (err) {
|
|
39539
|
+
console.error(`[${this.name}] resumeSession failed, creating new:`, err);
|
|
39540
|
+
this.copilotSessionId = "";
|
|
39541
|
+
}
|
|
39542
|
+
}
|
|
39543
|
+
const sessionId = `llm-party-${this.name}-${Date.now()}`;
|
|
39339
39544
|
this.session = await this.client.createSession({
|
|
39545
|
+
sessionId,
|
|
39340
39546
|
model: this.model,
|
|
39341
39547
|
systemMessage: { content: this.systemPrompt },
|
|
39342
39548
|
onPermissionRequest: approveAll
|
|
39343
39549
|
});
|
|
39344
|
-
|
|
39345
|
-
async sendToSession(transcript) {
|
|
39346
|
-
if (!this.session) {
|
|
39347
|
-
return "[Copilot session not initialized]";
|
|
39348
|
-
}
|
|
39349
|
-
const response = await this.session.sendAndWait({ prompt: transcript }, this.timeout);
|
|
39350
|
-
if (response && response.data && typeof response.data.content === "string" && response.data.content.length > 0) {
|
|
39351
|
-
return response.data.content;
|
|
39352
|
-
}
|
|
39353
|
-
return "[No text response from Copilot]";
|
|
39550
|
+
this.copilotSessionId = sessionId;
|
|
39354
39551
|
}
|
|
39355
39552
|
}
|
|
39356
39553
|
|
|
39357
|
-
// src/adapters/
|
|
39358
|
-
|
|
39359
|
-
|
|
39360
|
-
provider = "glm";
|
|
39361
|
-
async buildEnv(config) {
|
|
39362
|
-
const aliasEnv = await loadGlmAliasEnv();
|
|
39363
|
-
return { ...process.env, ...aliasEnv, ...config.env ?? {} };
|
|
39364
|
-
}
|
|
39365
|
-
}
|
|
39366
|
-
function detectShell() {
|
|
39367
|
-
if (process.env.SHELL) {
|
|
39368
|
-
return process.env.SHELL;
|
|
39369
|
-
}
|
|
39370
|
-
return "/bin/sh";
|
|
39371
|
-
}
|
|
39372
|
-
async function loadGlmAliasEnv() {
|
|
39373
|
-
const shell = detectShell();
|
|
39374
|
-
const isInteractive = shell.endsWith("zsh") || shell.endsWith("bash");
|
|
39375
|
-
const args = isInteractive ? ["-ic", "alias glm"] : ["-c", "alias glm"];
|
|
39376
|
-
return new Promise((resolve4) => {
|
|
39377
|
-
const child = spawn3(shell, args, {
|
|
39378
|
-
cwd: process.cwd(),
|
|
39379
|
-
env: process.env,
|
|
39380
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
39381
|
-
});
|
|
39382
|
-
let stdout = "";
|
|
39383
|
-
const timeout = setTimeout(() => {
|
|
39384
|
-
child.kill("SIGTERM");
|
|
39385
|
-
resolve4({});
|
|
39386
|
-
}, 5000);
|
|
39387
|
-
child.stdout.on("data", (chunk) => {
|
|
39388
|
-
stdout += String(chunk);
|
|
39389
|
-
});
|
|
39390
|
-
child.on("close", (code) => {
|
|
39391
|
-
clearTimeout(timeout);
|
|
39392
|
-
if (code !== 0) {
|
|
39393
|
-
resolve4({});
|
|
39394
|
-
return;
|
|
39395
|
-
}
|
|
39396
|
-
const env2 = {};
|
|
39397
|
-
const tokens = stdout.match(/[A-Z_]+="[^"]*"/g) ?? [];
|
|
39398
|
-
for (const token of tokens) {
|
|
39399
|
-
const eqIdx = token.indexOf("=");
|
|
39400
|
-
if (eqIdx === -1)
|
|
39401
|
-
continue;
|
|
39402
|
-
const key = token.slice(0, eqIdx);
|
|
39403
|
-
const raw = token.slice(eqIdx + 1);
|
|
39404
|
-
env2[key] = raw.replace(/^"|"$/g, "");
|
|
39405
|
-
}
|
|
39406
|
-
resolve4(env2);
|
|
39407
|
-
});
|
|
39408
|
-
child.on("error", () => {
|
|
39409
|
-
clearTimeout(timeout);
|
|
39410
|
-
resolve4({});
|
|
39411
|
-
});
|
|
39412
|
-
});
|
|
39554
|
+
// src/adapters/custom.ts
|
|
39555
|
+
class CustomAdapter extends ClaudeBaseAdapter {
|
|
39556
|
+
provider = "custom";
|
|
39413
39557
|
}
|
|
39414
39558
|
|
|
39415
39559
|
// src/config/loader.ts
|
|
@@ -39448,27 +39592,11 @@ var PROVIDERS = [
|
|
|
39448
39592
|
defaultTag: "copilot",
|
|
39449
39593
|
detectCommand: "copilot",
|
|
39450
39594
|
detectType: "binary"
|
|
39451
|
-
},
|
|
39452
|
-
{
|
|
39453
|
-
id: "glm",
|
|
39454
|
-
displayName: "GLM",
|
|
39455
|
-
description: "glm alias configured on Claude Code CLI",
|
|
39456
|
-
unavailableHint: "glm shell alias not configured",
|
|
39457
|
-
defaultModel: "glm-5",
|
|
39458
|
-
defaultTag: "glm",
|
|
39459
|
-
detectCommand: "glm",
|
|
39460
|
-
detectType: "alias",
|
|
39461
|
-
env: {
|
|
39462
|
-
ANTHROPIC_BASE_URL: "https://api.z.ai/api/anthropic",
|
|
39463
|
-
ANTHROPIC_DEFAULT_HAIKU_MODEL: "glm-4.5-air",
|
|
39464
|
-
ANTHROPIC_DEFAULT_SONNET_MODEL: "glm-4.5",
|
|
39465
|
-
ANTHROPIC_DEFAULT_OPUS_MODEL: "glm-5"
|
|
39466
|
-
}
|
|
39467
39595
|
}
|
|
39468
39596
|
];
|
|
39469
39597
|
|
|
39470
39598
|
// src/config/loader.ts
|
|
39471
|
-
var VALID_PROVIDER_IDS = new Set(PROVIDERS.map((p) => p.id));
|
|
39599
|
+
var VALID_PROVIDER_IDS = new Set([...PROVIDERS.map((p) => p.id), "custom"]);
|
|
39472
39600
|
var LLM_PARTY_HOME = path8.join(homedir(), ".llm-party");
|
|
39473
39601
|
var MIND_MAP_INDEX = `# Living Memory Neural Network
|
|
39474
39602
|
|
|
@@ -39654,15 +39782,29 @@ async function configExists() {
|
|
|
39654
39782
|
return false;
|
|
39655
39783
|
}
|
|
39656
39784
|
}
|
|
39785
|
+
function migrateProviders(data) {
|
|
39786
|
+
if (!Array.isArray(data.agents))
|
|
39787
|
+
return;
|
|
39788
|
+
for (const agent of data.agents) {
|
|
39789
|
+
if (!agent || typeof agent !== "object")
|
|
39790
|
+
continue;
|
|
39791
|
+
if (typeof agent.provider === "string" && !VALID_PROVIDER_IDS.has(agent.provider)) {
|
|
39792
|
+
agent.provider = "custom";
|
|
39793
|
+
if (!agent.cli)
|
|
39794
|
+
agent.cli = "claude";
|
|
39795
|
+
}
|
|
39796
|
+
}
|
|
39797
|
+
}
|
|
39657
39798
|
async function loadConfig2(configPath) {
|
|
39658
39799
|
const raw = await readFile3(configPath, "utf8");
|
|
39659
39800
|
const parsed = JSON.parse(raw);
|
|
39801
|
+
migrateProviders(parsed);
|
|
39660
39802
|
validateConfig(parsed);
|
|
39661
39803
|
return normalizeConfig(parsed);
|
|
39662
39804
|
}
|
|
39663
39805
|
|
|
39664
39806
|
// src/orchestrator.ts
|
|
39665
|
-
import { appendFile, mkdir as mkdir5, writeFile as writeFile5 } from "fs/promises";
|
|
39807
|
+
import { appendFile, mkdir as mkdir5, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
39666
39808
|
import { randomBytes } from "crypto";
|
|
39667
39809
|
import path9 from "path";
|
|
39668
39810
|
|
|
@@ -39687,6 +39829,72 @@ var DEFAULT_REMINDERS = [
|
|
|
39687
39829
|
"Self-memory check: did you receive a correction this session? Write it to your agent file now.",
|
|
39688
39830
|
"Global awareness: if this work affects other projects, write a one-liner to projects.yml history."
|
|
39689
39831
|
];
|
|
39832
|
+
var QUEUE_TTL_MS = 5 * 60 * 1000;
|
|
39833
|
+
var MAX_QUEUE_SIZE = 20;
|
|
39834
|
+
|
|
39835
|
+
class AgentQueueManager {
|
|
39836
|
+
queues = new Map;
|
|
39837
|
+
register(agentName) {
|
|
39838
|
+
this.queues.set(agentName, { processing: false, pending: [] });
|
|
39839
|
+
}
|
|
39840
|
+
enqueue(agentName, message, maxSize = MAX_QUEUE_SIZE) {
|
|
39841
|
+
const queue = this.queues.get(agentName);
|
|
39842
|
+
if (!queue)
|
|
39843
|
+
return false;
|
|
39844
|
+
if (queue.pending.length >= maxSize) {
|
|
39845
|
+
queue.pending.shift();
|
|
39846
|
+
}
|
|
39847
|
+
queue.pending.push(message);
|
|
39848
|
+
return true;
|
|
39849
|
+
}
|
|
39850
|
+
drain(agentName, ttlMs = QUEUE_TTL_MS) {
|
|
39851
|
+
const queue = this.queues.get(agentName);
|
|
39852
|
+
if (!queue)
|
|
39853
|
+
return [];
|
|
39854
|
+
const now = Date.now();
|
|
39855
|
+
const valid = queue.pending.filter((m2) => now - new Date(m2.queuedAt).getTime() < ttlMs);
|
|
39856
|
+
queue.pending = [];
|
|
39857
|
+
return valid;
|
|
39858
|
+
}
|
|
39859
|
+
isProcessing(agentName) {
|
|
39860
|
+
return this.queues.get(agentName)?.processing ?? false;
|
|
39861
|
+
}
|
|
39862
|
+
setProcessing(agentName, value) {
|
|
39863
|
+
const queue = this.queues.get(agentName);
|
|
39864
|
+
if (queue)
|
|
39865
|
+
queue.processing = value;
|
|
39866
|
+
}
|
|
39867
|
+
hasPending(agentName) {
|
|
39868
|
+
return (this.queues.get(agentName)?.pending.length ?? 0) > 0;
|
|
39869
|
+
}
|
|
39870
|
+
pendingCount(agentName) {
|
|
39871
|
+
return this.queues.get(agentName)?.pending.length ?? 0;
|
|
39872
|
+
}
|
|
39873
|
+
get anyProcessing() {
|
|
39874
|
+
for (const q2 of this.queues.values()) {
|
|
39875
|
+
if (q2.processing)
|
|
39876
|
+
return true;
|
|
39877
|
+
}
|
|
39878
|
+
return false;
|
|
39879
|
+
}
|
|
39880
|
+
setController(agentName, controller) {
|
|
39881
|
+
const queue = this.queues.get(agentName);
|
|
39882
|
+
if (queue)
|
|
39883
|
+
queue.controller = controller;
|
|
39884
|
+
}
|
|
39885
|
+
abortAll() {
|
|
39886
|
+
for (const q2 of this.queues.values()) {
|
|
39887
|
+
q2.controller?.abort();
|
|
39888
|
+
q2.pending = [];
|
|
39889
|
+
}
|
|
39890
|
+
}
|
|
39891
|
+
clearAll() {
|
|
39892
|
+
for (const q2 of this.queues.values()) {
|
|
39893
|
+
q2.pending = [];
|
|
39894
|
+
q2.processing = false;
|
|
39895
|
+
}
|
|
39896
|
+
}
|
|
39897
|
+
}
|
|
39690
39898
|
|
|
39691
39899
|
class Orchestrator {
|
|
39692
39900
|
agents;
|
|
@@ -39702,7 +39910,16 @@ class Orchestrator {
|
|
|
39702
39910
|
contextWindowSize;
|
|
39703
39911
|
reminderInterval;
|
|
39704
39912
|
reminderCursors = new Map;
|
|
39913
|
+
maxAutoHops;
|
|
39914
|
+
queueTtlMs;
|
|
39915
|
+
maxQueueSize;
|
|
39705
39916
|
messageId = 0;
|
|
39917
|
+
stickyTargets;
|
|
39918
|
+
queueManager = new AgentQueueManager;
|
|
39919
|
+
manifestSavePromise = Promise.resolve();
|
|
39920
|
+
onMessage = () => {};
|
|
39921
|
+
onActivity = () => {};
|
|
39922
|
+
onSystem = () => {};
|
|
39706
39923
|
constructor(agents, humanName = "USER", agentTags, humanTag, defaultTimeout = 600000, agentTimeouts, options) {
|
|
39707
39924
|
this.agents = new Map(agents.map((agent) => [agent.name, agent]));
|
|
39708
39925
|
this.agentTags = new Map(agents.map((agent) => [agent.name, agentTags?.[agent.name] ?? toTag(agent.name)]));
|
|
@@ -39712,12 +39929,21 @@ class Orchestrator {
|
|
|
39712
39929
|
this.agentTimeouts = new Map(Object.entries(agentTimeouts ?? {}));
|
|
39713
39930
|
this.contextWindowSize = options?.contextWindowSize ?? 16;
|
|
39714
39931
|
this.reminderInterval = options?.reminderInterval ?? 8;
|
|
39932
|
+
this.maxAutoHops = options?.maxAutoHops ?? 15;
|
|
39933
|
+
this.queueTtlMs = options?.queueTtlMs ?? QUEUE_TTL_MS;
|
|
39934
|
+
this.maxQueueSize = options?.maxQueueSize ?? MAX_QUEUE_SIZE;
|
|
39715
39935
|
this.sessionId = createSessionId();
|
|
39716
39936
|
this.transcriptPath = path9.resolve(".llm-party", "sessions", `transcript-${this.sessionId}.jsonl`);
|
|
39717
39937
|
for (const agent of agents) {
|
|
39718
39938
|
this.lastSeenByAgent.set(agent.name, 0);
|
|
39939
|
+
this.queueManager.register(agent.name);
|
|
39719
39940
|
}
|
|
39720
39941
|
}
|
|
39942
|
+
setCallbacks(onMessage, onActivity, onSystem) {
|
|
39943
|
+
this.onMessage = onMessage;
|
|
39944
|
+
this.onActivity = onActivity;
|
|
39945
|
+
this.onSystem = onSystem;
|
|
39946
|
+
}
|
|
39721
39947
|
getSessionId() {
|
|
39722
39948
|
return this.sessionId;
|
|
39723
39949
|
}
|
|
@@ -39730,12 +39956,29 @@ class Orchestrator {
|
|
|
39730
39956
|
getHumanTag() {
|
|
39731
39957
|
return this.humanTag;
|
|
39732
39958
|
}
|
|
39959
|
+
get dispatching() {
|
|
39960
|
+
return this.queueManager.anyProcessing;
|
|
39961
|
+
}
|
|
39962
|
+
getStickyTarget() {
|
|
39963
|
+
return this.stickyTargets;
|
|
39964
|
+
}
|
|
39965
|
+
setStickyTarget(targets) {
|
|
39966
|
+
this.stickyTargets = targets;
|
|
39967
|
+
}
|
|
39968
|
+
getQueueStatus() {
|
|
39969
|
+
return this.listAgents().map((a) => ({
|
|
39970
|
+
name: a.name,
|
|
39971
|
+
processing: this.queueManager.isProcessing(a.name),
|
|
39972
|
+
pending: this.queueManager.pendingCount(a.name)
|
|
39973
|
+
}));
|
|
39974
|
+
}
|
|
39733
39975
|
clearConversation() {
|
|
39734
39976
|
this.conversation.length = 0;
|
|
39735
39977
|
this.messageId = 0;
|
|
39736
39978
|
for (const agent of this.agents.keys()) {
|
|
39737
39979
|
this.lastSeenByAgent.set(agent, 0);
|
|
39738
39980
|
}
|
|
39981
|
+
this.queueManager.clearAll();
|
|
39739
39982
|
this.sessionId = createSessionId();
|
|
39740
39983
|
this.transcriptPath = path9.resolve(".llm-party", "sessions", `transcript-${this.sessionId}.jsonl`);
|
|
39741
39984
|
}
|
|
@@ -39772,62 +40015,158 @@ class Orchestrator {
|
|
|
39772
40015
|
const tag = this.agentTags.get(agent.name) ?? toTag(agent.name);
|
|
39773
40016
|
return agent.name.toLowerCase() === normalized || tag.toLowerCase() === normalized;
|
|
39774
40017
|
}).map((agent) => agent.name);
|
|
39775
|
-
if (byName.length > 0)
|
|
40018
|
+
if (byName.length > 0)
|
|
39776
40019
|
return byName;
|
|
39777
|
-
}
|
|
39778
40020
|
return Array.from(this.agents.values()).filter((agent) => agent.provider.toLowerCase() === normalized).map((agent) => agent.name);
|
|
39779
40021
|
}
|
|
39780
|
-
|
|
39781
|
-
|
|
39782
|
-
|
|
39783
|
-
|
|
39784
|
-
const requestedTargets = targetAgentNames && targetAgentNames.length > 0 ? targetAgentNames : Array.from(this.agents.keys());
|
|
39785
|
-
const targets = requestedTargets.map((name) => this.agents.get(name)).filter((agent) => Boolean(agent));
|
|
39786
|
-
const historyMaxId = this.messageId;
|
|
39787
|
-
const settled = await Promise.allSettled(targets.map(async (agent) => {
|
|
39788
|
-
const lastSeen = this.lastSeenByAgent.get(agent.name) ?? 0;
|
|
39789
|
-
const unseen = this.conversation.filter((msg) => msg.id > lastSeen && msg.from.toUpperCase() !== agent.name.toUpperCase());
|
|
39790
|
-
if (unseen.length === 0) {
|
|
39791
|
-
this.lastSeenByAgent.set(agent.name, historyMaxId);
|
|
39792
|
-
return null;
|
|
39793
|
-
}
|
|
39794
|
-
const inputMessages = this.buildInputForAgent(agent.name, unseen);
|
|
39795
|
-
const responseText = await this.sendWithTimeout(agent, inputMessages, this.timeoutFor(agent.name));
|
|
39796
|
-
const response = {
|
|
39797
|
-
id: ++this.messageId,
|
|
39798
|
-
from: agent.name.toUpperCase(),
|
|
39799
|
-
text: responseText,
|
|
39800
|
-
createdAt: new Date().toISOString()
|
|
39801
|
-
};
|
|
39802
|
-
this.lastSeenByAgent.set(agent.name, historyMaxId);
|
|
39803
|
-
this.conversation.push(response);
|
|
39804
|
-
await this.appendTranscript(response);
|
|
39805
|
-
onMessage(response);
|
|
39806
|
-
return response;
|
|
39807
|
-
}));
|
|
39808
|
-
const results = [];
|
|
39809
|
-
for (let idx = 0;idx < settled.length; idx++) {
|
|
39810
|
-
const item = settled[idx];
|
|
39811
|
-
if (item.status === "fulfilled") {
|
|
39812
|
-
if (item.value) {
|
|
39813
|
-
results.push(item.value);
|
|
39814
|
-
}
|
|
40022
|
+
dispatchToTargets(targetAgentNames, chainHops = 0) {
|
|
40023
|
+
for (const name of targetAgentNames) {
|
|
40024
|
+
const agent = this.agents.get(name);
|
|
40025
|
+
if (!agent)
|
|
39815
40026
|
continue;
|
|
40027
|
+
if (this.queueManager.isProcessing(name)) {
|
|
40028
|
+
this.queueManager.enqueue(name, {
|
|
40029
|
+
from: "dispatch",
|
|
40030
|
+
text: "",
|
|
40031
|
+
queuedAt: new Date().toISOString(),
|
|
40032
|
+
chainHops
|
|
40033
|
+
}, this.maxQueueSize);
|
|
40034
|
+
this.onSystem(`Queued for ${name} (busy, ${this.queueManager.pendingCount(name)} pending)`);
|
|
40035
|
+
} else {
|
|
40036
|
+
this.processAgent(name, chainHops);
|
|
39816
40037
|
}
|
|
39817
|
-
const agent = targets[idx];
|
|
39818
|
-
const response = {
|
|
39819
|
-
id: ++this.messageId,
|
|
39820
|
-
from: agent.name.toUpperCase(),
|
|
39821
|
-
text: `[Adapter Error] ${item.reason instanceof Error ? item.reason.message : String(item.reason)}`,
|
|
39822
|
-
createdAt: new Date().toISOString()
|
|
39823
|
-
};
|
|
39824
|
-
this.lastSeenByAgent.set(agent.name, historyMaxId);
|
|
39825
|
-
this.conversation.push(response);
|
|
39826
|
-
await this.appendTranscript(response);
|
|
39827
|
-
onMessage(response);
|
|
39828
|
-
results.push(response);
|
|
39829
40038
|
}
|
|
39830
|
-
|
|
40039
|
+
}
|
|
40040
|
+
async processAgent(agentName, chainHops) {
|
|
40041
|
+
const agent = this.agents.get(agentName);
|
|
40042
|
+
if (!agent)
|
|
40043
|
+
return;
|
|
40044
|
+
this.queueManager.setProcessing(agentName, true);
|
|
40045
|
+
this.onActivity(agentName, "thinking");
|
|
40046
|
+
const historyMaxId = this.messageId;
|
|
40047
|
+
const lastSeen = this.lastSeenByAgent.get(agentName) ?? 0;
|
|
40048
|
+
const unseen = this.conversation.filter((msg) => msg.id > lastSeen && msg.from.toUpperCase() !== agentName.toUpperCase());
|
|
40049
|
+
if (unseen.length === 0) {
|
|
40050
|
+
this.lastSeenByAgent.set(agentName, historyMaxId);
|
|
40051
|
+
this.queueManager.setProcessing(agentName, false);
|
|
40052
|
+
this.onActivity(agentName, "idle");
|
|
40053
|
+
this.drainQueue(agentName);
|
|
40054
|
+
return;
|
|
40055
|
+
}
|
|
40056
|
+
const inputMessages = this.buildInputForAgent(agentName, unseen);
|
|
40057
|
+
const responseText = await this.streamWithTimeout(agentName, agent, inputMessages, this.timeoutFor(agentName));
|
|
40058
|
+
const response = {
|
|
40059
|
+
id: ++this.messageId,
|
|
40060
|
+
from: agentName.toUpperCase(),
|
|
40061
|
+
text: responseText,
|
|
40062
|
+
createdAt: new Date().toISOString()
|
|
40063
|
+
};
|
|
40064
|
+
this.lastSeenByAgent.set(agentName, historyMaxId);
|
|
40065
|
+
this.conversation.push(response);
|
|
40066
|
+
await this.appendTranscript(response);
|
|
40067
|
+
this.onMessage(response);
|
|
40068
|
+
await this.saveManifest();
|
|
40069
|
+
this.queueManager.setProcessing(agentName, false);
|
|
40070
|
+
const isError = responseText.startsWith("[Timeout]") || responseText.startsWith("[Error]") || responseText.startsWith("[Adapter Error]");
|
|
40071
|
+
if (!isError) {
|
|
40072
|
+
this.processHandoffs(response, chainHops);
|
|
40073
|
+
}
|
|
40074
|
+
this.drainQueue(agentName);
|
|
40075
|
+
}
|
|
40076
|
+
processHandoffs(response, currentHops) {
|
|
40077
|
+
const selectors = extractNextSelectors([response]);
|
|
40078
|
+
if (selectors.length === 0)
|
|
40079
|
+
return;
|
|
40080
|
+
const humanTag = this.humanTag.toLowerCase();
|
|
40081
|
+
const humanName = this.humanName.toLowerCase();
|
|
40082
|
+
const agentSelectors = selectors.filter((s) => {
|
|
40083
|
+
const n = s.toLowerCase();
|
|
40084
|
+
return n !== humanTag && n !== humanName;
|
|
40085
|
+
});
|
|
40086
|
+
if (agentSelectors.length === 0)
|
|
40087
|
+
return;
|
|
40088
|
+
const resolvedTargets = Array.from(new Set(agentSelectors.flatMap((s) => this.resolveTargets(s))));
|
|
40089
|
+
if (resolvedTargets.length === 0)
|
|
40090
|
+
return;
|
|
40091
|
+
const nextHops = currentHops + 1;
|
|
40092
|
+
if (nextHops >= this.maxAutoHops) {
|
|
40093
|
+
this.onSystem(`Stopped auto-handoff after ${this.maxAutoHops} hops.`);
|
|
40094
|
+
return;
|
|
40095
|
+
}
|
|
40096
|
+
this.onSystem(`Auto handoff via @next to ${resolvedTargets.join(", ")}`);
|
|
40097
|
+
this.dispatchToTargets(resolvedTargets, nextHops);
|
|
40098
|
+
}
|
|
40099
|
+
drainQueue(agentName) {
|
|
40100
|
+
if (!this.queueManager.hasPending(agentName)) {
|
|
40101
|
+
this.onActivity(agentName, "idle");
|
|
40102
|
+
return;
|
|
40103
|
+
}
|
|
40104
|
+
const pending = this.queueManager.drain(agentName, this.queueTtlMs);
|
|
40105
|
+
if (pending.length === 0) {
|
|
40106
|
+
this.onActivity(agentName, "idle");
|
|
40107
|
+
return;
|
|
40108
|
+
}
|
|
40109
|
+
const maxHops = Math.max(...pending.map((m2) => m2.chainHops));
|
|
40110
|
+
if (maxHops >= this.maxAutoHops) {
|
|
40111
|
+
this.onSystem(`Stopped auto-handoff for ${agentName} after ${this.maxAutoHops} hops.`);
|
|
40112
|
+
this.onActivity(agentName, "idle");
|
|
40113
|
+
return;
|
|
40114
|
+
}
|
|
40115
|
+
this.processAgent(agentName, maxHops);
|
|
40116
|
+
}
|
|
40117
|
+
async streamWithTimeout(agentName, agent, messages, timeoutMs) {
|
|
40118
|
+
const controller = new AbortController;
|
|
40119
|
+
this.queueManager.setController(agentName, controller);
|
|
40120
|
+
let timer;
|
|
40121
|
+
let resolved = false;
|
|
40122
|
+
return new Promise((resolve4) => {
|
|
40123
|
+
timer = setTimeout(() => {
|
|
40124
|
+
if (!resolved) {
|
|
40125
|
+
resolved = true;
|
|
40126
|
+
controller.abort();
|
|
40127
|
+
this.onActivity(agentName, "error", "timeout");
|
|
40128
|
+
resolve4(`[Timeout] ${agentName} exceeded ${Math.floor(timeoutMs / 1000)}s`);
|
|
40129
|
+
}
|
|
40130
|
+
}, timeoutMs);
|
|
40131
|
+
(async () => {
|
|
40132
|
+
try {
|
|
40133
|
+
for await (const event of agent.stream(messages, controller.signal)) {
|
|
40134
|
+
if (resolved)
|
|
40135
|
+
return;
|
|
40136
|
+
if (event.type === "activity") {
|
|
40137
|
+
this.onActivity(agentName, event.activity, event.detail);
|
|
40138
|
+
} else if (event.type === "response") {
|
|
40139
|
+
resolved = true;
|
|
40140
|
+
if (timer)
|
|
40141
|
+
clearTimeout(timer);
|
|
40142
|
+
resolve4(event.text);
|
|
40143
|
+
return;
|
|
40144
|
+
} else if (event.type === "error") {
|
|
40145
|
+
resolved = true;
|
|
40146
|
+
if (timer)
|
|
40147
|
+
clearTimeout(timer);
|
|
40148
|
+
this.onActivity(agentName, "error");
|
|
40149
|
+
resolve4(`[Error] ${agentName}: ${event.message}`);
|
|
40150
|
+
return;
|
|
40151
|
+
}
|
|
40152
|
+
}
|
|
40153
|
+
if (!resolved) {
|
|
40154
|
+
resolved = true;
|
|
40155
|
+
if (timer)
|
|
40156
|
+
clearTimeout(timer);
|
|
40157
|
+
resolve4(`[No text response from ${agentName}]`);
|
|
40158
|
+
}
|
|
40159
|
+
} catch (err) {
|
|
40160
|
+
if (!resolved) {
|
|
40161
|
+
resolved = true;
|
|
40162
|
+
if (timer)
|
|
40163
|
+
clearTimeout(timer);
|
|
40164
|
+
this.onActivity(agentName, "error");
|
|
40165
|
+
resolve4(`[Error] ${agentName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
40166
|
+
}
|
|
40167
|
+
}
|
|
40168
|
+
})();
|
|
40169
|
+
});
|
|
39831
40170
|
}
|
|
39832
40171
|
async appendTranscript(message) {
|
|
39833
40172
|
try {
|
|
@@ -39840,23 +40179,85 @@ class Orchestrator {
|
|
|
39840
40179
|
async saveHistory(targetPath) {
|
|
39841
40180
|
await writeFile5(targetPath, JSON.stringify(this.conversation, null, 2), "utf8");
|
|
39842
40181
|
}
|
|
39843
|
-
async
|
|
39844
|
-
const
|
|
39845
|
-
|
|
39846
|
-
const
|
|
39847
|
-
|
|
39848
|
-
|
|
39849
|
-
|
|
39850
|
-
|
|
40182
|
+
async loadTranscript(sessionId) {
|
|
40183
|
+
const transcriptFile = path9.resolve(".llm-party", "sessions", `transcript-${sessionId}.jsonl`);
|
|
40184
|
+
const content = await readFile5(transcriptFile, "utf8");
|
|
40185
|
+
const lines = content.trim().split(`
|
|
40186
|
+
`).filter(Boolean);
|
|
40187
|
+
const messages = lines.map((line) => JSON.parse(line));
|
|
40188
|
+
this.conversation.length = 0;
|
|
40189
|
+
this.conversation.push(...messages);
|
|
40190
|
+
const maxId = messages.length > 0 ? Math.max(...messages.map((m2) => m2.id)) : 0;
|
|
40191
|
+
this.messageId = maxId;
|
|
40192
|
+
for (const agent of this.agents.keys()) {
|
|
40193
|
+
this.lastSeenByAgent.set(agent, maxId);
|
|
40194
|
+
}
|
|
40195
|
+
this.sessionId = sessionId;
|
|
40196
|
+
this.transcriptPath = transcriptFile;
|
|
40197
|
+
await this.loadManifest();
|
|
40198
|
+
return messages;
|
|
40199
|
+
}
|
|
40200
|
+
hasMessages() {
|
|
40201
|
+
return this.conversation.length > 0;
|
|
40202
|
+
}
|
|
40203
|
+
manifestPath() {
|
|
40204
|
+
const dir = path9.dirname(this.transcriptPath);
|
|
40205
|
+
const base = path9.basename(this.transcriptPath, ".jsonl");
|
|
40206
|
+
return path9.join(dir, `${base}.manifest.json`);
|
|
40207
|
+
}
|
|
40208
|
+
async saveManifest() {
|
|
40209
|
+
this.manifestSavePromise = this.manifestSavePromise.then(async () => {
|
|
40210
|
+
try {
|
|
40211
|
+
const agents = {};
|
|
40212
|
+
for (const [name, adapter] of this.agents) {
|
|
40213
|
+
const sid = adapter.getSdkSessionId();
|
|
40214
|
+
agents[name] = {
|
|
40215
|
+
provider: adapter.provider,
|
|
40216
|
+
sdkSessionId: sid || "",
|
|
40217
|
+
lastSeenId: this.lastSeenByAgent.get(name) ?? 0
|
|
40218
|
+
};
|
|
40219
|
+
}
|
|
40220
|
+
const manifest = {
|
|
40221
|
+
orchestratorSessionId: this.sessionId,
|
|
40222
|
+
messageId: this.messageId,
|
|
40223
|
+
stickyTarget: this.stickyTargets,
|
|
40224
|
+
agents
|
|
40225
|
+
};
|
|
40226
|
+
await writeFile5(this.manifestPath(), JSON.stringify(manifest, null, 2), "utf8");
|
|
40227
|
+
} catch (err) {
|
|
40228
|
+
console.error("[manifest] write failed:", err);
|
|
40229
|
+
}
|
|
39851
40230
|
});
|
|
40231
|
+
return this.manifestSavePromise;
|
|
40232
|
+
}
|
|
40233
|
+
async loadManifest() {
|
|
39852
40234
|
try {
|
|
39853
|
-
|
|
39854
|
-
|
|
39855
|
-
if (
|
|
39856
|
-
|
|
40235
|
+
const content = await readFile5(this.manifestPath(), "utf8");
|
|
40236
|
+
const manifest = JSON.parse(content);
|
|
40237
|
+
if (Array.isArray(manifest.stickyTarget)) {
|
|
40238
|
+
this.stickyTargets = manifest.stickyTarget;
|
|
40239
|
+
}
|
|
40240
|
+
const agentMap = manifest.agents ?? {};
|
|
40241
|
+
for (const [name, data] of Object.entries(agentMap)) {
|
|
40242
|
+
const adapter = this.agents.get(name);
|
|
40243
|
+
const agentData = data;
|
|
40244
|
+
if (!adapter || !agentData)
|
|
40245
|
+
continue;
|
|
40246
|
+
if (typeof agentData.sdkSessionId === "string" && agentData.sdkSessionId) {
|
|
40247
|
+
adapter.setSdkSessionId(agentData.sdkSessionId);
|
|
40248
|
+
}
|
|
40249
|
+
if (typeof agentData.lastSeenId === "number") {
|
|
40250
|
+
this.lastSeenByAgent.set(name, agentData.lastSeenId);
|
|
40251
|
+
}
|
|
39857
40252
|
}
|
|
40253
|
+
} catch (err) {
|
|
40254
|
+
console.error("[manifest] load failed (agents start fresh):", err);
|
|
39858
40255
|
}
|
|
39859
40256
|
}
|
|
40257
|
+
async abortAll() {
|
|
40258
|
+
this.queueManager.abortAll();
|
|
40259
|
+
await this.saveManifest();
|
|
40260
|
+
}
|
|
39860
40261
|
timeoutFor(agentName) {
|
|
39861
40262
|
return this.agentTimeouts.get(agentName) ?? this.defaultTimeout;
|
|
39862
40263
|
}
|
|
@@ -39890,9 +40291,24 @@ function createSessionId() {
|
|
|
39890
40291
|
const rand = randomBytes(4).toString("hex");
|
|
39891
40292
|
return `${timestamp}-${process.pid}-${rand}`;
|
|
39892
40293
|
}
|
|
40294
|
+
function extractNextSelectors(messages) {
|
|
40295
|
+
const selectors = [];
|
|
40296
|
+
for (const msg of messages) {
|
|
40297
|
+
const regex = /@next\s*:\s*([A-Za-z0-9_-]+)/gi;
|
|
40298
|
+
let match = null;
|
|
40299
|
+
while ((match = regex.exec(msg.text)) !== null) {
|
|
40300
|
+
selectors.push(match[1]);
|
|
40301
|
+
}
|
|
40302
|
+
const controlMatch = msg.text.match(/@control[\s\S]*?next\s*:\s*([A-Za-z0-9_-]+)[\s\S]*?@end/i);
|
|
40303
|
+
if (controlMatch?.[1]) {
|
|
40304
|
+
selectors.push(controlMatch[1]);
|
|
40305
|
+
}
|
|
40306
|
+
}
|
|
40307
|
+
return selectors;
|
|
40308
|
+
}
|
|
39893
40309
|
|
|
39894
40310
|
// src/ui/App.tsx
|
|
39895
|
-
import { spawn as
|
|
40311
|
+
import { spawn as spawn4 } from "child_process";
|
|
39896
40312
|
|
|
39897
40313
|
// src/ui/useOrchestrator.ts
|
|
39898
40314
|
import { execFile } from "child_process";
|
|
@@ -39901,14 +40317,56 @@ function nextSystemId() {
|
|
|
39901
40317
|
systemIdCounter -= 1;
|
|
39902
40318
|
return systemIdCounter;
|
|
39903
40319
|
}
|
|
39904
|
-
function useOrchestrator(orchestrator
|
|
40320
|
+
function useOrchestrator(orchestrator) {
|
|
39905
40321
|
const [messages, setMessages] = createSignal([]);
|
|
39906
40322
|
const [agentStates, setAgentStates] = createSignal(new Map(orchestrator.listAgents().map((a) => [a.name, "idle"])));
|
|
39907
|
-
const [stickyTarget,
|
|
40323
|
+
const [stickyTarget, setStickyTargetSignal] = createSignal(orchestrator.getStickyTarget());
|
|
40324
|
+
const setStickyTarget = (targets) => {
|
|
40325
|
+
setStickyTargetSignal(targets);
|
|
40326
|
+
orchestrator.setStickyTarget(targets);
|
|
40327
|
+
};
|
|
39908
40328
|
const [dispatching, setDispatching] = createSignal(false);
|
|
40329
|
+
const [queueCounts, setQueueCounts] = createSignal(new Map(orchestrator.listAgents().map((a) => [a.name, 0])));
|
|
39909
40330
|
let projectFolderReady = false;
|
|
39910
|
-
|
|
39911
|
-
|
|
40331
|
+
const agentProviders = new Map(orchestrator.listAgents().map((a) => [a.name.toUpperCase(), a.provider]));
|
|
40332
|
+
const agentTagsMap = new Map(orchestrator.listAgents().map((a) => [a.name.toUpperCase(), a.tag]));
|
|
40333
|
+
const nameMap = new Map(orchestrator.listAgents().map((a) => [a.name.toUpperCase(), a.name]));
|
|
40334
|
+
const updateQueueCounts = () => {
|
|
40335
|
+
const status = orchestrator.getQueueStatus();
|
|
40336
|
+
setQueueCounts(new Map(status.map((s) => [s.name, s.pending])));
|
|
40337
|
+
};
|
|
40338
|
+
orchestrator.setCallbacks((msg) => {
|
|
40339
|
+
const provider = agentProviders.get(msg.from) ?? "";
|
|
40340
|
+
const tag = agentTagsMap.get(msg.from) ?? "";
|
|
40341
|
+
const display = {
|
|
40342
|
+
...msg,
|
|
40343
|
+
type: "agent",
|
|
40344
|
+
provider,
|
|
40345
|
+
tag
|
|
40346
|
+
};
|
|
40347
|
+
setMessages((prev) => [...prev, display]);
|
|
40348
|
+
const originalName = nameMap.get(msg.from) ?? msg.from;
|
|
40349
|
+
setAgentStates((prev) => {
|
|
40350
|
+
const next = new Map(prev);
|
|
40351
|
+
const isErr = msg.text.startsWith("[Adapter Error]") || msg.text.startsWith("[Error]") || msg.text.startsWith("[Timeout]");
|
|
40352
|
+
next.set(originalName, isErr ? "error" : "idle");
|
|
40353
|
+
return next;
|
|
40354
|
+
});
|
|
40355
|
+
setDispatching(orchestrator.dispatching);
|
|
40356
|
+
updateQueueCounts();
|
|
40357
|
+
}, (agentName, activity) => {
|
|
40358
|
+
const originalName = nameMap.get(agentName.toUpperCase()) ?? agentName;
|
|
40359
|
+
setAgentStates((prev) => {
|
|
40360
|
+
const next = new Map(prev);
|
|
40361
|
+
next.set(originalName, activity);
|
|
40362
|
+
return next;
|
|
40363
|
+
});
|
|
40364
|
+
setDispatching(orchestrator.dispatching);
|
|
40365
|
+
updateQueueCounts();
|
|
40366
|
+
}, (text) => {
|
|
40367
|
+
addSystemMessage(text);
|
|
40368
|
+
updateQueueCounts();
|
|
40369
|
+
});
|
|
39912
40370
|
const dispatch = async (line) => {
|
|
39913
40371
|
if (!line.trim())
|
|
39914
40372
|
return;
|
|
@@ -39922,7 +40380,7 @@ function useOrchestrator(orchestrator, maxAutoHops) {
|
|
|
39922
40380
|
if (explicitTargets && explicitTargets.length > 0) {
|
|
39923
40381
|
setStickyTarget(explicitTargets);
|
|
39924
40382
|
}
|
|
39925
|
-
const targets = explicitTargets ?? stickyTarget();
|
|
40383
|
+
const targets = explicitTargets ?? stickyTarget() ?? Array.from(orchestrator.listAgents().map((a) => a.name));
|
|
39926
40384
|
if (!projectFolderReady) {
|
|
39927
40385
|
await initProjectFolder(process.cwd());
|
|
39928
40386
|
projectFolderReady = true;
|
|
@@ -39935,11 +40393,7 @@ function useOrchestrator(orchestrator, maxAutoHops) {
|
|
|
39935
40393
|
};
|
|
39936
40394
|
setMessages((prev) => [...prev, userDisplay]);
|
|
39937
40395
|
setDispatching(true);
|
|
39938
|
-
|
|
39939
|
-
await dispatchWithHandoffs(orchestrator, targets, maxAutoHops, agentProviders, agentTags, setMessages, setAgentStates);
|
|
39940
|
-
} finally {
|
|
39941
|
-
setDispatching(false);
|
|
39942
|
-
}
|
|
40396
|
+
orchestrator.dispatchToTargets(targets);
|
|
39943
40397
|
};
|
|
39944
40398
|
const addSystemMessage = (text) => {
|
|
39945
40399
|
const msg = {
|
|
@@ -39951,89 +40405,17 @@ function useOrchestrator(orchestrator, maxAutoHops) {
|
|
|
39951
40405
|
};
|
|
39952
40406
|
setMessages((prev) => [...prev, msg]);
|
|
39953
40407
|
};
|
|
40408
|
+
const addDisplayMessage = (msg) => {
|
|
40409
|
+
setMessages((prev) => [...prev, msg]);
|
|
40410
|
+
};
|
|
39954
40411
|
const clearMessages = () => {
|
|
39955
40412
|
orchestrator.clearConversation();
|
|
39956
40413
|
setMessages([]);
|
|
39957
40414
|
};
|
|
39958
|
-
|
|
39959
|
-
|
|
39960
|
-
|
|
39961
|
-
|
|
39962
|
-
let hops = 0;
|
|
39963
|
-
while (true) {
|
|
39964
|
-
const targetNames = targets ?? Array.from(orchestrator.listAgents().map((a) => a.name));
|
|
39965
|
-
setAgentStates((prev) => {
|
|
39966
|
-
const next = new Map(prev);
|
|
39967
|
-
for (const name of targetNames) {
|
|
39968
|
-
next.set(name, "thinking");
|
|
39969
|
-
}
|
|
39970
|
-
return next;
|
|
39971
|
-
});
|
|
39972
|
-
const nameMap = new Map(orchestrator.listAgents().map((a) => [a.name.toUpperCase(), a.name]));
|
|
39973
|
-
const batch = [];
|
|
39974
|
-
await orchestrator.fanOutWithProgress(targets, (msg) => {
|
|
39975
|
-
batch.push(msg);
|
|
39976
|
-
const provider = agentProviders.get(msg.from) ?? "";
|
|
39977
|
-
const tag = agentTags.get(msg.from) ?? "";
|
|
39978
|
-
const display = {
|
|
39979
|
-
...msg,
|
|
39980
|
-
type: "agent",
|
|
39981
|
-
provider,
|
|
39982
|
-
tag
|
|
39983
|
-
};
|
|
39984
|
-
setMessages((prev) => [...prev, display]);
|
|
39985
|
-
const originalName = nameMap.get(msg.from) ?? msg.from;
|
|
39986
|
-
setAgentStates((prev) => {
|
|
39987
|
-
const next = new Map(prev);
|
|
39988
|
-
next.set(originalName, msg.text.startsWith("[Adapter Error]") ? "error" : "idle");
|
|
39989
|
-
return next;
|
|
39990
|
-
});
|
|
39991
|
-
});
|
|
39992
|
-
setAgentStates((prev) => {
|
|
39993
|
-
const next = new Map(prev);
|
|
39994
|
-
for (const name of targetNames) {
|
|
39995
|
-
if (next.get(name) === "thinking") {
|
|
39996
|
-
next.set(name, "idle");
|
|
39997
|
-
}
|
|
39998
|
-
}
|
|
39999
|
-
return next;
|
|
40000
|
-
});
|
|
40001
|
-
const nextSelectors = extractNextSelectors(batch);
|
|
40002
|
-
if (nextSelectors.length === 0)
|
|
40003
|
-
return;
|
|
40004
|
-
const humanTag = orchestrator.getHumanTag().toLowerCase();
|
|
40005
|
-
const humanName = orchestrator.getHumanName().toLowerCase();
|
|
40006
|
-
const agentSelectors = nextSelectors.filter((s) => {
|
|
40007
|
-
const n = s.toLowerCase();
|
|
40008
|
-
return n !== humanTag && n !== humanName;
|
|
40009
|
-
});
|
|
40010
|
-
if (agentSelectors.length === 0)
|
|
40011
|
-
return;
|
|
40012
|
-
const resolvedTargets = Array.from(new Set(agentSelectors.flatMap((s) => orchestrator.resolveTargets(s))));
|
|
40013
|
-
if (resolvedTargets.length === 0)
|
|
40014
|
-
return;
|
|
40015
|
-
hops += 1;
|
|
40016
|
-
if (Number.isFinite(maxHops) && hops >= maxHops) {
|
|
40017
|
-
const systemMsg = {
|
|
40018
|
-
id: nextSystemId(),
|
|
40019
|
-
from: "SYSTEM",
|
|
40020
|
-
text: `Stopped auto-handoff after ${maxHops} hops.`,
|
|
40021
|
-
createdAt: new Date().toISOString(),
|
|
40022
|
-
type: "system"
|
|
40023
|
-
};
|
|
40024
|
-
setMessages((prev) => [...prev, systemMsg]);
|
|
40025
|
-
return;
|
|
40026
|
-
}
|
|
40027
|
-
const handoffMsg = {
|
|
40028
|
-
id: nextSystemId(),
|
|
40029
|
-
from: "SYSTEM",
|
|
40030
|
-
text: `Auto handoff via @next to ${resolvedTargets.join(", ")}`,
|
|
40031
|
-
createdAt: new Date().toISOString(),
|
|
40032
|
-
type: "system"
|
|
40033
|
-
};
|
|
40034
|
-
setMessages((prev) => [...prev, handoffMsg]);
|
|
40035
|
-
targets = resolvedTargets;
|
|
40036
|
-
}
|
|
40415
|
+
const refreshStickyTarget = () => {
|
|
40416
|
+
setStickyTargetSignal(orchestrator.getStickyTarget());
|
|
40417
|
+
};
|
|
40418
|
+
return { messages, agentStates, queueCounts, stickyTarget, dispatching, dispatch, addSystemMessage, addDisplayMessage, clearMessages, refreshStickyTarget };
|
|
40037
40419
|
}
|
|
40038
40420
|
function getChangedFiles() {
|
|
40039
40421
|
return new Promise((resolve4) => {
|
|
@@ -40048,21 +40430,6 @@ function getChangedFiles() {
|
|
|
40048
40430
|
});
|
|
40049
40431
|
});
|
|
40050
40432
|
}
|
|
40051
|
-
function extractNextSelectors(messages) {
|
|
40052
|
-
const selectors = [];
|
|
40053
|
-
for (const msg of messages) {
|
|
40054
|
-
const regex = /@next\s*:\s*([A-Za-z0-9_-]+)/gi;
|
|
40055
|
-
let match = null;
|
|
40056
|
-
while ((match = regex.exec(msg.text)) !== null) {
|
|
40057
|
-
selectors.push(match[1]);
|
|
40058
|
-
}
|
|
40059
|
-
const controlMatch = msg.text.match(/@control[\s\S]*?next\s*:\s*([A-Za-z0-9_-]+)[\s\S]*?@end/i);
|
|
40060
|
-
if (controlMatch?.[1]) {
|
|
40061
|
-
selectors.push(controlMatch[1]);
|
|
40062
|
-
}
|
|
40063
|
-
}
|
|
40064
|
-
return selectors;
|
|
40065
|
-
}
|
|
40066
40433
|
function parseRouting(line) {
|
|
40067
40434
|
const mentionRegex = /(^|[^A-Za-z0-9_-])@([A-Za-z0-9_-]+)\b/g;
|
|
40068
40435
|
const mentions = [];
|
|
@@ -40151,27 +40518,21 @@ function MessageBubble(props) {
|
|
|
40151
40518
|
}
|
|
40152
40519
|
|
|
40153
40520
|
// src/ui/constants.ts
|
|
40154
|
-
var SPINNER_FRAMES =
|
|
40521
|
+
var SPINNER_FRAMES = "\u280B\u2819\u281A\u281E\u2816\u2826\u2834\u2832\u2833\u2813".split("");
|
|
40522
|
+
var ACTIVITY_SPINNERS = {
|
|
40523
|
+
thinking_bkp: "\u2733\u2734\u2736\u2735\u2737\u2738\u2739\u273A".split(""),
|
|
40524
|
+
thinking: " ..ooOO@@@@@@*".split(""),
|
|
40525
|
+
writing: "\u258F\u258E\u258D\u258C\u258B\u258A\u2589\u2588\u2589\u258A\u258B\u258C\u258D\u258E".split(""),
|
|
40526
|
+
reading: ["\u2801", "\u2809", "\u280B", "\u281B", "\u281F", "\u283F", "\u287F", "\u28FF"],
|
|
40527
|
+
running: [" ", "\u2591", "\u2592", "\u2593", "\u2588"],
|
|
40528
|
+
searching: "\u25D0\u25D3\u25D1\u25D2".split("")
|
|
40529
|
+
};
|
|
40530
|
+
var SUPERSCRIPT_DIGITS = ["\u2070", "\xB9", "\xB2", "\xB3", "\u2074", "\u2075", "\u2076", "\u2077", "\u2078", "\u2079"];
|
|
40155
40531
|
|
|
40156
40532
|
// src/ui/StatusBar.tsx
|
|
40157
40533
|
var PULSE_COLORS = ["#005F87", "#0087AF", "#00AFD7", "#00D7FF", "#5FF", "#00D7FF", "#0087AF"];
|
|
40158
|
-
|
|
40159
|
-
|
|
40160
|
-
createEffect(() => {
|
|
40161
|
-
if (!active()) {
|
|
40162
|
-
setFrame(0);
|
|
40163
|
-
return;
|
|
40164
|
-
}
|
|
40165
|
-
const interval = setInterval(() => {
|
|
40166
|
-
setFrame((f) => (f + 1) % (SPINNER_FRAMES.length * PULSE_COLORS.length));
|
|
40167
|
-
}, 80);
|
|
40168
|
-
onCleanup(() => clearInterval(interval));
|
|
40169
|
-
});
|
|
40170
|
-
return {
|
|
40171
|
-
spinner: () => active() ? SPINNER_FRAMES[frame() % SPINNER_FRAMES.length] : "",
|
|
40172
|
-
color: () => active() ? PULSE_COLORS[frame() % PULSE_COLORS.length] : COLORS.textMuted
|
|
40173
|
-
};
|
|
40174
|
-
}
|
|
40534
|
+
var [globalTick, setGlobalTick] = createSignal(0);
|
|
40535
|
+
setInterval(() => setGlobalTick((t2) => t2 + 1), 80);
|
|
40175
40536
|
function StatusBar(props) {
|
|
40176
40537
|
const targetNames = () => props.stickyTarget ?? props.agents.map((a) => a.name);
|
|
40177
40538
|
const isTargeted = (name) => targetNames().includes(name);
|
|
@@ -40219,65 +40580,59 @@ function StatusBar(props) {
|
|
|
40219
40580
|
}), _el$4);
|
|
40220
40581
|
insertNode(_el$4, createTextNode(`| /info`));
|
|
40221
40582
|
setProp(_el$6, "flexDirection", "row");
|
|
40222
|
-
setProp(_el$6, "gap", 2);
|
|
40223
40583
|
insert(_el$6, createComponent2(For, {
|
|
40224
40584
|
get each() {
|
|
40225
40585
|
return props.agents;
|
|
40226
40586
|
},
|
|
40227
|
-
children: (a) => createComponent2(AgentChip, {
|
|
40587
|
+
children: (a, i) => [createComponent2(AgentChip, {
|
|
40228
40588
|
get name() {
|
|
40229
40589
|
return a.name;
|
|
40230
40590
|
},
|
|
40231
|
-
|
|
40232
|
-
|
|
40233
|
-
|
|
40234
|
-
|
|
40591
|
+
getState: () => props.agentStates.get(a.name) ?? "idle",
|
|
40592
|
+
getQueued: () => props.queueCounts?.get(a.name) ?? 0
|
|
40593
|
+
}), memo2(() => memo2(() => i() < props.agents.length - 1)() ? (() => {
|
|
40594
|
+
var _el$12 = createElement("text");
|
|
40595
|
+
insertNode(_el$12, createTextNode(` \u2502 `));
|
|
40596
|
+
effect((_$p) => setProp(_el$12, "fg", COLORS.textDim, _$p));
|
|
40597
|
+
return _el$12;
|
|
40598
|
+
})() : null)]
|
|
40235
40599
|
}));
|
|
40236
40600
|
effect((_$p) => setProp(_el$4, "fg", COLORS.textDim, _$p));
|
|
40237
40601
|
return _el$;
|
|
40238
40602
|
})();
|
|
40239
40603
|
}
|
|
40604
|
+
function toSuperscript(n) {
|
|
40605
|
+
if (n <= 0)
|
|
40606
|
+
return "";
|
|
40607
|
+
return String(n).split("").map((d2) => SUPERSCRIPT_DIGITS[parseInt(d2, 10)] ?? d2).join("");
|
|
40608
|
+
}
|
|
40240
40609
|
function AgentChip(props) {
|
|
40241
|
-
const {
|
|
40242
|
-
|
|
40243
|
-
|
|
40244
|
-
}
|
|
40245
|
-
|
|
40246
|
-
|
|
40247
|
-
|
|
40248
|
-
|
|
40249
|
-
|
|
40250
|
-
|
|
40251
|
-
|
|
40252
|
-
|
|
40253
|
-
|
|
40254
|
-
|
|
40255
|
-
|
|
40256
|
-
|
|
40257
|
-
|
|
40258
|
-
|
|
40259
|
-
|
|
40260
|
-
|
|
40261
|
-
|
|
40262
|
-
|
|
40263
|
-
|
|
40264
|
-
|
|
40265
|
-
|
|
40266
|
-
|
|
40267
|
-
get when() {
|
|
40268
|
-
return props.state === "thinking";
|
|
40269
|
-
},
|
|
40270
|
-
get children() {
|
|
40271
|
-
var _el$14 = createElement("text"), _el$15 = createTextNode(` `);
|
|
40272
|
-
insertNode(_el$14, _el$15);
|
|
40273
|
-
insert(_el$14, () => props.name, _el$15);
|
|
40274
|
-
insert(_el$14, spinner, null);
|
|
40275
|
-
effect((_$p) => setProp(_el$14, "fg", color(), _$p));
|
|
40276
|
-
return _el$14;
|
|
40277
|
-
}
|
|
40278
|
-
})];
|
|
40279
|
-
}
|
|
40280
|
-
});
|
|
40610
|
+
const isActive = () => {
|
|
40611
|
+
const s = props.getState();
|
|
40612
|
+
return s !== "idle" && s !== "error" && s !== "queued";
|
|
40613
|
+
};
|
|
40614
|
+
const frames = () => ACTIVITY_SPINNERS[props.getState()] ?? SPINNER_FRAMES;
|
|
40615
|
+
const tick = () => globalTick();
|
|
40616
|
+
const spinner = () => isActive() ? frames()[tick() % frames().length] : " ";
|
|
40617
|
+
const pulseColor = () => isActive() ? PULSE_COLORS[tick() % PULSE_COLORS.length] : COLORS.textMuted;
|
|
40618
|
+
const queueSlot = () => props.getQueued() > 0 ? toSuperscript(props.getQueued()) : " ";
|
|
40619
|
+
const stateColor = () => {
|
|
40620
|
+
if (props.getState() === "error")
|
|
40621
|
+
return COLORS.error;
|
|
40622
|
+
if (isActive())
|
|
40623
|
+
return pulseColor();
|
|
40624
|
+
return COLORS.textMuted;
|
|
40625
|
+
};
|
|
40626
|
+
return (() => {
|
|
40627
|
+
var _el$14 = createElement("text"), _el$15 = createTextNode(` `);
|
|
40628
|
+
insertNode(_el$14, _el$15);
|
|
40629
|
+
insert(_el$14, queueSlot, _el$15);
|
|
40630
|
+
insert(_el$14, () => props.name, _el$15);
|
|
40631
|
+
insert(_el$14, spinner, null);
|
|
40632
|
+
insert(_el$14, () => props.getState() === "error" ? " ERR" : "", null);
|
|
40633
|
+
effect((_$p) => setProp(_el$14, "fg", stateColor(), _$p));
|
|
40634
|
+
return _el$14;
|
|
40635
|
+
})();
|
|
40281
40636
|
}
|
|
40282
40637
|
|
|
40283
40638
|
// src/ui/InputLine.tsx
|
|
@@ -40314,7 +40669,7 @@ function InputLine(props) {
|
|
|
40314
40669
|
useKeyboard((key) => {
|
|
40315
40670
|
if (props.disabled)
|
|
40316
40671
|
return;
|
|
40317
|
-
if (key.shift && (key.name === "enter" || key.name === "return")) {
|
|
40672
|
+
if ((key.shift || key.option || key.meta) && (key.name === "enter" || key.name === "return")) {
|
|
40318
40673
|
update(value.slice(0, cursor) + `
|
|
40319
40674
|
` + value.slice(cursor), cursor + 1);
|
|
40320
40675
|
return;
|
|
@@ -40529,15 +40884,15 @@ function InputLine(props) {
|
|
|
40529
40884
|
}
|
|
40530
40885
|
|
|
40531
40886
|
// src/ui/ConfigWizard.tsx
|
|
40532
|
-
import { userInfo as
|
|
40887
|
+
import { userInfo as userInfo2 } from "os";
|
|
40533
40888
|
|
|
40534
40889
|
// src/config/detector.ts
|
|
40535
|
-
import { spawn as
|
|
40536
|
-
var DETECT_TIMEOUT =
|
|
40890
|
+
import { spawn as spawn3 } from "child_process";
|
|
40891
|
+
var DETECT_TIMEOUT = 1e4;
|
|
40537
40892
|
function detectBinary(command) {
|
|
40538
40893
|
return new Promise((resolve4) => {
|
|
40539
40894
|
const timer = setTimeout(() => resolve4({ available: false }), DETECT_TIMEOUT);
|
|
40540
|
-
const proc =
|
|
40895
|
+
const proc = spawn3(command, ["--version"], {
|
|
40541
40896
|
stdio: ["ignore", "pipe", "ignore"],
|
|
40542
40897
|
shell: true,
|
|
40543
40898
|
timeout: DETECT_TIMEOUT,
|
|
@@ -40562,33 +40917,13 @@ function detectBinary(command) {
|
|
|
40562
40917
|
});
|
|
40563
40918
|
});
|
|
40564
40919
|
}
|
|
40565
|
-
function detectAlias(command) {
|
|
40566
|
-
return new Promise((resolve4) => {
|
|
40567
|
-
const shell = process.env.SHELL || "/bin/bash";
|
|
40568
|
-
const timer = setTimeout(() => resolve4({ available: false }), DETECT_TIMEOUT);
|
|
40569
|
-
const proc = spawn4(shell, ["-ic", `type ${command}`], {
|
|
40570
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
40571
|
-
timeout: DETECT_TIMEOUT,
|
|
40572
|
-
detached: true
|
|
40573
|
-
});
|
|
40574
|
-
proc.unref();
|
|
40575
|
-
proc.on("close", (code) => {
|
|
40576
|
-
clearTimeout(timer);
|
|
40577
|
-
resolve4({ available: code === 0 });
|
|
40578
|
-
});
|
|
40579
|
-
proc.on("error", () => {
|
|
40580
|
-
clearTimeout(timer);
|
|
40581
|
-
resolve4({ available: false });
|
|
40582
|
-
});
|
|
40583
|
-
});
|
|
40584
|
-
}
|
|
40585
40920
|
async function detectProviders() {
|
|
40586
40921
|
const results = await Promise.allSettled(PROVIDERS.map(async (provider) => {
|
|
40587
|
-
const result =
|
|
40922
|
+
const result = await detectBinary(provider.detectCommand);
|
|
40588
40923
|
return {
|
|
40589
40924
|
id: provider.id,
|
|
40590
40925
|
available: result.available,
|
|
40591
|
-
version:
|
|
40926
|
+
version: result.version
|
|
40592
40927
|
};
|
|
40593
40928
|
}));
|
|
40594
40929
|
return results.map((result, i) => {
|
|
@@ -40600,57 +40935,8 @@ async function detectProviders() {
|
|
|
40600
40935
|
|
|
40601
40936
|
// src/config/writer.ts
|
|
40602
40937
|
import { writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
|
|
40603
|
-
import { userInfo as userInfo2 } from "os";
|
|
40604
40938
|
import path10 from "path";
|
|
40605
|
-
async function
|
|
40606
|
-
const overrideMap = new Map((overrides || []).map((o) => [o.id, o]));
|
|
40607
|
-
const existingByProvider = new Map;
|
|
40608
|
-
if (existingConfig?.agents) {
|
|
40609
|
-
for (const agent of existingConfig.agents) {
|
|
40610
|
-
existingByProvider.set(agent.provider, agent);
|
|
40611
|
-
}
|
|
40612
|
-
}
|
|
40613
|
-
const agents = selectedIds.map((id) => {
|
|
40614
|
-
const def = PROVIDERS.find((p) => p.id === id);
|
|
40615
|
-
if (!def)
|
|
40616
|
-
throw new Error(`Unknown provider: ${id}`);
|
|
40617
|
-
const override = overrideMap.get(id);
|
|
40618
|
-
const existing = existingByProvider.get(id);
|
|
40619
|
-
const agent = {
|
|
40620
|
-
name: override?.name || def.displayName,
|
|
40621
|
-
tag: override?.tag || def.defaultTag,
|
|
40622
|
-
provider: def.id,
|
|
40623
|
-
model: override?.model || def.defaultModel
|
|
40624
|
-
};
|
|
40625
|
-
if (existing?.env) {
|
|
40626
|
-
agent.env = { ...existing.env };
|
|
40627
|
-
} else if (def.env) {
|
|
40628
|
-
agent.env = { ...def.env };
|
|
40629
|
-
}
|
|
40630
|
-
if (existing?.prompts)
|
|
40631
|
-
agent.prompts = existing.prompts;
|
|
40632
|
-
if (existing?.preloadSkills)
|
|
40633
|
-
agent.preloadSkills = existing.preloadSkills;
|
|
40634
|
-
if (existing?.executablePath)
|
|
40635
|
-
agent.executablePath = existing.executablePath;
|
|
40636
|
-
if (existing?.timeout)
|
|
40637
|
-
agent.timeout = existing.timeout;
|
|
40638
|
-
return agent;
|
|
40639
|
-
});
|
|
40640
|
-
const config = {
|
|
40641
|
-
humanName: existingConfig?.humanName || userInfo2().username || "USER",
|
|
40642
|
-
humanTag: existingConfig?.humanTag,
|
|
40643
|
-
maxAutoHops: existingConfig?.maxAutoHops ?? 15,
|
|
40644
|
-
timeout: existingConfig?.timeout,
|
|
40645
|
-
reminderInterval: existingConfig?.reminderInterval,
|
|
40646
|
-
agents
|
|
40647
|
-
};
|
|
40648
|
-
if (!config.humanTag)
|
|
40649
|
-
delete config.humanTag;
|
|
40650
|
-
if (config.timeout === undefined)
|
|
40651
|
-
delete config.timeout;
|
|
40652
|
-
if (config.reminderInterval === undefined)
|
|
40653
|
-
delete config.reminderInterval;
|
|
40939
|
+
async function writeConfig(config) {
|
|
40654
40940
|
await mkdir6(LLM_PARTY_HOME, { recursive: true });
|
|
40655
40941
|
const configPath = path10.join(LLM_PARTY_HOME, "config.json");
|
|
40656
40942
|
await writeFile6(configPath, JSON.stringify(config, null, 2) + `
|
|
@@ -40663,16 +40949,114 @@ function MultiSelect(props) {
|
|
|
40663
40949
|
const [focused, setFocused] = createSignal(props.items.findIndex((item) => !item.disabled));
|
|
40664
40950
|
const [selected, setSelected] = createSignal(new Set(props.initialSelected || []));
|
|
40665
40951
|
const [error, setError] = createSignal("");
|
|
40952
|
+
const [addingCustom, setAddingCustom] = createSignal(false);
|
|
40953
|
+
const [customName, setCustomName] = createSignal("");
|
|
40954
|
+
const [customCursor, setCustomCursor] = createSignal(0);
|
|
40955
|
+
const tuiRenderer = useRenderer();
|
|
40956
|
+
createEffect(() => {
|
|
40957
|
+
const handlePaste = (event) => {
|
|
40958
|
+
if (!addingCustom())
|
|
40959
|
+
return;
|
|
40960
|
+
const text = new TextDecoder().decode(event.bytes);
|
|
40961
|
+
if (!text)
|
|
40962
|
+
return;
|
|
40963
|
+
const cleaned = text.replace(/\n/g, "");
|
|
40964
|
+
if (!cleaned)
|
|
40965
|
+
return;
|
|
40966
|
+
const c = customCursor();
|
|
40967
|
+
const val = customName();
|
|
40968
|
+
setCustomName(val.slice(0, c) + cleaned + val.slice(c));
|
|
40969
|
+
setCustomCursor(c + cleaned.length);
|
|
40970
|
+
};
|
|
40971
|
+
tuiRenderer.keyInput.on("paste", handlePaste);
|
|
40972
|
+
onCleanup(() => {
|
|
40973
|
+
tuiRenderer.keyInput.off("paste", handlePaste);
|
|
40974
|
+
});
|
|
40975
|
+
});
|
|
40976
|
+
const totalRows = () => props.items.length + (props.addCustom ? 1 : 0);
|
|
40977
|
+
const isAddCustomRow = (idx) => props.addCustom && idx === props.items.length;
|
|
40666
40978
|
const findNextEnabled = (from, direction) => {
|
|
40979
|
+
const total = totalRows();
|
|
40667
40980
|
let idx = from;
|
|
40668
|
-
for (let i = 0;i <
|
|
40669
|
-
idx = (idx + direction +
|
|
40981
|
+
for (let i = 0;i < total; i++) {
|
|
40982
|
+
idx = (idx + direction + total) % total;
|
|
40983
|
+
if (isAddCustomRow(idx))
|
|
40984
|
+
return idx;
|
|
40670
40985
|
if (!props.items[idx].disabled)
|
|
40671
40986
|
return idx;
|
|
40672
40987
|
}
|
|
40673
40988
|
return from;
|
|
40674
40989
|
};
|
|
40675
40990
|
useKeyboard((key) => {
|
|
40991
|
+
if (addingCustom()) {
|
|
40992
|
+
if (key.name === "escape") {
|
|
40993
|
+
setAddingCustom(false);
|
|
40994
|
+
setCustomName("");
|
|
40995
|
+
setCustomCursor(0);
|
|
40996
|
+
return;
|
|
40997
|
+
}
|
|
40998
|
+
if (key.name === "enter" || key.name === "return") {
|
|
40999
|
+
const name = customName().trim();
|
|
41000
|
+
if (name.length > 0) {
|
|
41001
|
+
props.addCustom.onAdd(name);
|
|
41002
|
+
setAddingCustom(false);
|
|
41003
|
+
setCustomName("");
|
|
41004
|
+
setCustomCursor(0);
|
|
41005
|
+
}
|
|
41006
|
+
return;
|
|
41007
|
+
}
|
|
41008
|
+
if (key.name === "backspace") {
|
|
41009
|
+
const c = customCursor();
|
|
41010
|
+
if (c > 0) {
|
|
41011
|
+
const val = customName();
|
|
41012
|
+
setCustomName(val.slice(0, c - 1) + val.slice(c));
|
|
41013
|
+
setCustomCursor(c - 1);
|
|
41014
|
+
}
|
|
41015
|
+
return;
|
|
41016
|
+
}
|
|
41017
|
+
if (key.name === "delete") {
|
|
41018
|
+
const c = customCursor();
|
|
41019
|
+
const val = customName();
|
|
41020
|
+
if (c < val.length) {
|
|
41021
|
+
setCustomName(val.slice(0, c) + val.slice(c + 1));
|
|
41022
|
+
}
|
|
41023
|
+
return;
|
|
41024
|
+
}
|
|
41025
|
+
if (key.name === "left") {
|
|
41026
|
+
setCustomCursor((c) => Math.max(0, c - 1));
|
|
41027
|
+
return;
|
|
41028
|
+
}
|
|
41029
|
+
if (key.name === "right") {
|
|
41030
|
+
setCustomCursor((c) => Math.min(customName().length, c + 1));
|
|
41031
|
+
return;
|
|
41032
|
+
}
|
|
41033
|
+
if (key.name === "home" || key.ctrl && key.name === "a") {
|
|
41034
|
+
setCustomCursor(0);
|
|
41035
|
+
return;
|
|
41036
|
+
}
|
|
41037
|
+
if (key.name === "end" || key.ctrl && key.name === "e") {
|
|
41038
|
+
setCustomCursor(customName().length);
|
|
41039
|
+
return;
|
|
41040
|
+
}
|
|
41041
|
+
if (key.ctrl && key.name === "u") {
|
|
41042
|
+
setCustomName("");
|
|
41043
|
+
setCustomCursor(0);
|
|
41044
|
+
return;
|
|
41045
|
+
}
|
|
41046
|
+
if (key.ctrl || key.name === "up" || key.name === "down" || key.name === "pageup" || key.name === "pagedown" || key.name === "tab") {
|
|
41047
|
+
return;
|
|
41048
|
+
}
|
|
41049
|
+
const ch = key.sequence;
|
|
41050
|
+
if (ch && ch.length > 0 && !ch.startsWith("\x1B")) {
|
|
41051
|
+
if (ch === "'" || ch === '"' || ch === "`")
|
|
41052
|
+
return;
|
|
41053
|
+
const c = customCursor();
|
|
41054
|
+
const val = customName();
|
|
41055
|
+
setCustomName(val.slice(0, c) + ch + val.slice(c));
|
|
41056
|
+
setCustomCursor(c + ch.length);
|
|
41057
|
+
}
|
|
41058
|
+
return;
|
|
41059
|
+
}
|
|
40676
41060
|
if (key.name === "up" || key.name === "k") {
|
|
40677
41061
|
setFocused((f) => findNextEnabled(f, -1));
|
|
40678
41062
|
setError("");
|
|
@@ -40684,13 +41068,20 @@ function MultiSelect(props) {
|
|
|
40684
41068
|
return;
|
|
40685
41069
|
}
|
|
40686
41070
|
if (key.name === "space" || key.sequence === " ") {
|
|
40687
|
-
|
|
41071
|
+
const f = focused();
|
|
41072
|
+
if (isAddCustomRow(f)) {
|
|
41073
|
+
setAddingCustom(true);
|
|
41074
|
+
setCustomName("");
|
|
41075
|
+
setCustomCursor(0);
|
|
41076
|
+
return;
|
|
41077
|
+
}
|
|
41078
|
+
if (f >= 0 && !props.items[f].disabled) {
|
|
40688
41079
|
setSelected((prev) => {
|
|
40689
41080
|
const next = new Set(prev);
|
|
40690
|
-
if (next.has(
|
|
40691
|
-
next.delete(
|
|
41081
|
+
if (next.has(f)) {
|
|
41082
|
+
next.delete(f);
|
|
40692
41083
|
} else {
|
|
40693
|
-
next.add(
|
|
41084
|
+
next.add(f);
|
|
40694
41085
|
}
|
|
40695
41086
|
return next;
|
|
40696
41087
|
});
|
|
@@ -40699,6 +41090,13 @@ function MultiSelect(props) {
|
|
|
40699
41090
|
return;
|
|
40700
41091
|
}
|
|
40701
41092
|
if (key.name === "enter" || key.name === "return") {
|
|
41093
|
+
const f = focused();
|
|
41094
|
+
if (isAddCustomRow(f)) {
|
|
41095
|
+
setAddingCustom(true);
|
|
41096
|
+
setCustomName("");
|
|
41097
|
+
setCustomCursor(0);
|
|
41098
|
+
return;
|
|
41099
|
+
}
|
|
40702
41100
|
if (selected().size === 0) {
|
|
40703
41101
|
setError("Select at least one agent");
|
|
40704
41102
|
return;
|
|
@@ -40720,7 +41118,7 @@ function MultiSelect(props) {
|
|
|
40720
41118
|
},
|
|
40721
41119
|
children: (item, i) => {
|
|
40722
41120
|
const isSelected = () => selected().has(i());
|
|
40723
|
-
const isFocused = () => i() === focused();
|
|
41121
|
+
const isFocused = () => i() === focused() && !addingCustom();
|
|
40724
41122
|
const isDisabled = () => !!item.disabled;
|
|
40725
41123
|
const bullet = () => isSelected() ? "\u25CF" : "\u25CB";
|
|
40726
41124
|
const bulletColor = () => isDisabled() ? COLORS.textFaint : isSelected() ? COLORS.success : COLORS.textSecondary;
|
|
@@ -40728,29 +41126,29 @@ function MultiSelect(props) {
|
|
|
40728
41126
|
const descColor = () => isDisabled() ? COLORS.textFaint : COLORS.textMuted;
|
|
40729
41127
|
const bgColor = () => isFocused() && !isDisabled() ? COLORS.bgFocus : undefined;
|
|
40730
41128
|
return (() => {
|
|
40731
|
-
var _el$
|
|
40732
|
-
insertNode(_el$
|
|
40733
|
-
insertNode(_el$
|
|
40734
|
-
insertNode(_el$
|
|
40735
|
-
setProp(_el$
|
|
40736
|
-
insertNode(_el$
|
|
40737
|
-
insertNode(_el$
|
|
40738
|
-
insert(_el$
|
|
40739
|
-
insert(_el$
|
|
40740
|
-
insertNode(_el$
|
|
40741
|
-
insert(_el$
|
|
41129
|
+
var _el$0 = createElement("text"), _el$1 = createElement("span"), _el$10 = createTextNode(` `), _el$11 = createTextNode(` `), _el$12 = createElement("span"), _el$13 = createElement("span"), _el$14 = createTextNode(` `);
|
|
41130
|
+
insertNode(_el$0, _el$1);
|
|
41131
|
+
insertNode(_el$0, _el$12);
|
|
41132
|
+
insertNode(_el$0, _el$13);
|
|
41133
|
+
setProp(_el$0, "selectable", false);
|
|
41134
|
+
insertNode(_el$1, _el$10);
|
|
41135
|
+
insertNode(_el$1, _el$11);
|
|
41136
|
+
insert(_el$1, bullet, _el$11);
|
|
41137
|
+
insert(_el$12, () => item.label);
|
|
41138
|
+
insertNode(_el$13, _el$14);
|
|
41139
|
+
insert(_el$13, () => item.description, null);
|
|
40742
41140
|
effect((_p$) => {
|
|
40743
|
-
var _v$ = bgColor(), _v$
|
|
41141
|
+
var _v$4 = bgColor(), _v$5 = {
|
|
40744
41142
|
fg: bulletColor()
|
|
40745
|
-
}, _v$
|
|
41143
|
+
}, _v$6 = {
|
|
40746
41144
|
fg: labelColor()
|
|
40747
|
-
}, _v$
|
|
41145
|
+
}, _v$7 = {
|
|
40748
41146
|
fg: descColor()
|
|
40749
41147
|
};
|
|
40750
|
-
_v$ !== _p$.e && (_p$.e = setProp(_el$
|
|
40751
|
-
_v$
|
|
40752
|
-
_v$
|
|
40753
|
-
_v$
|
|
41148
|
+
_v$4 !== _p$.e && (_p$.e = setProp(_el$0, "bg", _v$4, _p$.e));
|
|
41149
|
+
_v$5 !== _p$.t && (_p$.t = setProp(_el$1, "style", _v$5, _p$.t));
|
|
41150
|
+
_v$6 !== _p$.a && (_p$.a = setProp(_el$12, "style", _v$6, _p$.a));
|
|
41151
|
+
_v$7 !== _p$.o && (_p$.o = setProp(_el$13, "style", _v$7, _p$.o));
|
|
40754
41152
|
return _p$;
|
|
40755
41153
|
}, {
|
|
40756
41154
|
e: undefined,
|
|
@@ -40758,21 +41156,96 @@ function MultiSelect(props) {
|
|
|
40758
41156
|
a: undefined,
|
|
40759
41157
|
o: undefined
|
|
40760
41158
|
});
|
|
40761
|
-
return _el$
|
|
41159
|
+
return _el$0;
|
|
40762
41160
|
})();
|
|
40763
41161
|
}
|
|
40764
41162
|
}), null);
|
|
41163
|
+
insert(_el$, createComponent2(Show, {
|
|
41164
|
+
get when() {
|
|
41165
|
+
return props.addCustom;
|
|
41166
|
+
},
|
|
41167
|
+
get children() {
|
|
41168
|
+
return createComponent2(Show, {
|
|
41169
|
+
get when() {
|
|
41170
|
+
return addingCustom();
|
|
41171
|
+
},
|
|
41172
|
+
get fallback() {
|
|
41173
|
+
return (() => {
|
|
41174
|
+
var _el$15 = createElement("text"), _el$16 = createElement("span"), _el$18 = createElement("span");
|
|
41175
|
+
insertNode(_el$15, _el$16);
|
|
41176
|
+
insertNode(_el$15, _el$18);
|
|
41177
|
+
setProp(_el$15, "selectable", false);
|
|
41178
|
+
insertNode(_el$16, createTextNode(` + `));
|
|
41179
|
+
insertNode(_el$18, createTextNode(`Add Custom...`));
|
|
41180
|
+
effect((_p$) => {
|
|
41181
|
+
var _v$8 = focused() === props.items.length && !addingCustom() ? COLORS.bgFocus : undefined, _v$9 = {
|
|
41182
|
+
fg: COLORS.primary
|
|
41183
|
+
}, _v$0 = {
|
|
41184
|
+
fg: COLORS.textSecondary
|
|
41185
|
+
};
|
|
41186
|
+
_v$8 !== _p$.e && (_p$.e = setProp(_el$15, "bg", _v$8, _p$.e));
|
|
41187
|
+
_v$9 !== _p$.t && (_p$.t = setProp(_el$16, "style", _v$9, _p$.t));
|
|
41188
|
+
_v$0 !== _p$.a && (_p$.a = setProp(_el$18, "style", _v$0, _p$.a));
|
|
41189
|
+
return _p$;
|
|
41190
|
+
}, {
|
|
41191
|
+
e: undefined,
|
|
41192
|
+
t: undefined,
|
|
41193
|
+
a: undefined
|
|
41194
|
+
});
|
|
41195
|
+
return _el$15;
|
|
41196
|
+
})();
|
|
41197
|
+
},
|
|
41198
|
+
get children() {
|
|
41199
|
+
var _el$2 = createElement("text"), _el$3 = createElement("span"), _el$5 = createElement("span"), _el$7 = createElement("span");
|
|
41200
|
+
insertNode(_el$2, _el$3);
|
|
41201
|
+
insertNode(_el$2, _el$5);
|
|
41202
|
+
insertNode(_el$2, _el$7);
|
|
41203
|
+
setProp(_el$2, "selectable", false);
|
|
41204
|
+
insertNode(_el$3, createTextNode(` + `));
|
|
41205
|
+
insertNode(_el$5, createTextNode(`Name: `));
|
|
41206
|
+
insert(_el$2, () => customName().slice(0, customCursor()), _el$7);
|
|
41207
|
+
insert(_el$7, (() => {
|
|
41208
|
+
var _c$ = memo2(() => customCursor() < customName().length);
|
|
41209
|
+
return () => _c$() ? customName()[customCursor()] : " ";
|
|
41210
|
+
})());
|
|
41211
|
+
insert(_el$2, (() => {
|
|
41212
|
+
var _c$2 = memo2(() => customCursor() < customName().length);
|
|
41213
|
+
return () => _c$2() ? customName().slice(customCursor() + 1) : "";
|
|
41214
|
+
})(), null);
|
|
41215
|
+
effect((_p$) => {
|
|
41216
|
+
var _v$ = {
|
|
41217
|
+
fg: COLORS.primary
|
|
41218
|
+
}, _v$2 = {
|
|
41219
|
+
fg: COLORS.textSecondary
|
|
41220
|
+
}, _v$3 = {
|
|
41221
|
+
bg: COLORS.textPrimary,
|
|
41222
|
+
fg: "#000000"
|
|
41223
|
+
};
|
|
41224
|
+
_v$ !== _p$.e && (_p$.e = setProp(_el$3, "style", _v$, _p$.e));
|
|
41225
|
+
_v$2 !== _p$.t && (_p$.t = setProp(_el$5, "style", _v$2, _p$.t));
|
|
41226
|
+
_v$3 !== _p$.a && (_p$.a = setProp(_el$7, "style", _v$3, _p$.a));
|
|
41227
|
+
return _p$;
|
|
41228
|
+
}, {
|
|
41229
|
+
e: undefined,
|
|
41230
|
+
t: undefined,
|
|
41231
|
+
a: undefined
|
|
41232
|
+
});
|
|
41233
|
+
return _el$2;
|
|
41234
|
+
}
|
|
41235
|
+
});
|
|
41236
|
+
}
|
|
41237
|
+
}), null);
|
|
40765
41238
|
insert(_el$, createComponent2(Show, {
|
|
40766
41239
|
get when() {
|
|
40767
41240
|
return error();
|
|
40768
41241
|
},
|
|
40769
41242
|
get children() {
|
|
40770
|
-
var _el$
|
|
40771
|
-
insertNode(_el$
|
|
40772
|
-
setProp(_el$
|
|
40773
|
-
insert(_el$
|
|
40774
|
-
effect((_$p) => setProp(_el$
|
|
40775
|
-
return _el$
|
|
41243
|
+
var _el$8 = createElement("text"), _el$9 = createTextNode(` `);
|
|
41244
|
+
insertNode(_el$8, _el$9);
|
|
41245
|
+
setProp(_el$8, "marginTop", 1);
|
|
41246
|
+
insert(_el$8, error, null);
|
|
41247
|
+
effect((_$p) => setProp(_el$8, "fg", COLORS.error, _$p));
|
|
41248
|
+
return _el$8;
|
|
40776
41249
|
}
|
|
40777
41250
|
}), null);
|
|
40778
41251
|
return _el$;
|
|
@@ -40793,7 +41266,6 @@ var SWEEP_CHARS = ["\u2591", "\u2592", "\u2593", "\u2588", "\u2593", "\u2592", "
|
|
|
40793
41266
|
var BAR_WIDTH = 6;
|
|
40794
41267
|
function SweepBar(props) {
|
|
40795
41268
|
const glow = SWEEP_CHARS.length;
|
|
40796
|
-
const totalWidth = BAR_WIDTH * 2 + props.title.length + 2;
|
|
40797
41269
|
const [pos, setPos] = createSignal(0);
|
|
40798
41270
|
createEffect(() => {
|
|
40799
41271
|
const interval = setInterval(() => setPos((p) => (p + 1) % (BAR_WIDTH + glow)), 50);
|
|
@@ -40869,22 +41341,105 @@ function useDiscoColor() {
|
|
|
40869
41341
|
});
|
|
40870
41342
|
return () => PARTY_COLORS[idx()];
|
|
40871
41343
|
}
|
|
41344
|
+
function personaToEntry(agent) {
|
|
41345
|
+
const env2 = agent.env ?? {};
|
|
41346
|
+
return {
|
|
41347
|
+
name: agent.name,
|
|
41348
|
+
tag: agent.tag,
|
|
41349
|
+
model: agent.model,
|
|
41350
|
+
provider: agent.provider,
|
|
41351
|
+
active: agent.active !== false,
|
|
41352
|
+
authUrl: env2.AUTH_URL ?? "",
|
|
41353
|
+
authToken: env2.AUTH_TOKEN ?? "",
|
|
41354
|
+
cli: agent.cli ?? "claude",
|
|
41355
|
+
prompts: agent.prompts,
|
|
41356
|
+
preloadSkills: agent.preloadSkills,
|
|
41357
|
+
executablePath: agent.executablePath,
|
|
41358
|
+
timeout: agent.timeout,
|
|
41359
|
+
extraEnv: extractExtraEnv(env2)
|
|
41360
|
+
};
|
|
41361
|
+
}
|
|
41362
|
+
function extractExtraEnv(env2) {
|
|
41363
|
+
const extra = {};
|
|
41364
|
+
for (const [k2, v2] of Object.entries(env2)) {
|
|
41365
|
+
if (k2 !== "AUTH_URL" && k2 !== "AUTH_TOKEN") {
|
|
41366
|
+
extra[k2] = v2;
|
|
41367
|
+
}
|
|
41368
|
+
}
|
|
41369
|
+
return Object.keys(extra).length > 0 ? extra : undefined;
|
|
41370
|
+
}
|
|
41371
|
+
function entryToPersona(entry) {
|
|
41372
|
+
const config = {
|
|
41373
|
+
name: entry.name.trim(),
|
|
41374
|
+
tag: entry.tag.trim(),
|
|
41375
|
+
provider: entry.provider,
|
|
41376
|
+
model: entry.model.trim(),
|
|
41377
|
+
active: entry.active
|
|
41378
|
+
};
|
|
41379
|
+
if (entry.provider === "custom") {
|
|
41380
|
+
config.cli = entry.cli || "claude";
|
|
41381
|
+
const env2 = {};
|
|
41382
|
+
if (entry.authUrl)
|
|
41383
|
+
env2.AUTH_URL = entry.authUrl;
|
|
41384
|
+
if (entry.authToken)
|
|
41385
|
+
env2.AUTH_TOKEN = entry.authToken;
|
|
41386
|
+
if (entry.extraEnv)
|
|
41387
|
+
Object.assign(env2, entry.extraEnv);
|
|
41388
|
+
if (Object.keys(env2).length > 0)
|
|
41389
|
+
config.env = env2;
|
|
41390
|
+
}
|
|
41391
|
+
if (entry.prompts)
|
|
41392
|
+
config.prompts = entry.prompts;
|
|
41393
|
+
if (entry.preloadSkills)
|
|
41394
|
+
config.preloadSkills = entry.preloadSkills;
|
|
41395
|
+
if (entry.executablePath)
|
|
41396
|
+
config.executablePath = entry.executablePath;
|
|
41397
|
+
if (entry.timeout)
|
|
41398
|
+
config.timeout = entry.timeout;
|
|
41399
|
+
return config;
|
|
41400
|
+
}
|
|
40872
41401
|
function ConfigWizard(props) {
|
|
40873
41402
|
const [step, setStep] = createSignal("detect");
|
|
40874
41403
|
const [detection, setDetection] = createSignal([]);
|
|
40875
|
-
const [selectedIds, setSelectedIds] = createSignal([]);
|
|
40876
|
-
const [, setAgentConfigs] = createSignal([]);
|
|
40877
41404
|
const [activeTab, setActiveTab] = createSignal(0);
|
|
40878
41405
|
const [focusedField, setFocusedField] = createSignal(0);
|
|
40879
41406
|
const [error, setError] = createSignal("");
|
|
40880
41407
|
const [tick, setTick] = createSignal(0);
|
|
40881
|
-
|
|
40882
|
-
let
|
|
40883
|
-
|
|
40884
|
-
|
|
41408
|
+
const [customItems, setCustomItems] = createSignal([]);
|
|
41409
|
+
let agentEntries = [];
|
|
41410
|
+
let settingsData = {
|
|
41411
|
+
name: props.existingConfig?.humanName || userInfo2().username || "USER",
|
|
41412
|
+
tag: props.existingConfig?.humanTag || toTag(props.existingConfig?.humanName || userInfo2().username || "USER"),
|
|
41413
|
+
maxHops: String(props.existingConfig?.maxAutoHops ?? 15),
|
|
41414
|
+
timeout: String(props.existingConfig?.timeout ?? 600)
|
|
40885
41415
|
};
|
|
40886
41416
|
let cursorPos = 0;
|
|
40887
41417
|
const spinner = useSpinner();
|
|
41418
|
+
const tuiRenderer = useRenderer();
|
|
41419
|
+
createEffect(() => {
|
|
41420
|
+
const handlePaste = (event) => {
|
|
41421
|
+
if (step() !== "configure")
|
|
41422
|
+
return;
|
|
41423
|
+
const text = new TextDecoder().decode(event.bytes);
|
|
41424
|
+
if (!text)
|
|
41425
|
+
return;
|
|
41426
|
+
const cleaned = text.replace(/\n/g, "");
|
|
41427
|
+
if (!cleaned)
|
|
41428
|
+
return;
|
|
41429
|
+
const fieldValue = getCurrentFieldValue();
|
|
41430
|
+
const cursor = cursorPos;
|
|
41431
|
+
updateField(fieldValue.slice(0, cursor) + cleaned + fieldValue.slice(cursor), cursor + cleaned.length);
|
|
41432
|
+
};
|
|
41433
|
+
tuiRenderer.keyInput.on("paste", handlePaste);
|
|
41434
|
+
onCleanup(() => {
|
|
41435
|
+
tuiRenderer.keyInput.off("paste", handlePaste);
|
|
41436
|
+
});
|
|
41437
|
+
});
|
|
41438
|
+
createEffect(() => {
|
|
41439
|
+
const existing = props.existingConfig?.agents ?? [];
|
|
41440
|
+
const customs = existing.filter((a) => a.provider === "custom").map(personaToEntry);
|
|
41441
|
+
setCustomItems(customs);
|
|
41442
|
+
});
|
|
40888
41443
|
createEffect(() => {
|
|
40889
41444
|
detectProviders().then((results) => {
|
|
40890
41445
|
setDetection(results);
|
|
@@ -40894,103 +41449,255 @@ function ConfigWizard(props) {
|
|
|
40894
41449
|
setStep("providers");
|
|
40895
41450
|
});
|
|
40896
41451
|
});
|
|
40897
|
-
const
|
|
40898
|
-
|
|
40899
|
-
|
|
40900
|
-
|
|
40901
|
-
|
|
40902
|
-
|
|
40903
|
-
|
|
40904
|
-
|
|
40905
|
-
|
|
40906
|
-
|
|
40907
|
-
|
|
40908
|
-
|
|
40909
|
-
const ids = selectedIndices.map((i) => PROVIDERS[i].id);
|
|
40910
|
-
setSelectedIds(ids);
|
|
40911
|
-
const configs = ids.map((id) => {
|
|
40912
|
-
const def = PROVIDERS.find((p) => p.id === id);
|
|
40913
|
-
const existing = existingByProvider().get(id);
|
|
41452
|
+
const existingNative = () => {
|
|
41453
|
+
const map = new Map;
|
|
41454
|
+
for (const a of props.existingConfig?.agents ?? []) {
|
|
41455
|
+
if (a.provider !== "custom")
|
|
41456
|
+
map.set(a.provider, a);
|
|
41457
|
+
}
|
|
41458
|
+
return map;
|
|
41459
|
+
};
|
|
41460
|
+
const multiSelectItems = () => {
|
|
41461
|
+
const nativeItems = PROVIDERS.map((provider) => {
|
|
41462
|
+
const result = detection().find((d2) => d2.id === provider.id);
|
|
41463
|
+
const available = result?.available ?? false;
|
|
40914
41464
|
return {
|
|
40915
|
-
|
|
40916
|
-
|
|
40917
|
-
|
|
40918
|
-
model: existing?.model || def.defaultModel
|
|
41465
|
+
label: provider.displayName,
|
|
41466
|
+
description: available ? provider.description : provider.unavailableHint,
|
|
41467
|
+
disabled: !available
|
|
40919
41468
|
};
|
|
40920
41469
|
});
|
|
40921
|
-
|
|
40922
|
-
|
|
40923
|
-
|
|
41470
|
+
const customs = customItems();
|
|
41471
|
+
if (customs.length > 0) {
|
|
41472
|
+
nativeItems.push({
|
|
41473
|
+
label: "\u2500\u2500 Custom \u2500\u2500",
|
|
41474
|
+
description: "",
|
|
41475
|
+
disabled: true
|
|
41476
|
+
});
|
|
41477
|
+
}
|
|
41478
|
+
const customEntries = customs.map((c) => ({
|
|
41479
|
+
label: c.name,
|
|
41480
|
+
description: "custom provider"
|
|
40924
41481
|
}));
|
|
41482
|
+
return [...nativeItems, ...customEntries];
|
|
41483
|
+
};
|
|
41484
|
+
const initialSelected = () => {
|
|
41485
|
+
if (!props.existingConfig)
|
|
41486
|
+
return;
|
|
41487
|
+
const indices = [];
|
|
41488
|
+
const nativeMap = existingNative();
|
|
41489
|
+
PROVIDERS.forEach((p, i) => {
|
|
41490
|
+
const existing = nativeMap.get(p.id);
|
|
41491
|
+
if (existing && existing.active !== false)
|
|
41492
|
+
indices.push(i);
|
|
41493
|
+
});
|
|
41494
|
+
const customs = customItems();
|
|
41495
|
+
if (customs.length > 0) {
|
|
41496
|
+
const offset = PROVIDERS.length + 1;
|
|
41497
|
+
customs.forEach((c, i) => {
|
|
41498
|
+
if (c.active)
|
|
41499
|
+
indices.push(offset + i);
|
|
41500
|
+
});
|
|
41501
|
+
}
|
|
41502
|
+
return indices.length > 0 ? indices : undefined;
|
|
41503
|
+
};
|
|
41504
|
+
const handleAddCustom = (name) => {
|
|
41505
|
+
const entry = {
|
|
41506
|
+
name,
|
|
41507
|
+
tag: toTag(name),
|
|
41508
|
+
model: "",
|
|
41509
|
+
provider: "custom",
|
|
41510
|
+
active: true,
|
|
41511
|
+
authUrl: "",
|
|
41512
|
+
authToken: "",
|
|
41513
|
+
cli: "claude"
|
|
41514
|
+
};
|
|
41515
|
+
setCustomItems((prev) => [...prev, entry]);
|
|
41516
|
+
};
|
|
41517
|
+
const handleProviderConfirm = (selectedIndices) => {
|
|
41518
|
+
const nativeMap = existingNative();
|
|
41519
|
+
const customs = customItems();
|
|
41520
|
+
const hasCustoms = customs.length > 0;
|
|
41521
|
+
const customOffset = PROVIDERS.length + (hasCustoms ? 1 : 0);
|
|
41522
|
+
const entries = [];
|
|
41523
|
+
for (let i = 0;i < PROVIDERS.length; i++) {
|
|
41524
|
+
const def = PROVIDERS[i];
|
|
41525
|
+
const isSelected = selectedIndices.includes(i);
|
|
41526
|
+
const existing = nativeMap.get(def.id);
|
|
41527
|
+
if (isSelected || existing) {
|
|
41528
|
+
entries.push({
|
|
41529
|
+
name: existing?.name || def.displayName,
|
|
41530
|
+
tag: existing?.tag || def.defaultTag,
|
|
41531
|
+
model: existing?.model || def.defaultModel,
|
|
41532
|
+
provider: def.id,
|
|
41533
|
+
active: isSelected,
|
|
41534
|
+
authUrl: "",
|
|
41535
|
+
authToken: "",
|
|
41536
|
+
cli: "claude",
|
|
41537
|
+
prompts: existing?.prompts,
|
|
41538
|
+
preloadSkills: existing?.preloadSkills,
|
|
41539
|
+
executablePath: existing?.executablePath,
|
|
41540
|
+
timeout: existing?.timeout
|
|
41541
|
+
});
|
|
41542
|
+
}
|
|
41543
|
+
}
|
|
41544
|
+
for (let i = 0;i < customs.length; i++) {
|
|
41545
|
+
const isSelected = selectedIndices.includes(customOffset + i);
|
|
41546
|
+
entries.push({
|
|
41547
|
+
...customs[i],
|
|
41548
|
+
active: isSelected
|
|
41549
|
+
});
|
|
41550
|
+
}
|
|
41551
|
+
agentEntries = entries;
|
|
40925
41552
|
setActiveTab(0);
|
|
40926
41553
|
setFocusedField(0);
|
|
40927
|
-
cursorPos =
|
|
41554
|
+
cursorPos = settingsData.name.length;
|
|
40928
41555
|
setStep("configure");
|
|
40929
41556
|
};
|
|
40930
41557
|
const handleProviderCancel = () => {
|
|
40931
41558
|
if (props.onCancel)
|
|
40932
41559
|
props.onCancel();
|
|
40933
41560
|
};
|
|
40934
|
-
const
|
|
41561
|
+
const activeEntries = () => agentEntries.filter((e) => e.active);
|
|
41562
|
+
const isSettingsTab = () => activeTab() === 0;
|
|
40935
41563
|
const agentTabIndex = () => activeTab() - 1;
|
|
40936
|
-
const totalTabs = () => (
|
|
40937
|
-
const
|
|
41564
|
+
const totalTabs = () => activeEntries().length + 1;
|
|
41565
|
+
const isCustomAgent = () => {
|
|
41566
|
+
if (isSettingsTab())
|
|
41567
|
+
return false;
|
|
41568
|
+
const entry = activeEntries()[agentTabIndex()];
|
|
41569
|
+
return entry?.provider === "custom";
|
|
41570
|
+
};
|
|
41571
|
+
const maxFieldIndex = () => {
|
|
41572
|
+
if (isSettingsTab())
|
|
41573
|
+
return 3;
|
|
41574
|
+
return isCustomAgent() ? 4 : 2;
|
|
41575
|
+
};
|
|
41576
|
+
const getFieldValueForEntry = (entry, field) => {
|
|
41577
|
+
if (entry.provider === "custom") {
|
|
41578
|
+
return [entry.name, entry.tag, entry.model, entry.authUrl, entry.authToken][field];
|
|
41579
|
+
}
|
|
41580
|
+
return [entry.name, entry.tag, entry.model][field];
|
|
41581
|
+
};
|
|
41582
|
+
const getSettingsFieldValue = (field) => {
|
|
41583
|
+
return [settingsData.name, settingsData.tag, settingsData.maxHops, settingsData.timeout][field];
|
|
41584
|
+
};
|
|
41585
|
+
const getCurrentFieldValue = () => {
|
|
41586
|
+
if (isSettingsTab())
|
|
41587
|
+
return getSettingsFieldValue(focusedField());
|
|
41588
|
+
const entry = activeEntries()[agentTabIndex()];
|
|
41589
|
+
if (!entry)
|
|
41590
|
+
return "";
|
|
41591
|
+
return getFieldValueForEntry(entry, focusedField());
|
|
41592
|
+
};
|
|
41593
|
+
const updateField = (value, newCursor) => {
|
|
41594
|
+
if (isSettingsTab()) {
|
|
41595
|
+
if (focusedField() === 0)
|
|
41596
|
+
settingsData.name = value;
|
|
41597
|
+
else if (focusedField() === 1)
|
|
41598
|
+
settingsData.tag = value;
|
|
41599
|
+
else if (focusedField() === 2)
|
|
41600
|
+
settingsData.maxHops = value;
|
|
41601
|
+
else
|
|
41602
|
+
settingsData.timeout = value;
|
|
41603
|
+
} else {
|
|
41604
|
+
const entry = activeEntries()[agentTabIndex()];
|
|
41605
|
+
if (!entry)
|
|
41606
|
+
return;
|
|
41607
|
+
if (entry.provider === "custom") {
|
|
41608
|
+
if (focusedField() === 0)
|
|
41609
|
+
entry.name = value;
|
|
41610
|
+
else if (focusedField() === 1)
|
|
41611
|
+
entry.tag = value;
|
|
41612
|
+
else if (focusedField() === 2)
|
|
41613
|
+
entry.model = value;
|
|
41614
|
+
else if (focusedField() === 3)
|
|
41615
|
+
entry.authUrl = value;
|
|
41616
|
+
else
|
|
41617
|
+
entry.authToken = value;
|
|
41618
|
+
} else {
|
|
41619
|
+
if (focusedField() === 0)
|
|
41620
|
+
entry.name = value;
|
|
41621
|
+
else if (focusedField() === 1)
|
|
41622
|
+
entry.tag = value;
|
|
41623
|
+
else
|
|
41624
|
+
entry.model = value;
|
|
41625
|
+
}
|
|
41626
|
+
}
|
|
41627
|
+
cursorPos = newCursor;
|
|
41628
|
+
setError("");
|
|
41629
|
+
setTick((n) => n + 1);
|
|
41630
|
+
};
|
|
41631
|
+
const isTagField = () => focusedField() === 1;
|
|
41632
|
+
const isNumberField = () => isSettingsTab() && (focusedField() === 2 || focusedField() === 3);
|
|
40938
41633
|
const saveConfig = async () => {
|
|
40939
|
-
|
|
40940
|
-
|
|
40941
|
-
|
|
40942
|
-
|
|
41634
|
+
if (!settingsData.name.trim()) {
|
|
41635
|
+
setError("Name cannot be empty");
|
|
41636
|
+
return;
|
|
41637
|
+
}
|
|
41638
|
+
if (!settingsData.tag.trim()) {
|
|
41639
|
+
setError("Tag cannot be empty");
|
|
40943
41640
|
return;
|
|
40944
41641
|
}
|
|
40945
|
-
if (!
|
|
40946
|
-
setError("
|
|
41642
|
+
if (!TAG_PATTERN.test(settingsData.tag.trim())) {
|
|
41643
|
+
setError("Tag can only contain letters, numbers, hyphens, underscores");
|
|
40947
41644
|
return;
|
|
40948
41645
|
}
|
|
40949
|
-
|
|
40950
|
-
|
|
41646
|
+
const maxHops = parseInt(settingsData.maxHops, 10);
|
|
41647
|
+
if (isNaN(maxHops) || maxHops < 0) {
|
|
41648
|
+
setError("Max Hops must be 0 or a positive number");
|
|
40951
41649
|
return;
|
|
40952
41650
|
}
|
|
40953
|
-
|
|
40954
|
-
|
|
40955
|
-
|
|
41651
|
+
const timeout = parseInt(settingsData.timeout, 10);
|
|
41652
|
+
if (isNaN(timeout) || timeout < 0) {
|
|
41653
|
+
setError("Timeout must be 0 or a positive number");
|
|
41654
|
+
return;
|
|
41655
|
+
}
|
|
41656
|
+
const tags = new Set;
|
|
41657
|
+
tags.add(settingsData.tag.trim().toLowerCase());
|
|
41658
|
+
for (const entry of agentEntries) {
|
|
41659
|
+
if (!entry.name.trim()) {
|
|
41660
|
+
setError(`Name cannot be empty for an agent`);
|
|
40956
41661
|
return;
|
|
40957
41662
|
}
|
|
40958
|
-
if (!
|
|
40959
|
-
setError(`Tag cannot be empty for ${
|
|
41663
|
+
if (!entry.tag.trim()) {
|
|
41664
|
+
setError(`Tag cannot be empty for ${entry.name}`);
|
|
40960
41665
|
return;
|
|
40961
41666
|
}
|
|
40962
|
-
if (!TAG_PATTERN.test(
|
|
40963
|
-
setError(`Tag for ${
|
|
41667
|
+
if (!TAG_PATTERN.test(entry.tag.trim())) {
|
|
41668
|
+
setError(`Tag for ${entry.name} can only contain letters, numbers, hyphens, underscores`);
|
|
40964
41669
|
return;
|
|
40965
41670
|
}
|
|
40966
|
-
if (!
|
|
40967
|
-
setError(`Model cannot be empty for ${
|
|
41671
|
+
if (!entry.model.trim()) {
|
|
41672
|
+
setError(`Model cannot be empty for ${entry.name}`);
|
|
40968
41673
|
return;
|
|
40969
41674
|
}
|
|
40970
|
-
|
|
40971
|
-
|
|
40972
|
-
|
|
40973
|
-
|
|
40974
|
-
|
|
40975
|
-
|
|
41675
|
+
const tagLower = entry.tag.trim().toLowerCase();
|
|
41676
|
+
if (tags.has(tagLower)) {
|
|
41677
|
+
setError(`Duplicate tag: ${entry.tag}`);
|
|
41678
|
+
return;
|
|
41679
|
+
}
|
|
41680
|
+
tags.add(tagLower);
|
|
41681
|
+
if (entry.provider === "custom" && entry.active && !entry.authUrl.trim()) {
|
|
41682
|
+
setError(`URL is required for ${entry.name}`);
|
|
40976
41683
|
return;
|
|
40977
41684
|
}
|
|
40978
|
-
names.add(lower);
|
|
40979
41685
|
}
|
|
40980
|
-
const
|
|
40981
|
-
|
|
40982
|
-
|
|
40983
|
-
|
|
40984
|
-
|
|
40985
|
-
|
|
40986
|
-
|
|
40987
|
-
|
|
40988
|
-
humanName: human.name.trim(),
|
|
40989
|
-
humanTag: human.tag.trim(),
|
|
40990
|
-
agents: props.existingConfig?.agents || []
|
|
41686
|
+
const agents = agentEntries.map(entryToPersona);
|
|
41687
|
+
const config = {
|
|
41688
|
+
humanName: settingsData.name.trim(),
|
|
41689
|
+
humanTag: settingsData.tag.trim(),
|
|
41690
|
+
maxAutoHops: maxHops,
|
|
41691
|
+
timeout: timeout > 0 ? timeout : undefined,
|
|
41692
|
+
reminderInterval: props.existingConfig?.reminderInterval,
|
|
41693
|
+
agents
|
|
40991
41694
|
};
|
|
41695
|
+
if (config.timeout === undefined)
|
|
41696
|
+
delete config.timeout;
|
|
41697
|
+
if (config.reminderInterval === undefined)
|
|
41698
|
+
delete config.reminderInterval;
|
|
40992
41699
|
try {
|
|
40993
|
-
await
|
|
41700
|
+
await writeConfig(config);
|
|
40994
41701
|
setStep("done");
|
|
40995
41702
|
} catch (err) {
|
|
40996
41703
|
setError(`Failed to save: ${err.message}`);
|
|
@@ -41002,9 +41709,8 @@ function ConfigWizard(props) {
|
|
|
41002
41709
|
return;
|
|
41003
41710
|
}
|
|
41004
41711
|
if (step() !== "configure") {
|
|
41005
|
-
if (step() === "detect")
|
|
41712
|
+
if (step() === "detect")
|
|
41006
41713
|
return;
|
|
41007
|
-
}
|
|
41008
41714
|
if (step() === "done") {
|
|
41009
41715
|
if (key.name === "enter" || key.name === "return" || key.name === "space") {
|
|
41010
41716
|
props.onComplete();
|
|
@@ -41013,49 +41719,20 @@ function ConfigWizard(props) {
|
|
|
41013
41719
|
}
|
|
41014
41720
|
return;
|
|
41015
41721
|
}
|
|
41016
|
-
const
|
|
41017
|
-
const human = humanData;
|
|
41018
|
-
let fieldValue;
|
|
41019
|
-
if (isYouTab()) {
|
|
41020
|
-
fieldValue = focusedField() === 0 ? human.name : human.tag;
|
|
41021
|
-
} else {
|
|
41022
|
-
const current = configs[agentTabIndex()];
|
|
41023
|
-
if (!current)
|
|
41024
|
-
return;
|
|
41025
|
-
fieldValue = [current.name, current.tag, current.model][focusedField()];
|
|
41026
|
-
}
|
|
41722
|
+
const fieldValue = getCurrentFieldValue();
|
|
41027
41723
|
const cursor = cursorPos;
|
|
41028
|
-
const updateField = (value, newCursor) => {
|
|
41029
|
-
if (isYouTab()) {
|
|
41030
|
-
if (focusedField() === 0)
|
|
41031
|
-
human.name = value;
|
|
41032
|
-
else
|
|
41033
|
-
human.tag = value;
|
|
41034
|
-
} else {
|
|
41035
|
-
const current = configs[agentTabIndex()];
|
|
41036
|
-
if (focusedField() === 0)
|
|
41037
|
-
current.name = value;
|
|
41038
|
-
else if (focusedField() === 1)
|
|
41039
|
-
current.tag = value;
|
|
41040
|
-
else
|
|
41041
|
-
current.model = value;
|
|
41042
|
-
}
|
|
41043
|
-
cursorPos = newCursor;
|
|
41044
|
-
setError("");
|
|
41045
|
-
setTick((n) => n + 1);
|
|
41046
|
-
};
|
|
41047
41724
|
if (key.sequence === "[" || key.sequence === "]") {
|
|
41048
41725
|
const dir = key.sequence === "[" ? -1 : 1;
|
|
41049
41726
|
const next = (activeTab() + dir + totalTabs()) % totalTabs();
|
|
41050
41727
|
setActiveTab(next);
|
|
41051
|
-
const newMax = next === 0 ? 1 : 2;
|
|
41728
|
+
const newMax = next === 0 ? 3 : activeEntries()[next - 1]?.provider === "custom" ? 4 : 2;
|
|
41052
41729
|
const newField = Math.min(focusedField(), newMax);
|
|
41053
41730
|
setFocusedField(newField);
|
|
41054
41731
|
let newVal;
|
|
41055
41732
|
if (next === 0) {
|
|
41056
|
-
newVal = newField
|
|
41733
|
+
newVal = getSettingsFieldValue(newField);
|
|
41057
41734
|
} else {
|
|
41058
|
-
newVal =
|
|
41735
|
+
newVal = getFieldValueForEntry(activeEntries()[next - 1], newField);
|
|
41059
41736
|
}
|
|
41060
41737
|
cursorPos = newVal.length;
|
|
41061
41738
|
setTick((n) => n + 1);
|
|
@@ -41065,12 +41742,7 @@ function ConfigWizard(props) {
|
|
|
41065
41742
|
const fieldCount = maxFieldIndex() + 1;
|
|
41066
41743
|
const nextField = key.shift ? (focusedField() - 1 + fieldCount) % fieldCount : (focusedField() + 1) % fieldCount;
|
|
41067
41744
|
setFocusedField(nextField);
|
|
41068
|
-
|
|
41069
|
-
if (isYouTab()) {
|
|
41070
|
-
newVal = nextField === 0 ? human.name : human.tag;
|
|
41071
|
-
} else {
|
|
41072
|
-
newVal = getFieldValue(configs[agentTabIndex()], nextField);
|
|
41073
|
-
}
|
|
41745
|
+
const newVal = isSettingsTab() ? getSettingsFieldValue(nextField) : getFieldValueForEntry(activeEntries()[agentTabIndex()], nextField);
|
|
41074
41746
|
cursorPos = newVal.length;
|
|
41075
41747
|
setTick((n) => n + 1);
|
|
41076
41748
|
return;
|
|
@@ -41125,7 +41797,7 @@ function ConfigWizard(props) {
|
|
|
41125
41797
|
return;
|
|
41126
41798
|
}
|
|
41127
41799
|
if (key.name === "space" || key.sequence === " ") {
|
|
41128
|
-
if (
|
|
41800
|
+
if (!isTagField() && !isNumberField()) {
|
|
41129
41801
|
updateField(fieldValue.slice(0, cursor) + " " + fieldValue.slice(cursor), cursor + 1);
|
|
41130
41802
|
}
|
|
41131
41803
|
return;
|
|
@@ -41134,7 +41806,9 @@ function ConfigWizard(props) {
|
|
|
41134
41806
|
if (ch && ch.length > 0 && !ch.startsWith("\x1B")) {
|
|
41135
41807
|
if (ch === "'" || ch === '"' || ch === "`")
|
|
41136
41808
|
return;
|
|
41137
|
-
if (
|
|
41809
|
+
if (isTagField() && !TAG_PATTERN.test(ch))
|
|
41810
|
+
return;
|
|
41811
|
+
if (isNumberField() && !/^[0-9]$/.test(ch))
|
|
41138
41812
|
return;
|
|
41139
41813
|
updateField(fieldValue.slice(0, cursor) + ch + fieldValue.slice(cursor), cursor + ch.length);
|
|
41140
41814
|
}
|
|
@@ -41152,7 +41826,7 @@ function ConfigWizard(props) {
|
|
|
41152
41826
|
})();
|
|
41153
41827
|
}
|
|
41154
41828
|
const discoColor = useDiscoColor();
|
|
41155
|
-
function renderField(label, value, isFocused) {
|
|
41829
|
+
function renderField(label, value, isFocused, hint) {
|
|
41156
41830
|
tick();
|
|
41157
41831
|
const cursor = cursorPos;
|
|
41158
41832
|
const labelColor = isFocused ? COLORS.primary : COLORS.textDim;
|
|
@@ -41175,7 +41849,7 @@ function ConfigWizard(props) {
|
|
|
41175
41849
|
setProp(_el$12, "style", {
|
|
41176
41850
|
fg: valueColor
|
|
41177
41851
|
});
|
|
41178
|
-
insert(_el$12, value);
|
|
41852
|
+
insert(_el$12, value || (hint ? hint : ""));
|
|
41179
41853
|
effect((_$p) => setProp(_el$0, "style", {
|
|
41180
41854
|
fg: COLORS.borderStrong
|
|
41181
41855
|
}, _$p));
|
|
@@ -41210,6 +41884,13 @@ function ConfigWizard(props) {
|
|
|
41210
41884
|
return _el$13;
|
|
41211
41885
|
})();
|
|
41212
41886
|
}
|
|
41887
|
+
function renderTokenField(label, value, isFocused) {
|
|
41888
|
+
if (!isFocused && value.length > 0) {
|
|
41889
|
+
const masked = value.length > 4 ? "*".repeat(value.length - 4) + value.slice(-4) : "*".repeat(value.length);
|
|
41890
|
+
return renderField(label, masked, false);
|
|
41891
|
+
}
|
|
41892
|
+
return renderField(label, value, isFocused);
|
|
41893
|
+
}
|
|
41213
41894
|
const DetectStep = () => (() => {
|
|
41214
41895
|
var _el$19 = createElement("box"), _el$20 = createElement("box"), _el$21 = createElement("box"), _el$22 = createElement("text"), _el$23 = createTextNode(` Scanning for installed CLIs...`);
|
|
41215
41896
|
insertNode(_el$19, _el$20);
|
|
@@ -41325,6 +42006,9 @@ function ConfigWizard(props) {
|
|
|
41325
42006
|
},
|
|
41326
42007
|
get initialSelected() {
|
|
41327
42008
|
return initialSelected();
|
|
42009
|
+
},
|
|
42010
|
+
addCustom: {
|
|
42011
|
+
onAdd: handleAddCustom
|
|
41328
42012
|
}
|
|
41329
42013
|
}));
|
|
41330
42014
|
effect((_p$) => {
|
|
@@ -41362,12 +42046,8 @@ function ConfigWizard(props) {
|
|
|
41362
42046
|
})();
|
|
41363
42047
|
const ConfigureStep = () => {
|
|
41364
42048
|
tick();
|
|
41365
|
-
const
|
|
41366
|
-
const
|
|
41367
|
-
const tabLabels = ["You", ...selectedIds().map((id) => {
|
|
41368
|
-
const def = PROVIDERS.find((p) => p.id === id);
|
|
41369
|
-
return def?.displayName || id;
|
|
41370
|
-
})];
|
|
42049
|
+
const active = activeEntries();
|
|
42050
|
+
const tabLabels = ["Settings", ...active.map((e) => e.name)];
|
|
41371
42051
|
return (() => {
|
|
41372
42052
|
var _el$48 = createElement("box"), _el$49 = createElement("box"), _el$50 = createElement("box"), _el$51 = createElement("box"), _el$52 = createElement("box"), _el$53 = createElement("text"), _el$55 = createElement("box"), _el$56 = createElement("box"), _el$60 = createElement("box"), _el$61 = createElement("text"), _el$62 = createElement("span"), _el$64 = createElement("span"), _el$66 = createElement("span"), _el$68 = createElement("span"), _el$70 = createElement("span"), _el$72 = createElement("span"), _el$74 = createElement("span"), _el$76 = createElement("span"), _el$78 = createElement("span"), _el$80 = createElement("span"), _el$82 = createElement("span"), _el$84 = createElement("span"), _el$86 = createElement("span");
|
|
41373
42053
|
insertNode(_el$48, _el$49);
|
|
@@ -41439,7 +42119,7 @@ function ConfigWizard(props) {
|
|
|
41439
42119
|
setProp(_el$56, "flexDirection", "column");
|
|
41440
42120
|
insert(_el$56, createComponent2(Show, {
|
|
41441
42121
|
get when() {
|
|
41442
|
-
return
|
|
42122
|
+
return isSettingsTab();
|
|
41443
42123
|
},
|
|
41444
42124
|
get fallback() {
|
|
41445
42125
|
return [(() => {
|
|
@@ -41448,19 +42128,39 @@ function ConfigWizard(props) {
|
|
|
41448
42128
|
setProp(_el$94, "marginBottom", 1);
|
|
41449
42129
|
insertNode(_el$95, _el$96);
|
|
41450
42130
|
insert(_el$95, () => tabLabels[activeTab()], _el$96);
|
|
42131
|
+
insert(_el$94, createComponent2(Show, {
|
|
42132
|
+
get when() {
|
|
42133
|
+
return activeEntries()[agentTabIndex()]?.provider === "custom";
|
|
42134
|
+
},
|
|
42135
|
+
get children() {
|
|
42136
|
+
var _el$97 = createElement("span");
|
|
42137
|
+
insertNode(_el$97, createTextNode(` (custom)`));
|
|
42138
|
+
effect((_$p) => setProp(_el$97, "style", {
|
|
42139
|
+
fg: COLORS.textFaint
|
|
42140
|
+
}, _$p));
|
|
42141
|
+
return _el$97;
|
|
42142
|
+
}
|
|
42143
|
+
}), null);
|
|
41451
42144
|
effect((_$p) => setProp(_el$94, "fg", COLORS.success, _$p));
|
|
41452
42145
|
return _el$94;
|
|
41453
|
-
})(), memo2(() => renderField("Name ",
|
|
42146
|
+
})(), memo2(() => renderField("Name ", active[agentTabIndex()].name, focusedField() === 0)), memo2(() => renderField("Tag ", active[agentTabIndex()].tag, focusedField() === 1)), memo2(() => renderField("Model", active[agentTabIndex()].model, focusedField() === 2)), createComponent2(Show, {
|
|
42147
|
+
get when() {
|
|
42148
|
+
return active[agentTabIndex()]?.provider === "custom";
|
|
42149
|
+
},
|
|
42150
|
+
get children() {
|
|
42151
|
+
return [memo2(() => renderField("URL ", active[agentTabIndex()].authUrl, focusedField() === 3)), memo2(() => renderTokenField("Token", active[agentTabIndex()].authToken, focusedField() === 4))];
|
|
42152
|
+
}
|
|
42153
|
+
})];
|
|
41454
42154
|
},
|
|
41455
42155
|
get children() {
|
|
41456
42156
|
return [(() => {
|
|
41457
42157
|
var _el$57 = createElement("text"), _el$58 = createElement("strong");
|
|
41458
42158
|
insertNode(_el$57, _el$58);
|
|
41459
42159
|
setProp(_el$57, "marginBottom", 1);
|
|
41460
|
-
insertNode(_el$58, createTextNode(`
|
|
42160
|
+
insertNode(_el$58, createTextNode(`General Settings`));
|
|
41461
42161
|
effect((_$p) => setProp(_el$57, "fg", COLORS.agent, _$p));
|
|
41462
42162
|
return _el$57;
|
|
41463
|
-
})(), memo2(() => renderField("Name",
|
|
42163
|
+
})(), memo2(() => renderField("Name ", settingsData.name, focusedField() === 0)), memo2(() => renderField("Tag ", settingsData.tag, focusedField() === 1)), memo2(() => renderField("Max Hops", settingsData.maxHops, focusedField() === 2, "0 = unlimited")), memo2(() => renderField("Timeout ", settingsData.timeout, focusedField() === 3, "0 = unlimited"))];
|
|
41464
42164
|
}
|
|
41465
42165
|
}));
|
|
41466
42166
|
insertNode(_el$60, _el$61);
|
|
@@ -41520,7 +42220,7 @@ function ConfigWizard(props) {
|
|
|
41520
42220
|
}
|
|
41521
42221
|
}), null);
|
|
41522
42222
|
effect((_p$) => {
|
|
41523
|
-
var _v$13 = discoColor(), _v$14 = COLORS.bgPanel, _v$15 = COLORS.borderStrong, _v$16 =
|
|
42223
|
+
var _v$13 = discoColor(), _v$14 = COLORS.bgPanel, _v$15 = COLORS.borderStrong, _v$16 = isSettingsTab() ? COLORS.agent : COLORS.success, _v$17 = COLORS.bgContent, _v$18 = {
|
|
41524
42224
|
fg: COLORS.textFaint
|
|
41525
42225
|
}, _v$19 = {
|
|
41526
42226
|
fg: COLORS.success
|
|
@@ -41590,57 +42290,57 @@ function ConfigWizard(props) {
|
|
|
41590
42290
|
})();
|
|
41591
42291
|
};
|
|
41592
42292
|
const DoneStep = () => (() => {
|
|
41593
|
-
var _el$
|
|
41594
|
-
insertNode(_el$97, _el$98);
|
|
41595
|
-
setProp(_el$97, "flexDirection", "column");
|
|
41596
|
-
setProp(_el$97, "width", "100%");
|
|
41597
|
-
setProp(_el$97, "height", "100%");
|
|
41598
|
-
setProp(_el$97, "justifyContent", "center");
|
|
41599
|
-
setProp(_el$97, "alignItems", "center");
|
|
41600
|
-
insertNode(_el$98, _el$99);
|
|
41601
|
-
setProp(_el$98, "border", true);
|
|
41602
|
-
setProp(_el$98, "borderStyle", "double");
|
|
41603
|
-
setProp(_el$98, "paddingX", 4);
|
|
41604
|
-
setProp(_el$98, "paddingY", 2);
|
|
42293
|
+
var _el$99 = createElement("box"), _el$100 = createElement("box"), _el$101 = createElement("box"), _el$102 = createElement("text"), _el$104 = createElement("text"), _el$106 = createElement("text"), _el$108 = createElement("text"), _el$110 = createElement("text"), _el$112 = createElement("text"), _el$113 = createTextNode(`Press `), _el$114 = createElement("span"), _el$115 = createElement("strong"), _el$117 = createTextNode(` to continue`);
|
|
41605
42294
|
insertNode(_el$99, _el$100);
|
|
41606
|
-
insertNode(_el$99, _el$102);
|
|
41607
|
-
insertNode(_el$99, _el$104);
|
|
41608
|
-
insertNode(_el$99, _el$106);
|
|
41609
|
-
insertNode(_el$99, _el$108);
|
|
41610
|
-
insertNode(_el$99, _el$110);
|
|
41611
42295
|
setProp(_el$99, "flexDirection", "column");
|
|
42296
|
+
setProp(_el$99, "width", "100%");
|
|
42297
|
+
setProp(_el$99, "height", "100%");
|
|
42298
|
+
setProp(_el$99, "justifyContent", "center");
|
|
41612
42299
|
setProp(_el$99, "alignItems", "center");
|
|
41613
|
-
|
|
42300
|
+
insertNode(_el$100, _el$101);
|
|
42301
|
+
setProp(_el$100, "border", true);
|
|
42302
|
+
setProp(_el$100, "borderStyle", "double");
|
|
42303
|
+
setProp(_el$100, "paddingX", 4);
|
|
42304
|
+
setProp(_el$100, "paddingY", 2);
|
|
42305
|
+
insertNode(_el$101, _el$102);
|
|
42306
|
+
insertNode(_el$101, _el$104);
|
|
42307
|
+
insertNode(_el$101, _el$106);
|
|
42308
|
+
insertNode(_el$101, _el$108);
|
|
42309
|
+
insertNode(_el$101, _el$110);
|
|
42310
|
+
insertNode(_el$101, _el$112);
|
|
42311
|
+
setProp(_el$101, "flexDirection", "column");
|
|
42312
|
+
setProp(_el$101, "alignItems", "center");
|
|
42313
|
+
insert(_el$101, createComponent2(SweepBar, {
|
|
41614
42314
|
title: "Config Saved"
|
|
41615
|
-
}), _el$
|
|
41616
|
-
insertNode(_el$
|
|
41617
|
-
setProp(_el$100, "marginTop", 1);
|
|
41618
|
-
insertNode(_el$102, createTextNode(`Written to ~/.llm-party/config.json`));
|
|
42315
|
+
}), _el$102);
|
|
42316
|
+
insertNode(_el$102, createTextNode(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
|
|
41619
42317
|
setProp(_el$102, "marginTop", 1);
|
|
41620
|
-
insertNode(_el$104, createTextNode(`
|
|
42318
|
+
insertNode(_el$104, createTextNode(`Written to ~/.llm-party/config.json`));
|
|
41621
42319
|
setProp(_el$104, "marginTop", 1);
|
|
41622
|
-
insertNode(_el$106, createTextNode(`
|
|
41623
|
-
|
|
41624
|
-
|
|
41625
|
-
insertNode(_el$110,
|
|
41626
|
-
insertNode(_el$110, _el$112);
|
|
41627
|
-
insertNode(_el$110, _el$115);
|
|
42320
|
+
insertNode(_el$106, createTextNode(`Edit this file anytime to add prompts,`));
|
|
42321
|
+
setProp(_el$106, "marginTop", 1);
|
|
42322
|
+
insertNode(_el$108, createTextNode(`env vars, or tweak settings.`));
|
|
42323
|
+
insertNode(_el$110, createTextNode(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
|
|
41628
42324
|
setProp(_el$110, "marginTop", 1);
|
|
41629
42325
|
insertNode(_el$112, _el$113);
|
|
41630
|
-
insertNode(_el$
|
|
42326
|
+
insertNode(_el$112, _el$114);
|
|
42327
|
+
insertNode(_el$112, _el$117);
|
|
42328
|
+
setProp(_el$112, "marginTop", 1);
|
|
42329
|
+
insertNode(_el$114, _el$115);
|
|
42330
|
+
insertNode(_el$115, createTextNode(`Enter`));
|
|
41631
42331
|
effect((_p$) => {
|
|
41632
42332
|
var _v$33 = discoColor(), _v$34 = COLORS.bgPanel, _v$35 = COLORS.textSubtle, _v$36 = COLORS.textMuted, _v$37 = COLORS.textSubtle, _v$38 = COLORS.textSubtle, _v$39 = COLORS.textSubtle, _v$40 = COLORS.primary, _v$41 = {
|
|
41633
42333
|
fg: COLORS.success
|
|
41634
42334
|
};
|
|
41635
|
-
_v$33 !== _p$.e && (_p$.e = setProp(_el$
|
|
41636
|
-
_v$34 !== _p$.t && (_p$.t = setProp(_el$
|
|
41637
|
-
_v$35 !== _p$.a && (_p$.a = setProp(_el$
|
|
41638
|
-
_v$36 !== _p$.o && (_p$.o = setProp(_el$
|
|
41639
|
-
_v$37 !== _p$.i && (_p$.i = setProp(_el$
|
|
41640
|
-
_v$38 !== _p$.n && (_p$.n = setProp(_el$
|
|
41641
|
-
_v$39 !== _p$.s && (_p$.s = setProp(_el$
|
|
41642
|
-
_v$40 !== _p$.h && (_p$.h = setProp(_el$
|
|
41643
|
-
_v$41 !== _p$.r && (_p$.r = setProp(_el$
|
|
42335
|
+
_v$33 !== _p$.e && (_p$.e = setProp(_el$100, "borderColor", _v$33, _p$.e));
|
|
42336
|
+
_v$34 !== _p$.t && (_p$.t = setProp(_el$100, "backgroundColor", _v$34, _p$.t));
|
|
42337
|
+
_v$35 !== _p$.a && (_p$.a = setProp(_el$102, "fg", _v$35, _p$.a));
|
|
42338
|
+
_v$36 !== _p$.o && (_p$.o = setProp(_el$104, "fg", _v$36, _p$.o));
|
|
42339
|
+
_v$37 !== _p$.i && (_p$.i = setProp(_el$106, "fg", _v$37, _p$.i));
|
|
42340
|
+
_v$38 !== _p$.n && (_p$.n = setProp(_el$108, "fg", _v$38, _p$.n));
|
|
42341
|
+
_v$39 !== _p$.s && (_p$.s = setProp(_el$110, "fg", _v$39, _p$.s));
|
|
42342
|
+
_v$40 !== _p$.h && (_p$.h = setProp(_el$112, "fg", _v$40, _p$.h));
|
|
42343
|
+
_v$41 !== _p$.r && (_p$.r = setProp(_el$114, "style", _v$41, _p$.r));
|
|
41644
42344
|
return _p$;
|
|
41645
42345
|
}, {
|
|
41646
42346
|
e: undefined,
|
|
@@ -41653,7 +42353,7 @@ function ConfigWizard(props) {
|
|
|
41653
42353
|
h: undefined,
|
|
41654
42354
|
r: undefined
|
|
41655
42355
|
});
|
|
41656
|
-
return _el$
|
|
42356
|
+
return _el$99;
|
|
41657
42357
|
})();
|
|
41658
42358
|
return [createComponent2(Show, {
|
|
41659
42359
|
get when() {
|
|
@@ -41685,13 +42385,6 @@ function ConfigWizard(props) {
|
|
|
41685
42385
|
}
|
|
41686
42386
|
})];
|
|
41687
42387
|
}
|
|
41688
|
-
function getFieldValue(config, field) {
|
|
41689
|
-
if (field === 0)
|
|
41690
|
-
return config.name;
|
|
41691
|
-
if (field === 1)
|
|
41692
|
-
return config.tag;
|
|
41693
|
-
return config.model;
|
|
41694
|
-
}
|
|
41695
42388
|
|
|
41696
42389
|
// src/ui/AgentsPanel.tsx
|
|
41697
42390
|
function AgentsPanel(props) {
|
|
@@ -41996,7 +42689,7 @@ function InfoPanel(props) {
|
|
|
41996
42689
|
|
|
41997
42690
|
// src/ui/App.tsx
|
|
41998
42691
|
function copyToClipboard(text) {
|
|
41999
|
-
const proc =
|
|
42692
|
+
const proc = spawn4("pbcopy", [], {
|
|
42000
42693
|
stdio: ["pipe", "ignore", "ignore"]
|
|
42001
42694
|
});
|
|
42002
42695
|
proc.stdin?.write(text);
|
|
@@ -42018,29 +42711,64 @@ function App(props) {
|
|
|
42018
42711
|
const {
|
|
42019
42712
|
messages,
|
|
42020
42713
|
agentStates,
|
|
42714
|
+
queueCounts,
|
|
42021
42715
|
stickyTarget,
|
|
42022
42716
|
dispatching,
|
|
42023
42717
|
dispatch,
|
|
42024
42718
|
addSystemMessage,
|
|
42025
|
-
|
|
42026
|
-
|
|
42719
|
+
addDisplayMessage,
|
|
42720
|
+
clearMessages,
|
|
42721
|
+
refreshStickyTarget
|
|
42722
|
+
} = useOrchestrator(props.orchestrator);
|
|
42027
42723
|
const humanName = props.orchestrator.getHumanName();
|
|
42028
42724
|
const agents = props.orchestrator.listAgents();
|
|
42029
42725
|
let scrollRef = null;
|
|
42030
42726
|
const [screen, setScreen] = createSignal("chat");
|
|
42727
|
+
const [freshConfig, setFreshConfig] = createSignal(props.config);
|
|
42031
42728
|
const [showAgents, setShowAgents] = createSignal(false);
|
|
42032
42729
|
const [showInfo, setShowInfo] = createSignal(false);
|
|
42033
|
-
|
|
42034
|
-
|
|
42035
|
-
|
|
42730
|
+
const resumeSession = async (sessionId) => {
|
|
42731
|
+
try {
|
|
42732
|
+
const restored = await props.orchestrator.loadTranscript(sessionId);
|
|
42733
|
+
const displayMsgs = restored.map((msg) => {
|
|
42734
|
+
const isHuman = msg.from.toUpperCase() === humanName.toUpperCase();
|
|
42735
|
+
const agentInfo = agents.find((a) => a.name.toUpperCase() === msg.from.toUpperCase());
|
|
42736
|
+
return {
|
|
42737
|
+
...msg,
|
|
42738
|
+
type: isHuman ? "user" : "agent",
|
|
42739
|
+
provider: agentInfo?.provider ?? "",
|
|
42740
|
+
tag: agentInfo?.tag ?? ""
|
|
42741
|
+
};
|
|
42742
|
+
});
|
|
42743
|
+
for (const msg of displayMsgs) {
|
|
42744
|
+
addDisplayMessage(msg);
|
|
42745
|
+
}
|
|
42746
|
+
refreshStickyTarget();
|
|
42747
|
+
addSystemMessage(`Resumed session ${sessionId} (${restored.length} messages)`);
|
|
42748
|
+
} catch (err) {
|
|
42749
|
+
addSystemMessage(`Failed to resume: ${err instanceof Error ? err.message : String(err)}`);
|
|
42750
|
+
}
|
|
42751
|
+
};
|
|
42752
|
+
onMount(() => {
|
|
42753
|
+
if (props.resumeSessionId) {
|
|
42754
|
+
resumeSession(props.resumeSessionId);
|
|
42755
|
+
}
|
|
42756
|
+
});
|
|
42757
|
+
process.on("SIGINT", () => gracefulExit());
|
|
42758
|
+
process.on("SIGTERM", () => gracefulExit());
|
|
42759
|
+
process.on("SIGHUP", () => gracefulExit());
|
|
42036
42760
|
process.on("SIGTSTP", () => {
|
|
42037
42761
|
process.once("SIGCONT", () => renderer.resume());
|
|
42038
42762
|
renderer.suspend();
|
|
42039
42763
|
});
|
|
42040
|
-
const gracefulExit = () => {
|
|
42764
|
+
const gracefulExit = async () => {
|
|
42765
|
+
await props.orchestrator.abortAll();
|
|
42041
42766
|
renderer.destroy();
|
|
42042
42767
|
const adapters = props.orchestrator.getAdapters();
|
|
42043
|
-
Promise.allSettled(adapters.map((a) => a.destroy()))
|
|
42768
|
+
Promise.allSettled(adapters.map((a) => a.destroy())).finally(() => {
|
|
42769
|
+
process.exit(0);
|
|
42770
|
+
});
|
|
42771
|
+
setTimeout(() => process.exit(0), 2000);
|
|
42044
42772
|
};
|
|
42045
42773
|
useKeyboard((key) => {
|
|
42046
42774
|
if (key.ctrl && key.name === "p") {
|
|
@@ -42101,6 +42829,10 @@ Transcript: ${props.orchestrator.getTranscriptPath()}`);
|
|
|
42101
42829
|
return;
|
|
42102
42830
|
}
|
|
42103
42831
|
if (line === "/config") {
|
|
42832
|
+
try {
|
|
42833
|
+
const reloaded = await loadConfig2(props.configPath);
|
|
42834
|
+
setFreshConfig(reloaded);
|
|
42835
|
+
} catch {}
|
|
42104
42836
|
setScreen("config");
|
|
42105
42837
|
return;
|
|
42106
42838
|
}
|
|
@@ -42115,6 +42847,19 @@ ${files.map((f) => ` ${f}`).join(`
|
|
|
42115
42847
|
setShowInfo(true);
|
|
42116
42848
|
return;
|
|
42117
42849
|
}
|
|
42850
|
+
if (line.startsWith("/resume")) {
|
|
42851
|
+
const sid = line.replace("/resume", "").trim();
|
|
42852
|
+
if (!sid) {
|
|
42853
|
+
addSystemMessage("Usage: /resume <sessionId>");
|
|
42854
|
+
return;
|
|
42855
|
+
}
|
|
42856
|
+
if (props.orchestrator.hasMessages()) {
|
|
42857
|
+
addSystemMessage("Resume only works before the first message.");
|
|
42858
|
+
return;
|
|
42859
|
+
}
|
|
42860
|
+
await resumeSession(sid);
|
|
42861
|
+
return;
|
|
42862
|
+
}
|
|
42118
42863
|
if (line.startsWith("/flood")) {
|
|
42119
42864
|
const args = line.split(/\s+/);
|
|
42120
42865
|
const count = parseInt(args[1], 10) || 50;
|
|
@@ -42141,7 +42886,7 @@ ${lines.join(`
|
|
|
42141
42886
|
return createComponent2(ConfigWizard, {
|
|
42142
42887
|
isFirstRun: false,
|
|
42143
42888
|
get existingConfig() {
|
|
42144
|
-
return
|
|
42889
|
+
return freshConfig();
|
|
42145
42890
|
},
|
|
42146
42891
|
onComplete: () => {
|
|
42147
42892
|
addSystemMessage("Config saved. Restart llm-party to apply changes.");
|
|
@@ -42179,13 +42924,16 @@ ${lines.join(`
|
|
|
42179
42924
|
},
|
|
42180
42925
|
get stickyTarget() {
|
|
42181
42926
|
return stickyTarget();
|
|
42927
|
+
},
|
|
42928
|
+
get queueCounts() {
|
|
42929
|
+
return queueCounts();
|
|
42182
42930
|
}
|
|
42183
42931
|
}), null);
|
|
42184
42932
|
insert(_el$, createComponent2(InputLine, {
|
|
42185
42933
|
humanName,
|
|
42186
42934
|
onSubmit: handleSubmit,
|
|
42187
42935
|
get disabled() {
|
|
42188
|
-
return
|
|
42936
|
+
return showAgents() || showInfo();
|
|
42189
42937
|
},
|
|
42190
42938
|
get disabledMessage() {
|
|
42191
42939
|
return showAgents() ? "" : undefined;
|
|
@@ -42221,6 +42969,8 @@ ${lines.join(`
|
|
|
42221
42969
|
async function main2() {
|
|
42222
42970
|
const appRoot = path11.resolve(path11.dirname(fileURLToPath3(import.meta.url)), "..");
|
|
42223
42971
|
await initLlmPartyHome(appRoot);
|
|
42972
|
+
const resumeIndex = process.argv.indexOf("--resume");
|
|
42973
|
+
const resumeSessionId = resumeIndex !== -1 ? process.argv[resumeIndex + 1] : undefined;
|
|
42224
42974
|
const rendererConfig = {
|
|
42225
42975
|
exitOnCtrlC: false,
|
|
42226
42976
|
useMouse: true,
|
|
@@ -42231,14 +42981,14 @@ async function main2() {
|
|
|
42231
42981
|
await render(() => ConfigWizard({
|
|
42232
42982
|
isFirstRun: true,
|
|
42233
42983
|
onComplete: async () => {
|
|
42234
|
-
await bootApp(appRoot, rendererConfig);
|
|
42984
|
+
await bootApp(appRoot, rendererConfig, resumeSessionId);
|
|
42235
42985
|
}
|
|
42236
42986
|
}), rendererConfig);
|
|
42237
42987
|
} else {
|
|
42238
|
-
await bootApp(appRoot, rendererConfig);
|
|
42988
|
+
await bootApp(appRoot, rendererConfig, resumeSessionId);
|
|
42239
42989
|
}
|
|
42240
42990
|
}
|
|
42241
|
-
async function bootApp(appRoot, rendererConfig) {
|
|
42991
|
+
async function bootApp(appRoot, rendererConfig, resumeSessionId) {
|
|
42242
42992
|
const configPath = await resolveConfigPath(appRoot);
|
|
42243
42993
|
const config = await loadConfig2(configPath);
|
|
42244
42994
|
const humanName = config.humanName?.trim() || "USER";
|
|
@@ -42258,7 +43008,8 @@ async function bootApp(appRoot, rendererConfig) {
|
|
|
42258
43008
|
` + obsidianPrompt;
|
|
42259
43009
|
const availableSkills = await discoverSkills();
|
|
42260
43010
|
const agentVerifiedSkills = new Map;
|
|
42261
|
-
|
|
43011
|
+
const activeAgents = config.agents.filter((a) => a.active !== false);
|
|
43012
|
+
for (const agent of activeAgents) {
|
|
42262
43013
|
if (agent.preloadSkills && agent.preloadSkills.length > 0) {
|
|
42263
43014
|
const verified = [];
|
|
42264
43015
|
const report = [];
|
|
@@ -42279,11 +43030,11 @@ async function bootApp(appRoot, rendererConfig) {
|
|
|
42279
43030
|
const resolveFromConfig = (value) => {
|
|
42280
43031
|
return path11.isAbsolute(value) ? value : path11.resolve(configDir, value);
|
|
42281
43032
|
};
|
|
42282
|
-
const adapters = await Promise.all(
|
|
43033
|
+
const adapters = await Promise.all(activeAgents.map(async (agent, _index, allAgents) => {
|
|
42283
43034
|
const promptParts = [mergedBase];
|
|
42284
43035
|
if (agent.prompts && agent.prompts.length > 0) {
|
|
42285
43036
|
const extraPaths = agent.prompts.map((p) => resolveFromConfig(p));
|
|
42286
|
-
const extraParts = await Promise.all(extraPaths.map((p) =>
|
|
43037
|
+
const extraParts = await Promise.all(extraPaths.map((p) => readFile6(p, "utf8")));
|
|
42287
43038
|
promptParts.push(...extraParts);
|
|
42288
43039
|
}
|
|
42289
43040
|
const promptTemplate = promptParts.join(`
|
|
@@ -42318,7 +43069,7 @@ ${mySkills.map((s) => `- ${s}`).join(`
|
|
|
42318
43069
|
agentCount: String(allAgents.length),
|
|
42319
43070
|
preloadedSkills
|
|
42320
43071
|
});
|
|
42321
|
-
const adapter = agent.provider === "claude" ? new ClaudeAdapter(agent.name, agent.model) : agent.provider === "codex" ? new CodexAdapter(agent.name, agent.model) : agent.provider === "copilot" ? new CopilotAdapter(agent.name, agent.model) : agent.provider === "
|
|
43072
|
+
const adapter = agent.provider === "claude" ? new ClaudeAdapter(agent.name, agent.model, humanName) : agent.provider === "codex" ? new CodexAdapter(agent.name, agent.model, humanName) : agent.provider === "copilot" ? new CopilotAdapter(agent.name, agent.model, humanName) : agent.provider === "custom" ? new CustomAdapter(agent.name, agent.model, humanName) : null;
|
|
42322
43073
|
if (!adapter) {
|
|
42323
43074
|
throw new Error(`Unsupported provider: ${agent.provider}`);
|
|
42324
43075
|
}
|
|
@@ -42326,12 +43077,12 @@ ${mySkills.map((s) => `- ${s}`).join(`
|
|
|
42326
43077
|
return adapter;
|
|
42327
43078
|
}));
|
|
42328
43079
|
const defaultTimeout = typeof config.timeout === "number" && config.timeout > 0 ? config.timeout * 1000 : 600000;
|
|
42329
|
-
const agentTimeouts = Object.fromEntries(
|
|
42330
|
-
const orchestrator = new Orchestrator(adapters, humanName, Object.fromEntries(
|
|
42331
|
-
await render(() => App({ orchestrator,
|
|
43080
|
+
const agentTimeouts = Object.fromEntries(activeAgents.filter((agent) => typeof agent.timeout === "number" && agent.timeout > 0).map((agent) => [agent.name, agent.timeout * 1000]));
|
|
43081
|
+
const orchestrator = new Orchestrator(adapters, humanName, Object.fromEntries(activeAgents.map((agent) => [agent.name, agent.tag?.trim() || toTag(agent.name)])), humanTag, defaultTimeout, agentTimeouts, { reminderInterval: config.reminderInterval, maxAutoHops });
|
|
43082
|
+
await render(() => App({ orchestrator, config, configPath, resumeSessionId }), rendererConfig);
|
|
42332
43083
|
}
|
|
42333
43084
|
function resolveMaxAutoHops(value) {
|
|
42334
|
-
if (value === "
|
|
43085
|
+
if (typeof value === "number" && value === 0) {
|
|
42335
43086
|
return Number.POSITIVE_INFINITY;
|
|
42336
43087
|
}
|
|
42337
43088
|
if (typeof value === "number" && Number.isFinite(value) && value >= 1) {
|