llm-party-cli 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -37551,8 +37551,11 @@ var render = async (node, rendererOrConfig = {}) => {
37551
37551
  import { query } from "@anthropic-ai/claude-agent-sdk";
37552
37552
 
37553
37553
  // src/adapters/base.ts
37554
- function formatTranscript(messages) {
37555
- return messages.map((m2) => `[${m2.from}]: ${m2.text}`).join(`
37554
+ function formatTranscript(messages, agentName, humanName) {
37555
+ return messages.map((m2) => {
37556
+ const role = m2.from === agentName ? "you" : m2.from === humanName ? "user" : "agent";
37557
+ return `${m2.from} (${role}):: ${m2.text}`;
37558
+ }).join(`
37556
37559
 
37557
37560
  `);
37558
37561
  }
@@ -37561,13 +37564,15 @@ function formatTranscript(messages) {
37561
37564
  class ClaudeBaseAdapter {
37562
37565
  name;
37563
37566
  model;
37567
+ humanName;
37564
37568
  systemPrompt = "";
37565
37569
  sessionId = "";
37566
37570
  runtimeEnv = {};
37567
37571
  claudeExecutable;
37568
- constructor(name, model) {
37572
+ constructor(name, model, humanName) {
37569
37573
  this.name = name;
37570
37574
  this.model = model;
37575
+ this.humanName = humanName;
37571
37576
  }
37572
37577
  async init(config) {
37573
37578
  this.systemPrompt = config.resolvedPrompt ?? "";
@@ -37575,10 +37580,23 @@ class ClaudeBaseAdapter {
37575
37580
  this.claudeExecutable = config.executablePath ?? process.env.CLAUDE_CODE_EXECUTABLE;
37576
37581
  }
37577
37582
  async buildEnv(config) {
37578
- return { ...process.env, ...config.env ?? {} };
37583
+ const configEnv = config.env ?? {};
37584
+ const mapped = {};
37585
+ if (configEnv.AUTH_URL) {
37586
+ mapped.ANTHROPIC_BASE_URL = configEnv.AUTH_URL;
37587
+ }
37588
+ if (configEnv.AUTH_TOKEN) {
37589
+ mapped.ANTHROPIC_AUTH_TOKEN = configEnv.AUTH_TOKEN;
37590
+ }
37591
+ if (configEnv.AUTH_URL || configEnv.AUTH_TOKEN) {
37592
+ mapped.ANTHROPIC_DEFAULT_HAIKU_MODEL = this.model;
37593
+ mapped.ANTHROPIC_DEFAULT_SONNET_MODEL = this.model;
37594
+ mapped.ANTHROPIC_DEFAULT_OPUS_MODEL = this.model;
37595
+ }
37596
+ return { ...process.env, ...mapped, ...configEnv };
37579
37597
  }
37580
37598
  async send(messages, signal) {
37581
- return await this.querySDK(formatTranscript(messages), signal);
37599
+ return await this.querySDK(formatTranscript(messages, this.name, this.humanName), signal);
37582
37600
  }
37583
37601
  async destroy() {
37584
37602
  return;
@@ -38061,11 +38079,13 @@ class CodexAdapter {
38061
38079
  name;
38062
38080
  provider = "codex";
38063
38081
  model;
38082
+ humanName;
38064
38083
  codex;
38065
38084
  thread;
38066
- constructor(name, model) {
38085
+ constructor(name, model, humanName) {
38067
38086
  this.name = name;
38068
38087
  this.model = model;
38088
+ this.humanName = humanName;
38069
38089
  }
38070
38090
  async init(config) {
38071
38091
  const cliPath = config.executablePath ?? process.env.CODEX_CLI_EXECUTABLE;
@@ -38090,7 +38110,7 @@ class CodexAdapter {
38090
38110
  if (signal?.aborted) {
38091
38111
  return "[Aborted] Codex was cancelled";
38092
38112
  }
38093
- const turn = await this.thread.run(formatTranscript(messages));
38113
+ const turn = await this.thread.run(formatTranscript(messages, this.name, this.humanName));
38094
38114
  if (turn.finalResponse && turn.finalResponse.length > 0) {
38095
38115
  return turn.finalResponse;
38096
38116
  }
@@ -39276,14 +39296,16 @@ class CopilotAdapter {
39276
39296
  name;
39277
39297
  provider = "copilot";
39278
39298
  model;
39299
+ humanName;
39279
39300
  client;
39280
39301
  session;
39281
39302
  systemPrompt = "";
39282
39303
  cliPath;
39283
39304
  timeout = 600000;
39284
- constructor(name, model) {
39305
+ constructor(name, model, humanName) {
39285
39306
  this.name = name;
39286
39307
  this.model = model;
39308
+ this.humanName = humanName;
39287
39309
  }
39288
39310
  async init(config) {
39289
39311
  this.systemPrompt = config.resolvedPrompt ?? "";
@@ -39300,7 +39322,7 @@ class CopilotAdapter {
39300
39322
  if (signal?.aborted) {
39301
39323
  return "[Aborted] Copilot was cancelled";
39302
39324
  }
39303
- const transcript = formatTranscript(messages);
39325
+ const transcript = formatTranscript(messages, this.name, this.humanName);
39304
39326
  try {
39305
39327
  return await this.sendToSession(transcript);
39306
39328
  } catch (err) {
@@ -39354,62 +39376,9 @@ class CopilotAdapter {
39354
39376
  }
39355
39377
  }
39356
39378
 
39357
- // src/adapters/glm.ts
39358
- import { spawn as spawn3 } from "child_process";
39359
- class GlmAdapter extends ClaudeBaseAdapter {
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
- });
39379
+ // src/adapters/custom.ts
39380
+ class CustomAdapter extends ClaudeBaseAdapter {
39381
+ provider = "custom";
39413
39382
  }
39414
39383
 
39415
39384
  // src/config/loader.ts
@@ -39448,27 +39417,11 @@ var PROVIDERS = [
39448
39417
  defaultTag: "copilot",
39449
39418
  detectCommand: "copilot",
39450
39419
  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
39420
  }
39468
39421
  ];
39469
39422
 
39470
39423
  // src/config/loader.ts
39471
- var VALID_PROVIDER_IDS = new Set(PROVIDERS.map((p) => p.id));
39424
+ var VALID_PROVIDER_IDS = new Set([...PROVIDERS.map((p) => p.id), "custom"]);
39472
39425
  var LLM_PARTY_HOME = path8.join(homedir(), ".llm-party");
39473
39426
  var MIND_MAP_INDEX = `# Living Memory Neural Network
39474
39427
 
@@ -39654,9 +39607,23 @@ async function configExists() {
39654
39607
  return false;
39655
39608
  }
39656
39609
  }
39610
+ function migrateProviders(data) {
39611
+ if (!Array.isArray(data.agents))
39612
+ return;
39613
+ for (const agent of data.agents) {
39614
+ if (!agent || typeof agent !== "object")
39615
+ continue;
39616
+ if (typeof agent.provider === "string" && !VALID_PROVIDER_IDS.has(agent.provider)) {
39617
+ agent.provider = "custom";
39618
+ if (!agent.cli)
39619
+ agent.cli = "claude";
39620
+ }
39621
+ }
39622
+ }
39657
39623
  async function loadConfig2(configPath) {
39658
39624
  const raw = await readFile3(configPath, "utf8");
39659
39625
  const parsed = JSON.parse(raw);
39626
+ migrateProviders(parsed);
39660
39627
  validateConfig(parsed);
39661
39628
  return normalizeConfig(parsed);
39662
39629
  }
@@ -39892,7 +39859,7 @@ function createSessionId() {
39892
39859
  }
39893
39860
 
39894
39861
  // src/ui/App.tsx
39895
- import { spawn as spawn5 } from "child_process";
39862
+ import { spawn as spawn4 } from "child_process";
39896
39863
 
39897
39864
  // src/ui/useOrchestrator.ts
39898
39865
  import { execFile } from "child_process";
@@ -40314,7 +40281,7 @@ function InputLine(props) {
40314
40281
  useKeyboard((key) => {
40315
40282
  if (props.disabled)
40316
40283
  return;
40317
- if (key.shift && (key.name === "enter" || key.name === "return")) {
40284
+ if ((key.shift || key.option || key.meta) && (key.name === "enter" || key.name === "return")) {
40318
40285
  update(value.slice(0, cursor) + `
40319
40286
  ` + value.slice(cursor), cursor + 1);
40320
40287
  return;
@@ -40529,15 +40496,15 @@ function InputLine(props) {
40529
40496
  }
40530
40497
 
40531
40498
  // src/ui/ConfigWizard.tsx
40532
- import { userInfo as userInfo3 } from "os";
40499
+ import { userInfo as userInfo2 } from "os";
40533
40500
 
40534
40501
  // src/config/detector.ts
40535
- import { spawn as spawn4 } from "child_process";
40502
+ import { spawn as spawn3 } from "child_process";
40536
40503
  var DETECT_TIMEOUT = 5000;
40537
40504
  function detectBinary(command) {
40538
40505
  return new Promise((resolve4) => {
40539
40506
  const timer = setTimeout(() => resolve4({ available: false }), DETECT_TIMEOUT);
40540
- const proc = spawn4(command, ["--version"], {
40507
+ const proc = spawn3(command, ["--version"], {
40541
40508
  stdio: ["ignore", "pipe", "ignore"],
40542
40509
  shell: true,
40543
40510
  timeout: DETECT_TIMEOUT,
@@ -40562,33 +40529,13 @@ function detectBinary(command) {
40562
40529
  });
40563
40530
  });
40564
40531
  }
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
40532
  async function detectProviders() {
40586
40533
  const results = await Promise.allSettled(PROVIDERS.map(async (provider) => {
40587
- const result = provider.detectType === "alias" ? await detectAlias(provider.detectCommand) : await detectBinary(provider.detectCommand);
40534
+ const result = await detectBinary(provider.detectCommand);
40588
40535
  return {
40589
40536
  id: provider.id,
40590
40537
  available: result.available,
40591
- version: "version" in result ? result.version : undefined
40538
+ version: result.version
40592
40539
  };
40593
40540
  }));
40594
40541
  return results.map((result, i) => {
@@ -40600,57 +40547,8 @@ async function detectProviders() {
40600
40547
 
40601
40548
  // src/config/writer.ts
40602
40549
  import { writeFile as writeFile6, mkdir as mkdir6 } from "fs/promises";
40603
- import { userInfo as userInfo2 } from "os";
40604
40550
  import path10 from "path";
40605
- async function writeWizardConfig(selectedIds, overrides, existingConfig) {
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;
40551
+ async function writeConfig(config) {
40654
40552
  await mkdir6(LLM_PARTY_HOME, { recursive: true });
40655
40553
  const configPath = path10.join(LLM_PARTY_HOME, "config.json");
40656
40554
  await writeFile6(configPath, JSON.stringify(config, null, 2) + `
@@ -40663,16 +40561,114 @@ function MultiSelect(props) {
40663
40561
  const [focused, setFocused] = createSignal(props.items.findIndex((item) => !item.disabled));
40664
40562
  const [selected, setSelected] = createSignal(new Set(props.initialSelected || []));
40665
40563
  const [error, setError] = createSignal("");
40564
+ const [addingCustom, setAddingCustom] = createSignal(false);
40565
+ const [customName, setCustomName] = createSignal("");
40566
+ const [customCursor, setCustomCursor] = createSignal(0);
40567
+ const tuiRenderer = useRenderer();
40568
+ createEffect(() => {
40569
+ const handlePaste = (event) => {
40570
+ if (!addingCustom())
40571
+ return;
40572
+ const text = new TextDecoder().decode(event.bytes);
40573
+ if (!text)
40574
+ return;
40575
+ const cleaned = text.replace(/\n/g, "");
40576
+ if (!cleaned)
40577
+ return;
40578
+ const c = customCursor();
40579
+ const val = customName();
40580
+ setCustomName(val.slice(0, c) + cleaned + val.slice(c));
40581
+ setCustomCursor(c + cleaned.length);
40582
+ };
40583
+ tuiRenderer.keyInput.on("paste", handlePaste);
40584
+ onCleanup(() => {
40585
+ tuiRenderer.keyInput.off("paste", handlePaste);
40586
+ });
40587
+ });
40588
+ const totalRows = () => props.items.length + (props.addCustom ? 1 : 0);
40589
+ const isAddCustomRow = (idx) => props.addCustom && idx === props.items.length;
40666
40590
  const findNextEnabled = (from, direction) => {
40591
+ const total = totalRows();
40667
40592
  let idx = from;
40668
- for (let i = 0;i < props.items.length; i++) {
40669
- idx = (idx + direction + props.items.length) % props.items.length;
40593
+ for (let i = 0;i < total; i++) {
40594
+ idx = (idx + direction + total) % total;
40595
+ if (isAddCustomRow(idx))
40596
+ return idx;
40670
40597
  if (!props.items[idx].disabled)
40671
40598
  return idx;
40672
40599
  }
40673
40600
  return from;
40674
40601
  };
40675
40602
  useKeyboard((key) => {
40603
+ if (addingCustom()) {
40604
+ if (key.name === "escape") {
40605
+ setAddingCustom(false);
40606
+ setCustomName("");
40607
+ setCustomCursor(0);
40608
+ return;
40609
+ }
40610
+ if (key.name === "enter" || key.name === "return") {
40611
+ const name = customName().trim();
40612
+ if (name.length > 0) {
40613
+ props.addCustom.onAdd(name);
40614
+ setAddingCustom(false);
40615
+ setCustomName("");
40616
+ setCustomCursor(0);
40617
+ }
40618
+ return;
40619
+ }
40620
+ if (key.name === "backspace") {
40621
+ const c = customCursor();
40622
+ if (c > 0) {
40623
+ const val = customName();
40624
+ setCustomName(val.slice(0, c - 1) + val.slice(c));
40625
+ setCustomCursor(c - 1);
40626
+ }
40627
+ return;
40628
+ }
40629
+ if (key.name === "delete") {
40630
+ const c = customCursor();
40631
+ const val = customName();
40632
+ if (c < val.length) {
40633
+ setCustomName(val.slice(0, c) + val.slice(c + 1));
40634
+ }
40635
+ return;
40636
+ }
40637
+ if (key.name === "left") {
40638
+ setCustomCursor((c) => Math.max(0, c - 1));
40639
+ return;
40640
+ }
40641
+ if (key.name === "right") {
40642
+ setCustomCursor((c) => Math.min(customName().length, c + 1));
40643
+ return;
40644
+ }
40645
+ if (key.name === "home" || key.ctrl && key.name === "a") {
40646
+ setCustomCursor(0);
40647
+ return;
40648
+ }
40649
+ if (key.name === "end" || key.ctrl && key.name === "e") {
40650
+ setCustomCursor(customName().length);
40651
+ return;
40652
+ }
40653
+ if (key.ctrl && key.name === "u") {
40654
+ setCustomName("");
40655
+ setCustomCursor(0);
40656
+ return;
40657
+ }
40658
+ if (key.ctrl || key.name === "up" || key.name === "down" || key.name === "pageup" || key.name === "pagedown" || key.name === "tab") {
40659
+ return;
40660
+ }
40661
+ const ch = key.sequence;
40662
+ if (ch && ch.length > 0 && !ch.startsWith("\x1B")) {
40663
+ if (ch === "'" || ch === '"' || ch === "`")
40664
+ return;
40665
+ const c = customCursor();
40666
+ const val = customName();
40667
+ setCustomName(val.slice(0, c) + ch + val.slice(c));
40668
+ setCustomCursor(c + ch.length);
40669
+ }
40670
+ return;
40671
+ }
40676
40672
  if (key.name === "up" || key.name === "k") {
40677
40673
  setFocused((f) => findNextEnabled(f, -1));
40678
40674
  setError("");
@@ -40684,13 +40680,20 @@ function MultiSelect(props) {
40684
40680
  return;
40685
40681
  }
40686
40682
  if (key.name === "space" || key.sequence === " ") {
40687
- if (focused() >= 0 && !props.items[focused()].disabled) {
40683
+ const f = focused();
40684
+ if (isAddCustomRow(f)) {
40685
+ setAddingCustom(true);
40686
+ setCustomName("");
40687
+ setCustomCursor(0);
40688
+ return;
40689
+ }
40690
+ if (f >= 0 && !props.items[f].disabled) {
40688
40691
  setSelected((prev) => {
40689
40692
  const next = new Set(prev);
40690
- if (next.has(focused())) {
40691
- next.delete(focused());
40693
+ if (next.has(f)) {
40694
+ next.delete(f);
40692
40695
  } else {
40693
- next.add(focused());
40696
+ next.add(f);
40694
40697
  }
40695
40698
  return next;
40696
40699
  });
@@ -40699,6 +40702,13 @@ function MultiSelect(props) {
40699
40702
  return;
40700
40703
  }
40701
40704
  if (key.name === "enter" || key.name === "return") {
40705
+ const f = focused();
40706
+ if (isAddCustomRow(f)) {
40707
+ setAddingCustom(true);
40708
+ setCustomName("");
40709
+ setCustomCursor(0);
40710
+ return;
40711
+ }
40702
40712
  if (selected().size === 0) {
40703
40713
  setError("Select at least one agent");
40704
40714
  return;
@@ -40720,7 +40730,7 @@ function MultiSelect(props) {
40720
40730
  },
40721
40731
  children: (item, i) => {
40722
40732
  const isSelected = () => selected().has(i());
40723
- const isFocused = () => i() === focused();
40733
+ const isFocused = () => i() === focused() && !addingCustom();
40724
40734
  const isDisabled = () => !!item.disabled;
40725
40735
  const bullet = () => isSelected() ? "\u25CF" : "\u25CB";
40726
40736
  const bulletColor = () => isDisabled() ? COLORS.textFaint : isSelected() ? COLORS.success : COLORS.textSecondary;
@@ -40728,29 +40738,29 @@ function MultiSelect(props) {
40728
40738
  const descColor = () => isDisabled() ? COLORS.textFaint : COLORS.textMuted;
40729
40739
  const bgColor = () => isFocused() && !isDisabled() ? COLORS.bgFocus : undefined;
40730
40740
  return (() => {
40731
- var _el$4 = createElement("text"), _el$5 = createElement("span"), _el$6 = createTextNode(` `), _el$7 = createTextNode(` `), _el$8 = createElement("span"), _el$9 = createElement("span"), _el$0 = createTextNode(` `);
40732
- insertNode(_el$4, _el$5);
40733
- insertNode(_el$4, _el$8);
40734
- insertNode(_el$4, _el$9);
40735
- setProp(_el$4, "selectable", false);
40736
- insertNode(_el$5, _el$6);
40737
- insertNode(_el$5, _el$7);
40738
- insert(_el$5, bullet, _el$7);
40739
- insert(_el$8, () => item.label);
40740
- insertNode(_el$9, _el$0);
40741
- insert(_el$9, () => item.description, null);
40741
+ 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(` `);
40742
+ insertNode(_el$0, _el$1);
40743
+ insertNode(_el$0, _el$12);
40744
+ insertNode(_el$0, _el$13);
40745
+ setProp(_el$0, "selectable", false);
40746
+ insertNode(_el$1, _el$10);
40747
+ insertNode(_el$1, _el$11);
40748
+ insert(_el$1, bullet, _el$11);
40749
+ insert(_el$12, () => item.label);
40750
+ insertNode(_el$13, _el$14);
40751
+ insert(_el$13, () => item.description, null);
40742
40752
  effect((_p$) => {
40743
- var _v$ = bgColor(), _v$2 = {
40753
+ var _v$4 = bgColor(), _v$5 = {
40744
40754
  fg: bulletColor()
40745
- }, _v$3 = {
40755
+ }, _v$6 = {
40746
40756
  fg: labelColor()
40747
- }, _v$4 = {
40757
+ }, _v$7 = {
40748
40758
  fg: descColor()
40749
40759
  };
40750
- _v$ !== _p$.e && (_p$.e = setProp(_el$4, "bg", _v$, _p$.e));
40751
- _v$2 !== _p$.t && (_p$.t = setProp(_el$5, "style", _v$2, _p$.t));
40752
- _v$3 !== _p$.a && (_p$.a = setProp(_el$8, "style", _v$3, _p$.a));
40753
- _v$4 !== _p$.o && (_p$.o = setProp(_el$9, "style", _v$4, _p$.o));
40760
+ _v$4 !== _p$.e && (_p$.e = setProp(_el$0, "bg", _v$4, _p$.e));
40761
+ _v$5 !== _p$.t && (_p$.t = setProp(_el$1, "style", _v$5, _p$.t));
40762
+ _v$6 !== _p$.a && (_p$.a = setProp(_el$12, "style", _v$6, _p$.a));
40763
+ _v$7 !== _p$.o && (_p$.o = setProp(_el$13, "style", _v$7, _p$.o));
40754
40764
  return _p$;
40755
40765
  }, {
40756
40766
  e: undefined,
@@ -40758,21 +40768,96 @@ function MultiSelect(props) {
40758
40768
  a: undefined,
40759
40769
  o: undefined
40760
40770
  });
40761
- return _el$4;
40771
+ return _el$0;
40762
40772
  })();
40763
40773
  }
40764
40774
  }), null);
40775
+ insert(_el$, createComponent2(Show, {
40776
+ get when() {
40777
+ return props.addCustom;
40778
+ },
40779
+ get children() {
40780
+ return createComponent2(Show, {
40781
+ get when() {
40782
+ return addingCustom();
40783
+ },
40784
+ get fallback() {
40785
+ return (() => {
40786
+ var _el$15 = createElement("text"), _el$16 = createElement("span"), _el$18 = createElement("span");
40787
+ insertNode(_el$15, _el$16);
40788
+ insertNode(_el$15, _el$18);
40789
+ setProp(_el$15, "selectable", false);
40790
+ insertNode(_el$16, createTextNode(` + `));
40791
+ insertNode(_el$18, createTextNode(`Add Custom...`));
40792
+ effect((_p$) => {
40793
+ var _v$8 = focused() === props.items.length && !addingCustom() ? COLORS.bgFocus : undefined, _v$9 = {
40794
+ fg: COLORS.primary
40795
+ }, _v$0 = {
40796
+ fg: COLORS.textSecondary
40797
+ };
40798
+ _v$8 !== _p$.e && (_p$.e = setProp(_el$15, "bg", _v$8, _p$.e));
40799
+ _v$9 !== _p$.t && (_p$.t = setProp(_el$16, "style", _v$9, _p$.t));
40800
+ _v$0 !== _p$.a && (_p$.a = setProp(_el$18, "style", _v$0, _p$.a));
40801
+ return _p$;
40802
+ }, {
40803
+ e: undefined,
40804
+ t: undefined,
40805
+ a: undefined
40806
+ });
40807
+ return _el$15;
40808
+ })();
40809
+ },
40810
+ get children() {
40811
+ var _el$2 = createElement("text"), _el$3 = createElement("span"), _el$5 = createElement("span"), _el$7 = createElement("span");
40812
+ insertNode(_el$2, _el$3);
40813
+ insertNode(_el$2, _el$5);
40814
+ insertNode(_el$2, _el$7);
40815
+ setProp(_el$2, "selectable", false);
40816
+ insertNode(_el$3, createTextNode(` + `));
40817
+ insertNode(_el$5, createTextNode(`Name: `));
40818
+ insert(_el$2, () => customName().slice(0, customCursor()), _el$7);
40819
+ insert(_el$7, (() => {
40820
+ var _c$ = memo2(() => customCursor() < customName().length);
40821
+ return () => _c$() ? customName()[customCursor()] : " ";
40822
+ })());
40823
+ insert(_el$2, (() => {
40824
+ var _c$2 = memo2(() => customCursor() < customName().length);
40825
+ return () => _c$2() ? customName().slice(customCursor() + 1) : "";
40826
+ })(), null);
40827
+ effect((_p$) => {
40828
+ var _v$ = {
40829
+ fg: COLORS.primary
40830
+ }, _v$2 = {
40831
+ fg: COLORS.textSecondary
40832
+ }, _v$3 = {
40833
+ bg: COLORS.textPrimary,
40834
+ fg: "#000000"
40835
+ };
40836
+ _v$ !== _p$.e && (_p$.e = setProp(_el$3, "style", _v$, _p$.e));
40837
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$5, "style", _v$2, _p$.t));
40838
+ _v$3 !== _p$.a && (_p$.a = setProp(_el$7, "style", _v$3, _p$.a));
40839
+ return _p$;
40840
+ }, {
40841
+ e: undefined,
40842
+ t: undefined,
40843
+ a: undefined
40844
+ });
40845
+ return _el$2;
40846
+ }
40847
+ });
40848
+ }
40849
+ }), null);
40765
40850
  insert(_el$, createComponent2(Show, {
40766
40851
  get when() {
40767
40852
  return error();
40768
40853
  },
40769
40854
  get children() {
40770
- var _el$2 = createElement("text"), _el$3 = createTextNode(` `);
40771
- insertNode(_el$2, _el$3);
40772
- setProp(_el$2, "marginTop", 1);
40773
- insert(_el$2, error, null);
40774
- effect((_$p) => setProp(_el$2, "fg", COLORS.error, _$p));
40775
- return _el$2;
40855
+ var _el$8 = createElement("text"), _el$9 = createTextNode(` `);
40856
+ insertNode(_el$8, _el$9);
40857
+ setProp(_el$8, "marginTop", 1);
40858
+ insert(_el$8, error, null);
40859
+ effect((_$p) => setProp(_el$8, "fg", COLORS.error, _$p));
40860
+ return _el$8;
40776
40861
  }
40777
40862
  }), null);
40778
40863
  return _el$;
@@ -40793,7 +40878,6 @@ var SWEEP_CHARS = ["\u2591", "\u2592", "\u2593", "\u2588", "\u2593", "\u2592", "
40793
40878
  var BAR_WIDTH = 6;
40794
40879
  function SweepBar(props) {
40795
40880
  const glow = SWEEP_CHARS.length;
40796
- const totalWidth = BAR_WIDTH * 2 + props.title.length + 2;
40797
40881
  const [pos, setPos] = createSignal(0);
40798
40882
  createEffect(() => {
40799
40883
  const interval = setInterval(() => setPos((p) => (p + 1) % (BAR_WIDTH + glow)), 50);
@@ -40869,22 +40953,105 @@ function useDiscoColor() {
40869
40953
  });
40870
40954
  return () => PARTY_COLORS[idx()];
40871
40955
  }
40956
+ function personaToEntry(agent) {
40957
+ const env2 = agent.env ?? {};
40958
+ return {
40959
+ name: agent.name,
40960
+ tag: agent.tag,
40961
+ model: agent.model,
40962
+ provider: agent.provider,
40963
+ active: agent.active !== false,
40964
+ authUrl: env2.AUTH_URL ?? "",
40965
+ authToken: env2.AUTH_TOKEN ?? "",
40966
+ cli: agent.cli ?? "claude",
40967
+ prompts: agent.prompts,
40968
+ preloadSkills: agent.preloadSkills,
40969
+ executablePath: agent.executablePath,
40970
+ timeout: agent.timeout,
40971
+ extraEnv: extractExtraEnv(env2)
40972
+ };
40973
+ }
40974
+ function extractExtraEnv(env2) {
40975
+ const extra = {};
40976
+ for (const [k2, v2] of Object.entries(env2)) {
40977
+ if (k2 !== "AUTH_URL" && k2 !== "AUTH_TOKEN") {
40978
+ extra[k2] = v2;
40979
+ }
40980
+ }
40981
+ return Object.keys(extra).length > 0 ? extra : undefined;
40982
+ }
40983
+ function entryToPersona(entry) {
40984
+ const config = {
40985
+ name: entry.name.trim(),
40986
+ tag: entry.tag.trim(),
40987
+ provider: entry.provider,
40988
+ model: entry.model.trim(),
40989
+ active: entry.active
40990
+ };
40991
+ if (entry.provider === "custom") {
40992
+ config.cli = entry.cli || "claude";
40993
+ const env2 = {};
40994
+ if (entry.authUrl)
40995
+ env2.AUTH_URL = entry.authUrl;
40996
+ if (entry.authToken)
40997
+ env2.AUTH_TOKEN = entry.authToken;
40998
+ if (entry.extraEnv)
40999
+ Object.assign(env2, entry.extraEnv);
41000
+ if (Object.keys(env2).length > 0)
41001
+ config.env = env2;
41002
+ }
41003
+ if (entry.prompts)
41004
+ config.prompts = entry.prompts;
41005
+ if (entry.preloadSkills)
41006
+ config.preloadSkills = entry.preloadSkills;
41007
+ if (entry.executablePath)
41008
+ config.executablePath = entry.executablePath;
41009
+ if (entry.timeout)
41010
+ config.timeout = entry.timeout;
41011
+ return config;
41012
+ }
40872
41013
  function ConfigWizard(props) {
40873
41014
  const [step, setStep] = createSignal("detect");
40874
41015
  const [detection, setDetection] = createSignal([]);
40875
- const [selectedIds, setSelectedIds] = createSignal([]);
40876
- const [, setAgentConfigs] = createSignal([]);
40877
41016
  const [activeTab, setActiveTab] = createSignal(0);
40878
41017
  const [focusedField, setFocusedField] = createSignal(0);
40879
41018
  const [error, setError] = createSignal("");
40880
41019
  const [tick, setTick] = createSignal(0);
40881
- let inputRefsData = [];
40882
- let humanData = {
40883
- name: props.existingConfig?.humanName || userInfo3().username || "USER",
40884
- tag: props.existingConfig?.humanTag || toTag(props.existingConfig?.humanName || userInfo3().username || "USER")
41020
+ const [customItems, setCustomItems] = createSignal([]);
41021
+ let agentEntries = [];
41022
+ let settingsData = {
41023
+ name: props.existingConfig?.humanName || userInfo2().username || "USER",
41024
+ tag: props.existingConfig?.humanTag || toTag(props.existingConfig?.humanName || userInfo2().username || "USER"),
41025
+ maxHops: String(props.existingConfig?.maxAutoHops ?? 15),
41026
+ timeout: String(props.existingConfig?.timeout ?? 600)
40885
41027
  };
40886
41028
  let cursorPos = 0;
40887
41029
  const spinner = useSpinner();
41030
+ const tuiRenderer = useRenderer();
41031
+ createEffect(() => {
41032
+ const handlePaste = (event) => {
41033
+ if (step() !== "configure")
41034
+ return;
41035
+ const text = new TextDecoder().decode(event.bytes);
41036
+ if (!text)
41037
+ return;
41038
+ const cleaned = text.replace(/\n/g, "");
41039
+ if (!cleaned)
41040
+ return;
41041
+ const fieldValue = getCurrentFieldValue();
41042
+ const cursor = cursorPos;
41043
+ updateField(fieldValue.slice(0, cursor) + cleaned + fieldValue.slice(cursor), cursor + cleaned.length);
41044
+ };
41045
+ tuiRenderer.keyInput.on("paste", handlePaste);
41046
+ onCleanup(() => {
41047
+ tuiRenderer.keyInput.off("paste", handlePaste);
41048
+ });
41049
+ });
41050
+ createEffect(() => {
41051
+ const existing = props.existingConfig?.agents ?? [];
41052
+ const customs = existing.filter((a) => a.provider === "custom").map(personaToEntry);
41053
+ setCustomItems(customs);
41054
+ });
40888
41055
  createEffect(() => {
40889
41056
  detectProviders().then((results) => {
40890
41057
  setDetection(results);
@@ -40894,103 +41061,255 @@ function ConfigWizard(props) {
40894
41061
  setStep("providers");
40895
41062
  });
40896
41063
  });
40897
- const existingByProvider = () => new Map((props.existingConfig?.agents || []).map((a) => [a.provider, a]));
40898
- const initialSelected = () => props.existingConfig ? PROVIDERS.map((p, i) => existingByProvider().has(p.id) ? i : -1).filter((i) => i >= 0) : undefined;
40899
- const multiSelectItems = () => PROVIDERS.map((provider) => {
40900
- const result = detection().find((d2) => d2.id === provider.id);
40901
- const available = result?.available ?? false;
40902
- return {
40903
- label: provider.displayName,
40904
- description: available ? provider.description : provider.unavailableHint,
40905
- disabled: !available
40906
- };
40907
- });
40908
- const handleProviderConfirm = (selectedIndices) => {
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);
41064
+ const existingNative = () => {
41065
+ const map = new Map;
41066
+ for (const a of props.existingConfig?.agents ?? []) {
41067
+ if (a.provider !== "custom")
41068
+ map.set(a.provider, a);
41069
+ }
41070
+ return map;
41071
+ };
41072
+ const multiSelectItems = () => {
41073
+ const nativeItems = PROVIDERS.map((provider) => {
41074
+ const result = detection().find((d2) => d2.id === provider.id);
41075
+ const available = result?.available ?? false;
40914
41076
  return {
40915
- id: def.id,
40916
- name: existing?.name || def.displayName,
40917
- tag: existing?.tag || def.defaultTag,
40918
- model: existing?.model || def.defaultModel
41077
+ label: provider.displayName,
41078
+ description: available ? provider.description : provider.unavailableHint,
41079
+ disabled: !available
40919
41080
  };
40920
41081
  });
40921
- setAgentConfigs(configs);
40922
- inputRefsData = configs.map((c) => ({
40923
- ...c
41082
+ const customs = customItems();
41083
+ if (customs.length > 0) {
41084
+ nativeItems.push({
41085
+ label: "\u2500\u2500 Custom \u2500\u2500",
41086
+ description: "",
41087
+ disabled: true
41088
+ });
41089
+ }
41090
+ const customEntries = customs.map((c) => ({
41091
+ label: c.name,
41092
+ description: "custom provider"
40924
41093
  }));
41094
+ return [...nativeItems, ...customEntries];
41095
+ };
41096
+ const initialSelected = () => {
41097
+ if (!props.existingConfig)
41098
+ return;
41099
+ const indices = [];
41100
+ const nativeMap = existingNative();
41101
+ PROVIDERS.forEach((p, i) => {
41102
+ const existing = nativeMap.get(p.id);
41103
+ if (existing && existing.active !== false)
41104
+ indices.push(i);
41105
+ });
41106
+ const customs = customItems();
41107
+ if (customs.length > 0) {
41108
+ const offset = PROVIDERS.length + 1;
41109
+ customs.forEach((c, i) => {
41110
+ if (c.active)
41111
+ indices.push(offset + i);
41112
+ });
41113
+ }
41114
+ return indices.length > 0 ? indices : undefined;
41115
+ };
41116
+ const handleAddCustom = (name) => {
41117
+ const entry = {
41118
+ name,
41119
+ tag: toTag(name),
41120
+ model: "",
41121
+ provider: "custom",
41122
+ active: true,
41123
+ authUrl: "",
41124
+ authToken: "",
41125
+ cli: "claude"
41126
+ };
41127
+ setCustomItems((prev) => [...prev, entry]);
41128
+ };
41129
+ const handleProviderConfirm = (selectedIndices) => {
41130
+ const nativeMap = existingNative();
41131
+ const customs = customItems();
41132
+ const hasCustoms = customs.length > 0;
41133
+ const customOffset = PROVIDERS.length + (hasCustoms ? 1 : 0);
41134
+ const entries = [];
41135
+ for (let i = 0;i < PROVIDERS.length; i++) {
41136
+ const def = PROVIDERS[i];
41137
+ const isSelected = selectedIndices.includes(i);
41138
+ const existing = nativeMap.get(def.id);
41139
+ if (isSelected || existing) {
41140
+ entries.push({
41141
+ name: existing?.name || def.displayName,
41142
+ tag: existing?.tag || def.defaultTag,
41143
+ model: existing?.model || def.defaultModel,
41144
+ provider: def.id,
41145
+ active: isSelected,
41146
+ authUrl: "",
41147
+ authToken: "",
41148
+ cli: "claude",
41149
+ prompts: existing?.prompts,
41150
+ preloadSkills: existing?.preloadSkills,
41151
+ executablePath: existing?.executablePath,
41152
+ timeout: existing?.timeout
41153
+ });
41154
+ }
41155
+ }
41156
+ for (let i = 0;i < customs.length; i++) {
41157
+ const isSelected = selectedIndices.includes(customOffset + i);
41158
+ entries.push({
41159
+ ...customs[i],
41160
+ active: isSelected
41161
+ });
41162
+ }
41163
+ agentEntries = entries;
40925
41164
  setActiveTab(0);
40926
41165
  setFocusedField(0);
40927
- cursorPos = configs[0]?.name.length || 0;
41166
+ cursorPos = settingsData.name.length;
40928
41167
  setStep("configure");
40929
41168
  };
40930
41169
  const handleProviderCancel = () => {
40931
41170
  if (props.onCancel)
40932
41171
  props.onCancel();
40933
41172
  };
40934
- const isYouTab = () => activeTab() === 0;
41173
+ const activeEntries = () => agentEntries.filter((e) => e.active);
41174
+ const isSettingsTab = () => activeTab() === 0;
40935
41175
  const agentTabIndex = () => activeTab() - 1;
40936
- const totalTabs = () => (inputRefsData?.length || 0) + 1;
40937
- const maxFieldIndex = () => isYouTab() ? 1 : 2;
41176
+ const totalTabs = () => activeEntries().length + 1;
41177
+ const isCustomAgent = () => {
41178
+ if (isSettingsTab())
41179
+ return false;
41180
+ const entry = activeEntries()[agentTabIndex()];
41181
+ return entry?.provider === "custom";
41182
+ };
41183
+ const maxFieldIndex = () => {
41184
+ if (isSettingsTab())
41185
+ return 3;
41186
+ return isCustomAgent() ? 4 : 2;
41187
+ };
41188
+ const getFieldValueForEntry = (entry, field) => {
41189
+ if (entry.provider === "custom") {
41190
+ return [entry.name, entry.tag, entry.model, entry.authUrl, entry.authToken][field];
41191
+ }
41192
+ return [entry.name, entry.tag, entry.model][field];
41193
+ };
41194
+ const getSettingsFieldValue = (field) => {
41195
+ return [settingsData.name, settingsData.tag, settingsData.maxHops, settingsData.timeout][field];
41196
+ };
41197
+ const getCurrentFieldValue = () => {
41198
+ if (isSettingsTab())
41199
+ return getSettingsFieldValue(focusedField());
41200
+ const entry = activeEntries()[agentTabIndex()];
41201
+ if (!entry)
41202
+ return "";
41203
+ return getFieldValueForEntry(entry, focusedField());
41204
+ };
41205
+ const updateField = (value, newCursor) => {
41206
+ if (isSettingsTab()) {
41207
+ if (focusedField() === 0)
41208
+ settingsData.name = value;
41209
+ else if (focusedField() === 1)
41210
+ settingsData.tag = value;
41211
+ else if (focusedField() === 2)
41212
+ settingsData.maxHops = value;
41213
+ else
41214
+ settingsData.timeout = value;
41215
+ } else {
41216
+ const entry = activeEntries()[agentTabIndex()];
41217
+ if (!entry)
41218
+ return;
41219
+ if (entry.provider === "custom") {
41220
+ if (focusedField() === 0)
41221
+ entry.name = value;
41222
+ else if (focusedField() === 1)
41223
+ entry.tag = value;
41224
+ else if (focusedField() === 2)
41225
+ entry.model = value;
41226
+ else if (focusedField() === 3)
41227
+ entry.authUrl = value;
41228
+ else
41229
+ entry.authToken = value;
41230
+ } else {
41231
+ if (focusedField() === 0)
41232
+ entry.name = value;
41233
+ else if (focusedField() === 1)
41234
+ entry.tag = value;
41235
+ else
41236
+ entry.model = value;
41237
+ }
41238
+ }
41239
+ cursorPos = newCursor;
41240
+ setError("");
41241
+ setTick((n) => n + 1);
41242
+ };
41243
+ const isTagField = () => focusedField() === 1;
41244
+ const isNumberField = () => isSettingsTab() && (focusedField() === 2 || focusedField() === 3);
40938
41245
  const saveConfig = async () => {
40939
- const configs = inputRefsData;
40940
- const human = humanData;
40941
- if (!human.name.trim()) {
40942
- setError("Your name cannot be empty");
41246
+ if (!settingsData.name.trim()) {
41247
+ setError("Name cannot be empty");
41248
+ return;
41249
+ }
41250
+ if (!settingsData.tag.trim()) {
41251
+ setError("Tag cannot be empty");
40943
41252
  return;
40944
41253
  }
40945
- if (!human.tag.trim()) {
40946
- setError("Your tag cannot be empty");
41254
+ if (!TAG_PATTERN.test(settingsData.tag.trim())) {
41255
+ setError("Tag can only contain letters, numbers, hyphens, underscores");
40947
41256
  return;
40948
41257
  }
40949
- if (!TAG_PATTERN.test(human.tag.trim())) {
40950
- setError("Your tag can only contain letters, numbers, hyphens, underscores");
41258
+ const maxHops = parseInt(settingsData.maxHops, 10);
41259
+ if (isNaN(maxHops) || maxHops < 0) {
41260
+ setError("Max Hops must be 0 or a positive number");
40951
41261
  return;
40952
41262
  }
40953
- for (const c of configs) {
40954
- if (!c.name.trim()) {
40955
- setError(`Name cannot be empty for ${c.id}`);
41263
+ const timeout = parseInt(settingsData.timeout, 10);
41264
+ if (isNaN(timeout) || timeout < 0) {
41265
+ setError("Timeout must be 0 or a positive number");
41266
+ return;
41267
+ }
41268
+ const tags = new Set;
41269
+ tags.add(settingsData.tag.trim().toLowerCase());
41270
+ for (const entry of agentEntries) {
41271
+ if (!entry.name.trim()) {
41272
+ setError(`Name cannot be empty for an agent`);
40956
41273
  return;
40957
41274
  }
40958
- if (!c.tag.trim()) {
40959
- setError(`Tag cannot be empty for ${c.id}`);
41275
+ if (!entry.tag.trim()) {
41276
+ setError(`Tag cannot be empty for ${entry.name}`);
40960
41277
  return;
40961
41278
  }
40962
- if (!TAG_PATTERN.test(c.tag.trim())) {
40963
- setError(`Tag for ${c.name} can only contain letters, numbers, hyphens, underscores`);
41279
+ if (!TAG_PATTERN.test(entry.tag.trim())) {
41280
+ setError(`Tag for ${entry.name} can only contain letters, numbers, hyphens, underscores`);
40964
41281
  return;
40965
41282
  }
40966
- if (!c.model.trim()) {
40967
- setError(`Model cannot be empty for ${c.id}`);
41283
+ if (!entry.model.trim()) {
41284
+ setError(`Model cannot be empty for ${entry.name}`);
40968
41285
  return;
40969
41286
  }
40970
- }
40971
- const names = new Set;
40972
- for (const c of configs) {
40973
- const lower = c.name.trim().toLowerCase();
40974
- if (names.has(lower)) {
40975
- setError(`Duplicate agent name: ${c.name}`);
41287
+ const tagLower = entry.tag.trim().toLowerCase();
41288
+ if (tags.has(tagLower)) {
41289
+ setError(`Duplicate tag: ${entry.tag}`);
41290
+ return;
41291
+ }
41292
+ tags.add(tagLower);
41293
+ if (entry.provider === "custom" && entry.active && !entry.authUrl.trim()) {
41294
+ setError(`URL is required for ${entry.name}`);
40976
41295
  return;
40977
41296
  }
40978
- names.add(lower);
40979
41297
  }
40980
- const overrides = configs.map((c) => ({
40981
- id: c.id,
40982
- name: c.name.trim(),
40983
- tag: c.tag.trim(),
40984
- model: c.model.trim()
40985
- }));
40986
- const mergedExisting = {
40987
- ...props.existingConfig || {},
40988
- humanName: human.name.trim(),
40989
- humanTag: human.tag.trim(),
40990
- agents: props.existingConfig?.agents || []
41298
+ const agents = agentEntries.map(entryToPersona);
41299
+ const config = {
41300
+ humanName: settingsData.name.trim(),
41301
+ humanTag: settingsData.tag.trim(),
41302
+ maxAutoHops: maxHops,
41303
+ timeout: timeout > 0 ? timeout : undefined,
41304
+ reminderInterval: props.existingConfig?.reminderInterval,
41305
+ agents
40991
41306
  };
41307
+ if (config.timeout === undefined)
41308
+ delete config.timeout;
41309
+ if (config.reminderInterval === undefined)
41310
+ delete config.reminderInterval;
40992
41311
  try {
40993
- await writeWizardConfig(selectedIds(), overrides, mergedExisting);
41312
+ await writeConfig(config);
40994
41313
  setStep("done");
40995
41314
  } catch (err) {
40996
41315
  setError(`Failed to save: ${err.message}`);
@@ -41002,9 +41321,8 @@ function ConfigWizard(props) {
41002
41321
  return;
41003
41322
  }
41004
41323
  if (step() !== "configure") {
41005
- if (step() === "detect") {
41324
+ if (step() === "detect")
41006
41325
  return;
41007
- }
41008
41326
  if (step() === "done") {
41009
41327
  if (key.name === "enter" || key.name === "return" || key.name === "space") {
41010
41328
  props.onComplete();
@@ -41013,49 +41331,20 @@ function ConfigWizard(props) {
41013
41331
  }
41014
41332
  return;
41015
41333
  }
41016
- const configs = inputRefsData;
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
- }
41334
+ const fieldValue = getCurrentFieldValue();
41027
41335
  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
41336
  if (key.sequence === "[" || key.sequence === "]") {
41048
41337
  const dir = key.sequence === "[" ? -1 : 1;
41049
41338
  const next = (activeTab() + dir + totalTabs()) % totalTabs();
41050
41339
  setActiveTab(next);
41051
- const newMax = next === 0 ? 1 : 2;
41340
+ const newMax = next === 0 ? 3 : activeEntries()[next - 1]?.provider === "custom" ? 4 : 2;
41052
41341
  const newField = Math.min(focusedField(), newMax);
41053
41342
  setFocusedField(newField);
41054
41343
  let newVal;
41055
41344
  if (next === 0) {
41056
- newVal = newField === 0 ? human.name : human.tag;
41345
+ newVal = getSettingsFieldValue(newField);
41057
41346
  } else {
41058
- newVal = getFieldValue(configs[next - 1], newField);
41347
+ newVal = getFieldValueForEntry(activeEntries()[next - 1], newField);
41059
41348
  }
41060
41349
  cursorPos = newVal.length;
41061
41350
  setTick((n) => n + 1);
@@ -41065,12 +41354,7 @@ function ConfigWizard(props) {
41065
41354
  const fieldCount = maxFieldIndex() + 1;
41066
41355
  const nextField = key.shift ? (focusedField() - 1 + fieldCount) % fieldCount : (focusedField() + 1) % fieldCount;
41067
41356
  setFocusedField(nextField);
41068
- let newVal;
41069
- if (isYouTab()) {
41070
- newVal = nextField === 0 ? human.name : human.tag;
41071
- } else {
41072
- newVal = getFieldValue(configs[agentTabIndex()], nextField);
41073
- }
41357
+ const newVal = isSettingsTab() ? getSettingsFieldValue(nextField) : getFieldValueForEntry(activeEntries()[agentTabIndex()], nextField);
41074
41358
  cursorPos = newVal.length;
41075
41359
  setTick((n) => n + 1);
41076
41360
  return;
@@ -41125,7 +41409,7 @@ function ConfigWizard(props) {
41125
41409
  return;
41126
41410
  }
41127
41411
  if (key.name === "space" || key.sequence === " ") {
41128
- if (focusedField() !== 1) {
41412
+ if (!isTagField() && !isNumberField()) {
41129
41413
  updateField(fieldValue.slice(0, cursor) + " " + fieldValue.slice(cursor), cursor + 1);
41130
41414
  }
41131
41415
  return;
@@ -41134,7 +41418,9 @@ function ConfigWizard(props) {
41134
41418
  if (ch && ch.length > 0 && !ch.startsWith("\x1B")) {
41135
41419
  if (ch === "'" || ch === '"' || ch === "`")
41136
41420
  return;
41137
- if (focusedField() === 1 && !TAG_PATTERN.test(ch))
41421
+ if (isTagField() && !TAG_PATTERN.test(ch))
41422
+ return;
41423
+ if (isNumberField() && !/^[0-9]$/.test(ch))
41138
41424
  return;
41139
41425
  updateField(fieldValue.slice(0, cursor) + ch + fieldValue.slice(cursor), cursor + ch.length);
41140
41426
  }
@@ -41152,7 +41438,7 @@ function ConfigWizard(props) {
41152
41438
  })();
41153
41439
  }
41154
41440
  const discoColor = useDiscoColor();
41155
- function renderField(label, value, isFocused) {
41441
+ function renderField(label, value, isFocused, hint) {
41156
41442
  tick();
41157
41443
  const cursor = cursorPos;
41158
41444
  const labelColor = isFocused ? COLORS.primary : COLORS.textDim;
@@ -41175,7 +41461,7 @@ function ConfigWizard(props) {
41175
41461
  setProp(_el$12, "style", {
41176
41462
  fg: valueColor
41177
41463
  });
41178
- insert(_el$12, value);
41464
+ insert(_el$12, value || (hint ? hint : ""));
41179
41465
  effect((_$p) => setProp(_el$0, "style", {
41180
41466
  fg: COLORS.borderStrong
41181
41467
  }, _$p));
@@ -41210,6 +41496,13 @@ function ConfigWizard(props) {
41210
41496
  return _el$13;
41211
41497
  })();
41212
41498
  }
41499
+ function renderTokenField(label, value, isFocused) {
41500
+ if (!isFocused && value.length > 0) {
41501
+ const masked = value.length > 4 ? "*".repeat(value.length - 4) + value.slice(-4) : "*".repeat(value.length);
41502
+ return renderField(label, masked, false);
41503
+ }
41504
+ return renderField(label, value, isFocused);
41505
+ }
41213
41506
  const DetectStep = () => (() => {
41214
41507
  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
41508
  insertNode(_el$19, _el$20);
@@ -41325,6 +41618,9 @@ function ConfigWizard(props) {
41325
41618
  },
41326
41619
  get initialSelected() {
41327
41620
  return initialSelected();
41621
+ },
41622
+ addCustom: {
41623
+ onAdd: handleAddCustom
41328
41624
  }
41329
41625
  }));
41330
41626
  effect((_p$) => {
@@ -41362,12 +41658,8 @@ function ConfigWizard(props) {
41362
41658
  })();
41363
41659
  const ConfigureStep = () => {
41364
41660
  tick();
41365
- const configs = inputRefsData;
41366
- const human = humanData;
41367
- const tabLabels = ["You", ...selectedIds().map((id) => {
41368
- const def = PROVIDERS.find((p) => p.id === id);
41369
- return def?.displayName || id;
41370
- })];
41661
+ const active = activeEntries();
41662
+ const tabLabels = ["Settings", ...active.map((e) => e.name)];
41371
41663
  return (() => {
41372
41664
  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
41665
  insertNode(_el$48, _el$49);
@@ -41439,7 +41731,7 @@ function ConfigWizard(props) {
41439
41731
  setProp(_el$56, "flexDirection", "column");
41440
41732
  insert(_el$56, createComponent2(Show, {
41441
41733
  get when() {
41442
- return isYouTab();
41734
+ return isSettingsTab();
41443
41735
  },
41444
41736
  get fallback() {
41445
41737
  return [(() => {
@@ -41448,19 +41740,39 @@ function ConfigWizard(props) {
41448
41740
  setProp(_el$94, "marginBottom", 1);
41449
41741
  insertNode(_el$95, _el$96);
41450
41742
  insert(_el$95, () => tabLabels[activeTab()], _el$96);
41743
+ insert(_el$94, createComponent2(Show, {
41744
+ get when() {
41745
+ return activeEntries()[agentTabIndex()]?.provider === "custom";
41746
+ },
41747
+ get children() {
41748
+ var _el$97 = createElement("span");
41749
+ insertNode(_el$97, createTextNode(` (custom)`));
41750
+ effect((_$p) => setProp(_el$97, "style", {
41751
+ fg: COLORS.textFaint
41752
+ }, _$p));
41753
+ return _el$97;
41754
+ }
41755
+ }), null);
41451
41756
  effect((_$p) => setProp(_el$94, "fg", COLORS.success, _$p));
41452
41757
  return _el$94;
41453
- })(), memo2(() => renderField("Name ", configs[agentTabIndex()].name, focusedField() === 0)), memo2(() => renderField("Tag ", configs[agentTabIndex()].tag, focusedField() === 1)), memo2(() => renderField("Model", configs[agentTabIndex()].model, focusedField() === 2))];
41758
+ })(), 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, {
41759
+ get when() {
41760
+ return active[agentTabIndex()]?.provider === "custom";
41761
+ },
41762
+ get children() {
41763
+ return [memo2(() => renderField("URL ", active[agentTabIndex()].authUrl, focusedField() === 3)), memo2(() => renderTokenField("Token", active[agentTabIndex()].authToken, focusedField() === 4))];
41764
+ }
41765
+ })];
41454
41766
  },
41455
41767
  get children() {
41456
41768
  return [(() => {
41457
41769
  var _el$57 = createElement("text"), _el$58 = createElement("strong");
41458
41770
  insertNode(_el$57, _el$58);
41459
41771
  setProp(_el$57, "marginBottom", 1);
41460
- insertNode(_el$58, createTextNode(`Your Identity`));
41772
+ insertNode(_el$58, createTextNode(`General Settings`));
41461
41773
  effect((_$p) => setProp(_el$57, "fg", COLORS.agent, _$p));
41462
41774
  return _el$57;
41463
- })(), memo2(() => renderField("Name", human.name, focusedField() === 0)), memo2(() => renderField("Tag ", human.tag, focusedField() === 1))];
41775
+ })(), 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
41776
  }
41465
41777
  }));
41466
41778
  insertNode(_el$60, _el$61);
@@ -41520,7 +41832,7 @@ function ConfigWizard(props) {
41520
41832
  }
41521
41833
  }), null);
41522
41834
  effect((_p$) => {
41523
- var _v$13 = discoColor(), _v$14 = COLORS.bgPanel, _v$15 = COLORS.borderStrong, _v$16 = isYouTab() ? COLORS.agent : COLORS.success, _v$17 = COLORS.bgContent, _v$18 = {
41835
+ 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
41836
  fg: COLORS.textFaint
41525
41837
  }, _v$19 = {
41526
41838
  fg: COLORS.success
@@ -41590,57 +41902,57 @@ function ConfigWizard(props) {
41590
41902
  })();
41591
41903
  };
41592
41904
  const DoneStep = () => (() => {
41593
- var _el$97 = createElement("box"), _el$98 = createElement("box"), _el$99 = createElement("box"), _el$100 = createElement("text"), _el$102 = createElement("text"), _el$104 = createElement("text"), _el$106 = createElement("text"), _el$108 = createElement("text"), _el$110 = createElement("text"), _el$111 = createTextNode(`Press `), _el$112 = createElement("span"), _el$113 = createElement("strong"), _el$115 = createTextNode(` to continue`);
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);
41905
+ 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
41906
  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
41907
  setProp(_el$99, "flexDirection", "column");
41908
+ setProp(_el$99, "width", "100%");
41909
+ setProp(_el$99, "height", "100%");
41910
+ setProp(_el$99, "justifyContent", "center");
41612
41911
  setProp(_el$99, "alignItems", "center");
41613
- insert(_el$99, createComponent2(SweepBar, {
41912
+ insertNode(_el$100, _el$101);
41913
+ setProp(_el$100, "border", true);
41914
+ setProp(_el$100, "borderStyle", "double");
41915
+ setProp(_el$100, "paddingX", 4);
41916
+ setProp(_el$100, "paddingY", 2);
41917
+ insertNode(_el$101, _el$102);
41918
+ insertNode(_el$101, _el$104);
41919
+ insertNode(_el$101, _el$106);
41920
+ insertNode(_el$101, _el$108);
41921
+ insertNode(_el$101, _el$110);
41922
+ insertNode(_el$101, _el$112);
41923
+ setProp(_el$101, "flexDirection", "column");
41924
+ setProp(_el$101, "alignItems", "center");
41925
+ insert(_el$101, createComponent2(SweepBar, {
41614
41926
  title: "Config Saved"
41615
- }), _el$100);
41616
- insertNode(_el$100, 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`));
41617
- setProp(_el$100, "marginTop", 1);
41618
- insertNode(_el$102, createTextNode(`Written to ~/.llm-party/config.json`));
41927
+ }), _el$102);
41928
+ 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
41929
  setProp(_el$102, "marginTop", 1);
41620
- insertNode(_el$104, createTextNode(`Edit this file anytime to add prompts,`));
41930
+ insertNode(_el$104, createTextNode(`Written to ~/.llm-party/config.json`));
41621
41931
  setProp(_el$104, "marginTop", 1);
41622
- insertNode(_el$106, createTextNode(`env vars, or tweak settings.`));
41623
- insertNode(_el$108, 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`));
41624
- setProp(_el$108, "marginTop", 1);
41625
- insertNode(_el$110, _el$111);
41626
- insertNode(_el$110, _el$112);
41627
- insertNode(_el$110, _el$115);
41932
+ insertNode(_el$106, createTextNode(`Edit this file anytime to add prompts,`));
41933
+ setProp(_el$106, "marginTop", 1);
41934
+ insertNode(_el$108, createTextNode(`env vars, or tweak settings.`));
41935
+ 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
41936
  setProp(_el$110, "marginTop", 1);
41629
41937
  insertNode(_el$112, _el$113);
41630
- insertNode(_el$113, createTextNode(`Enter`));
41938
+ insertNode(_el$112, _el$114);
41939
+ insertNode(_el$112, _el$117);
41940
+ setProp(_el$112, "marginTop", 1);
41941
+ insertNode(_el$114, _el$115);
41942
+ insertNode(_el$115, createTextNode(`Enter`));
41631
41943
  effect((_p$) => {
41632
41944
  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
41945
  fg: COLORS.success
41634
41946
  };
41635
- _v$33 !== _p$.e && (_p$.e = setProp(_el$98, "borderColor", _v$33, _p$.e));
41636
- _v$34 !== _p$.t && (_p$.t = setProp(_el$98, "backgroundColor", _v$34, _p$.t));
41637
- _v$35 !== _p$.a && (_p$.a = setProp(_el$100, "fg", _v$35, _p$.a));
41638
- _v$36 !== _p$.o && (_p$.o = setProp(_el$102, "fg", _v$36, _p$.o));
41639
- _v$37 !== _p$.i && (_p$.i = setProp(_el$104, "fg", _v$37, _p$.i));
41640
- _v$38 !== _p$.n && (_p$.n = setProp(_el$106, "fg", _v$38, _p$.n));
41641
- _v$39 !== _p$.s && (_p$.s = setProp(_el$108, "fg", _v$39, _p$.s));
41642
- _v$40 !== _p$.h && (_p$.h = setProp(_el$110, "fg", _v$40, _p$.h));
41643
- _v$41 !== _p$.r && (_p$.r = setProp(_el$112, "style", _v$41, _p$.r));
41947
+ _v$33 !== _p$.e && (_p$.e = setProp(_el$100, "borderColor", _v$33, _p$.e));
41948
+ _v$34 !== _p$.t && (_p$.t = setProp(_el$100, "backgroundColor", _v$34, _p$.t));
41949
+ _v$35 !== _p$.a && (_p$.a = setProp(_el$102, "fg", _v$35, _p$.a));
41950
+ _v$36 !== _p$.o && (_p$.o = setProp(_el$104, "fg", _v$36, _p$.o));
41951
+ _v$37 !== _p$.i && (_p$.i = setProp(_el$106, "fg", _v$37, _p$.i));
41952
+ _v$38 !== _p$.n && (_p$.n = setProp(_el$108, "fg", _v$38, _p$.n));
41953
+ _v$39 !== _p$.s && (_p$.s = setProp(_el$110, "fg", _v$39, _p$.s));
41954
+ _v$40 !== _p$.h && (_p$.h = setProp(_el$112, "fg", _v$40, _p$.h));
41955
+ _v$41 !== _p$.r && (_p$.r = setProp(_el$114, "style", _v$41, _p$.r));
41644
41956
  return _p$;
41645
41957
  }, {
41646
41958
  e: undefined,
@@ -41653,7 +41965,7 @@ function ConfigWizard(props) {
41653
41965
  h: undefined,
41654
41966
  r: undefined
41655
41967
  });
41656
- return _el$97;
41968
+ return _el$99;
41657
41969
  })();
41658
41970
  return [createComponent2(Show, {
41659
41971
  get when() {
@@ -41685,13 +41997,6 @@ function ConfigWizard(props) {
41685
41997
  }
41686
41998
  })];
41687
41999
  }
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
42000
 
41696
42001
  // src/ui/AgentsPanel.tsx
41697
42002
  function AgentsPanel(props) {
@@ -41996,7 +42301,7 @@ function InfoPanel(props) {
41996
42301
 
41997
42302
  // src/ui/App.tsx
41998
42303
  function copyToClipboard(text) {
41999
- const proc = spawn5("pbcopy", [], {
42304
+ const proc = spawn4("pbcopy", [], {
42000
42305
  stdio: ["pipe", "ignore", "ignore"]
42001
42306
  });
42002
42307
  proc.stdin?.write(text);
@@ -42028,6 +42333,7 @@ function App(props) {
42028
42333
  const agents = props.orchestrator.listAgents();
42029
42334
  let scrollRef = null;
42030
42335
  const [screen, setScreen] = createSignal("chat");
42336
+ const [freshConfig, setFreshConfig] = createSignal(props.config);
42031
42337
  const [showAgents, setShowAgents] = createSignal(false);
42032
42338
  const [showInfo, setShowInfo] = createSignal(false);
42033
42339
  process.on("SIGINT", () => renderer.destroy());
@@ -42101,6 +42407,10 @@ Transcript: ${props.orchestrator.getTranscriptPath()}`);
42101
42407
  return;
42102
42408
  }
42103
42409
  if (line === "/config") {
42410
+ try {
42411
+ const reloaded = await loadConfig2(props.configPath);
42412
+ setFreshConfig(reloaded);
42413
+ } catch {}
42104
42414
  setScreen("config");
42105
42415
  return;
42106
42416
  }
@@ -42141,7 +42451,7 @@ ${lines.join(`
42141
42451
  return createComponent2(ConfigWizard, {
42142
42452
  isFirstRun: false,
42143
42453
  get existingConfig() {
42144
- return props.config;
42454
+ return freshConfig();
42145
42455
  },
42146
42456
  onComplete: () => {
42147
42457
  addSystemMessage("Config saved. Restart llm-party to apply changes.");
@@ -42258,7 +42568,8 @@ async function bootApp(appRoot, rendererConfig) {
42258
42568
  ` + obsidianPrompt;
42259
42569
  const availableSkills = await discoverSkills();
42260
42570
  const agentVerifiedSkills = new Map;
42261
- for (const agent of config.agents) {
42571
+ const activeAgents = config.agents.filter((a) => a.active !== false);
42572
+ for (const agent of activeAgents) {
42262
42573
  if (agent.preloadSkills && agent.preloadSkills.length > 0) {
42263
42574
  const verified = [];
42264
42575
  const report = [];
@@ -42279,7 +42590,7 @@ async function bootApp(appRoot, rendererConfig) {
42279
42590
  const resolveFromConfig = (value) => {
42280
42591
  return path11.isAbsolute(value) ? value : path11.resolve(configDir, value);
42281
42592
  };
42282
- const adapters = await Promise.all(config.agents.map(async (agent, _index, allAgents) => {
42593
+ const adapters = await Promise.all(activeAgents.map(async (agent, _index, allAgents) => {
42283
42594
  const promptParts = [mergedBase];
42284
42595
  if (agent.prompts && agent.prompts.length > 0) {
42285
42596
  const extraPaths = agent.prompts.map((p) => resolveFromConfig(p));
@@ -42318,7 +42629,7 @@ ${mySkills.map((s) => `- ${s}`).join(`
42318
42629
  agentCount: String(allAgents.length),
42319
42630
  preloadedSkills
42320
42631
  });
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 === "glm" ? new GlmAdapter(agent.name, agent.model) : null;
42632
+ 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
42633
  if (!adapter) {
42323
42634
  throw new Error(`Unsupported provider: ${agent.provider}`);
42324
42635
  }
@@ -42326,12 +42637,12 @@ ${mySkills.map((s) => `- ${s}`).join(`
42326
42637
  return adapter;
42327
42638
  }));
42328
42639
  const defaultTimeout = typeof config.timeout === "number" && config.timeout > 0 ? config.timeout * 1000 : 600000;
42329
- const agentTimeouts = Object.fromEntries(config.agents.filter((agent) => typeof agent.timeout === "number" && agent.timeout > 0).map((agent) => [agent.name, agent.timeout * 1000]));
42330
- const orchestrator = new Orchestrator(adapters, humanName, Object.fromEntries(config.agents.map((agent) => [agent.name, agent.tag?.trim() || toTag(agent.name)])), humanTag, defaultTimeout, agentTimeouts, { reminderInterval: config.reminderInterval });
42331
- await render(() => App({ orchestrator, maxAutoHops, config }), rendererConfig);
42640
+ const agentTimeouts = Object.fromEntries(activeAgents.filter((agent) => typeof agent.timeout === "number" && agent.timeout > 0).map((agent) => [agent.name, agent.timeout * 1000]));
42641
+ 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 });
42642
+ await render(() => App({ orchestrator, maxAutoHops, config, configPath }), rendererConfig);
42332
42643
  }
42333
42644
  function resolveMaxAutoHops(value) {
42334
- if (value === "unlimited") {
42645
+ if (typeof value === "number" && value === 0) {
42335
42646
  return Number.POSITIVE_INFINITY;
42336
42647
  }
42337
42648
  if (typeof value === "number" && Number.isFinite(value) && value >= 1) {