@wrongstack/cli 0.272.0 → 0.272.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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();
@@ -22430,8 +22567,8 @@ function startLoopbackServer(expectedState) {
22430
22567
  function openBrowser(url) {
22431
22568
  try {
22432
22569
  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 });
22570
+ const { command: command2, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
22571
+ const child = spawn(command2, args, { stdio: "ignore", windowsHide: true });
22435
22572
  child.on("error", () => {
22436
22573
  });
22437
22574
  child.unref();
@@ -22563,8 +22700,8 @@ var COPILOT_PROVIDER_ID = "github-copilot";
22563
22700
  function openBrowser2(url) {
22564
22701
  try {
22565
22702
  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 });
22703
+ const { command: command2, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
22704
+ const child = spawn(command2, args, { stdio: "ignore", windowsHide: true });
22568
22705
  child.on("error", () => {
22569
22706
  });
22570
22707
  child.unref();
@@ -22931,8 +23068,8 @@ function startLoopbackServer2(state) {
22931
23068
  function openBrowser3(url) {
22932
23069
  try {
22933
23070
  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 });
23071
+ const { command: command2, args } = platform3 === "win32" ? { command: "cmd", args: ["/c", "start", "", url] } : platform3 === "darwin" ? { command: "open", args: [url] } : { command: "xdg-open", args: [url] };
23072
+ const child = spawn(command2, args, { stdio: "ignore", windowsHide: true });
22936
23073
  child.on("error", () => {
22937
23074
  });
22938
23075
  child.unref();
@@ -26858,9 +26995,15 @@ var skillsCmd = async (_args, deps) => {
26858
26995
  init_update_check();
26859
26996
  var updateCmd = async (args, deps) => {
26860
26997
  const cwd = deps.cwd;
26861
- const checkOnly = args.includes("--check-only") || args.includes("-c");
26998
+ const parsed = parseUpdateArgs(args);
26999
+ if (parsed.error) {
27000
+ deps.renderer.write(`${parsed.error}
27001
+ `);
27002
+ deps.renderer.write("Usage: wrongstack update [--check-only] [--pm npm|pnpm|yarn|bun]\n");
27003
+ return 1;
27004
+ }
26862
27005
  const info = await checkForUpdate();
26863
- if (checkOnly) {
27006
+ if (parsed.checkOnly) {
26864
27007
  if (info.outdated) {
26865
27008
  deps.renderer.write(`Update available: v${info.current} \u2192 v${info.latest}
26866
27009
  `);
@@ -26875,40 +27018,58 @@ var updateCmd = async (args, deps) => {
26875
27018
  `);
26876
27019
  return 0;
26877
27020
  }
27021
+ const packageManager = parsed.packageManager ?? detectUpdatePackageManager();
27022
+ const updateCommand = buildUpdateCommand(packageManager);
26878
27023
  deps.renderer.write(`Updating wrongstack from v${info.current} to v${info.latest}...
27024
+ `);
27025
+ deps.renderer.write(`Running: ${updateCommand.display}
26879
27026
  `);
26880
27027
  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
- });
27028
+ const result = await new Promise(
27029
+ (resolve13, reject) => {
27030
+ const child = spawn(updateCommand.executable, updateCommand.args, {
27031
+ cwd,
27032
+ stdio: "pipe",
27033
+ signal: AbortSignal.timeout(12e4),
27034
+ windowsHide: true
27035
+ });
27036
+ let stdout = "";
27037
+ let stderr = "";
27038
+ child.stdout?.on("data", (d) => {
27039
+ stdout += d;
27040
+ });
27041
+ child.stderr?.on("data", (d) => {
27042
+ stderr += d;
27043
+ });
27044
+ child.on("error", reject);
27045
+ child.on("close", (code) => resolve13({ code: code ?? 0, stdout, stderr }));
27046
+ }
27047
+ );
26896
27048
  if (result.code === 0) {
26897
27049
  deps.renderer.write(
26898
27050
  `
26899
27051
  Updated to v${info.latest}. Restart wrongstack to use the new version.
26900
27052
  `
26901
27053
  );
27054
+ const warning = installWarningSummary(`${result.stderr}
27055
+ ${result.stdout}`);
27056
+ if (warning) deps.renderer.write(`
27057
+ ${warning}
27058
+ `);
26902
27059
  } else {
26903
27060
  deps.renderer.write(`
26904
27061
  Update failed with exit code ${result.code}.
26905
27062
  `);
26906
- const detail = result.stderr.trim();
27063
+ const detail = `${result.stderr}
27064
+ ${result.stdout}`.trim();
26907
27065
  if (detail) deps.renderer.write(`
26908
27066
  ${detail}
26909
27067
  `);
26910
27068
  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"
27069
+ `
27070
+ Try the matching global update command manually:
27071
+ ${updateCommand.display}
27072
+ ` + otherManagerCommands(packageManager)
26912
27073
  );
26913
27074
  }
26914
27075
  return result.code;
@@ -26916,7 +27077,7 @@ ${detail}
26916
27077
  const msg = err instanceof Error ? err.message : String(err);
26917
27078
  if (msg.includes("ENOENT")) {
26918
27079
  deps.renderer.write(`
26919
- Update failed: npm not found in PATH.
27080
+ Update failed: ${packageManager} not found in PATH.
26920
27081
  `);
26921
27082
  return 1;
26922
27083
  }
@@ -26926,6 +27087,100 @@ Update failed: ${msg}
26926
27087
  return 1;
26927
27088
  }
26928
27089
  };
27090
+ function parseUpdateArgs(args) {
27091
+ let checkOnly = false;
27092
+ let packageManager;
27093
+ for (let i = 0; i < args.length; i++) {
27094
+ const arg = args[i];
27095
+ if (arg === void 0) continue;
27096
+ if (arg === "--check-only" || arg === "-c") {
27097
+ checkOnly = true;
27098
+ continue;
27099
+ }
27100
+ if (arg === "--pm" || arg === "--package-manager") {
27101
+ const value = args[++i];
27102
+ const pm = parsePackageManager(value);
27103
+ if (!pm)
27104
+ return {
27105
+ checkOnly,
27106
+ packageManager,
27107
+ error: `Invalid package manager: ${value ?? "<missing>"}`
27108
+ };
27109
+ packageManager = pm;
27110
+ continue;
27111
+ }
27112
+ const pmEq = arg.match(/^--(?:pm|package-manager)=(.+)$/)?.[1];
27113
+ if (pmEq) {
27114
+ const pm = parsePackageManager(pmEq);
27115
+ if (!pm) return { checkOnly, packageManager, error: `Invalid package manager: ${pmEq}` };
27116
+ packageManager = pm;
27117
+ continue;
27118
+ }
27119
+ const shorthand = arg.match(/^--(npm|pnpm|yarn|bun)$/)?.[1];
27120
+ if (shorthand) {
27121
+ packageManager = shorthand;
27122
+ }
27123
+ }
27124
+ return { checkOnly, packageManager, error: void 0 };
27125
+ }
27126
+ function parsePackageManager(value) {
27127
+ if (value === "npm" || value === "pnpm" || value === "yarn" || value === "bun") return value;
27128
+ return void 0;
27129
+ }
27130
+ function detectUpdatePackageManager(env = process.env, argv = process.argv) {
27131
+ const forced = parsePackageManager(env.WRONGSTACK_UPDATE_PM);
27132
+ if (forced) return forced;
27133
+ const userAgent = env.npm_config_user_agent ?? "";
27134
+ if (/\bpnpm\//i.test(userAgent)) return "pnpm";
27135
+ if (/\byarn\//i.test(userAgent)) return "yarn";
27136
+ if (/\bbun\//i.test(userAgent)) return "bun";
27137
+ if (/\bnpm\//i.test(userAgent)) return "npm";
27138
+ const execPath = `${env.npm_execpath ?? ""} ${argv[1] ?? ""}`;
27139
+ const realPaths = [env.npm_execpath, argv[1]].filter((p) => typeof p === "string" && p.length > 0).map((p) => {
27140
+ try {
27141
+ return existsSync(p) ? realpathSync(p) : p;
27142
+ } catch {
27143
+ return p;
27144
+ }
27145
+ }).join(" ");
27146
+ const hint = `${execPath} ${realPaths}`.replace(/\\/g, "/").toLowerCase();
27147
+ if (hint.includes("/pnpm/") || hint.includes("/.pnpm/") || hint.includes("pnpm-global"))
27148
+ return "pnpm";
27149
+ if (hint.includes("/yarn/") || hint.includes("/.yarn/")) return "yarn";
27150
+ if (hint.includes("/bun/") || hint.includes("/.bun/")) return "bun";
27151
+ return "npm";
27152
+ }
27153
+ function buildUpdateCommand(packageManager) {
27154
+ switch (packageManager) {
27155
+ case "pnpm":
27156
+ return command(packageManager, ["add", "-g", "wrongstack@latest"]);
27157
+ case "yarn":
27158
+ return command(packageManager, ["global", "add", "wrongstack@latest"]);
27159
+ case "bun":
27160
+ return command(packageManager, ["add", "-g", "wrongstack@latest"]);
27161
+ case "npm":
27162
+ return command(packageManager, ["install", "-g", "wrongstack@latest"]);
27163
+ }
27164
+ }
27165
+ function command(pm, args) {
27166
+ const executable = process.platform === "win32" && pm !== "bun" ? `${pm}.cmd` : pm;
27167
+ return {
27168
+ executable,
27169
+ args,
27170
+ display: `${pm} ${args.join(" ")}`
27171
+ };
27172
+ }
27173
+ function otherManagerCommands(selected) {
27174
+ const commands = ["npm", "pnpm", "yarn", "bun"].filter((pm) => pm !== selected).map((pm) => ` ${buildUpdateCommand(pm).display}`);
27175
+ return commands.length > 0 ? `
27176
+ Other package managers:
27177
+ ${commands.join("\n")}
27178
+ ` : "";
27179
+ }
27180
+ function installWarningSummary(output) {
27181
+ if (!/allow-scripts|allowScripts/i.test(output)) return null;
27182
+ 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.";
27183
+ }
26929
27184
  var versionCmd = async (_args, deps) => {
26930
27185
  deps.renderer.write(
26931
27186
  `WrongStack ${CLI_VERSION} (apiVersion ${API_VERSION}, node ${process.version}, ${os.platform()})
@@ -29243,6 +29498,7 @@ async function predictNextTasks(input, opts) {
29243
29498
 
29244
29499
  // src/execution.ts
29245
29500
  init_provider_config_utils();
29501
+ init_hq_publisher();
29246
29502
  init_sdd();
29247
29503
  init_utils();
29248
29504
  var DEFAULT_MAX_CONSECUTIVE_AUTO_PROCEED = 50;
@@ -29297,9 +29553,8 @@ async function runRepl(opts) {
29297
29553
  const replProjectRoot = opts.projectRoot ?? process.cwd();
29298
29554
  const projectDir = resolveProjectDir(replProjectRoot, wstackGlobalRoot());
29299
29555
  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);
29556
+ const hqConnection = startCliHqConnection({ clientKind: "repl", projectRoot: replProjectRoot, projectName: path4.basename(replProjectRoot), appConfig: opts.appConfig });
29557
+ const clientMailbox = new GlobalMailbox(projectDir, void 0, () => hqConnection.getPublisher());
29303
29558
  let clientHeartbeat;
29304
29559
  clientMailbox.registerClient({
29305
29560
  clientId,
@@ -29879,6 +30134,7 @@ ${color.dim(lines)}
29879
30134
  await opts.reader.close().catch(() => {
29880
30135
  });
29881
30136
  clearInterval(clientHeartbeat);
30137
+ hqConnection.stop();
29882
30138
  opts.onDestroy?.();
29883
30139
  }
29884
30140
  }
@@ -30775,6 +31031,9 @@ async function execute(deps) {
30775
31031
  return code;
30776
31032
  }
30777
31033
 
31034
+ // src/cli-main.ts
31035
+ init_hq_publisher();
31036
+
30778
31037
  // src/hooks-wiring.ts
30779
31038
  var HookBlockedError = class extends Error {
30780
31039
  constructor(reason) {
@@ -30879,6 +31138,10 @@ var MultiAgentHost = class _MultiAgentHost {
30879
31138
  acpRunnerCache = /* @__PURE__ */ new Map();
30880
31139
  acpRunnerAccessOrder = [];
30881
31140
  static ACP_CACHE_MAX = 20;
31141
+ /** Adaptive concurrency controller — created in buildDirector() when config has
31142
+ * adaptiveConcurrency.enabled = true. Monitors FleetBus for 429 errors and
31143
+ * automatically adjusts maxConcurrent to prevent rate limiting. */
31144
+ adaptiveConcurrencyController;
30882
31145
  /**
30883
31146
  * Force the lazy build path to run *now* and return the live Director,
30884
31147
  * or null when director mode is off. Used by the CLI to register the
@@ -31040,6 +31303,14 @@ var MultiAgentHost = class _MultiAgentHost {
31040
31303
  this.coordinatorOffHandle = () => coordinator.off("task.assigned", coordinatorTaskAssignedHandler);
31041
31304
  this.fleetEmitTool = makeFleetEmitTool(this.director);
31042
31305
  this.fleetStatusTool = makeFleetStatusTool(this.director);
31306
+ const adaptiveConfig = this.deps.configStore.get().adaptiveConcurrency;
31307
+ if (adaptiveConfig?.enabled) {
31308
+ this.adaptiveConcurrencyController = new AdaptiveConcurrencyController(
31309
+ this.director.fleet,
31310
+ (n) => coordinator.setMaxConcurrent(n),
31311
+ adaptiveConfig
31312
+ );
31313
+ }
31043
31314
  const runner = await this.buildSubagentRunner(config);
31044
31315
  if (!this.directorRunnerSet) {
31045
31316
  this.getCoordinator().setRunner(runner);
@@ -31693,6 +31964,8 @@ Start your heartbeat loop now.`,
31693
31964
  this.directorOffHandles.length = 0;
31694
31965
  this.coordinatorOffHandle?.();
31695
31966
  this.coordinatorOffHandle = null;
31967
+ this.adaptiveConcurrencyController?.dispose();
31968
+ this.adaptiveConcurrencyController = void 0;
31696
31969
  if (this.director) {
31697
31970
  await this.director.shutdown();
31698
31971
  }
@@ -32810,7 +33083,7 @@ async function main(argv) {
32810
33083
  const promptBuilder = container.resolve(TOKENS.SystemPromptBuilder);
32811
33084
  let onlineAgents = [];
32812
33085
  try {
32813
- const hqPublisher2 = createHqPublisherFromEnv({ clientKind: "cli", projectRoot, projectName: path4.basename(projectRoot), appConfig: config });
33086
+ const hqPublisher2 = createCliHqPublisher({ clientKind: tuiOwnsScreen ? "tui" : "cli", projectRoot, projectName: path4.basename(projectRoot), appConfig: config });
32814
33087
  hqPublisher2?.connect();
32815
33088
  if (hqPublisher2) teardownHandlers.push(() => hqPublisher2.close());
32816
33089
  const systemMailbox = new GlobalMailbox(wpaths.projectDir, void 0, hqPublisher2);
@@ -33353,19 +33626,45 @@ async function main(argv) {
33353
33626
  outcome: e.intervened ? "steered the agent" : "observed (no action)"
33354
33627
  });
33355
33628
  });
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) {
33629
+ let hqPublisher;
33630
+ let stopHqSessionBridge;
33631
+ const hqConnection = startCliHqConnection({
33632
+ clientKind: tuiOwnsScreen ? "tui" : "cli",
33633
+ projectRoot,
33634
+ projectName: path4.basename(projectRoot),
33635
+ appConfig: config,
33636
+ onConnect: (publisher) => {
33637
+ hqPublisher = publisher;
33638
+ stopHqSessionBridge?.();
33639
+ stopHqSessionBridge = void 0;
33640
+ try {
33641
+ stopHqSessionBridge = startSessionTelemetryBridge({
33642
+ publisher,
33643
+ events,
33644
+ sessionId: session.id,
33645
+ projectRoot,
33646
+ projectName: path4.basename(projectRoot),
33647
+ globalRoot: wpaths.globalRoot,
33648
+ initialAgents: tracker?.getAgents(),
33649
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
33650
+ });
33651
+ } catch {
33652
+ }
33653
+ }
33654
+ });
33655
+ hqPublisher = hqConnection.getPublisher();
33656
+ teardownHandlers.push(() => stopHqSessionBridge?.());
33657
+ teardownHandlers.push(() => hqConnection.stop());
33658
+ if (agentMonitor) {
33360
33659
  const offMsg = events.on("agent.timeline.message", (payload) => {
33361
33660
  try {
33362
- hqPublisher.publishEvent({ type: "agent.message", payload, timestamp: payload.ts });
33661
+ hqPublisher?.publishEvent({ type: "agent.message", payload, timestamp: payload.ts });
33363
33662
  } catch {
33364
33663
  }
33365
33664
  });
33366
33665
  const offStatus = events.on("agent.status_changed", (payload) => {
33367
33666
  try {
33368
- hqPublisher.publishEvent({ type: "agent.status", payload, timestamp: payload.ts });
33667
+ hqPublisher?.publishEvent({ type: "agent.status", payload, timestamp: payload.ts });
33369
33668
  } catch {
33370
33669
  }
33371
33670
  });
@@ -33374,7 +33673,7 @@ async function main(argv) {
33374
33673
  offStatus();
33375
33674
  });
33376
33675
  }
33377
- const brainMailbox = new GlobalMailbox(wpaths.projectDir, events, hqPublisher);
33676
+ const brainMailbox = new GlobalMailbox(wpaths.projectDir, events, () => hqPublisher);
33378
33677
  const brainMonitor = new BrainMonitor({
33379
33678
  events,
33380
33679
  brain,