pikiloom 0.4.26 → 0.4.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (155) hide show
  1. package/dashboard/dist/assets/{AgentTab-BNJ73P0m.js → AgentTab-DIP-y4dl.js} +1 -1
  2. package/dashboard/dist/assets/ConnectionModal-BCfvhkiI.js +1 -0
  3. package/dashboard/dist/assets/{DirBrowser-D-GT-G-w.js → DirBrowser-Dot7ua9-.js} +1 -1
  4. package/dashboard/dist/assets/{ExtensionsTab-BrJMulJR.js → ExtensionsTab-GioMx4S6.js} +1 -1
  5. package/dashboard/dist/assets/{IMAccessTab-auPnx468.js → IMAccessTab-C9_r8jJP.js} +1 -1
  6. package/dashboard/dist/assets/{Modal-lYfO9m-I.js → Modal-M1AP1sgR.js} +1 -1
  7. package/dashboard/dist/assets/{Modals-PRdWOIY9.js → Modals-CCm3UUfJ.js} +1 -1
  8. package/dashboard/dist/assets/{Select-BhbU-rll.js → Select-YubDM16P.js} +1 -1
  9. package/dashboard/dist/assets/{SessionPanel-_0dLWvEb.js → SessionPanel-Cnv9o96n.js} +1 -1
  10. package/dashboard/dist/assets/SystemTab-VgNivIe3.js +1 -0
  11. package/dashboard/dist/assets/index-BY7l20bi.js +23 -0
  12. package/dashboard/dist/assets/index-BlqvzDUL.js +3 -0
  13. package/dashboard/dist/assets/index-CXIN3nTr.css +1 -0
  14. package/dashboard/dist/assets/{shared-C5uXvhZJ.js → shared-C0SAInnT.js} +1 -1
  15. package/dashboard/dist/index.html +2 -2
  16. package/dist/agent/acp-client.js +0 -59
  17. package/dist/agent/artifacts.js +1 -38
  18. package/dist/agent/auto-update.js +2 -78
  19. package/dist/agent/await-resume.js +0 -20
  20. package/dist/agent/cli/auth.js +3 -51
  21. package/dist/agent/cli/catalog.js +0 -3
  22. package/dist/agent/cli/detector.js +1 -19
  23. package/dist/agent/cli/index.js +0 -3
  24. package/dist/agent/cli/registry.js +0 -25
  25. package/dist/agent/driver.js +0 -14
  26. package/dist/agent/drivers/claude-tui.js +2 -769
  27. package/dist/agent/drivers/claude.js +12 -631
  28. package/dist/agent/drivers/codex.js +11 -162
  29. package/dist/agent/drivers/gemini.js +6 -114
  30. package/dist/agent/drivers/hermes.js +0 -128
  31. package/dist/agent/goal.js +0 -45
  32. package/dist/agent/handover.js +1 -46
  33. package/dist/agent/images.js +7 -133
  34. package/dist/agent/index.js +1 -29
  35. package/dist/agent/mcp/bridge.js +1 -197
  36. package/dist/agent/mcp/extensions.js +5 -84
  37. package/dist/agent/mcp/oauth.js +2 -69
  38. package/dist/agent/mcp/registry.js +2 -33
  39. package/dist/agent/mcp/session-server.js +2 -45
  40. package/dist/agent/mcp/tools/ask-user.js +0 -6
  41. package/dist/agent/mcp/tools/await-resume.js +0 -15
  42. package/dist/agent/mcp/tools/goal.js +0 -25
  43. package/dist/agent/mcp/tools/types.js +0 -5
  44. package/dist/agent/mcp/tools/workspace.js +0 -23
  45. package/dist/agent/npm.js +0 -14
  46. package/dist/agent/session.js +86 -196
  47. package/dist/agent/skill-installer.js +3 -70
  48. package/dist/agent/skills.js +0 -43
  49. package/dist/agent/stream.js +5 -148
  50. package/dist/agent/types.js +0 -12
  51. package/dist/agent/utils.js +2 -120
  52. package/dist/bot/bot.js +3 -468
  53. package/dist/bot/command-ui.js +0 -45
  54. package/dist/bot/commands.js +0 -51
  55. package/dist/bot/headless-bot.js +0 -21
  56. package/dist/bot/host.js +1 -5
  57. package/dist/bot/human-loop.js +0 -8
  58. package/dist/bot/menu.js +0 -3
  59. package/dist/bot/orchestration.js +0 -3
  60. package/dist/bot/render-shared.js +0 -63
  61. package/dist/bot/session-hub.js +14 -92
  62. package/dist/bot/session-status.js +1 -5
  63. package/dist/bot/streaming.js +0 -53
  64. package/dist/browser-profile.js +0 -51
  65. package/dist/browser-supervisor.js +0 -75
  66. package/dist/catalog/cli-tools.js +0 -53
  67. package/dist/catalog/index.js +0 -18
  68. package/dist/catalog/local-models.js +0 -18
  69. package/dist/catalog/mcp-servers.js +0 -35
  70. package/dist/catalog/skill-repos.js +0 -32
  71. package/dist/channels/base.js +0 -19
  72. package/dist/channels/dingtalk/bot.js +0 -3
  73. package/dist/channels/dingtalk/channel.js +0 -33
  74. package/dist/channels/discord/bot.js +0 -7
  75. package/dist/channels/discord/channel.js +0 -22
  76. package/dist/channels/feishu/bot.js +0 -71
  77. package/dist/channels/feishu/channel.js +0 -78
  78. package/dist/channels/feishu/markdown.js +0 -5
  79. package/dist/channels/feishu/render.js +0 -45
  80. package/dist/channels/health.js +0 -46
  81. package/dist/channels/slack/bot.js +0 -7
  82. package/dist/channels/slack/channel.js +1 -27
  83. package/dist/channels/states.js +0 -3
  84. package/dist/channels/telegram/bot.js +0 -60
  85. package/dist/channels/telegram/channel.js +2 -99
  86. package/dist/channels/telegram/directory.js +0 -3
  87. package/dist/channels/telegram/live-preview.js +0 -8
  88. package/dist/channels/telegram/render.js +0 -30
  89. package/dist/channels/wecom/bot.js +0 -3
  90. package/dist/channels/wecom/channel.js +0 -58
  91. package/dist/channels/weixin/api.js +0 -9
  92. package/dist/channels/weixin/bot.js +0 -88
  93. package/dist/channels/weixin/channel.js +0 -6
  94. package/dist/cli/autostart.js +1 -44
  95. package/dist/cli/channel-supervisor.js +1 -59
  96. package/dist/cli/channels.js +0 -6
  97. package/dist/cli/main.js +1 -145
  98. package/dist/cli/onboarding.js +0 -6
  99. package/dist/cli/run.js +0 -11
  100. package/dist/cli/setup-wizard.js +0 -3
  101. package/dist/core/config/runtime-config.js +0 -38
  102. package/dist/core/config/user-config.js +0 -63
  103. package/dist/core/config/validation.js +0 -9
  104. package/dist/core/constants.js +0 -268
  105. package/dist/core/git.js +0 -31
  106. package/dist/core/legacy-compat.js +1 -28
  107. package/dist/core/logging.js +0 -3
  108. package/dist/core/platform.js +0 -28
  109. package/dist/core/process-control.js +0 -8
  110. package/dist/core/secrets/index.js +0 -17
  111. package/dist/core/secrets/inline-seal.js +0 -7
  112. package/dist/core/secrets/ref.js +0 -19
  113. package/dist/core/secrets/resolver.js +0 -8
  114. package/dist/core/secrets/store.js +1 -12
  115. package/dist/core/utils.js +1 -37
  116. package/dist/core/version.js +0 -3
  117. package/dist/dashboard/platform.js +1 -35
  118. package/dist/dashboard/routes/agents.js +2 -71
  119. package/dist/dashboard/routes/cli.js +0 -27
  120. package/dist/dashboard/routes/config.js +0 -54
  121. package/dist/dashboard/routes/extensions.js +0 -132
  122. package/dist/dashboard/routes/local-models.js +0 -68
  123. package/dist/dashboard/routes/models.js +0 -46
  124. package/dist/dashboard/routes/sessions.js +0 -100
  125. package/dist/dashboard/runtime.js +1 -58
  126. package/dist/dashboard/server.js +0 -49
  127. package/dist/dashboard/session-control.js +2 -69
  128. package/dist/model/catalog.js +1 -17
  129. package/dist/model/index.js +0 -15
  130. package/dist/model/injector.js +1 -181
  131. package/dist/model/provider-models.js +1 -48
  132. package/dist/model/responses-bridge.js +3 -45
  133. package/dist/model/store.js +0 -17
  134. package/dist/model/types.js +0 -12
  135. package/dist/model/validation.js +1 -18
  136. package/dist/pikichannel/adapter-pikiloom.js +0 -31
  137. package/dist/pikichannel/code.js +0 -12
  138. package/dist/pikichannel/codec.js +0 -14
  139. package/dist/pikichannel/host.js +4 -33
  140. package/dist/pikichannel/protocol.js +0 -52
  141. package/dist/pikichannel/rendezvous-broker.js +5 -26
  142. package/dist/pikichannel/rendezvous-host.js +3 -16
  143. package/dist/pikichannel/server.js +6 -55
  144. package/dist/pikichannel/transport.js +0 -25
  145. package/dist/pikichannel/transports/webrtc-host.js +0 -18
  146. package/dist/pikichannel/transports/webrtc-shared.js +4 -34
  147. package/dist/pikichannel/transports/websocket-host.js +1 -14
  148. package/dist/pikichannel/turn.js +2 -69
  149. package/dist/pikichannel/web/sdk.js +14 -71
  150. package/package.json +1 -1
  151. package/dashboard/dist/assets/ConnectionModal-Dt05H2f9.js +0 -1
  152. package/dashboard/dist/assets/SystemTab-CN_QrRKt.js +0 -1
  153. package/dashboard/dist/assets/index-CP3LYJR2.js +0 -23
  154. package/dashboard/dist/assets/index-C_neLnaO.js +0 -3
  155. package/dashboard/dist/assets/index-CyCspgtc.css +0 -1
@@ -1,6 +1,3 @@
1
- /**
2
- * Background agent CLI version checking and update prompts.
3
- */
4
1
  import fs from 'node:fs';
5
2
  import os from 'node:os';
6
3
  import path from 'node:path';
@@ -17,39 +14,18 @@ function setUpdateState(agent, patch) {
17
14
  const current = updateStates.get(agent) || emptyState();
18
15
  updateStates.set(agent, { ...current, ...patch });
19
16
  }
20
- /** Returns the cached update state for a specific agent (or null). */
21
17
  export function getAgentUpdateState(agent) {
22
18
  return updateStates.get(agent) || null;
23
19
  }
24
- /** Returns all cached update states. */
25
20
  export function getAllAgentUpdateStates() {
26
21
  const result = {};
27
22
  for (const [key, value] of updateStates)
28
23
  result[key] = value;
29
24
  return result;
30
25
  }
31
- // ---------------------------------------------------------------------------
32
- // Spawn coordination
33
- //
34
- // A CLI reinstall (`npm install -g` / `brew upgrade`) briefly tears down and
35
- // rewrites the bin symlink, so an agent spawn that races it execs into
36
- // "/bin/sh: <cli>: command not found" (exit 127). The updating process drops a
37
- // per-agent marker file for the duration of the destructive step; the spawn
38
- // path waits while it's held. The marker is cross-process (this worker AND the
39
- // `npx pikiloom@latest` self-bootstrap both update + spawn), and carries the
40
- // updater's pid so a marker orphaned by a crashed updater is detected via
41
- // liveness and cleaned up — a spawn never hangs on a stale marker, and a
42
- // genuinely-missing CLI (no marker) fails fast instead of waiting.
43
- // ---------------------------------------------------------------------------
44
- /** Path of the in-flight-reinstall marker for `agent` (one file per agent). */
45
26
  export function agentUpdateMarkerPath(agent) {
46
27
  return path.join(os.homedir(), STATE_DIR_NAME, `agent-update-${agent}.installing`);
47
28
  }
48
- /**
49
- * True when a live updater is mid-reinstall of `agent`. Reads the marker's pid
50
- * and probes liveness with `kill(pid, 0)`; an orphaned marker (writer gone) is
51
- * removed and reported idle so spawns don't hang on a crashed updater.
52
- */
53
29
  function agentReinstallInFlight(agent) {
54
30
  const marker = agentUpdateMarkerPath(agent);
55
31
  let raw;
@@ -57,12 +33,12 @@ function agentReinstallInFlight(agent) {
57
33
  raw = fs.readFileSync(marker, 'utf8');
58
34
  }
59
35
  catch {
60
- return false; // no marker — nothing updating
36
+ return false;
61
37
  }
62
38
  const pid = Number.parseInt(raw.trim(), 10);
63
39
  if (Number.isInteger(pid) && pid > 0) {
64
40
  try {
65
- process.kill(pid, 0); // throws ESRCH if the updater is gone
41
+ process.kill(pid, 0);
66
42
  return true;
67
43
  }
68
44
  catch {
@@ -73,7 +49,6 @@ function agentReinstallInFlight(agent) {
73
49
  return false;
74
50
  }
75
51
  }
76
- // Unreadable pid — fall back to mtime so a corrupt marker still ages out.
77
52
  try {
78
53
  return Date.now() - fs.statSync(marker).mtimeMs <= AGENT_UPDATE_COMMAND_TIMEOUT_MS;
79
54
  }
@@ -81,11 +56,6 @@ function agentReinstallInFlight(agent) {
81
56
  return false;
82
57
  }
83
58
  }
84
- /**
85
- * Marks `agent` as mid-reinstall (cross-process) for the duration of
86
- * `install()` so concurrent spawns can wait it out. Always clears the marker,
87
- * even when the install throws.
88
- */
89
59
  export async function withAgentUpdateGate(agent, install) {
90
60
  const id = String(agent || '').trim();
91
61
  if (!id)
@@ -106,11 +76,6 @@ export async function withAgentUpdateGate(agent, install) {
106
76
  catch { }
107
77
  }
108
78
  }
109
- /**
110
- * Resolves once no live reinstall of `agent` is in flight, or after
111
- * `timeoutMs`. No-op (returns immediately) when nothing is updating. Called
112
- * from the spawn path so we never exec a half-swapped CLI binary.
113
- */
114
79
  export async function awaitAgentUpdateIdle(agent, timeoutMs) {
115
80
  const id = String(agent || '').trim();
116
81
  if (!id)
@@ -179,10 +144,6 @@ function isNpmPackageOwnedBinary(binPath, pkg, npmRoot) {
179
144
  return true;
180
145
  return isPathInside(realPackageDir, binPath);
181
146
  }
182
- /**
183
- * Check if a binary was installed via Homebrew by resolving its real path.
184
- * Homebrew cask binaries typically symlink through Caskroom or Cellar.
185
- */
186
147
  function isBrewInstalledBinary(binPath) {
187
148
  const realPath = realPathOrNull(binPath);
188
149
  const target = realPath || binPath;
@@ -196,14 +157,12 @@ export function resolveAgentUpdateStrategy(agent, npmPrefix, npmRoot = null) {
196
157
  const binPath = String(agent.path || '').trim();
197
158
  if (!binPath)
198
159
  return { kind: 'skip', reason: 'no binary path' };
199
- // Check for Homebrew install first (binary resolves to Caskroom/Cellar).
200
160
  if (isBrewInstalledBinary(binPath)) {
201
161
  const cask = getAgentBrewCask(id);
202
162
  if (cask)
203
163
  return { kind: 'brew', cask };
204
164
  return { kind: 'skip', reason: 'brew-installed but no known cask' };
205
165
  }
206
- // Check for npm global install.
207
166
  const npmBinDir = npmPrefix ? path.join(path.resolve(npmPrefix), 'bin') : null;
208
167
  const npmManaged = !!(npmBinDir && isPathInside(npmBinDir, binPath));
209
168
  if (!npmManaged)
@@ -223,14 +182,6 @@ async function runCommand(cmd, args, opts = {}) {
223
182
  let finished = false;
224
183
  const child = spawn(cmd, args, {
225
184
  stdio: ['ignore', 'pipe', 'pipe'],
226
- // HOMEBREW_NO_AUTO_UPDATE=1 skips brew's implicit `brew update` before
227
- // each command — we already resolve the latest version via the
228
- // formulae.brew.sh API, so the refresh is redundant. NOTE: this does NOT
229
- // prevent brew's vendor-install-ruby step, which contends with concurrent
230
- // brew processes (Homebrew's launchd autoupdate, a manual brew run, etc.)
231
- // on the `vendor-install-ruby` lockf and surfaces as "Failed to upgrade
232
- // Homebrew Portable Ruby". Those transient collisions are handled by
233
- // `isBrewBusyError` below, which downgrades the failure to a soft skip.
234
185
  env: { ...process.env, npm_config_yes: 'true', HOMEBREW_NO_AUTO_UPDATE: '1' },
235
186
  });
236
187
  const timeoutMs = Math.max(500, opts.timeoutMs ?? AGENT_UPDATE_COMMAND_TIMEOUT_MS);
@@ -274,9 +225,6 @@ async function getNpmGlobalRoot() {
274
225
  return result.ok ? result.stdout.trim().split('\n')[0] || null : null;
275
226
  }
276
227
  async function getLatestPackageVersion(pkg) {
277
- // `--prefer-online` bypasses the local npm metadata cache so we always see
278
- // the registry's current `latest` tag. Without it, `npm view` can serve a
279
- // stale version for several minutes after a release.
280
228
  const result = await runCommand('npm', ['view', pkg, 'version', '--json', '--prefer-online'], { timeoutMs: AGENT_UPDATE_TIMEOUTS.npmView });
281
229
  if (!result.ok)
282
230
  return null;
@@ -322,28 +270,11 @@ async function updateViaNpm(pkg) {
322
270
  const result = await runCommand('npm', ['install', '-g', `${pkg}@latest`]);
323
271
  return { ok: result.ok, detail: result.ok ? result.stdout.trim() || null : result.error };
324
272
  }
325
- /**
326
- * Detects the transient brew contention surfaced when another brew process is
327
- * already running its `vendor-install ruby` step (Homebrew's launchd
328
- * autoupdate, a manual `brew upgrade`, etc.). We treat these as soft skips
329
- * rather than failures so the dashboard doesn't shout an error at the user for
330
- * what is really "try again in a minute".
331
- */
332
273
  function isBrewBusyError(text) {
333
274
  if (!text)
334
275
  return false;
335
276
  return /vendor-install ruby|already locked|Failed to upgrade Homebrew Portable Ruby|is already running/i.test(text);
336
277
  }
337
- // ---------------------------------------------------------------------------
338
- // Homebrew helpers
339
- // ---------------------------------------------------------------------------
340
- /** Get latest available version for a Homebrew cask.
341
- *
342
- * Queries Homebrew's public formulae API rather than `brew info`, because the
343
- * local cask metadata is only refreshed by `brew update` — without it, a
344
- * just-published cask version can stay invisible for hours/days. The HTTPS API
345
- * always returns the current cask manifest. Falls back to local `brew info`
346
- * if the network call fails. */
347
278
  async function getLatestBrewCaskVersion(cask) {
348
279
  const apiVersion = await fetchBrewCaskVersionFromApi(cask);
349
280
  if (apiVersion)
@@ -413,7 +344,6 @@ export function startAgentAutoUpdate(opts) {
413
344
  setUpdateState(id, { status: 'skipped', detail: strategy.reason, checkedAt: Date.now() });
414
345
  continue;
415
346
  }
416
- // Use brew version check for brew installs, npm for npm installs.
417
347
  const latestVersion = strategy.kind === 'brew'
418
348
  ? await getLatestBrewCaskVersion(strategy.cask)
419
349
  : await getLatestPackageVersion(pkg);
@@ -456,10 +386,6 @@ export function startAgentAutoUpdate(opts) {
456
386
  }
457
387
  })();
458
388
  }
459
- // ---------------------------------------------------------------------------
460
- // On-demand version check (called from dashboard)
461
- // ---------------------------------------------------------------------------
462
- /** Check latest version for a single agent. Uses brew or npm depending on install method. */
463
389
  export async function checkAgentLatestVersion(agent) {
464
390
  const id = String(agent.agent || '').trim();
465
391
  const pkg = getAgentPackage(id);
@@ -467,7 +393,6 @@ export async function checkAgentLatestVersion(agent) {
467
393
  return { ...emptyState(), status: 'skipped', detail: 'unsupported agent', checkedAt: Date.now() };
468
394
  const currentVersion = extractAgentSemver(agent.version);
469
395
  setUpdateState(id, { currentVersion, status: 'checking' });
470
- // Detect brew install and use brew version check.
471
396
  const binPath = String(agent.path || '').trim();
472
397
  const brewCask = binPath && isBrewInstalledBinary(binPath) ? getAgentBrewCask(id) : null;
473
398
  const latestVersion = brewCask
@@ -490,7 +415,6 @@ export async function checkAgentLatestVersion(agent) {
490
415
  setUpdateState(id, state);
491
416
  return state;
492
417
  }
493
- /** Manually trigger an update for a specific agent (auto-detects brew vs npm). */
494
418
  export async function manualAgentUpdate(agent, log) {
495
419
  const id = String(agent.agent || '').trim();
496
420
  const pkg = getAgentPackage(id);
@@ -1,22 +1,3 @@
1
- /**
2
- * await-resume.ts — "waiting for background work" session marker.
3
- *
4
- * <sessionRoot>/awaiting.json — persisted marker
5
- *
6
- * A turn runs as a one-shot `claude -p` process that exits at its `result`
7
- * event. When the agent launches truly detached work (a daemon outliving the
8
- * harness, e.g. an install that must survive a restart) and ends the turn
9
- * intending to report back, the process exits and the session reads as plainly
10
- * "completed" — there is no live process for the background task to wake. This
11
- * marker lets the agent declare that intent (via the `await_background` MCP
12
- * tool, which writes the file directly) so the dashboard can show a distinct
13
- * "waiting" state instead of "completed".
14
- *
15
- * The MCP tool (child process) writes the file; the parent only reads and
16
- * clears it — the same split used by goal.ts / tools/goal.ts. The marker is
17
- * cleared the next time the session runs (clearAwaitResume in stream.ts), so a
18
- * resumed turn naturally drops back out of the "waiting" state.
19
- */
20
1
  import fs from 'node:fs';
21
2
  import path from 'node:path';
22
3
  const AWAIT_FILE = 'awaiting.json';
@@ -45,6 +26,5 @@ export function clearAwaitResume(workdir, agent, sessionId) {
45
26
  fs.rmSync(sessionAwaitPath(workdir, agent, sessionId), { force: true });
46
27
  }
47
28
  catch {
48
- /* best-effort */
49
29
  }
50
30
  }
@@ -1,19 +1,3 @@
1
- /**
2
- * CLI auth + install runner.
3
- *
4
- * Two flows share a single streaming-child-session core:
5
- *
6
- * - oauth-web: spawn `loginArgv`, stream stdout/stderr to the UI, poll
7
- * `statusArgv` in the background, and settle when the CLI reports ready.
8
- * Used by CLIs that print a device code / one-time-code non-interactively
9
- * (gh, wrangler, supabase, …). CLIs whose sign-in needs a real TTY use
10
- * `manualLoginCommands` instead and never reach this runner.
11
- * - install: spawn the `npm install -g <pkg>` argv, stream output, re-detect
12
- * once the child exits.
13
- *
14
- * Token CLIs (aws, mocli) skip this entirely — credentials come in via a plain
15
- * POST and are applied synchronously by `applyCliToken`.
16
- */
17
1
  import { spawn } from 'node:child_process';
18
2
  import { randomUUID } from 'node:crypto';
19
3
  import { EventEmitter } from 'node:events';
@@ -24,9 +8,6 @@ const MAX_SESSION_AGE_MS = 15 * 60 * 1000;
24
8
  const POLL_INTERVAL_MS = 2_000;
25
9
  const POLL_TIMEOUT_MS = 10 * 60 * 1000;
26
10
  const BACKLOG_LINES = 200;
27
- // ---------------------------------------------------------------------------
28
- // Session lifecycle
29
- // ---------------------------------------------------------------------------
30
11
  function reapExpiredSessions() {
31
12
  const now = Date.now();
32
13
  for (const [id, s] of SESSIONS) {
@@ -49,7 +30,6 @@ function startStreamingSession(opts) {
49
30
  const { cli, argv, env, shell, pollUntilReady, computeOk } = opts;
50
31
  const sessionId = randomUUID();
51
32
  const events = new EventEmitter();
52
- // Unlimited listeners — SSE clients may resubscribe multiple times.
53
33
  events.setMaxListeners(0);
54
34
  const session = {
55
35
  sessionId,
@@ -95,7 +75,7 @@ function startStreamingSession(opts) {
95
75
  try {
96
76
  finalStatus = await detectCli(cli);
97
77
  }
98
- catch { /* best-effort */ }
78
+ catch { }
99
79
  if (finalStatus) {
100
80
  events.emit('event', { type: 'status', status: finalStatus });
101
81
  }
@@ -124,15 +104,12 @@ function startStreamingSession(opts) {
124
104
  void settle(child.exitCode);
125
105
  }
126
106
  }
127
- catch { /* ignore polling errors */ }
107
+ catch { }
128
108
  }, POLL_INTERVAL_MS);
129
109
  }
130
110
  child.on('close', (code) => { void settle(code); });
131
111
  return { ok: true, sessionId };
132
112
  }
133
- // ---------------------------------------------------------------------------
134
- // oauth-web login
135
- // ---------------------------------------------------------------------------
136
113
  export async function startCliAuthSession(cliId) {
137
114
  const cli = getRecommendedCli(cliId);
138
115
  if (!cli)
@@ -140,8 +117,6 @@ export async function startCliAuthSession(cliId) {
140
117
  if (cli.auth.type !== 'oauth-web' || !cli.auth.loginArgv) {
141
118
  return { ok: false, error: `cli ${cliId} does not support oauth-web sign-in` };
142
119
  }
143
- // CLIs configured for manual login should never spawn here — guard so a
144
- // misbehaving client can't end-run the documented terminal flow.
145
120
  if (cli.auth.manualLoginCommands && cli.auth.manualLoginCommands.length > 0) {
146
121
  return { ok: false, error: `cli ${cliId} uses manual sign-in (run the commands in your own terminal)` };
147
122
  }
@@ -155,12 +130,6 @@ export async function startCliAuthSession(cliId) {
155
130
  }
156
131
  const NPM_GLOBAL_INSTALL_RE = /^npm\s+(?:install|i)\s+(?:-g|--global)\s+(\S.*)$/;
157
132
  const SHELL_METACHAR_RE = /[|;&`$()<>]/;
158
- /**
159
- * Inspect a CLI's install spec for the current platform and return a single
160
- * argv that's safe to spawn without user-side approvals. Returns null when no
161
- * such command exists (brew/apt/dnf/winget/scoop/curl-pipe-sh entries are all
162
- * rejected on purpose — those require sudo or interactive confirmation).
163
- */
164
133
  export function resolveAutoInstallSpec(cli, platform) {
165
134
  const commands = cli.install[platform] || [];
166
135
  for (const c of commands) {
@@ -190,24 +159,14 @@ export async function startCliInstallSession(cliId) {
190
159
  cli,
191
160
  argv: spec.argv,
192
161
  env: { ...process.env, NO_COLOR: '1', TERM: 'dumb', CI: '1' },
193
- // npm on Windows is npm.cmd — needs shell resolution. spawn() args are
194
- // still passed argv-style; we don't concat into a shell string.
195
162
  shell: process.platform === 'win32',
196
163
  pollUntilReady: false,
197
164
  computeOk: (exit, status) => exit === 0 && (status ? status.state !== 'not_installed' : true),
198
165
  });
199
166
  }
200
- // ---------------------------------------------------------------------------
201
- // Token auth — apply-credentials flow
202
- // ---------------------------------------------------------------------------
203
167
  import fs from 'node:fs';
204
168
  import path from 'node:path';
205
169
  import os from 'node:os';
206
- /**
207
- * Apply a set of credentials for a `token`-auth CLI and verify. Each CLI gets a
208
- * tailored write path because there's no universal convention — we only do this
209
- * for CLIs we explicitly support.
210
- */
211
170
  export async function applyCliToken(cliId, values) {
212
171
  const cli = getRecommendedCli(cliId);
213
172
  if (!cli)
@@ -232,8 +191,6 @@ export async function applyCliToken(cliId, values) {
232
191
  }
233
192
  }
234
193
  else if (cli.id === 'mocli') {
235
- // mocli stores its key via `mocli auth init --apik <KEY>` — let the CLI
236
- // own its storage path so future schema changes upstream don't break us.
237
194
  const key = (values.MOWEN_API_KEY || '').trim();
238
195
  if (!key)
239
196
  return { ok: false, error: 'Mowen API Key is required' };
@@ -262,16 +219,12 @@ export async function applyCliToken(cliId, values) {
262
219
  return { ok: false, error: e?.message || 'failed to apply token' };
263
220
  }
264
221
  }
265
- /**
266
- * Merge a `[section]` block into an INI-style file, replacing any existing
267
- * block with the same name. Idempotent; preserves other sections and comments.
268
- */
269
222
  function mergeIniSection(filePath, section, block) {
270
223
  let current = '';
271
224
  try {
272
225
  current = fs.readFileSync(filePath, 'utf-8');
273
226
  }
274
- catch { /* new file */ }
227
+ catch { }
275
228
  const header = `[${section}]`;
276
229
  const lines = current.split(/\r?\n/);
277
230
  const out = [];
@@ -287,7 +240,6 @@ function mergeIniSection(filePath, section, block) {
287
240
  inTarget = false;
288
241
  out.push(line);
289
242
  }
290
- // else: drop old line
291
243
  }
292
244
  else {
293
245
  out.push(line);
@@ -1,6 +1,3 @@
1
- /**
2
- * CLI catalog — merges the recommended registry with live detection status.
3
- */
4
1
  import { getRecommendedClis } from './registry.js';
5
2
  import { detectCli, getCachedCliStatus, currentPlatform } from './detector.js';
6
3
  import { resolveAutoInstallSpec } from './auth.js';
@@ -1,18 +1,9 @@
1
- /**
2
- * CLI detector — checks whether a CLI binary is on PATH, what version it is,
3
- * and whether the user is already signed in.
4
- *
5
- * Results are cached with a short TTL so catalog rendering stays snappy.
6
- */
7
1
  import { execFile } from 'node:child_process';
8
2
  import path from 'node:path';
9
3
  import os from 'node:os';
10
4
  import fs from 'node:fs';
11
5
  const DETECT_TTL_MS = 30_000;
12
6
  const cache = new Map();
13
- // ---------------------------------------------------------------------------
14
- // Helpers
15
- // ---------------------------------------------------------------------------
16
7
  function runArgv(argv, timeoutMs) {
17
8
  return new Promise((resolve) => {
18
9
  const [cmd, ...rest] = argv;
@@ -48,7 +39,7 @@ function which(binary) {
48
39
  if (stat.isFile())
49
40
  return candidate;
50
41
  }
51
- catch { /* next */ }
42
+ catch { }
52
43
  }
53
44
  }
54
45
  return null;
@@ -58,7 +49,6 @@ function extractVersion(stdout, stderr) {
58
49
  if (!text)
59
50
  return undefined;
60
51
  const firstLine = text.split(/\r?\n/, 1)[0].trim();
61
- // Common patterns: "gh version 2.56.0 (...)" / "1.2.3" / "aws-cli/2.x ..."
62
52
  const m = firstLine.match(/\b(\d+\.\d+(?:\.\d+)?(?:[-.+][0-9A-Za-z.]+)?)\b/);
63
53
  return m ? m[1] : firstLine.slice(0, 80);
64
54
  }
@@ -69,9 +59,6 @@ function trimDetail(s) {
69
59
  const first = text.split(/\r?\n/, 1)[0].trim();
70
60
  return first.slice(0, 200);
71
61
  }
72
- // ---------------------------------------------------------------------------
73
- // Public
74
- // ---------------------------------------------------------------------------
75
62
  export function getCachedCliStatus(id) {
76
63
  const cached = cache.get(id);
77
64
  if (!cached)
@@ -95,7 +82,6 @@ export async function detectCli(cli) {
95
82
  cache.set(cli.id, status);
96
83
  return status;
97
84
  }
98
- // Installed — read version, best-effort.
99
85
  let version;
100
86
  if (cli.versionArgv && cli.versionArgv.length) {
101
87
  const v = await runArgv(cli.versionArgv, 5_000);
@@ -109,8 +95,6 @@ export async function detectCli(cli) {
109
95
  return status;
110
96
  }
111
97
  const result = await runArgv(cli.auth.statusArgv, 6_000);
112
- // Some CLIs (gcloud) report success via exit 0 but emit empty output when no
113
- // account is configured — fall back to a content check when declared.
114
98
  const patternOk = !cli.auth.statusReadyPattern
115
99
  || new RegExp(cli.auth.statusReadyPattern).test(result.stdout);
116
100
  const state = (result.ok && patternOk) ? 'ready' : 'installed_not_auth';
@@ -122,7 +106,6 @@ export async function detectCli(cli) {
122
106
  cache.set(cli.id, status);
123
107
  return status;
124
108
  }
125
- /** Best-effort platform key for picking install commands. */
126
109
  export function currentPlatform() {
127
110
  if (process.platform === 'darwin')
128
111
  return 'darwin';
@@ -130,7 +113,6 @@ export function currentPlatform() {
130
113
  return 'win';
131
114
  return 'linux';
132
115
  }
133
- /** Where AWS credentials go for the `token` auth flow. */
134
116
  export function awsCredentialsPath() {
135
117
  return path.join(os.homedir(), '.aws', 'credentials');
136
118
  }
@@ -1,6 +1,3 @@
1
- /**
2
- * Barrel entry for the CLI extension module.
3
- */
4
1
  export { getRecommendedClis, getRecommendedCli, } from './registry.js';
5
2
  export { detectCli, getCachedCliStatus, invalidateCliStatus, currentPlatform, } from './detector.js';
6
3
  export { getCliCatalog, refreshCliStatus, } from './catalog.js';
@@ -1,30 +1,5 @@
1
- /**
2
- * CLI tool registry — curated command-line tools agents commonly need.
3
- *
4
- * Each entry declares how to install the binary on each OS, how to detect the
5
- * install / auth state, and (optionally) how to drive the sign-in flow.
6
- *
7
- * Two auth types are supported today:
8
- * - oauth-web: the CLI has a first-party `<cli> auth login --web` flavor that
9
- * prints a device code and opens the browser. We spawn it, stream output,
10
- * and poll the status command to know when the user finished in the browser.
11
- * - token: the user pastes an API key; we set it via the CLI's config command
12
- * (or via env var for CLIs that only read from env).
13
- *
14
- * Keep this list opinionated and small — better to nail the common case than to
15
- * ship a wall of half-working entries.
16
- */
17
- // ---------------------------------------------------------------------------
18
- // Recommended CLI tools — data lives in src/catalog/
19
- //
20
- // This module owns the *types* and helper functions. Edit
21
- // `src/catalog/cli-tools.ts` to add or hide a CLI tool entry.
22
- // ---------------------------------------------------------------------------
23
1
  import { CLI_TOOLS } from '../../catalog/index.js';
24
2
  const RECOMMENDED_CLIS = CLI_TOOLS;
25
- // ---------------------------------------------------------------------------
26
- // Public API
27
- // ---------------------------------------------------------------------------
28
3
  export function getRecommendedClis() {
29
4
  return RECOMMENDED_CLIS;
30
5
  }
@@ -1,12 +1,3 @@
1
- /**
2
- * agent-driver.ts — Agent driver interface and registry.
3
- *
4
- * Each CLI agent (claude, codex, gemini, ...) implements AgentDriver.
5
- * Register with `registerDriver()`, look up with `getDriver()`.
6
- */
7
- // ---------------------------------------------------------------------------
8
- // Registry
9
- // ---------------------------------------------------------------------------
10
1
  const drivers = new Map();
11
2
  export function registerDriver(d) { drivers.set(d.id, d); }
12
3
  export function getDriver(id) {
@@ -29,11 +20,6 @@ export function getDriverCapabilities(id) {
29
20
  return DEFAULT_CAPABILITIES;
30
21
  return { ...DEFAULT_CAPABILITIES, ...d.capabilities };
31
22
  }
32
- /**
33
- * Provider kinds this driver can route through. Empty array means the driver
34
- * declared no compatibility (so no Profiles will be listed for it). Callers
35
- * should treat this as the filter for cross-provider model offerings.
36
- */
37
23
  export function getAcceptedProviderKinds(id) {
38
24
  return drivers.get(id)?.acceptedProviderKinds ?? [];
39
25
  }