@wrongstack/cli 0.272.0 → 0.272.2

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
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { color, writeErr, loadPlugins, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, withFileLock, resolveHqDataDir, ensureHqFirstRunAuthFile, DEFAULT_HQ_REDACTION_POLICY, watchHqAuthFile, parseHqFrame, HQ_PROTOCOL_VERSION, parseHqEventPayload, scrubAndTruncateHqPreview, DefaultSecretScrubber, projectHash, wstackGlobalRoot, TOKENS, ToolRegistry, createHqPublisherFromEnv, GlobalMailbox, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, normalizeTokenSavingTier, SlashCommandRegistry, attachDepWatcherBridge, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, createDelegateTool, FLEET_ROSTER, createMcpControlTool, startTechStackConsumer, startPackageOutdatedWatcher, recordFileAction, createAutonomyBrain, DefaultPluginAPI, SpecVersioning, buildTranscriptFromEvents, DEFAULT_CONTEXT_WINDOW_MODE_ID, resolveProjectDir, recentTextTurns, gatedEnhancerReasoning, enhanceUserPrompt, projectSlug, DefaultSystemPromptBuilder, mutateTasks, loadTasks, resolveContextWindowPolicy, repairToolUseAdjacency, mutatePlan, setPlanItemStatus, getPlanTemplate, loadPlan, emptyPlan, addPlanItem, savePlan, resolveProviderModelList, DefaultLogger, DefaultModelsRegistry, isStdinTTY, atomicWrite, DefaultPathResolver, EventBus, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, mergeCustomModelDefs, makeAutonomyPromptContributor, createContextManagerTool, makeMailboxTool, makeMailSendTool, makeMailInboxTool, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, DEFAULT_SESSION_PRUNE_DAYS, RecoveryLock, DefaultAttachmentStore, Context, QueueStore, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, createDefaultPipelines, applyModelRuntime, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, WIDE_SUBAGENT_CAPABILITIES, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, writeOut, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, CHIMERA_REVIEW_PROMPT, setQueuedMessagesSnapshot, DefaultSessionRewinder, bootConfig as bootConfig$1, setOutputLineGuard, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionStore as DefaultSessionStore$1, ProviderRegistry, StreamHangError, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, getContextWindowMode, AGENT_CATALOG, dispatchAgent, noOpVault, formatTodosList, formatTaskList, formatTaskProgress, formatPlan, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, readHqRuntimeFileSync, resolveHqConfig, MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, onResize, InputBuilder, DefaultSecretVault, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, HQ_AUTH_FILE_VERSION, FsError, ERROR_CODES, truncate, estimateMessageTokens, AGENTS_BY_PHASE, validateAgainstSchema, ConfigError, resolveMailboxIdentity, AutonomousCoordinator, mutateHqAuthFile, mintHqToken, readHqAuthFile, DefaultTokenCounter, isSecretField as isSecretField$1 } from '@wrongstack/core';
2
+ import { color, writeErr, loadPlugins, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, withFileLock, resolveHqDataDir, ensureHqFirstRunAuthFile, DEFAULT_HQ_REDACTION_POLICY, watchHqAuthFile, parseHqFrame, HQ_PROTOCOL_VERSION, parseHqEventPayload, scrubAndTruncateHqPreview, DefaultSecretScrubber, projectHash, wstackGlobalRoot, TOKENS, ToolRegistry, GlobalMailbox, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, normalizeTokenSavingTier, SlashCommandRegistry, attachDepWatcherBridge, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, createDelegateTool, FLEET_ROSTER, createMcpControlTool, startTechStackConsumer, startPackageOutdatedWatcher, recordFileAction, createAutonomyBrain, DefaultPluginAPI, SpecVersioning, buildTranscriptFromEvents, DEFAULT_CONTEXT_WINDOW_MODE_ID, resolveProjectDir, recentTextTurns, gatedEnhancerReasoning, enhanceUserPrompt, projectSlug, DefaultSystemPromptBuilder, mutateTasks, loadTasks, resolveContextWindowPolicy, repairToolUseAdjacency, mutatePlan, setPlanItemStatus, getPlanTemplate, loadPlan, emptyPlan, addPlanItem, savePlan, resolveProviderModelList, DefaultLogger, DefaultModelsRegistry, isStdinTTY, atomicWrite, DefaultPathResolver, EventBus, runProviderWithRetry, ReplayLogStore, ReplayProviderRunner, mergeCustomModelDefs, makeAutonomyPromptContributor, createContextManagerTool, makeMailboxTool, makeMailSendTool, makeMailInboxTool, InMemoryMetricsSink, wireMetricsToEvents, DefaultHealthRegistry, startMetricsServer, createHqPublisherFromEnv, DEFAULT_SESSION_PRUNE_DAYS, RecoveryLock, DefaultAttachmentStore, Context, QueueStore, loadTodosCheckpoint, attachTodosCheckpoint, loadDirectorState, createDefaultPipelines, applyModelRuntime, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, AdaptiveConcurrencyController, resolveModelMatrix, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, WIDE_SUBAGENT_CAPABILITIES, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, writeOut, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, CHIMERA_REVIEW_PROMPT, setQueuedMessagesSnapshot, DefaultSessionRewinder, bootConfig as bootConfig$1, setOutputLineGuard, setRawMode, DefaultSessionReader, resolveWstackPaths, ToolAuditLog, DefaultSessionStore as DefaultSessionStore$1, ProviderRegistry, StreamHangError, ProviderError, makeAgentSubagentRunner, NULL_FLEET_BUS, buildChildEnv, formatContextWindowModeList, getContextWindowMode, AGENT_CATALOG, dispatchAgent, noOpVault, formatTodosList, formatTaskList, formatTaskProgress, formatPlan, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, readHqRuntimeFileSync, resolveHqConfig, MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, onResize, InputBuilder, DefaultSecretVault, decryptConfigSecrets as decryptConfigSecrets$1, encryptConfigSecrets as encryptConfigSecrets$1, HQ_AUTH_FILE_VERSION, FsError, ERROR_CODES, truncate, estimateMessageTokens, AGENTS_BY_PHASE, validateAgainstSchema, ConfigError, resolveMailboxIdentity, AutonomousCoordinator, mutateHqAuthFile, mintHqToken, readHqAuthFile, DefaultTokenCounter, isSecretField as isSecretField$1, startSessionTelemetryBridge } from '@wrongstack/core';
3
3
  import * as fs4 from 'fs/promises';
4
4
  import { decryptConfigSecrets, encryptConfigSecrets, DefaultSecretVault as DefaultSecretVault$1, isSecretField } from '@wrongstack/core/security';
5
5
  import * as path4 from 'path';
@@ -19,7 +19,7 @@ import { getProcessRegistry, builtinToolsPack, rememberTool, forgetTool, searchM
19
19
  import { DefaultSessionStore } from '@wrongstack/core/storage';
20
20
  import { probeLocalLlm } from '@wrongstack/runtime/probe';
21
21
  import * as fs3 from 'fs';
22
- import { watch, writeFileSync, existsSync, readFileSync } from 'fs';
22
+ import { watch, writeFileSync, existsSync, realpathSync, readFileSync } from 'fs';
23
23
  import { SkillInstaller } from '@wrongstack/core/skills';
24
24
  import { spawn, execFile, execFileSync } from 'child_process';
25
25
  import { MCPRegistry, MCPServer, serveHttp, serveStdio } from '@wrongstack/mcp';
@@ -3040,6 +3040,8 @@ var init_hq_dashboard_html = __esm({
3040
3040
  .acard-stream { margin-top: 8px; font-size: 11px; color: var(--muted); background: var(--inset); border: 1px solid var(--border); border-radius: 8px; padding: 6px 8px; font-family: ui-monospace, monospace; max-height: 58px; overflow: hidden; white-space: pre-wrap; word-break: break-word; }
3041
3041
  .acard-meta { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 9px; font-size: 10.5px; color: var(--dim); font-variant-numeric: tabular-nums; }
3042
3042
  .acard-meta .mut { color: var(--dim); }
3043
+ .acard-meta .warm { color: var(--amber); }
3044
+ .acard-meta .hot { color: var(--red); }
3043
3045
  .ctxbar { margin-top: 9px; height: 4px; border-radius: 999px; background: var(--inset); overflow: hidden; }
3044
3046
  .ctxbar-fill { height: 100%; background: var(--accent); border-radius: 999px; transition: width 0.3s ease; }
3045
3047
  .ctxbar-fill.warm { background: var(--amber); }
@@ -3082,7 +3084,7 @@ var init_hq_dashboard_html = __esm({
3082
3084
  .fnode.terminal.k-repl { border-left-color: var(--amber); }
3083
3085
  .fnode.terminal.k-webui { border-left-color: var(--accent); }
3084
3086
  .fnode.terminal.k-cli { border-left-color: var(--cyan); }
3085
- .fnode.agent { width: 200px; }
3087
+ .fnode.agent { width: 220px; }
3086
3088
  .fnode.agent.s-running, .fnode.agent.s-streaming { border-color: var(--green); box-shadow: 0 0 0 1px rgba(63,185,80,0.25), 0 10px 22px rgba(0,0,0,0.4); animation: pulse 1.8s ease-in-out infinite; }
3087
3089
  .fnode.agent.s-waiting_user { border-color: var(--amber); }
3088
3090
  .fnode.agent.s-error { border-color: var(--red); }
@@ -3164,6 +3166,7 @@ function withTok(p){ var u = new URL(p, location.href); var t = tokenStr(); if (
3164
3166
  function shortId(s){ if(!s) return '\u2014'; s=String(s); return s.length>16 ? s.slice(0,8)+'\u2026'+s.slice(-5) : s; }
3165
3167
  function fmtTime(iso){ if(!iso) return ''; var d=new Date(iso); return isNaN(d.getTime())?'':d.toLocaleTimeString(); }
3166
3168
  function fmtAgo(iso){ if(!iso) return ''; var d=new Date(iso).getTime(); if(isNaN(d)) return ''; var s=Math.max(0,Math.floor((Date.now()-d)/1000)); if(s<5) return 'now'; if(s<60) return s+'s ago'; var m=Math.floor(s/60); if(m<60) return m+'m ago'; var hh=Math.floor(m/60); if(hh<24) return hh+'h ago'; return Math.floor(hh/24)+'d ago'; }
3169
+ function fmtElapsed(iso){ if(!iso) return ''; var d=new Date(iso).getTime(); if(isNaN(d)) return ''; var s=Math.max(0,Math.floor((Date.now()-d)/1000)); if(s<60) return s+'s'; var m=Math.floor(s/60); if(m<60) return m+'m '+(s%60)+'s'; var h=Math.floor(m/60); if(h<24) return h+'h '+(m%60)+'m'; return Math.floor(h/24)+'d '+(h%24)+'h'; }
3167
3170
  function fmtNum(n){ n=Number(n)||0; if(n>=1e6) return (n/1e6).toFixed(1)+'M'; if(n>=1e3) return (n/1e3).toFixed(1)+'k'; return String(n); }
3168
3171
  function esc(s){ if(s==null) return ''; return String(s); }
3169
3172
 
@@ -3298,19 +3301,60 @@ function machineKey(hostname, machineId){
3298
3301
  function buildTree(snap){
3299
3302
  var sessions = (snap && snap.liveSessions) || [];
3300
3303
  var machines = (snap && snap.machines) || [];
3304
+ var clients = (snap && snap.clients) || [];
3305
+ var projects = (snap && snap.projects) || [];
3301
3306
  var mMap = {};
3307
+ var pMap = {};
3308
+ projects.forEach(function(p){ if(p && p.projectId) pMap[p.projectId] = p; });
3302
3309
  function ensure(hostname, machineId){
3303
3310
  var key = machineKey(hostname, machineId);
3304
3311
  if(!mMap[key]) mMap[key] = { key: key, machineId: machineId || key, hostname: (hostname && String(hostname).trim()) || machineId || 'machine', projects: {}, sessionCount: 0, agentCount: 0 };
3305
3312
  return mMap[key];
3306
3313
  }
3314
+ function ensureProject(mm, pid, seed){
3315
+ if(!mm.projects[pid]) mm.projects[pid] = {
3316
+ projectId: pid,
3317
+ projectName: (seed && (seed.projectName || seed.projectId)) || pid,
3318
+ gitBranch: seed && seed.gitBranch,
3319
+ terminals: []
3320
+ };
3321
+ return mm.projects[pid];
3322
+ }
3307
3323
  sessions.forEach(function(s){
3308
3324
  var mm = ensure(s.hostname, s.machineId);
3309
3325
  mm.sessionCount++;
3310
3326
  mm.agentCount += (s.agents ? s.agents.length : 0);
3311
3327
  var pid = s.projectId || 'unknown';
3312
- if(!mm.projects[pid]) mm.projects[pid] = { projectId: pid, projectName: s.projectName || pid, gitBranch: s.gitBranch, terminals: [] };
3313
- mm.projects[pid].terminals.push(s);
3328
+ ensureProject(mm, pid, s).terminals.push(s);
3329
+ });
3330
+ clients.forEach(function(c){
3331
+ var alreadyRepresented = sessions.some(function(s){
3332
+ return s.projectId === c.projectId &&
3333
+ String(s.clientKind||'') === String(c.kind||'') &&
3334
+ (!c.pid || !s.pid || c.pid === s.pid);
3335
+ });
3336
+ if(alreadyRepresented) return;
3337
+ var project = pMap[c.projectId] || {};
3338
+ var mm = ensure(c.hostname, c.machineId);
3339
+ mm.sessionCount++;
3340
+ var terminal = {
3341
+ sessionId: 'client:' + (c.clientId || c.projectId || 'unknown'),
3342
+ clientKind: c.kind || 'cli',
3343
+ machineId: c.machineId,
3344
+ hostname: c.hostname,
3345
+ projectId: c.projectId || 'unknown',
3346
+ projectName: project.projectName || c.projectId || 'unknown',
3347
+ projectRoot: project.projectRootDisplay || '',
3348
+ gitBranch: project.gitBranch,
3349
+ status: c.connected ? 'active' : 'stale',
3350
+ startedAt: c.connectedAt,
3351
+ lastActivityAt: c.lastSeenAt,
3352
+ pid: c.pid,
3353
+ agentCount: 0,
3354
+ agents: [],
3355
+ synthetic: true
3356
+ };
3357
+ ensureProject(mm, terminal.projectId, terminal).terminals.push(terminal);
3314
3358
  });
3315
3359
  // Include machines that have a connected client but no live session yet.
3316
3360
  machines.forEach(function(m){ ensure(m.hostname, m.machineId); });
@@ -3379,21 +3423,26 @@ function projNode(id, p, machine){
3379
3423
  });
3380
3424
  }
3381
3425
  function termNode(id, t, sel){
3426
+ var synthetic = !!t.synthetic;
3382
3427
  return fleetNode(id, 'terminal', {
3383
3428
  termKind: t.clientKind, status: t.status, icon: kindIcon(t.clientKind),
3384
3429
  label: (t.clientKind||'cli').toUpperCase() + ' \xB7 ' + shortId(t.sessionId),
3385
- sub: t.status + (t.pid ? (' \xB7 pid '+t.pid) : ''),
3386
- chips: [ (t.agentCount||(t.agents?t.agents.length:0))+' agents' ],
3387
- clickable: true, selected: !!(sel && sel.sessionId === t.sessionId && !sel.agentId),
3388
- onClick: function(){ selectSession(t.sessionId); }
3430
+ sub: t.status + (t.pid ? (' \xB7 pid '+t.pid) : '') + (synthetic ? ' \xB7 waiting for session telemetry' : ''),
3431
+ chips: synthetic ? ['connected', '0 agents'] : [ (t.agentCount||(t.agents?t.agents.length:0))+' agents' ],
3432
+ clickable: !synthetic, selected: !synthetic && !!(sel && sel.sessionId === t.sessionId && !sel.agentId),
3433
+ onClick: synthetic ? undefined : function(){ selectSession(t.sessionId); }
3389
3434
  });
3390
3435
  }
3391
3436
  function agentNode(id, a, t, sel){
3392
3437
  var chips = [];
3438
+ var ctx = typeof a.ctxPct==='number' ? Math.max(0, Math.min(100, a.ctxPct)) : null;
3439
+ var active = a.status==='running'||a.status==='streaming'||a.status==='waiting_user';
3393
3440
  if(a.currentTool) chips.push('\u2699 '+a.currentTool);
3441
+ if(a.model) chips.push(a.model);
3442
+ if(ctx!=null) chips.push('ctx '+ctx+'%');
3443
+ if(a.startedAt) chips.push((active?'run ':'last ')+fmtElapsed(a.startedAt));
3394
3444
  chips.push((a.iterations||0)+' it');
3395
3445
  if(typeof a.costUsd === 'number' && a.costUsd > 0) chips.push('$'+a.costUsd.toFixed(2));
3396
- if(a.model) chips.push(a.model);
3397
3446
  return fleetNode(id, 'agent', {
3398
3447
  status: a.status, label: a.name || a.id,
3399
3448
  sub: a.status + (a.partialText ? (' \xB7 '+String(a.partialText).slice(0,44)) : ''),
@@ -3406,7 +3455,7 @@ function kindIcon(k){ return k==='tui'?'\u{1F5B3}':k==='webui'?'\u{1F310}':k==='
3406
3455
  function miniColor(n){ var k=n.data&&n.data.kind; return k==='machine'?'#a371f7':k==='project'?'#58a6ff':k==='agent'?'#3fb950':'#39d0d8'; }
3407
3456
 
3408
3457
  // Node footprints (width \xD7 height) for dagre sizing.
3409
- var NODE_SIZE = { machine: [220, 78], project: [220, 78], terminal: [220, 70], agent: [210, 62] };
3458
+ var NODE_SIZE = { machine: [220, 78], project: [220, 78], terminal: [220, 70], agent: [230, 92] };
3410
3459
  // Auto-layout the logical nodes into a clean tree using dagre.
3411
3460
  function layoutTree(nodes, edges, dir, dagre){
3412
3461
  if(!dagre || !nodes.length) return nodes;
@@ -3702,13 +3751,16 @@ async function boot(){
3702
3751
  var a = p.a, s = p.s, sel = Store.selected;
3703
3752
  var seld = sel && sel.sessionId===s.sessionId && sel.agentId===a.id;
3704
3753
  var meta = [];
3754
+ var active = a.status==='running'||a.status==='streaming'||a.status==='waiting_user';
3755
+ var ctx = typeof a.ctxPct==='number' ? Math.max(0, Math.min(100, a.ctxPct)) : null;
3756
+ if(a.model) meta.push(h('span', { key:'md', className:'mut' }, 'model '+a.model));
3757
+ if(ctx!=null) meta.push(h('span', { key:'cx', className: ctx>=85?'hot':ctx>=60?'warm':'mut' }, 'ctx '+ctx+'%'));
3758
+ if(a.startedAt) meta.push(h('span', { key:'rt', className:'mut' }, (active?'run ':'last run ')+fmtElapsed(a.startedAt)));
3705
3759
  meta.push(h('span', { key:'it' }, (a.iterations||0)+' it'));
3706
3760
  if(a.toolCalls!=null) meta.push(h('span', { key:'tc' }, (a.toolCalls||0)+' tools'));
3707
3761
  if(a.tokensIn||a.tokensOut) meta.push(h('span', { key:'tk' }, fmtNum((a.tokensIn||0)+(a.tokensOut||0))+' tok'));
3708
3762
  if(typeof a.costUsd==='number' && a.costUsd>0) meta.push(h('span', { key:'co' }, '$'+a.costUsd.toFixed(3)));
3709
- if(a.model) meta.push(h('span', { key:'md', className:'mut' }, a.model));
3710
3763
  if(a.lastActivityAt) meta.push(h('span', { key:'ag', className:'mut' }, fmtAgo(a.lastActivityAt)));
3711
- var ctx = typeof a.ctxPct==='number' ? Math.max(0, Math.min(100, a.ctxPct)) : null;
3712
3764
  return h('div', { className: 'acard s-'+(a.status||'idle')+(seld?' selected':''), onClick: function(){ selectSession(s.sessionId, a.id); } },
3713
3765
  h('div', { className: 'acard-top' },
3714
3766
  h('span', { className: 'dot '+(a.status||'idle') }),
@@ -3832,6 +3884,10 @@ async function boot(){
3832
3884
  var streaming = ag && (ag.status==='streaming' || ag.status==='running');
3833
3885
  var liveText = streaming && ag.partialText ? String(ag.partialText) : '';
3834
3886
  var liveTool = streaming && ag.currentTool ? ag.currentTool : '';
3887
+ var agBits = [];
3888
+ if(ag && ag.model) agBits.push('model '+ag.model);
3889
+ if(ag && typeof ag.ctxPct==='number') agBits.push('ctx '+Math.max(0, Math.min(100, ag.ctxPct))+'%');
3890
+ if(ag && ag.startedAt) agBits.push((streaming?'run ':'last run ')+fmtElapsed(ag.startedAt));
3835
3891
 
3836
3892
  // Keep pinned to the bottom while new content streams in, unless the user
3837
3893
  // has scrolled up to read history.
@@ -3840,7 +3896,8 @@ async function boot(){
3840
3896
  }, [entries.length, liveText, liveTool, sel && sel.sessionId, sel && sel.agentId]);
3841
3897
  function onScroll(){ var el = bodyRef.current; if(!el) return; stickRef.current = (el.scrollHeight - el.scrollTop - el.clientHeight) < 40; }
3842
3898
 
3843
- var metaText = isSub ? (entries.length + ' messages' + (streaming?' \xB7 live':'')) : ((tc && tc.total!=null ? (tc.total+' turns') : '') + (tc && tc.source ? (' \xB7 '+tc.source) : ''));
3899
+ var baseMeta = isSub ? (entries.length + ' messages' + (streaming?' \xB7 live':'')) : ((tc && tc.total!=null ? (tc.total+' turns') : '') + (tc && tc.source ? (' \xB7 '+tc.source) : ''));
3900
+ var metaText = (agBits.length ? (agBits.join(' \xB7 ') + (baseMeta ? ' \xB7 ' : '')) : '') + baseMeta;
3844
3901
  var bodyEls = [];
3845
3902
  if(!isSub && tc && tc.loading && !entries.length && !liveText){ bodyEls.push(h('div', { key:'l', className: 'loading' }, 'Loading full chat history\u2026')); }
3846
3903
  else if(!entries.length && !liveText){ bodyEls.push(h('div', { key:'e', className: 'side-empty' }, isSub ? ('No messages from ' + (ag?ag.name:'this subagent') + ' yet \u2014 its conversation streams here live as it works.') : ((tc&&tc.error)?'Could not load history.':'No transcript yet for this terminal.'))); }
@@ -3937,9 +3994,15 @@ function renderFallback(){
3937
3994
  html += '<div style="margin:6px 0 4px;color:var(--accent)">\u{1F4C1} '+escAttr(p.projectName)+(p.gitBranch?(' \u2387 '+escAttr(p.gitBranch)):'')+'</div>';
3938
3995
  p.terminals.forEach(function(term){
3939
3996
  html += '<div style="margin:2px 0 2px 14px">';
3940
- html += '<a href="#" data-sid="'+escAttr(term.sessionId)+'" style="color:var(--cyan);text-decoration:none">\u25B7 '+escAttr((term.clientKind||'cli').toUpperCase())+' \xB7 '+escAttr(shortId(term.sessionId))+'</a> <span class="pill">'+escAttr(term.status)+'</span>';
3997
+ if(term.synthetic) html += '<span style="color:var(--cyan)">\u25B7 '+escAttr((term.clientKind||'cli').toUpperCase())+' \xB7 '+escAttr(shortId(term.sessionId))+'</span> <span class="pill">'+escAttr(term.status)+'</span> <span class="pill">waiting for session telemetry</span>';
3998
+ else html += '<a href="#" data-sid="'+escAttr(term.sessionId)+'" style="color:var(--cyan);text-decoration:none">\u25B7 '+escAttr((term.clientKind||'cli').toUpperCase())+' \xB7 '+escAttr(shortId(term.sessionId))+'</a> <span class="pill">'+escAttr(term.status)+'</span>';
3941
3999
  (term.agents||[]).forEach(function(a){
3942
- html += '<div style="margin-left:22px;color:var(--muted)"><a href="#" data-sid="'+escAttr(term.sessionId)+'" data-aid="'+escAttr(a.id)+'" style="color:var(--text);text-decoration:none"><span class="dot '+escAttr(a.status||'idle')+'"></span> '+escAttr(a.name||a.id)+'</a> <span class="pill">'+escAttr(a.status)+'</span>'+(a.currentTool?(' <span class="pill">\u2699 '+escAttr(a.currentTool)+'</span>'):'')+'</div>';
4000
+ var active = a.status==='running'||a.status==='streaming'||a.status==='waiting_user';
4001
+ var extra = '';
4002
+ if(a.model) extra += ' <span class="pill">model '+escAttr(a.model)+'</span>';
4003
+ if(typeof a.ctxPct==='number') extra += ' <span class="pill">ctx '+escAttr(Math.max(0, Math.min(100, a.ctxPct)))+'%</span>';
4004
+ if(a.startedAt) extra += ' <span class="pill">'+escAttr(active?'run ':'last ')+escAttr(fmtElapsed(a.startedAt))+'</span>';
4005
+ html += '<div style="margin-left:22px;color:var(--muted)"><a href="#" data-sid="'+escAttr(term.sessionId)+'" data-aid="'+escAttr(a.id)+'" style="color:var(--text);text-decoration:none"><span class="dot '+escAttr(a.status||'idle')+'"></span> '+escAttr(a.name||a.id)+'</a> <span class="pill">'+escAttr(a.status)+'</span>'+(a.currentTool?(' <span class="pill">\u2699 '+escAttr(a.currentTool)+'</span>'):'')+extra+'</div>';
3943
4006
  });
3944
4007
  html += '</div>';
3945
4008
  });
@@ -5058,6 +5121,70 @@ var init_update_check = __esm({
5058
5121
  CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
5059
5122
  }
5060
5123
  });
5124
+ function nodeWsSocketFactory(url) {
5125
+ return new WebSocket(url);
5126
+ }
5127
+ function createCliHqPublisher(options) {
5128
+ return createHqPublisherFromEnv({
5129
+ ...options,
5130
+ socketFactory: options.socketFactory ?? nodeWsSocketFactory
5131
+ });
5132
+ }
5133
+ function hqExplicitlyDisabled(options) {
5134
+ const envEnabled = process.env["WRONGSTACK_HQ_ENABLED"]?.trim();
5135
+ if (envEnabled !== void 0 && envEnabled.length > 0) return envEnabled === "0";
5136
+ if (options.config?.enabled !== void 0) return options.config.enabled === false;
5137
+ return options.appConfig?.hq?.enabled === false;
5138
+ }
5139
+ function resolvedHqConnectionKey(options) {
5140
+ if (options.config !== void 0) {
5141
+ return options.config.enabled === false ? void 0 : `${options.config.url}
5142
+ ${options.config.token ?? ""}`;
5143
+ }
5144
+ const config = resolveHqConfig({ config: options.appConfig?.hq });
5145
+ return config === void 0 ? void 0 : `${config.url}
5146
+ ${config.token ?? ""}`;
5147
+ }
5148
+ function startCliHqConnection(options) {
5149
+ let publisher;
5150
+ let publisherKey;
5151
+ let timer;
5152
+ const tryConnect = () => {
5153
+ const nextKey = resolvedHqConnectionKey(options);
5154
+ if (nextKey === void 0) return;
5155
+ if (publisher !== void 0 && publisherKey === nextKey) return;
5156
+ publisher?.close();
5157
+ publisher = void 0;
5158
+ publisherKey = void 0;
5159
+ const next = createCliHqPublisher(options);
5160
+ if (next === void 0) return;
5161
+ publisher = next;
5162
+ publisherKey = nextKey;
5163
+ next.connect();
5164
+ options.onConnect?.(next);
5165
+ };
5166
+ tryConnect();
5167
+ if (!hqExplicitlyDisabled(options)) {
5168
+ timer = setInterval(tryConnect, options.retryIntervalMs ?? 2500);
5169
+ timer.unref?.();
5170
+ }
5171
+ return {
5172
+ getPublisher: () => publisher,
5173
+ stop: () => {
5174
+ if (timer !== void 0) {
5175
+ clearInterval(timer);
5176
+ timer = void 0;
5177
+ }
5178
+ publisher?.close();
5179
+ publisher = void 0;
5180
+ publisherKey = void 0;
5181
+ }
5182
+ };
5183
+ }
5184
+ var init_hq_publisher = __esm({
5185
+ "src/hq-publisher.ts"() {
5186
+ }
5187
+ });
5061
5188
 
5062
5189
  // src/webui-server/cost-helpers.ts
5063
5190
  function getCostRates(model) {
@@ -7168,33 +7295,40 @@ async function runWebUI(opts) {
7168
7295
  let webuiClientId = null;
7169
7296
  let webuiHeartbeatTimer = null;
7170
7297
  let stopWebuiHqBridge;
7298
+ let webuiHqConnection;
7171
7299
  const CLIENT_HEARTBEAT_MS = 15e3;
7172
7300
  const registerWebuiClient = async () => {
7173
7301
  if (!opts.projectRoot) return null;
7174
7302
  try {
7175
- const projectDir = resolveProjectDir(opts.projectRoot, wstackGlobalRoot());
7176
- const hqPublisher = createHqPublisherFromEnv({ clientKind: "webui", projectRoot: opts.projectRoot, projectName: path4.basename(opts.projectRoot), appConfig: opts.appConfig });
7177
- hqPublisher?.connect();
7178
- if (hqPublisher) {
7179
- try {
7180
- const { startSessionTelemetryBridge } = await import('@wrongstack/core');
7181
- stopWebuiHqBridge = startSessionTelemetryBridge({
7182
- publisher: hqPublisher,
7183
- events: opts.events,
7184
- sessionId: opts.session.id,
7185
- projectRoot: opts.projectRoot,
7186
- projectName: path4.basename(opts.projectRoot),
7187
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
7303
+ const projectRoot = opts.projectRoot;
7304
+ const projectDir = resolveProjectDir(projectRoot, wstackGlobalRoot());
7305
+ webuiHqConnection = startCliHqConnection({
7306
+ clientKind: "webui",
7307
+ projectRoot,
7308
+ projectName: path4.basename(projectRoot),
7309
+ appConfig: opts.appConfig,
7310
+ onConnect: (publisher) => {
7311
+ stopWebuiHqBridge?.();
7312
+ stopWebuiHqBridge = void 0;
7313
+ void import('@wrongstack/core').then(({ startSessionTelemetryBridge: startSessionTelemetryBridge2 }) => {
7314
+ stopWebuiHqBridge = startSessionTelemetryBridge2({
7315
+ publisher,
7316
+ events: opts.events,
7317
+ sessionId: opts.session.id,
7318
+ projectRoot,
7319
+ projectName: path4.basename(projectRoot),
7320
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
7321
+ });
7322
+ }).catch(() => {
7188
7323
  });
7189
- } catch {
7190
7324
  }
7191
- }
7192
- const mailbox = new GlobalMailbox(projectDir, opts.events, hqPublisher);
7325
+ });
7326
+ const mailbox = new GlobalMailbox(projectDir, opts.events, () => webuiHqConnection?.getPublisher());
7193
7327
  webuiClientId = `webui@${crypto2.randomUUID().slice(0, 8)}`;
7194
7328
  const projectName = opts.projectRoot ? path4.basename(opts.projectRoot) : "unknown";
7195
7329
  await mailbox.registerClient({
7196
7330
  clientId: webuiClientId,
7197
- sessionId: opts.projectRoot,
7331
+ sessionId: projectRoot,
7198
7332
  name: `WebUI [${projectName}]`,
7199
7333
  source: "webui",
7200
7334
  pid: process.pid
@@ -7218,6 +7352,8 @@ async function runWebUI(opts) {
7218
7352
  stopWebuiHqBridge();
7219
7353
  stopWebuiHqBridge = void 0;
7220
7354
  }
7355
+ webuiHqConnection?.stop();
7356
+ webuiHqConnection = void 0;
7221
7357
  };
7222
7358
  registerWebuiClient();
7223
7359
  const wsToken = generateAuthToken();
@@ -8768,6 +8904,7 @@ ${text}` : text;
8768
8904
  }
8769
8905
  var init_webui_server = __esm({
8770
8906
  "src/webui-server.ts"() {
8907
+ init_hq_publisher();
8771
8908
  init_cost_helpers();
8772
8909
  init_prefs_seeding();
8773
8910
  init_lifecycle();
@@ -21054,11 +21191,24 @@ function buildBadges(chosen) {
21054
21191
  return badges;
21055
21192
  }
21056
21193
  async function persistLaunchChoices(configPath2, choices) {
21194
+ let fileExists2 = false;
21195
+ try {
21196
+ await fs4.access(configPath2);
21197
+ fileExists2 = true;
21198
+ } catch {
21199
+ }
21057
21200
  let existing = {};
21058
21201
  try {
21059
21202
  const raw = await fs4.readFile(configPath2, "utf8");
21060
21203
  existing = JSON.parse(raw);
21061
- } catch {
21204
+ } catch (err) {
21205
+ if (fileExists2) {
21206
+ throw new Error(
21207
+ `Refusing to overwrite corrupt config at ${configPath2} (${err.message}). Fix or move the file aside before retrying.`,
21208
+ { cause: err }
21209
+ );
21210
+ }
21211
+ existing = {};
21062
21212
  }
21063
21213
  existing.yolo = choices.yolo;
21064
21214
  existing.launch = {
@@ -22430,8 +22580,8 @@ function startLoopbackServer(expectedState) {
22430
22580
  function openBrowser(url) {
22431
22581
  try {
22432
22582
  const platform3 = process.platform;
22433
- const { command, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
22434
- const child = spawn(command, args, { stdio: "ignore", windowsHide: true });
22583
+ const { command: command2, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
22584
+ const child = spawn(command2, args, { stdio: "ignore", windowsHide: true });
22435
22585
  child.on("error", () => {
22436
22586
  });
22437
22587
  child.unref();
@@ -22563,8 +22713,8 @@ var COPILOT_PROVIDER_ID = "github-copilot";
22563
22713
  function openBrowser2(url) {
22564
22714
  try {
22565
22715
  const platform3 = process.platform;
22566
- const { command, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
22567
- const child = spawn(command, args, { stdio: "ignore", windowsHide: true });
22716
+ const { command: command2, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
22717
+ const child = spawn(command2, args, { stdio: "ignore", windowsHide: true });
22568
22718
  child.on("error", () => {
22569
22719
  });
22570
22720
  child.unref();
@@ -22931,8 +23081,8 @@ function startLoopbackServer2(state) {
22931
23081
  function openBrowser3(url) {
22932
23082
  try {
22933
23083
  const platform3 = process.platform;
22934
- const { command, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
22935
- const child = spawn(command, args, { stdio: "ignore", windowsHide: true });
23084
+ const { command: command2, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
23085
+ const child = spawn(command2, args, { stdio: "ignore", windowsHide: true });
22936
23086
  child.on("error", () => {
22937
23087
  });
22938
23088
  child.unref();
@@ -26858,9 +27008,15 @@ var skillsCmd = async (_args, deps) => {
26858
27008
  init_update_check();
26859
27009
  var updateCmd = async (args, deps) => {
26860
27010
  const cwd = deps.cwd;
26861
- const checkOnly = args.includes("--check-only") || args.includes("-c");
27011
+ const parsed = parseUpdateArgs(args);
27012
+ if (parsed.error) {
27013
+ deps.renderer.write(`${parsed.error}
27014
+ `);
27015
+ deps.renderer.write("Usage: wrongstack update [--check-only] [--pm npm|pnpm|yarn|bun]\n");
27016
+ return 1;
27017
+ }
26862
27018
  const info = await checkForUpdate();
26863
- if (checkOnly) {
27019
+ if (parsed.checkOnly) {
26864
27020
  if (info.outdated) {
26865
27021
  deps.renderer.write(`Update available: v${info.current} \u2192 v${info.latest}
26866
27022
  `);
@@ -26875,40 +27031,58 @@ var updateCmd = async (args, deps) => {
26875
27031
  `);
26876
27032
  return 0;
26877
27033
  }
27034
+ const packageManager = parsed.packageManager ?? detectUpdatePackageManager();
27035
+ const updateCommand = buildUpdateCommand(packageManager);
26878
27036
  deps.renderer.write(`Updating wrongstack from v${info.current} to v${info.latest}...
27037
+ `);
27038
+ deps.renderer.write(`Running: ${updateCommand.display}
26879
27039
  `);
26880
27040
  try {
26881
- const result = await new Promise((resolve13, reject) => {
26882
- const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
26883
- const child = spawn(npmCommand, ["install", "-g", "wrongstack@latest"], {
26884
- cwd,
26885
- stdio: "pipe",
26886
- signal: AbortSignal.timeout(12e4),
26887
- windowsHide: true
26888
- });
26889
- let stderr = "";
26890
- child.stderr?.on("data", (d) => {
26891
- stderr += d;
26892
- });
26893
- child.on("error", reject);
26894
- child.on("close", (code) => resolve13({ code: code ?? 0, stderr }));
26895
- });
27041
+ const result = await new Promise(
27042
+ (resolve13, reject) => {
27043
+ const child = spawn(updateCommand.executable, updateCommand.args, {
27044
+ cwd,
27045
+ stdio: "pipe",
27046
+ signal: AbortSignal.timeout(12e4),
27047
+ windowsHide: true
27048
+ });
27049
+ let stdout = "";
27050
+ let stderr = "";
27051
+ child.stdout?.on("data", (d) => {
27052
+ stdout += d;
27053
+ });
27054
+ child.stderr?.on("data", (d) => {
27055
+ stderr += d;
27056
+ });
27057
+ child.on("error", reject);
27058
+ child.on("close", (code) => resolve13({ code: code ?? 0, stdout, stderr }));
27059
+ }
27060
+ );
26896
27061
  if (result.code === 0) {
26897
27062
  deps.renderer.write(
26898
27063
  `
26899
27064
  Updated to v${info.latest}. Restart wrongstack to use the new version.
26900
27065
  `
26901
27066
  );
27067
+ const warning = installWarningSummary(`${result.stderr}
27068
+ ${result.stdout}`);
27069
+ if (warning) deps.renderer.write(`
27070
+ ${warning}
27071
+ `);
26902
27072
  } else {
26903
27073
  deps.renderer.write(`
26904
27074
  Update failed with exit code ${result.code}.
26905
27075
  `);
26906
- const detail = result.stderr.trim();
27076
+ const detail = `${result.stderr}
27077
+ ${result.stdout}`.trim();
26907
27078
  if (detail) deps.renderer.write(`
26908
27079
  ${detail}
26909
27080
  `);
26910
27081
  deps.renderer.write(
26911
- "\nWrongStack updates itself with npm. If you installed it with a different\npackage manager, update with the matching command instead:\n pnpm add -g wrongstack@latest\n yarn global add wrongstack@latest\n bun add -g wrongstack@latest\n"
27082
+ `
27083
+ Try the matching global update command manually:
27084
+ ${updateCommand.display}
27085
+ ` + otherManagerCommands(packageManager)
26912
27086
  );
26913
27087
  }
26914
27088
  return result.code;
@@ -26916,7 +27090,7 @@ ${detail}
26916
27090
  const msg = err instanceof Error ? err.message : String(err);
26917
27091
  if (msg.includes("ENOENT")) {
26918
27092
  deps.renderer.write(`
26919
- Update failed: npm not found in PATH.
27093
+ Update failed: ${packageManager} not found in PATH.
26920
27094
  `);
26921
27095
  return 1;
26922
27096
  }
@@ -26926,6 +27100,100 @@ Update failed: ${msg}
26926
27100
  return 1;
26927
27101
  }
26928
27102
  };
27103
+ function parseUpdateArgs(args) {
27104
+ let checkOnly = false;
27105
+ let packageManager;
27106
+ for (let i = 0; i < args.length; i++) {
27107
+ const arg = args[i];
27108
+ if (arg === void 0) continue;
27109
+ if (arg === "--check-only" || arg === "-c") {
27110
+ checkOnly = true;
27111
+ continue;
27112
+ }
27113
+ if (arg === "--pm" || arg === "--package-manager") {
27114
+ const value = args[++i];
27115
+ const pm = parsePackageManager(value);
27116
+ if (!pm)
27117
+ return {
27118
+ checkOnly,
27119
+ packageManager,
27120
+ error: `Invalid package manager: ${value ?? "<missing>"}`
27121
+ };
27122
+ packageManager = pm;
27123
+ continue;
27124
+ }
27125
+ const pmEq = arg.match(/^--(?:pm|package-manager)=(.+)$/)?.[1];
27126
+ if (pmEq) {
27127
+ const pm = parsePackageManager(pmEq);
27128
+ if (!pm) return { checkOnly, packageManager, error: `Invalid package manager: ${pmEq}` };
27129
+ packageManager = pm;
27130
+ continue;
27131
+ }
27132
+ const shorthand = arg.match(/^--(npm|pnpm|yarn|bun)$/)?.[1];
27133
+ if (shorthand) {
27134
+ packageManager = shorthand;
27135
+ }
27136
+ }
27137
+ return { checkOnly, packageManager, error: void 0 };
27138
+ }
27139
+ function parsePackageManager(value) {
27140
+ if (value === "npm" || value === "pnpm" || value === "yarn" || value === "bun") return value;
27141
+ return void 0;
27142
+ }
27143
+ function detectUpdatePackageManager(env = process.env, argv = process.argv) {
27144
+ const forced = parsePackageManager(env.WRONGSTACK_UPDATE_PM);
27145
+ if (forced) return forced;
27146
+ const userAgent = env.npm_config_user_agent ?? "";
27147
+ if (/\bpnpm\//i.test(userAgent)) return "pnpm";
27148
+ if (/\byarn\//i.test(userAgent)) return "yarn";
27149
+ if (/\bbun\//i.test(userAgent)) return "bun";
27150
+ if (/\bnpm\//i.test(userAgent)) return "npm";
27151
+ const execPath = `${env.npm_execpath ?? ""} ${argv[1] ?? ""}`;
27152
+ const realPaths = [env.npm_execpath, argv[1]].filter((p) => typeof p === "string" && p.length > 0).map((p) => {
27153
+ try {
27154
+ return existsSync(p) ? realpathSync(p) : p;
27155
+ } catch {
27156
+ return p;
27157
+ }
27158
+ }).join(" ");
27159
+ const hint = `${execPath} ${realPaths}`.replace(/\\/g, "/").toLowerCase();
27160
+ if (hint.includes("/pnpm/") || hint.includes("/.pnpm/") || hint.includes("pnpm-global"))
27161
+ return "pnpm";
27162
+ if (hint.includes("/yarn/") || hint.includes("/.yarn/")) return "yarn";
27163
+ if (hint.includes("/bun/") || hint.includes("/.bun/")) return "bun";
27164
+ return "npm";
27165
+ }
27166
+ function buildUpdateCommand(packageManager) {
27167
+ switch (packageManager) {
27168
+ case "pnpm":
27169
+ return command(packageManager, ["add", "-g", "wrongstack@latest"]);
27170
+ case "yarn":
27171
+ return command(packageManager, ["global", "add", "wrongstack@latest"]);
27172
+ case "bun":
27173
+ return command(packageManager, ["add", "-g", "wrongstack@latest"]);
27174
+ case "npm":
27175
+ return command(packageManager, ["install", "-g", "wrongstack@latest"]);
27176
+ }
27177
+ }
27178
+ function command(pm, args) {
27179
+ const executable = process.platform === "win32" && pm !== "bun" ? `${pm}.cmd` : pm;
27180
+ return {
27181
+ executable,
27182
+ args,
27183
+ display: `${pm} ${args.join(" ")}`
27184
+ };
27185
+ }
27186
+ function otherManagerCommands(selected) {
27187
+ const commands = ["npm", "pnpm", "yarn", "bun"].filter((pm) => pm !== selected).map((pm) => ` ${buildUpdateCommand(pm).display}`);
27188
+ return commands.length > 0 ? `
27189
+ Other package managers:
27190
+ ${commands.join("\n")}
27191
+ ` : "";
27192
+ }
27193
+ function installWarningSummary(output) {
27194
+ if (!/allow-scripts|allowScripts/i.test(output)) return null;
27195
+ return "Install completed, but npm reported blocked lifecycle scripts. If a native optional feature is missing, rerun the update with npm script approval for the named package.";
27196
+ }
26929
27197
  var versionCmd = async (_args, deps) => {
26930
27198
  deps.renderer.write(
26931
27199
  `WrongStack ${CLI_VERSION} (apiVersion ${API_VERSION}, node ${process.version}, ${os.platform()})
@@ -29243,6 +29511,7 @@ async function predictNextTasks(input, opts) {
29243
29511
 
29244
29512
  // src/execution.ts
29245
29513
  init_provider_config_utils();
29514
+ init_hq_publisher();
29246
29515
  init_sdd();
29247
29516
  init_utils();
29248
29517
  var DEFAULT_MAX_CONSECUTIVE_AUTO_PROCEED = 50;
@@ -29297,9 +29566,8 @@ async function runRepl(opts) {
29297
29566
  const replProjectRoot = opts.projectRoot ?? process.cwd();
29298
29567
  const projectDir = resolveProjectDir(replProjectRoot, wstackGlobalRoot());
29299
29568
  const clientId = `repl@${crypto2.randomUUID().slice(0, 8)}`;
29300
- const hqPublisher = createHqPublisherFromEnv({ clientKind: "repl", projectRoot: replProjectRoot, projectName: path4.basename(replProjectRoot), appConfig: opts.appConfig });
29301
- hqPublisher?.connect();
29302
- const clientMailbox = new GlobalMailbox(projectDir, void 0, hqPublisher);
29569
+ const hqConnection = startCliHqConnection({ clientKind: "repl", projectRoot: replProjectRoot, projectName: path4.basename(replProjectRoot), appConfig: opts.appConfig });
29570
+ const clientMailbox = new GlobalMailbox(projectDir, void 0, () => hqConnection.getPublisher());
29303
29571
  let clientHeartbeat;
29304
29572
  clientMailbox.registerClient({
29305
29573
  clientId,
@@ -29879,6 +30147,7 @@ ${color.dim(lines)}
29879
30147
  await opts.reader.close().catch(() => {
29880
30148
  });
29881
30149
  clearInterval(clientHeartbeat);
30150
+ hqConnection.stop();
29882
30151
  opts.onDestroy?.();
29883
30152
  }
29884
30153
  }
@@ -30775,6 +31044,9 @@ async function execute(deps) {
30775
31044
  return code;
30776
31045
  }
30777
31046
 
31047
+ // src/cli-main.ts
31048
+ init_hq_publisher();
31049
+
30778
31050
  // src/hooks-wiring.ts
30779
31051
  var HookBlockedError = class extends Error {
30780
31052
  constructor(reason) {
@@ -30879,6 +31151,10 @@ var MultiAgentHost = class _MultiAgentHost {
30879
31151
  acpRunnerCache = /* @__PURE__ */ new Map();
30880
31152
  acpRunnerAccessOrder = [];
30881
31153
  static ACP_CACHE_MAX = 20;
31154
+ /** Adaptive concurrency controller — created in buildDirector() when config has
31155
+ * adaptiveConcurrency.enabled = true. Monitors FleetBus for 429 errors and
31156
+ * automatically adjusts maxConcurrent to prevent rate limiting. */
31157
+ adaptiveConcurrencyController;
30882
31158
  /**
30883
31159
  * Force the lazy build path to run *now* and return the live Director,
30884
31160
  * or null when director mode is off. Used by the CLI to register the
@@ -31040,6 +31316,14 @@ var MultiAgentHost = class _MultiAgentHost {
31040
31316
  this.coordinatorOffHandle = () => coordinator.off("task.assigned", coordinatorTaskAssignedHandler);
31041
31317
  this.fleetEmitTool = makeFleetEmitTool(this.director);
31042
31318
  this.fleetStatusTool = makeFleetStatusTool(this.director);
31319
+ const adaptiveConfig = this.deps.configStore.get().adaptiveConcurrency;
31320
+ if (adaptiveConfig?.enabled) {
31321
+ this.adaptiveConcurrencyController = new AdaptiveConcurrencyController(
31322
+ this.director.fleet,
31323
+ (n) => coordinator.setMaxConcurrent(n),
31324
+ adaptiveConfig
31325
+ );
31326
+ }
31043
31327
  const runner = await this.buildSubagentRunner(config);
31044
31328
  if (!this.directorRunnerSet) {
31045
31329
  this.getCoordinator().setRunner(runner);
@@ -31693,6 +31977,8 @@ Start your heartbeat loop now.`,
31693
31977
  this.directorOffHandles.length = 0;
31694
31978
  this.coordinatorOffHandle?.();
31695
31979
  this.coordinatorOffHandle = null;
31980
+ this.adaptiveConcurrencyController?.dispose();
31981
+ this.adaptiveConcurrencyController = void 0;
31696
31982
  if (this.director) {
31697
31983
  await this.director.shutdown();
31698
31984
  }
@@ -32810,7 +33096,7 @@ async function main(argv) {
32810
33096
  const promptBuilder = container.resolve(TOKENS.SystemPromptBuilder);
32811
33097
  let onlineAgents = [];
32812
33098
  try {
32813
- const hqPublisher2 = createHqPublisherFromEnv({ clientKind: "cli", projectRoot, projectName: path4.basename(projectRoot), appConfig: config });
33099
+ const hqPublisher2 = createCliHqPublisher({ clientKind: tuiOwnsScreen ? "tui" : "cli", projectRoot, projectName: path4.basename(projectRoot), appConfig: config });
32814
33100
  hqPublisher2?.connect();
32815
33101
  if (hqPublisher2) teardownHandlers.push(() => hqPublisher2.close());
32816
33102
  const systemMailbox = new GlobalMailbox(wpaths.projectDir, void 0, hqPublisher2);
@@ -33353,19 +33639,45 @@ async function main(argv) {
33353
33639
  outcome: e.intervened ? "steered the agent" : "observed (no action)"
33354
33640
  });
33355
33641
  });
33356
- const hqPublisher = createHqPublisherFromEnv({ clientKind: "cli", projectRoot, projectName: path4.basename(projectRoot), appConfig: config });
33357
- hqPublisher?.connect();
33358
- if (hqPublisher) teardownHandlers.push(() => hqPublisher.close());
33359
- if (hqPublisher && agentMonitor) {
33642
+ let hqPublisher;
33643
+ let stopHqSessionBridge;
33644
+ const hqConnection = startCliHqConnection({
33645
+ clientKind: tuiOwnsScreen ? "tui" : "cli",
33646
+ projectRoot,
33647
+ projectName: path4.basename(projectRoot),
33648
+ appConfig: config,
33649
+ onConnect: (publisher) => {
33650
+ hqPublisher = publisher;
33651
+ stopHqSessionBridge?.();
33652
+ stopHqSessionBridge = void 0;
33653
+ try {
33654
+ stopHqSessionBridge = startSessionTelemetryBridge({
33655
+ publisher,
33656
+ events,
33657
+ sessionId: session.id,
33658
+ projectRoot,
33659
+ projectName: path4.basename(projectRoot),
33660
+ globalRoot: wpaths.globalRoot,
33661
+ initialAgents: tracker?.getAgents(),
33662
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
33663
+ });
33664
+ } catch {
33665
+ }
33666
+ }
33667
+ });
33668
+ hqPublisher = hqConnection.getPublisher();
33669
+ teardownHandlers.push(() => stopHqSessionBridge?.());
33670
+ teardownHandlers.push(() => hqConnection.stop());
33671
+ if (agentMonitor) {
33360
33672
  const offMsg = events.on("agent.timeline.message", (payload) => {
33361
33673
  try {
33362
- hqPublisher.publishEvent({ type: "agent.message", payload, timestamp: payload.ts });
33674
+ hqPublisher?.publishEvent({ type: "agent.message", payload, timestamp: payload.ts });
33363
33675
  } catch {
33364
33676
  }
33365
33677
  });
33366
33678
  const offStatus = events.on("agent.status_changed", (payload) => {
33367
33679
  try {
33368
- hqPublisher.publishEvent({ type: "agent.status", payload, timestamp: payload.ts });
33680
+ hqPublisher?.publishEvent({ type: "agent.status", payload, timestamp: payload.ts });
33369
33681
  } catch {
33370
33682
  }
33371
33683
  });
@@ -33374,7 +33686,7 @@ async function main(argv) {
33374
33686
  offStatus();
33375
33687
  });
33376
33688
  }
33377
- const brainMailbox = new GlobalMailbox(wpaths.projectDir, events, hqPublisher);
33689
+ const brainMailbox = new GlobalMailbox(wpaths.projectDir, events, () => hqPublisher);
33378
33690
  const brainMonitor = new BrainMonitor({
33379
33691
  events,
33380
33692
  brain,