@wrongstack/cli 0.260.0 → 0.264.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +807 -133
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import * as fsp5 from 'fs/promises';
|
|
3
3
|
import * as path39 from 'path';
|
|
4
4
|
import { join } from 'path';
|
|
5
|
-
import { color, writeErr, loadPlugins, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, withFileLock, DefaultSecretScrubber, resolveProjectDir, GlobalMailbox, TOKENS, ToolRegistry, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, attachDepWatcherBridge, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, createDelegateTool, FLEET_ROSTER, createMcpControlTool, startTechStackConsumer, startPackageOutdatedWatcher, recordFileAction, createAutonomyBrain, DefaultPluginAPI, SpecVersioning, wstackGlobalRoot, DEFAULT_CONTEXT_WINDOW_MODE_ID, recentTextTurns, enhanceUserPrompt, projectSlug, DefaultSystemPromptBuilder, mutateTasks, loadTasks, resolveContextWindowPolicy, repairToolUseAdjacency, mutatePlan, setPlanItemStatus, getPlanTemplate, loadPlan, emptyPlan, addPlanItem, savePlan, DefaultLogger, DefaultModelsRegistry, isStdinTTY, 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, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, writeOut, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, CHIMERA_REVIEW_PROMPT, noOpVault, decryptConfigSecrets, encryptConfigSecrets, atomicWrite, 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, formatTodosList, formatTaskList, formatTaskProgress, formatPlan, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, onResize, ERROR_CODES, FsError, ConfigError, InputBuilder, truncate, estimateMessageTokens, AGENTS_BY_PHASE, validateAgainstSchema, resolveMailboxIdentity, isSecretField as isSecretField$1 } from '@wrongstack/core';
|
|
5
|
+
import { color, writeErr, loadPlugins, renderProgress, SpecStore, TaskGraphStore, analyzeCriticalPath, getTemplate, listTemplates, templateToMarkdown, SpecParser, renderSpecAnalysis, AISpecBuilder, expectDefined, DefaultTaskStore, TaskTracker, renderTaskGraph, withFileLock, DefaultSecretScrubber, resolveProjectDir, GlobalMailbox, TOKENS, ToolRegistry, resolveSessionLoggingConfig, createSessionEventBridge, HookRegistry, HookRunner, SlashCommandRegistry, attachDepWatcherBridge, SessionMemoryConsolidator, BrainDecisionQueue, ObservableBrainArbiter, HumanEscalatingBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, createDelegateTool, FLEET_ROSTER, createMcpControlTool, startTechStackConsumer, startPackageOutdatedWatcher, recordFileAction, createAutonomyBrain, DefaultPluginAPI, SpecVersioning, wstackGlobalRoot, DEFAULT_CONTEXT_WINDOW_MODE_ID, recentTextTurns, enhanceUserPrompt, projectSlug, DefaultSystemPromptBuilder, mutateTasks, loadTasks, resolveContextWindowPolicy, repairToolUseAdjacency, mutatePlan, setPlanItemStatus, getPlanTemplate, loadPlan, emptyPlan, addPlanItem, savePlan, DefaultLogger, DefaultModelsRegistry, isStdinTTY, 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, resolveAuditLevel, AutoCompactionMiddleware, estimateRequestTokensCalibrated, Agent, FleetManager, makeDirectorSessionFactory, Director, makeFleetEmitTool, makeFleetStatusTool, resolveModelMatrix, DEFAULT_SUBAGENT_BASELINE, AutoApprovePermissionPolicy, PhaseStore, AutoPhasePlanner, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, makeLLMClassifier, writeOut, ParallelEternalEngine, EternalAutonomyEngine, allServers as allServers$1, CHIMERA_REVIEW_PROMPT, AutonomousCoordinator, noOpVault, decryptConfigSecrets, encryptConfigSecrets, atomicWrite, 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, formatTodosList, formatTaskList, formatTaskProgress, formatPlan, SessionRecovery, loadGoal, goalFilePath, summarizeUsage, saveGoal, formatGoal, emptyGoal, buildGoalPreamble, pendingBtwCount, setBtwNote, MATRIX_PHASE_KEYS, matrixKeyKind, phaseForRole, onResize, ERROR_CODES, FsError, ConfigError, InputBuilder, truncate, estimateMessageTokens, AGENTS_BY_PHASE, validateAgainstSchema, resolveMailboxIdentity, isSecretField as isSecretField$1 } from '@wrongstack/core';
|
|
6
6
|
import { DefaultSecretVault, encryptConfigSecrets as encryptConfigSecrets$1, decryptConfigSecrets as decryptConfigSecrets$1, isSecretField } from '@wrongstack/core/security';
|
|
7
7
|
import * as crypto3 from 'crypto';
|
|
8
8
|
import { createHash, randomBytes, randomUUID } from 'crypto';
|
|
@@ -11,8 +11,10 @@ import * as os from 'os';
|
|
|
11
11
|
import os__default from 'os';
|
|
12
12
|
import { findFreePort, AutoPhaseWebSocketHandler, handleShellOpen, handleMemoryForget, handleMemoryRemember, handleMemoryList, handleFilesWrite, handleFilesRead, handleFilesTree, handleFilesList, createEternalSubscription, createHttpServer, registerInstance, openBrowser, unregisterInstance, estimateTokens as estimateTokens$1, stringifyContent, messagePreview, messageTokens, createCustomModeStore } from '@wrongstack/webui/server';
|
|
13
13
|
import { makeProviderFromConfig, capabilitiesFor, buildProviderFactoriesFromRegistry } from '@wrongstack/providers';
|
|
14
|
+
import { toErrorMessage } from '@wrongstack/core/utils';
|
|
14
15
|
import { getProcessRegistry, builtinToolsPack, TIER1_TOOLS, rememberTool, forgetTool, searchMemoryTool, relatedMemoryTool, runStartupIndex, isIndexableFile, enqueueReindex, cancelPendingReindexes, shutdownCodebaseIndexHost, resetIndexCircuitBreaker } from '@wrongstack/tools';
|
|
15
16
|
import { DefaultSessionStore } from '@wrongstack/core/storage';
|
|
17
|
+
import { probeLocalLlm } from '@wrongstack/runtime/probe';
|
|
16
18
|
import { WebSocketServer, WebSocket } from 'ws';
|
|
17
19
|
import { spawn, execFile, execFileSync } from 'child_process';
|
|
18
20
|
import { MCPRegistry, MCPServer, serveHttp, serveStdio } from '@wrongstack/mcp';
|
|
@@ -21,10 +23,10 @@ import { writeFileSync, existsSync, readFileSync } from 'fs';
|
|
|
21
23
|
import { fileURLToPath } from 'url';
|
|
22
24
|
import { createDefaultContainer, routeImagesForModel, readClipboardImage } from '@wrongstack/runtime';
|
|
23
25
|
import * as readline from 'readline';
|
|
26
|
+
import { ACP_AGENT_COMMANDS, makeACPSubagentRunner, runEnsemble, renderEnsembleText, EnsembleRegistry, makeACPSubagentRunnerWithStop, findAgentDescriptor } from '@wrongstack/acp';
|
|
24
27
|
import { parseNextSteps } from '@wrongstack/tui';
|
|
25
|
-
import { ACP_AGENT_COMMANDS, makeACPSubagentRunner, makeACPSubagentRunnerWithStop } from '@wrongstack/acp';
|
|
26
28
|
import { WrongStackACPServer } from '@wrongstack/acp/agent';
|
|
27
|
-
import {
|
|
29
|
+
import { SubagentBudget } from '@wrongstack/core/coordination';
|
|
28
30
|
import { loadBenchConfig, reportHeaderLine, readSummary, renderMarkdownReport, createPolyglotSuite, createSwebenchSuite, runBenchmark, writeJsonArtifacts, collectCellPredictions, writePredictionsJsonl, gradePolyglot, gradeSwebench } from '@wrongstack/bench';
|
|
29
31
|
import { allServers } from '@wrongstack/core/infrastructure';
|
|
30
32
|
import { ToolExecutor } from '@wrongstack/core/execution';
|
|
@@ -372,26 +374,26 @@ function fmtDuration(ms) {
|
|
|
372
374
|
const remMin = m - h * 60;
|
|
373
375
|
return `${h}h${remMin}m`;
|
|
374
376
|
}
|
|
375
|
-
function fmtTaskResultLine(r,
|
|
377
|
+
function fmtTaskResultLine(r, color74) {
|
|
376
378
|
const stats = `${r.iterations}it ${r.toolCalls}tc ${fmtDuration(r.durationMs)}`;
|
|
377
379
|
const errMsg = typeof r.error === "string" ? r.error : r.error?.message;
|
|
378
380
|
const errKind = typeof r.error === "object" ? r.error?.kind : void 0;
|
|
379
381
|
const errTail = errMsg ? ` \u2014 ${errMsg.replace(/\s+/g, " ").slice(0, 80)}${errMsg.length > 80 ? "\u2026" : ""}` : "";
|
|
380
|
-
const errKindChip = errKind ?
|
|
381
|
-
const errSnip = errMsg || errKind ? `${errKindChip}${
|
|
382
|
+
const errKindChip = errKind ? color74.dim(` [${errKind}]`) : "";
|
|
383
|
+
const errSnip = errMsg || errKind ? `${errKindChip}${color74.dim(errTail)}` : "";
|
|
382
384
|
switch (r.status) {
|
|
383
385
|
case "success":
|
|
384
|
-
return { mark:
|
|
386
|
+
return { mark: color74.green("\u2713"), stats, tail: "" };
|
|
385
387
|
case "timeout":
|
|
386
388
|
return {
|
|
387
|
-
mark:
|
|
388
|
-
stats: `${
|
|
389
|
+
mark: color74.yellow("\u23F1"),
|
|
390
|
+
stats: `${color74.yellow("timeout")} ${stats}`,
|
|
389
391
|
tail: errSnip
|
|
390
392
|
};
|
|
391
393
|
case "stopped":
|
|
392
|
-
return { mark:
|
|
394
|
+
return { mark: color74.dim("\u2298"), stats: `${color74.dim("stopped")} ${stats}`, tail: errSnip };
|
|
393
395
|
case "failed":
|
|
394
|
-
return { mark:
|
|
396
|
+
return { mark: color74.red("\u2717"), stats: `${color74.red("failed")} ${stats}`, tail: errSnip };
|
|
395
397
|
}
|
|
396
398
|
}
|
|
397
399
|
var init_utils = __esm({
|
|
@@ -2908,7 +2910,7 @@ async function handleModesList(ctx, ws) {
|
|
|
2908
2910
|
payload: {
|
|
2909
2911
|
modes: [],
|
|
2910
2912
|
activeId: "default",
|
|
2911
|
-
error:
|
|
2913
|
+
error: toErrorMessage(err)
|
|
2912
2914
|
}
|
|
2913
2915
|
});
|
|
2914
2916
|
}
|
|
@@ -2931,7 +2933,7 @@ async function handleModeSwitch(ctx, ws, id) {
|
|
|
2931
2933
|
const payload = await ctx.buildSessionStart({ mode: id });
|
|
2932
2934
|
ctx.broadcast({ type: "session.start", payload });
|
|
2933
2935
|
} catch (err) {
|
|
2934
|
-
sendResult(ctx, ws, false,
|
|
2936
|
+
sendResult(ctx, ws, false, toErrorMessage(err));
|
|
2935
2937
|
}
|
|
2936
2938
|
}
|
|
2937
2939
|
async function handleModelSwitch(ctx, ws, payload) {
|
|
@@ -2950,7 +2952,7 @@ async function handleModelSwitch(ctx, ws, payload) {
|
|
|
2950
2952
|
ctx,
|
|
2951
2953
|
ws,
|
|
2952
2954
|
false,
|
|
2953
|
-
`Switch failed: ${
|
|
2955
|
+
`Switch failed: ${toErrorMessage(err)}`
|
|
2954
2956
|
);
|
|
2955
2957
|
}
|
|
2956
2958
|
}
|
|
@@ -2999,7 +3001,7 @@ async function handleModelRefine(ctx, ws, text) {
|
|
|
2999
3001
|
payload: {
|
|
3000
3002
|
refined: text,
|
|
3001
3003
|
english: text,
|
|
3002
|
-
error:
|
|
3004
|
+
error: toErrorMessage(err)
|
|
3003
3005
|
}
|
|
3004
3006
|
});
|
|
3005
3007
|
}
|
|
@@ -3009,8 +3011,6 @@ var init_agent_config = __esm({
|
|
|
3009
3011
|
init_provider_config();
|
|
3010
3012
|
}
|
|
3011
3013
|
});
|
|
3012
|
-
|
|
3013
|
-
// src/webui-server/ws-handlers/brain.ts
|
|
3014
3014
|
function sendResult2(ctx, ws, success, message) {
|
|
3015
3015
|
ctx.send(ws, { type: "key.operation_result", payload: { success, message } });
|
|
3016
3016
|
}
|
|
@@ -3064,7 +3064,7 @@ async function handleBrainAsk(ctx, ws, question) {
|
|
|
3064
3064
|
ctx,
|
|
3065
3065
|
ws,
|
|
3066
3066
|
false,
|
|
3067
|
-
`Brain consultation failed: ${
|
|
3067
|
+
`Brain consultation failed: ${toErrorMessage(err)}`
|
|
3068
3068
|
);
|
|
3069
3069
|
}
|
|
3070
3070
|
}
|
|
@@ -3072,8 +3072,6 @@ var init_brain = __esm({
|
|
|
3072
3072
|
"src/webui-server/ws-handlers/brain.ts"() {
|
|
3073
3073
|
}
|
|
3074
3074
|
});
|
|
3075
|
-
|
|
3076
|
-
// src/webui-server/ws-handlers/connection.ts
|
|
3077
3075
|
async function handleUserMessage(ctx, ws, content) {
|
|
3078
3076
|
if (ctx.abortControllers.has(ws)) {
|
|
3079
3077
|
ctx.send(ws, {
|
|
@@ -3106,7 +3104,7 @@ async function handleUserMessage(ctx, ws, content) {
|
|
|
3106
3104
|
type: "error",
|
|
3107
3105
|
payload: {
|
|
3108
3106
|
phase: "agent.run",
|
|
3109
|
-
message:
|
|
3107
|
+
message: toErrorMessage(err)
|
|
3110
3108
|
}
|
|
3111
3109
|
});
|
|
3112
3110
|
} finally {
|
|
@@ -3355,8 +3353,6 @@ var init_cost_helpers = __esm({
|
|
|
3355
3353
|
"src/webui-server/cost-helpers.ts"() {
|
|
3356
3354
|
}
|
|
3357
3355
|
});
|
|
3358
|
-
|
|
3359
|
-
// src/webui-server/ws-handlers/introspection.ts
|
|
3360
3356
|
async function handleSkillsList(ctx, ws) {
|
|
3361
3357
|
if (!ctx.skillLoader) {
|
|
3362
3358
|
ctx.send(ws, { type: "skills.list", payload: { skills: [], enabled: false } });
|
|
@@ -3387,7 +3383,7 @@ async function handleSkillsList(ctx, ws) {
|
|
|
3387
3383
|
payload: {
|
|
3388
3384
|
skills: [],
|
|
3389
3385
|
enabled: true,
|
|
3390
|
-
error:
|
|
3386
|
+
error: toErrorMessage(err)
|
|
3391
3387
|
}
|
|
3392
3388
|
});
|
|
3393
3389
|
}
|
|
@@ -3644,7 +3640,7 @@ async function handleProjectsSelect(ctx, ws, payload) {
|
|
|
3644
3640
|
const switchedP = await ctx.buildSessionStart({ reset: true, clearedSessionId: oldSessionId });
|
|
3645
3641
|
ctx.broadcast({ type: "session.start", payload: switchedP });
|
|
3646
3642
|
} catch (err) {
|
|
3647
|
-
sendResult6(ctx, ws, false,
|
|
3643
|
+
sendResult6(ctx, ws, false, toErrorMessage(err));
|
|
3648
3644
|
}
|
|
3649
3645
|
}
|
|
3650
3646
|
async function handleProjectsAdd(ctx, ws, payload) {
|
|
@@ -3684,7 +3680,7 @@ async function handleProjectsAdd(ctx, ws, payload) {
|
|
|
3684
3680
|
name: path39.basename(addRoot),
|
|
3685
3681
|
root: addRoot,
|
|
3686
3682
|
slug: "",
|
|
3687
|
-
message:
|
|
3683
|
+
message: toErrorMessage(err)
|
|
3688
3684
|
}
|
|
3689
3685
|
});
|
|
3690
3686
|
}
|
|
@@ -3706,7 +3702,7 @@ async function handleWorkingDirSet(ctx, ws, newPath) {
|
|
|
3706
3702
|
ctx.broadcast({ type: "working_dir.changed", payload: { cwd: resolved, projectRoot: wdRoot } });
|
|
3707
3703
|
sendResult6(ctx, ws, true, `Working directory set to ${resolved}`);
|
|
3708
3704
|
} catch (err) {
|
|
3709
|
-
sendResult6(ctx, ws, false,
|
|
3705
|
+
sendResult6(ctx, ws, false, toErrorMessage(err));
|
|
3710
3706
|
}
|
|
3711
3707
|
}
|
|
3712
3708
|
var init_projects = __esm({
|
|
@@ -3714,11 +3710,27 @@ var init_projects = __esm({
|
|
|
3714
3710
|
init_project_utils();
|
|
3715
3711
|
}
|
|
3716
3712
|
});
|
|
3717
|
-
|
|
3718
|
-
// src/webui-server/ws-handlers/providers.ts
|
|
3719
3713
|
function sendResult7(ctx, ws, success, message) {
|
|
3720
3714
|
ctx.send(ws, { type: "key.operation_result", payload: { success, message } });
|
|
3721
3715
|
}
|
|
3716
|
+
function broadcastSaved(ctx, providers) {
|
|
3717
|
+
ctx.broadcast({
|
|
3718
|
+
type: "providers.saved",
|
|
3719
|
+
payload: {
|
|
3720
|
+
providers: Object.entries(providers).map(([id, cfg]) => ({
|
|
3721
|
+
id,
|
|
3722
|
+
family: cfg.family,
|
|
3723
|
+
baseUrl: cfg.baseUrl,
|
|
3724
|
+
apiKeys: normalizeKeys(cfg).map((k) => ({
|
|
3725
|
+
label: k.label,
|
|
3726
|
+
maskedKey: maskedKey(k.apiKey),
|
|
3727
|
+
isActive: k.label === cfg.activeKey,
|
|
3728
|
+
createdAt: k.createdAt
|
|
3729
|
+
}))
|
|
3730
|
+
}))
|
|
3731
|
+
}
|
|
3732
|
+
});
|
|
3733
|
+
}
|
|
3722
3734
|
async function handleProvidersList(ctx, ws) {
|
|
3723
3735
|
if (!ctx.modelsRegistry) {
|
|
3724
3736
|
sendResult7(ctx, ws, false, "Models registry not available");
|
|
@@ -3743,7 +3755,7 @@ async function handleProvidersList(ctx, ws) {
|
|
|
3743
3755
|
}
|
|
3744
3756
|
});
|
|
3745
3757
|
} catch (err) {
|
|
3746
|
-
sendResult7(ctx, ws, false,
|
|
3758
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3747
3759
|
}
|
|
3748
3760
|
}
|
|
3749
3761
|
async function handleProviderModels(ctx, ws, providerId) {
|
|
@@ -3778,7 +3790,7 @@ async function handleProviderModels(ctx, ws, providerId) {
|
|
|
3778
3790
|
}
|
|
3779
3791
|
});
|
|
3780
3792
|
} catch (err) {
|
|
3781
|
-
sendResult7(ctx, ws, false,
|
|
3793
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3782
3794
|
}
|
|
3783
3795
|
}
|
|
3784
3796
|
async function handleProvidersSaved(ctx, ws) {
|
|
@@ -3801,7 +3813,7 @@ async function handleProvidersSaved(ctx, ws) {
|
|
|
3801
3813
|
}
|
|
3802
3814
|
});
|
|
3803
3815
|
} catch (err) {
|
|
3804
|
-
sendResult7(ctx, ws, false,
|
|
3816
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3805
3817
|
}
|
|
3806
3818
|
}
|
|
3807
3819
|
async function handleKeyUpsert(ctx, ws, providerId, label, apiKey) {
|
|
@@ -3821,7 +3833,7 @@ async function handleKeyUpsert(ctx, ws, providerId, label, apiKey) {
|
|
|
3821
3833
|
await ctx.providerStore.save(providers);
|
|
3822
3834
|
sendResult7(ctx, ws, true, `Key "${label}" saved for ${providerId}`);
|
|
3823
3835
|
} catch (err) {
|
|
3824
|
-
sendResult7(ctx, ws, false,
|
|
3836
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3825
3837
|
}
|
|
3826
3838
|
}
|
|
3827
3839
|
async function handleKeyDelete(ctx, ws, providerId, label) {
|
|
@@ -3845,7 +3857,7 @@ async function handleKeyDelete(ctx, ws, providerId, label) {
|
|
|
3845
3857
|
await ctx.providerStore.save(providers);
|
|
3846
3858
|
sendResult7(ctx, ws, true, `Key "${label}" deleted from ${providerId}`);
|
|
3847
3859
|
} catch (err) {
|
|
3848
|
-
sendResult7(ctx, ws, false,
|
|
3860
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3849
3861
|
}
|
|
3850
3862
|
}
|
|
3851
3863
|
async function handleKeySetActive(ctx, ws, providerId, label) {
|
|
@@ -3862,7 +3874,7 @@ async function handleKeySetActive(ctx, ws, providerId, label) {
|
|
|
3862
3874
|
await ctx.providerStore.save(providers);
|
|
3863
3875
|
sendResult7(ctx, ws, true, `Active key for ${providerId} set to "${label}"`);
|
|
3864
3876
|
} catch (err) {
|
|
3865
|
-
sendResult7(ctx, ws, false,
|
|
3877
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3866
3878
|
}
|
|
3867
3879
|
}
|
|
3868
3880
|
async function handleProviderAdd(ctx, ws, payload) {
|
|
@@ -3907,7 +3919,7 @@ async function handleProviderAdd(ctx, ws, payload) {
|
|
|
3907
3919
|
}
|
|
3908
3920
|
});
|
|
3909
3921
|
} catch (err) {
|
|
3910
|
-
sendResult7(ctx, ws, false,
|
|
3922
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3911
3923
|
}
|
|
3912
3924
|
}
|
|
3913
3925
|
async function handleProviderRemove(ctx, ws, providerId) {
|
|
@@ -3921,12 +3933,92 @@ async function handleProviderRemove(ctx, ws, providerId) {
|
|
|
3921
3933
|
await ctx.providerStore.save(providers);
|
|
3922
3934
|
sendResult7(ctx, ws, true, `Provider "${providerId}" removed`);
|
|
3923
3935
|
} catch (err) {
|
|
3924
|
-
sendResult7(ctx, ws, false,
|
|
3936
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
async function handleProviderClearModels(ctx, ws, providerId) {
|
|
3940
|
+
try {
|
|
3941
|
+
const providers = await ctx.providerStore.load();
|
|
3942
|
+
const cfg = providers[providerId];
|
|
3943
|
+
if (!cfg) {
|
|
3944
|
+
sendResult7(ctx, ws, false, `Unknown provider "${providerId}"`);
|
|
3945
|
+
return;
|
|
3946
|
+
}
|
|
3947
|
+
delete cfg.models;
|
|
3948
|
+
await ctx.providerStore.save(providers);
|
|
3949
|
+
sendResult7(ctx, ws, true, `Cleared model allowlist for ${providerId}`);
|
|
3950
|
+
broadcastSaved(ctx, providers);
|
|
3951
|
+
} catch (err) {
|
|
3952
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3955
|
+
async function handleProviderUndoClear(ctx, ws, providerId, previousModels) {
|
|
3956
|
+
try {
|
|
3957
|
+
const providers = await ctx.providerStore.load();
|
|
3958
|
+
const cfg = providers[providerId];
|
|
3959
|
+
if (!cfg) {
|
|
3960
|
+
sendResult7(ctx, ws, false, `Unknown provider "${providerId}"`);
|
|
3961
|
+
return;
|
|
3962
|
+
}
|
|
3963
|
+
cfg.models = [...previousModels];
|
|
3964
|
+
await ctx.providerStore.save(providers);
|
|
3965
|
+
sendResult7(ctx, ws, true, `Restored ${previousModels.length} model(s) for ${providerId}`);
|
|
3966
|
+
broadcastSaved(ctx, providers);
|
|
3967
|
+
} catch (err) {
|
|
3968
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3969
|
+
}
|
|
3970
|
+
}
|
|
3971
|
+
async function handleProviderUpdate(ctx, ws, payload) {
|
|
3972
|
+
try {
|
|
3973
|
+
const providers = await ctx.providerStore.load();
|
|
3974
|
+
const cfg = providers[payload.id];
|
|
3975
|
+
if (!cfg) {
|
|
3976
|
+
sendResult7(ctx, ws, false, `Unknown provider "${payload.id}"`);
|
|
3977
|
+
return;
|
|
3978
|
+
}
|
|
3979
|
+
if (payload.family !== void 0) cfg.family = payload.family;
|
|
3980
|
+
if (payload.baseUrl !== void 0) cfg.baseUrl = payload.baseUrl;
|
|
3981
|
+
if (payload.envVars !== void 0) cfg.envVars = payload.envVars;
|
|
3982
|
+
if (payload.models !== void 0) cfg.models = payload.models;
|
|
3983
|
+
await ctx.providerStore.save(providers);
|
|
3984
|
+
sendResult7(ctx, ws, true, `Updated ${payload.id}`);
|
|
3985
|
+
broadcastSaved(ctx, providers);
|
|
3986
|
+
} catch (err) {
|
|
3987
|
+
sendResult7(ctx, ws, false, toErrorMessage(err));
|
|
3988
|
+
}
|
|
3989
|
+
}
|
|
3990
|
+
async function handleProviderProbe(ctx, ws, providerId, timeoutMs) {
|
|
3991
|
+
const reply = (payload) => ctx.send(ws, { type: "provider.probe", payload: { providerId, ...payload } });
|
|
3992
|
+
try {
|
|
3993
|
+
const providers = await ctx.providerStore.load();
|
|
3994
|
+
const cfg = providers[providerId];
|
|
3995
|
+
if (!cfg) {
|
|
3996
|
+
reply({ ok: false, status: "no_provider" });
|
|
3997
|
+
return;
|
|
3998
|
+
}
|
|
3999
|
+
if (!cfg.baseUrl) {
|
|
4000
|
+
reply({ ok: false, status: "no_base_url" });
|
|
4001
|
+
return;
|
|
4002
|
+
}
|
|
4003
|
+
const keys = normalizeKeys(cfg);
|
|
4004
|
+
const active = keys.find((k) => k.label === cfg.activeKey) ?? keys[0];
|
|
4005
|
+
const result = await probeLocalLlm({
|
|
4006
|
+
baseUrl: cfg.baseUrl,
|
|
4007
|
+
apiKey: active?.apiKey,
|
|
4008
|
+
noAuth: false,
|
|
4009
|
+
scrubber: probeScrubber,
|
|
4010
|
+
...timeoutMs !== void 0 ? { timeoutMs } : {}
|
|
4011
|
+
});
|
|
4012
|
+
reply(result);
|
|
4013
|
+
} catch (err) {
|
|
4014
|
+
reply({ ok: false, status: "unreachable", detail: toErrorMessage(err) });
|
|
3925
4015
|
}
|
|
3926
4016
|
}
|
|
4017
|
+
var probeScrubber;
|
|
3927
4018
|
var init_providers = __esm({
|
|
3928
4019
|
"src/webui-server/ws-handlers/providers.ts"() {
|
|
3929
4020
|
init_provider_config();
|
|
4021
|
+
probeScrubber = new DefaultSecretScrubber();
|
|
3930
4022
|
}
|
|
3931
4023
|
});
|
|
3932
4024
|
function sendResult8(ctx, ws, success, message) {
|
|
@@ -3968,7 +4060,7 @@ async function handleSessionsList(ctx, ws, limit) {
|
|
|
3968
4060
|
} catch (err) {
|
|
3969
4061
|
ctx.send(ws, {
|
|
3970
4062
|
type: "sessions.list",
|
|
3971
|
-
payload: { sessions: [], error:
|
|
4063
|
+
payload: { sessions: [], error: toErrorMessage(err) }
|
|
3972
4064
|
});
|
|
3973
4065
|
}
|
|
3974
4066
|
}
|
|
@@ -4000,7 +4092,7 @@ async function handleSessionNew(ctx, _ws) {
|
|
|
4000
4092
|
JSON.stringify({
|
|
4001
4093
|
level: "warn",
|
|
4002
4094
|
event: "webui.session_new_store_failed",
|
|
4003
|
-
message:
|
|
4095
|
+
message: toErrorMessage(err),
|
|
4004
4096
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
4005
4097
|
})
|
|
4006
4098
|
);
|
|
@@ -4040,7 +4132,7 @@ async function handleSessionRewind(ctx, ws, checkpointIndex) {
|
|
|
4040
4132
|
const payload = await ctx.buildSessionStart({ reset: true });
|
|
4041
4133
|
ctx.broadcast({ type: "session.start", payload });
|
|
4042
4134
|
} catch (err) {
|
|
4043
|
-
sendResult8(ctx, ws, false,
|
|
4135
|
+
sendResult8(ctx, ws, false, toErrorMessage(err));
|
|
4044
4136
|
}
|
|
4045
4137
|
}
|
|
4046
4138
|
async function handleSessionDelete(ctx, ws, id) {
|
|
@@ -4052,7 +4144,7 @@ async function handleSessionDelete(ctx, ws, id) {
|
|
|
4052
4144
|
await storeFor(ctx.opts).delete(id);
|
|
4053
4145
|
sendResult8(ctx, ws, true, `Session ${id} deleted`);
|
|
4054
4146
|
} catch (err) {
|
|
4055
|
-
sendResult8(ctx, ws, false,
|
|
4147
|
+
sendResult8(ctx, ws, false, toErrorMessage(err));
|
|
4056
4148
|
}
|
|
4057
4149
|
}
|
|
4058
4150
|
function handleSessionSave(ctx, ws) {
|
|
@@ -4095,7 +4187,7 @@ async function handleSessionResume(ctx, ws, id) {
|
|
|
4095
4187
|
ctx.broadcast({ type: "session.start", payload });
|
|
4096
4188
|
sendResult8(ctx, ws, true, `Resumed session ${id}`);
|
|
4097
4189
|
} catch (err) {
|
|
4098
|
-
sendResult8(ctx, ws, false,
|
|
4190
|
+
sendResult8(ctx, ws, false, toErrorMessage(err));
|
|
4099
4191
|
}
|
|
4100
4192
|
}
|
|
4101
4193
|
var init_sessions = __esm({
|
|
@@ -5227,6 +5319,31 @@ async function runWebUI(opts) {
|
|
|
5227
5319
|
await handleProviderRemove(wsHandlerCtx, ws, m.payload.providerId);
|
|
5228
5320
|
break;
|
|
5229
5321
|
}
|
|
5322
|
+
case "provider.clear_models": {
|
|
5323
|
+
const m = msg;
|
|
5324
|
+
await handleProviderClearModels(wsHandlerCtx, ws, m.payload.providerId);
|
|
5325
|
+
break;
|
|
5326
|
+
}
|
|
5327
|
+
case "provider.undo_clear": {
|
|
5328
|
+
const m = msg;
|
|
5329
|
+
await handleProviderUndoClear(
|
|
5330
|
+
wsHandlerCtx,
|
|
5331
|
+
ws,
|
|
5332
|
+
m.payload.providerId,
|
|
5333
|
+
m.payload.previousModels
|
|
5334
|
+
);
|
|
5335
|
+
break;
|
|
5336
|
+
}
|
|
5337
|
+
case "provider.update": {
|
|
5338
|
+
const m = msg;
|
|
5339
|
+
await handleProviderUpdate(wsHandlerCtx, ws, m.payload);
|
|
5340
|
+
break;
|
|
5341
|
+
}
|
|
5342
|
+
case "provider.probe": {
|
|
5343
|
+
const m = msg;
|
|
5344
|
+
await handleProviderProbe(wsHandlerCtx, ws, m.payload.providerId, m.payload.timeoutMs);
|
|
5345
|
+
break;
|
|
5346
|
+
}
|
|
5230
5347
|
case "todos.get": {
|
|
5231
5348
|
handleTodosGet(worklistCtx, ws);
|
|
5232
5349
|
break;
|
|
@@ -5501,11 +5618,16 @@ async function runWebUI(opts) {
|
|
|
5501
5618
|
break;
|
|
5502
5619
|
}
|
|
5503
5620
|
// Collaboration messages — the CLI webui-server doesn't run a
|
|
5504
|
-
// full collab hub; silently acknowledge and ignore.
|
|
5621
|
+
// full collab hub; silently acknowledge and ignore. request_pause /
|
|
5622
|
+
// resume are included so the CollabPanel's pause/resume buttons don't
|
|
5623
|
+
// trip the "Unhandled message type" warning (the standalone webui
|
|
5624
|
+
// server is the one that wires the real CollaborationWebSocketHandler).
|
|
5505
5625
|
case "collab.join":
|
|
5506
5626
|
case "collab.leave":
|
|
5507
5627
|
case "collab.annotate":
|
|
5508
5628
|
case "collab.resolve":
|
|
5629
|
+
case "collab.request_pause":
|
|
5630
|
+
case "collab.resume":
|
|
5509
5631
|
break;
|
|
5510
5632
|
case "projects.list": {
|
|
5511
5633
|
await handleProjectsList(projectsCtx, ws);
|
|
@@ -5664,6 +5786,57 @@ async function runWebUI(opts) {
|
|
|
5664
5786
|
}
|
|
5665
5787
|
break;
|
|
5666
5788
|
}
|
|
5789
|
+
case "mailbox.purge": {
|
|
5790
|
+
const projectRoot = opts.projectRoot ?? opts.agent.ctx.projectRoot ?? "";
|
|
5791
|
+
const globalRoot = opts.globalConfigPath ? path39.dirname(opts.globalConfigPath) : "";
|
|
5792
|
+
if (!projectRoot || !globalRoot) {
|
|
5793
|
+
send(ws, { type: "mailbox.purged", payload: { error: "No project root available" } });
|
|
5794
|
+
break;
|
|
5795
|
+
}
|
|
5796
|
+
try {
|
|
5797
|
+
const mbDir = resolveProjectDir(projectRoot, globalRoot);
|
|
5798
|
+
const mb = new GlobalMailbox(mbDir);
|
|
5799
|
+
const payload = msg;
|
|
5800
|
+
const result = await mb.purgeStale(payload.payload);
|
|
5801
|
+
send(ws, { type: "mailbox.purged", payload: result });
|
|
5802
|
+
} catch (err) {
|
|
5803
|
+
send(ws, {
|
|
5804
|
+
type: "mailbox.purged",
|
|
5805
|
+
payload: { error: err instanceof Error ? err.message : String(err) }
|
|
5806
|
+
});
|
|
5807
|
+
}
|
|
5808
|
+
break;
|
|
5809
|
+
}
|
|
5810
|
+
case "git.info": {
|
|
5811
|
+
const projectRoot = opts.projectRoot ?? opts.agent.ctx.projectRoot ?? "";
|
|
5812
|
+
const cwd = projectRoot || void 0;
|
|
5813
|
+
const { execFile: ef } = await import('child_process');
|
|
5814
|
+
const git = (args) => new Promise((resolve11) => {
|
|
5815
|
+
ef("git", args, { cwd, timeout: 3e3 }, (err, stdout) => {
|
|
5816
|
+
resolve11(err ? "" : stdout.trim());
|
|
5817
|
+
});
|
|
5818
|
+
});
|
|
5819
|
+
const [branchRaw, diffRaw, statusRaw, upstreamRaw] = await Promise.all([
|
|
5820
|
+
git(["branch", "--show-current"]),
|
|
5821
|
+
git(["diff", "--stat"]),
|
|
5822
|
+
git(["status", "--porcelain"]),
|
|
5823
|
+
git(["rev-list", "--left-right", "--count", "@{upstream}...HEAD"])
|
|
5824
|
+
]);
|
|
5825
|
+
const branch = branchRaw || "(detached)";
|
|
5826
|
+
const addMatch = /(\d+)\s+insertion/i.exec(diffRaw);
|
|
5827
|
+
const delMatch = /(\d+)\s+deletion/i.exec(diffRaw);
|
|
5828
|
+
const added = addMatch ? Number(addMatch[1]) : 0;
|
|
5829
|
+
const deleted = delMatch ? Number(delMatch[1]) : 0;
|
|
5830
|
+
const untracked = statusRaw.split("\n").filter((l) => l.startsWith("??")).length;
|
|
5831
|
+
const [behindRaw, aheadRaw] = (upstreamRaw || "0 0").split(" ");
|
|
5832
|
+
const behind = Number(behindRaw) || 0;
|
|
5833
|
+
const ahead = Number(aheadRaw) || 0;
|
|
5834
|
+
send(ws, {
|
|
5835
|
+
type: "git.info",
|
|
5836
|
+
payload: { branch, added, deleted, untracked, ahead, behind }
|
|
5837
|
+
});
|
|
5838
|
+
break;
|
|
5839
|
+
}
|
|
5667
5840
|
default: {
|
|
5668
5841
|
const msgType = msg.type;
|
|
5669
5842
|
if (msgType.startsWith("autophase.")) {
|
|
@@ -6769,7 +6942,7 @@ async function ensureHistoryDir(homeFn = defaultHomeDir) {
|
|
|
6769
6942
|
await fsp5.mkdir(historyDir(homeFn), { recursive: true });
|
|
6770
6943
|
} catch (err) {
|
|
6771
6944
|
throw new FsError({
|
|
6772
|
-
message:
|
|
6945
|
+
message: toErrorMessage(err),
|
|
6773
6946
|
code: ERROR_CODES.FS_MKDIR_FAILED,
|
|
6774
6947
|
path: historyDir(homeFn),
|
|
6775
6948
|
cause: err
|
|
@@ -6790,7 +6963,7 @@ async function writeIndex(idx, homeFn = defaultHomeDir) {
|
|
|
6790
6963
|
await atomicWrite(historyIndexPath(homeFn), JSON.stringify(idx, null, 2));
|
|
6791
6964
|
} catch (err) {
|
|
6792
6965
|
throw new FsError({
|
|
6793
|
-
message:
|
|
6966
|
+
message: toErrorMessage(err),
|
|
6794
6967
|
code: ERROR_CODES.FS_ATOMIC_WRITE_FAILED,
|
|
6795
6968
|
path: historyIndexPath(homeFn),
|
|
6796
6969
|
cause: err
|
|
@@ -6811,7 +6984,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
|
|
|
6811
6984
|
await atomicWrite(last, content);
|
|
6812
6985
|
} catch (err) {
|
|
6813
6986
|
writeErr(
|
|
6814
|
-
`[config-history] .last backup failed: ${
|
|
6987
|
+
`[config-history] .last backup failed: ${toErrorMessage(err)}`
|
|
6815
6988
|
);
|
|
6816
6989
|
}
|
|
6817
6990
|
}
|
|
@@ -6821,7 +6994,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
|
|
|
6821
6994
|
await atomicWrite(bakPath, content);
|
|
6822
6995
|
} catch (err) {
|
|
6823
6996
|
writeErr(
|
|
6824
|
-
`[config-history] timestamped backup failed: ${
|
|
6997
|
+
`[config-history] timestamped backup failed: ${toErrorMessage(err)}`
|
|
6825
6998
|
);
|
|
6826
6999
|
}
|
|
6827
7000
|
}
|
|
@@ -6834,7 +7007,7 @@ async function backupCurrent(homeFn = defaultHomeDir) {
|
|
|
6834
7007
|
}
|
|
6835
7008
|
} catch (err) {
|
|
6836
7009
|
writeErr(
|
|
6837
|
-
`[config-history] backup prune failed: ${
|
|
7010
|
+
`[config-history] backup prune failed: ${toErrorMessage(err)}`
|
|
6838
7011
|
);
|
|
6839
7012
|
}
|
|
6840
7013
|
}
|
|
@@ -6857,7 +7030,7 @@ async function appendHistory(oldCfg, newCfg, description, homeFn = defaultHomeDi
|
|
|
6857
7030
|
);
|
|
6858
7031
|
} catch (err) {
|
|
6859
7032
|
throw new FsError({
|
|
6860
|
-
message:
|
|
7033
|
+
message: toErrorMessage(err),
|
|
6861
7034
|
code: ERROR_CODES.FS_WRITE_FAILED,
|
|
6862
7035
|
path: path39.join(historyDir(homeFn), `${id}.json`),
|
|
6863
7036
|
cause: err
|
|
@@ -6985,8 +7158,6 @@ async function buildPickableProviders(modelsRegistry, config) {
|
|
|
6985
7158
|
}
|
|
6986
7159
|
return out;
|
|
6987
7160
|
}
|
|
6988
|
-
|
|
6989
|
-
// src/picker.ts
|
|
6990
7161
|
var theme = { primary: color.amber };
|
|
6991
7162
|
async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => process.env.HOME ?? os__default.homedir()) {
|
|
6992
7163
|
try {
|
|
@@ -7008,7 +7179,7 @@ async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => p
|
|
|
7008
7179
|
JSON.stringify({
|
|
7009
7180
|
level: "warn",
|
|
7010
7181
|
event: "picker.backup_failed",
|
|
7011
|
-
message:
|
|
7182
|
+
message: toErrorMessage(err),
|
|
7012
7183
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
7013
7184
|
})
|
|
7014
7185
|
);
|
|
@@ -7029,7 +7200,7 @@ async function saveToGlobalConfig(configPath2, provider, model, homeFn = () => p
|
|
|
7029
7200
|
JSON.stringify({
|
|
7030
7201
|
level: "warn",
|
|
7031
7202
|
event: "picker.save_failed",
|
|
7032
|
-
message:
|
|
7203
|
+
message: toErrorMessage(err),
|
|
7033
7204
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
7034
7205
|
})
|
|
7035
7206
|
);
|
|
@@ -8027,7 +8198,7 @@ function buildCodebaseReindexCommand(opts) {
|
|
|
8027
8198
|
${color.yellow(` ${r.errors.length} file(s) had errors`)}` : "");
|
|
8028
8199
|
return { message: summary };
|
|
8029
8200
|
} catch (err) {
|
|
8030
|
-
const msg = `${color.red("Codebase reindex failed:")} ${
|
|
8201
|
+
const msg = `${color.red("Codebase reindex failed:")} ${toErrorMessage(err)}`;
|
|
8031
8202
|
return { message: msg };
|
|
8032
8203
|
}
|
|
8033
8204
|
}
|
|
@@ -8114,7 +8285,7 @@ async function historyCommand(opts, sessionId, args) {
|
|
|
8114
8285
|
} catch (err) {
|
|
8115
8286
|
return {
|
|
8116
8287
|
message: color.yellow(
|
|
8117
|
-
`Failed to read session: ${
|
|
8288
|
+
`Failed to read session: ${toErrorMessage(err)}`
|
|
8118
8289
|
)
|
|
8119
8290
|
};
|
|
8120
8291
|
}
|
|
@@ -8616,7 +8787,7 @@ async function spawnAgent(opts, role, _task, _name, header) {
|
|
|
8616
8787
|
opts.renderer.write(msg);
|
|
8617
8788
|
return { message: msg };
|
|
8618
8789
|
} catch (err) {
|
|
8619
|
-
const msg = `${color.red("\u2717 Spawn failed")}: ${
|
|
8790
|
+
const msg = `${color.red("\u2717 Spawn failed")}: ${toErrorMessage(err)}`;
|
|
8620
8791
|
opts.renderer.writeWarning(msg);
|
|
8621
8792
|
return { message: msg };
|
|
8622
8793
|
}
|
|
@@ -9415,7 +9586,7 @@ function buildDoctorCommand(opts) {
|
|
|
9415
9586
|
parsed = JSON.parse(raw);
|
|
9416
9587
|
} catch (err) {
|
|
9417
9588
|
errorCount++;
|
|
9418
|
-
const msg =
|
|
9589
|
+
const msg = toErrorMessage(err);
|
|
9419
9590
|
lines.push(` ${color.red("\u2717")} invalid JSON \u2014 ${msg}`);
|
|
9420
9591
|
if (!applyFixes) {
|
|
9421
9592
|
fixableCount++;
|
|
@@ -9554,6 +9725,65 @@ function buildEnhanceCommand(opts) {
|
|
|
9554
9725
|
}
|
|
9555
9726
|
};
|
|
9556
9727
|
}
|
|
9728
|
+
function buildEnsembleCommand(_opts) {
|
|
9729
|
+
return {
|
|
9730
|
+
name: "ensemble",
|
|
9731
|
+
category: "Agent",
|
|
9732
|
+
description: "Fan a task out to multiple ACP agents in parallel (claude-code, gemini-cli, codex-cli, etc.).",
|
|
9733
|
+
argsHint: "<agent-ids-csv> <task description>",
|
|
9734
|
+
help: [
|
|
9735
|
+
"Fan a single task out to multiple ACP-supporting agents in parallel.",
|
|
9736
|
+
"",
|
|
9737
|
+
"Usage:",
|
|
9738
|
+
" /ensemble <agent-ids-csv> <task description>",
|
|
9739
|
+
"",
|
|
9740
|
+
"Examples:",
|
|
9741
|
+
' /ensemble claude-code,gemini-cli "review this diff"',
|
|
9742
|
+
' /ensemble claude-code,codex-cli "refactor auth/session.ts"',
|
|
9743
|
+
' /ensemble claude-code,gemini-cli,codex-cli "explain the v1 protocol"',
|
|
9744
|
+
"",
|
|
9745
|
+
"Each agent runs in its own process. Agents not installed on the host",
|
|
9746
|
+
"are skipped with a warning. The command waits for all agents to finish",
|
|
9747
|
+
"and reports per-agent outcomes (success / failed / skipped / cancelled).",
|
|
9748
|
+
"",
|
|
9749
|
+
"Use /acp list (or wstack acp list) to see which agents are detected."
|
|
9750
|
+
].join("\n"),
|
|
9751
|
+
async run(args) {
|
|
9752
|
+
const trimmed = args.trim();
|
|
9753
|
+
if (!trimmed) {
|
|
9754
|
+
return {
|
|
9755
|
+
message: 'Usage: /ensemble <agent-ids-csv> <task description>\n\nExamples:\n /ensemble claude-code,gemini-cli "review this diff"\n /ensemble claude-code,codex-cli "refactor auth/session.ts"\n\nRun `wstack acp list` to see which agents are detected on this host.'
|
|
9756
|
+
};
|
|
9757
|
+
}
|
|
9758
|
+
const spaceIdx = trimmed.search(/\s/);
|
|
9759
|
+
if (spaceIdx === -1) {
|
|
9760
|
+
return {
|
|
9761
|
+
message: 'Task description is required.\n\nUsage: /ensemble <agent-ids-csv> <task description>\nExample: /ensemble claude-code,gemini-cli "explain this code"'
|
|
9762
|
+
};
|
|
9763
|
+
}
|
|
9764
|
+
const agentIds = trimmed.slice(0, spaceIdx);
|
|
9765
|
+
const task = stripSurroundingQuotes(trimmed.slice(spaceIdx + 1).trim());
|
|
9766
|
+
if (!task) {
|
|
9767
|
+
return { message: "Task description is required." };
|
|
9768
|
+
}
|
|
9769
|
+
try {
|
|
9770
|
+
const result = await runEnsemble({ agentIds, task });
|
|
9771
|
+
return { message: renderEnsembleText(result) };
|
|
9772
|
+
} catch (err) {
|
|
9773
|
+
return { message: `Ensemble failed: ${toErrorMessage(err)}` };
|
|
9774
|
+
}
|
|
9775
|
+
}
|
|
9776
|
+
};
|
|
9777
|
+
}
|
|
9778
|
+
function stripSurroundingQuotes(s) {
|
|
9779
|
+
if (s.length < 2) return s;
|
|
9780
|
+
const first = s[0];
|
|
9781
|
+
const last = s[s.length - 1];
|
|
9782
|
+
if ((first === '"' || first === "'") && first === last) {
|
|
9783
|
+
return s.slice(1, -1);
|
|
9784
|
+
}
|
|
9785
|
+
return s;
|
|
9786
|
+
}
|
|
9557
9787
|
function parseModelRef(ref) {
|
|
9558
9788
|
const trimmed = ref.trim();
|
|
9559
9789
|
const slash = trimmed.indexOf("/");
|
|
@@ -9854,7 +10084,7 @@ function buildFallbackCommand(opts) {
|
|
|
9854
10084
|
};
|
|
9855
10085
|
} catch (err) {
|
|
9856
10086
|
return {
|
|
9857
|
-
message: `${color.red("fallback error")}: ${
|
|
10087
|
+
message: `${color.red("fallback error")}: ${toErrorMessage(err)}`
|
|
9858
10088
|
};
|
|
9859
10089
|
}
|
|
9860
10090
|
}
|
|
@@ -11071,7 +11301,7 @@ async function handleSpawn(opts, subargs) {
|
|
|
11071
11301
|
const id = await opts.onFleetSpawn(role);
|
|
11072
11302
|
spawned.push(id);
|
|
11073
11303
|
} catch (err) {
|
|
11074
|
-
const warnMsg = `${color.red("\u2717 Spawn failed")} for slot ${i + 1}: ${
|
|
11304
|
+
const warnMsg = `${color.red("\u2717 Spawn failed")} for slot ${i + 1}: ${toErrorMessage(err)}`;
|
|
11075
11305
|
opts.renderer.writeWarning(warnMsg);
|
|
11076
11306
|
}
|
|
11077
11307
|
}
|
|
@@ -11125,7 +11355,7 @@ async function handleDispatch(opts, subargs) {
|
|
|
11125
11355
|
lines.push(` ${color.green("\u2713 spawned")} ${color.bold(decision.role)} as ${color.dim(id)}`);
|
|
11126
11356
|
} catch (err) {
|
|
11127
11357
|
lines.push(
|
|
11128
|
-
` ${color.amber("\u26A0 spawn failed:")} ${
|
|
11358
|
+
` ${color.amber("\u26A0 spawn failed:")} ${toErrorMessage(err)}`
|
|
11129
11359
|
);
|
|
11130
11360
|
}
|
|
11131
11361
|
} else {
|
|
@@ -11758,6 +11988,7 @@ function buildMailboxCommand(opts) {
|
|
|
11758
11988
|
" /mailbox broadcast <message> Message every agent on the project.",
|
|
11759
11989
|
" /mailbox history [n] Last n messages on the project (default 20).",
|
|
11760
11990
|
" /mailbox clear Delete all messages from the mailbox.",
|
|
11991
|
+
" /mailbox purge Remove stale/orphaned messages (completed >1d, incomplete >7d).",
|
|
11761
11992
|
"",
|
|
11762
11993
|
"Examples:",
|
|
11763
11994
|
" /mailbox broadcast pausing deploys, hold off on main",
|
|
@@ -11866,8 +12097,17 @@ function buildMailboxCommand(opts) {
|
|
|
11866
12097
|
await mb.clearAll();
|
|
11867
12098
|
return { message: color.green("\u2713 All messages deleted from the mailbox.") };
|
|
11868
12099
|
}
|
|
12100
|
+
if (sub === "purge") {
|
|
12101
|
+
const result = await mb.purgeStale();
|
|
12102
|
+
if (result.totalPurged === 0) {
|
|
12103
|
+
return { message: color.green("\u2713 No stale messages found. Mailbox is clean.") };
|
|
12104
|
+
}
|
|
12105
|
+
return {
|
|
12106
|
+
message: `\u2713 Purged ${result.totalPurged} message(s): ${result.completedPurged} completed, ${result.incompletePurged} incomplete. ${result.remaining} message(s) remain.`
|
|
12107
|
+
};
|
|
12108
|
+
}
|
|
11869
12109
|
return {
|
|
11870
|
-
message: `Unknown subcommand "${sub}". Use: /mailbox [agents|online|send|broadcast|history|clear]`
|
|
12110
|
+
message: `Unknown subcommand "${sub}". Use: /mailbox [agents|online|send|broadcast|history|clear purge]`
|
|
11871
12111
|
};
|
|
11872
12112
|
}
|
|
11873
12113
|
};
|
|
@@ -12484,7 +12724,7 @@ async function runCompact(opts) {
|
|
|
12484
12724
|
responseText = response.content.filter((b) => b.type === "text").map((b) => b.text).join("").trim();
|
|
12485
12725
|
} catch (err) {
|
|
12486
12726
|
return {
|
|
12487
|
-
message: `LLM call failed: ${
|
|
12727
|
+
message: `LLM call failed: ${toErrorMessage(err)}`
|
|
12488
12728
|
};
|
|
12489
12729
|
}
|
|
12490
12730
|
if (!responseText) {
|
|
@@ -12500,7 +12740,7 @@ ${responseText.slice(0, 500)}` };
|
|
|
12500
12740
|
parsed = JSON.parse(jsonMatch[0]);
|
|
12501
12741
|
} catch (err) {
|
|
12502
12742
|
return {
|
|
12503
|
-
message: `Failed to parse LLM response: ${
|
|
12743
|
+
message: `Failed to parse LLM response: ${toErrorMessage(err)}
|
|
12504
12744
|
|
|
12505
12745
|
Raw response:
|
|
12506
12746
|
${responseText.slice(0, 500)}`
|
|
@@ -12558,7 +12798,7 @@ ${responseText.slice(0, 500)}`
|
|
|
12558
12798
|
}
|
|
12559
12799
|
} catch (err) {
|
|
12560
12800
|
errors.push(
|
|
12561
|
-
`${op.action} failed for ${op.targets.join(", ")}: ${
|
|
12801
|
+
`${op.action} failed for ${op.targets.join(", ")}: ${toErrorMessage(err)}`
|
|
12562
12802
|
);
|
|
12563
12803
|
}
|
|
12564
12804
|
}
|
|
@@ -13195,7 +13435,7 @@ function buildModelsCommand(opts) {
|
|
|
13195
13435
|
};
|
|
13196
13436
|
} catch (err) {
|
|
13197
13437
|
return {
|
|
13198
|
-
message: `${color.red("models error")}: ${
|
|
13438
|
+
message: `${color.red("models error")}: ${toErrorMessage(err)}`
|
|
13199
13439
|
};
|
|
13200
13440
|
}
|
|
13201
13441
|
}
|
|
@@ -13879,7 +14119,7 @@ async function killSession(sessionId) {
|
|
|
13879
14119
|
} catch (err) {
|
|
13880
14120
|
return {
|
|
13881
14121
|
message: color.red(
|
|
13882
|
-
`Failed to kill session: ${
|
|
14122
|
+
`Failed to kill session: ${toErrorMessage(err)}`
|
|
13883
14123
|
)
|
|
13884
14124
|
};
|
|
13885
14125
|
}
|
|
@@ -14250,7 +14490,7 @@ function buildSetModelCommand(opts) {
|
|
|
14250
14490
|
};
|
|
14251
14491
|
} catch (err) {
|
|
14252
14492
|
return {
|
|
14253
|
-
message: `${color.red("setmodel error")}: ${
|
|
14493
|
+
message: `${color.red("setmodel error")}: ${toErrorMessage(err)}`
|
|
14254
14494
|
};
|
|
14255
14495
|
}
|
|
14256
14496
|
}
|
|
@@ -14353,7 +14593,7 @@ function buildSuggestCommand(opts) {
|
|
|
14353
14593
|
opts.onSuggestions?.(suggestions);
|
|
14354
14594
|
return { message: formatSuggestions(suggestions) };
|
|
14355
14595
|
} catch (err) {
|
|
14356
|
-
const msg = `Suggestion generation failed: ${
|
|
14596
|
+
const msg = `Suggestion generation failed: ${toErrorMessage(err)}`;
|
|
14357
14597
|
opts.renderer.writeWarning(msg);
|
|
14358
14598
|
return { message: msg };
|
|
14359
14599
|
}
|
|
@@ -15232,14 +15472,12 @@ function buildSettingsCommand(opts) {
|
|
|
15232
15472
|
};
|
|
15233
15473
|
} catch (err) {
|
|
15234
15474
|
return {
|
|
15235
|
-
message: `${color.red("Settings error")}: ${
|
|
15475
|
+
message: `${color.red("Settings error")}: ${toErrorMessage(err)}`
|
|
15236
15476
|
};
|
|
15237
15477
|
}
|
|
15238
15478
|
}
|
|
15239
15479
|
};
|
|
15240
15480
|
}
|
|
15241
|
-
|
|
15242
|
-
// src/slash-commands/spawn-agents.ts
|
|
15243
15481
|
function buildSpawnCommand(opts) {
|
|
15244
15482
|
return {
|
|
15245
15483
|
name: "spawn",
|
|
@@ -15276,7 +15514,7 @@ function buildSpawnCommand(opts) {
|
|
|
15276
15514
|
const summary = Object.keys(parsed).length > 0 ? await opts.onSpawn(description, parsed) : await opts.onSpawn(description);
|
|
15277
15515
|
return { message: summary };
|
|
15278
15516
|
} catch (err) {
|
|
15279
|
-
return { message: `Spawn failed: ${
|
|
15517
|
+
return { message: `Spawn failed: ${toErrorMessage(err)}` };
|
|
15280
15518
|
}
|
|
15281
15519
|
}
|
|
15282
15520
|
};
|
|
@@ -15381,7 +15619,7 @@ async function saveStatuslineConfig(cfg) {
|
|
|
15381
15619
|
await atomicWrite(p, JSON.stringify(cfg, null, 2));
|
|
15382
15620
|
} catch (err) {
|
|
15383
15621
|
throw new FsError({
|
|
15384
|
-
message:
|
|
15622
|
+
message: toErrorMessage(err),
|
|
15385
15623
|
code: err instanceof Error && err.message.includes("mkdir") ? ERROR_CODES.FS_MKDIR_FAILED : ERROR_CODES.FS_ATOMIC_WRITE_FAILED,
|
|
15386
15624
|
path: p,
|
|
15387
15625
|
cause: err
|
|
@@ -15616,7 +15854,7 @@ ${formatPlan(updated)}`;
|
|
|
15616
15854
|
const priority = validatePriority(parts[2] ?? "") ?? "medium";
|
|
15617
15855
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15618
15856
|
file.tasks.push({
|
|
15619
|
-
id: `task_${
|
|
15857
|
+
id: `task_${randomUUID()}`,
|
|
15620
15858
|
title,
|
|
15621
15859
|
type,
|
|
15622
15860
|
priority,
|
|
@@ -15739,7 +15977,7 @@ ${formatTaskProgress(file.tasks)}`;
|
|
|
15739
15977
|
];
|
|
15740
15978
|
if (found.item.description) {
|
|
15741
15979
|
todos.push({
|
|
15742
|
-
id: `todo_${
|
|
15980
|
+
id: `todo_${randomUUID()}`,
|
|
15743
15981
|
content: found.item.description.slice(0, 200),
|
|
15744
15982
|
status: "pending",
|
|
15745
15983
|
promotedFromTask: found.item.id
|
|
@@ -15947,7 +16185,7 @@ function buildTechStackCommand(opts) {
|
|
|
15947
16185
|
}
|
|
15948
16186
|
} catch (err) {
|
|
15949
16187
|
discoveryNote = color.red(
|
|
15950
|
-
`Could not scan for package files: ${
|
|
16188
|
+
`Could not scan for package files: ${toErrorMessage(err)}`
|
|
15951
16189
|
);
|
|
15952
16190
|
}
|
|
15953
16191
|
const task = buildTechStackTask({
|
|
@@ -15975,7 +16213,7 @@ function buildTechStackCommand(opts) {
|
|
|
15975
16213
|
const summary = await opts.onSpawnAndWait(task, { name });
|
|
15976
16214
|
return { message: summary };
|
|
15977
16215
|
} catch (err) {
|
|
15978
|
-
const msg = `Tech stack scan failed: ${
|
|
16216
|
+
const msg = `Tech stack scan failed: ${toErrorMessage(err)}`;
|
|
15979
16217
|
opts.renderer.writeWarning(msg);
|
|
15980
16218
|
return { message: msg };
|
|
15981
16219
|
}
|
|
@@ -16126,6 +16364,163 @@ ${color.dim("No default chat set. You can add it later: /telegram-setup <token>
|
|
|
16126
16364
|
}
|
|
16127
16365
|
};
|
|
16128
16366
|
}
|
|
16367
|
+
init_helpers();
|
|
16368
|
+
var HELP2 = [
|
|
16369
|
+
"Usage:",
|
|
16370
|
+
" /telegram-settings Show current Telegram notification settings",
|
|
16371
|
+
" /telegram-settings session-end on|off Notify on session end",
|
|
16372
|
+
" /telegram-settings delegate on|off Notify when a delegated subagent finishes",
|
|
16373
|
+
" /telegram-settings long-tool <ms|off> Notify for tools slower than <ms> (0/off = disabled)",
|
|
16374
|
+
" /telegram-settings poll <seconds> Bot polling interval (1\u201360)",
|
|
16375
|
+
" /telegram-settings chat <chatId> Default chat for notifications",
|
|
16376
|
+
"",
|
|
16377
|
+
"Aliases: /tg-settings",
|
|
16378
|
+
"",
|
|
16379
|
+
"Settings apply immediately \u2014 no restart needed."
|
|
16380
|
+
].join("\n");
|
|
16381
|
+
function buildTelegramSettingsCommand(opts) {
|
|
16382
|
+
function currentView() {
|
|
16383
|
+
const config = opts.configStore.get();
|
|
16384
|
+
const tg = config.extensions?.telegram ?? {};
|
|
16385
|
+
const sessionEnd = tg.notifyOnSessionEnd === true;
|
|
16386
|
+
const delegate = tg.notifyOnDelegate !== false;
|
|
16387
|
+
const longToolMs = typeof tg.longToolThresholdMs === "number" ? tg.longToolThresholdMs : 3e4;
|
|
16388
|
+
const longTool = longToolMs > 0 ? `${longToolMs}ms` : "off";
|
|
16389
|
+
const poll = typeof tg.pollIntervalSec === "number" ? `${tg.pollIntervalSec}s` : "2s";
|
|
16390
|
+
const chat = tg.notifyChatId !== void 0 && tg.notifyChatId !== null ? String(tg.notifyChatId) : "not set";
|
|
16391
|
+
const hasToken = typeof tg.botToken === "string" && tg.botToken.length > 0;
|
|
16392
|
+
return [
|
|
16393
|
+
`${color.bold("Telegram")} ${color.dim("\u2014 Notification Settings")}`,
|
|
16394
|
+
"",
|
|
16395
|
+
` session end: ${sessionEnd ? color.cyan("on") : color.dim("off")} ${color.dim("change: /telegram-settings session-end on|off")}`,
|
|
16396
|
+
` delegate done: ${delegate ? color.cyan("on") : color.dim("off")} ${color.dim("change: /telegram-settings delegate on|off")}`,
|
|
16397
|
+
` long tool: ${color.cyan(longTool)} ${color.dim("change: /telegram-settings long-tool <ms|off>")}`,
|
|
16398
|
+
` poll interval: ${color.cyan(poll)} ${color.dim("change: /telegram-settings poll <seconds>")}`,
|
|
16399
|
+
` notify chat: ${color.cyan(chat)} ${color.dim("change: /telegram-settings chat <chatId>")}`,
|
|
16400
|
+
"",
|
|
16401
|
+
hasToken ? color.dim(" Bot token configured. Changes apply immediately.") : `${color.amber("\u26A0")} No bot token configured. Run: /telegram-setup <botToken> [chatId]`
|
|
16402
|
+
].join("\n");
|
|
16403
|
+
}
|
|
16404
|
+
return {
|
|
16405
|
+
name: "telegram-settings",
|
|
16406
|
+
category: "Config",
|
|
16407
|
+
aliases: ["tg-settings"],
|
|
16408
|
+
description: "Toggle which agent events are reported to Telegram.",
|
|
16409
|
+
argsHint: "[session-end|delegate|long-tool|poll|chat <value>]",
|
|
16410
|
+
help: HELP2,
|
|
16411
|
+
async run(args) {
|
|
16412
|
+
const { cmd: sub, rest } = parseSubcommand(args);
|
|
16413
|
+
if (sub === "help" || sub === "--help" || sub === "-h") {
|
|
16414
|
+
return { message: HELP2 };
|
|
16415
|
+
}
|
|
16416
|
+
if (!opts.configStore || !opts.paths?.globalConfig) {
|
|
16417
|
+
return { message: `${color.red("Error")} config store not available.` };
|
|
16418
|
+
}
|
|
16419
|
+
if (!sub) {
|
|
16420
|
+
return { message: currentView() };
|
|
16421
|
+
}
|
|
16422
|
+
const persistDeps = {
|
|
16423
|
+
configStore: opts.configStore,
|
|
16424
|
+
globalConfigPath: opts.paths.globalConfig,
|
|
16425
|
+
vault: noOpVault
|
|
16426
|
+
};
|
|
16427
|
+
try {
|
|
16428
|
+
if (sub === "session-end") {
|
|
16429
|
+
const raw = (rest[0] ?? "").toLowerCase();
|
|
16430
|
+
if (!["on", "off"].includes(raw)) {
|
|
16431
|
+
return { message: `${color.amber("Usage:")} /telegram-settings session-end on|off` };
|
|
16432
|
+
}
|
|
16433
|
+
const on = raw === "on";
|
|
16434
|
+
await persistTelegramConfig(persistDeps, (tg) => {
|
|
16435
|
+
tg.notifyOnSessionEnd = on;
|
|
16436
|
+
});
|
|
16437
|
+
return {
|
|
16438
|
+
message: `${color.green("\u2713")} session-end \u2192 ${on ? color.cyan("on") : color.dim("off")}`
|
|
16439
|
+
};
|
|
16440
|
+
}
|
|
16441
|
+
if (sub === "delegate") {
|
|
16442
|
+
const raw = (rest[0] ?? "").toLowerCase();
|
|
16443
|
+
if (!["on", "off"].includes(raw)) {
|
|
16444
|
+
return { message: `${color.amber("Usage:")} /telegram-settings delegate on|off` };
|
|
16445
|
+
}
|
|
16446
|
+
const on = raw === "on";
|
|
16447
|
+
await persistTelegramConfig(persistDeps, (tg) => {
|
|
16448
|
+
tg.notifyOnDelegate = on;
|
|
16449
|
+
});
|
|
16450
|
+
return {
|
|
16451
|
+
message: `${color.green("\u2713")} delegate \u2192 ${on ? color.cyan("on") : color.dim("off")}`
|
|
16452
|
+
};
|
|
16453
|
+
}
|
|
16454
|
+
if (sub === "long-tool") {
|
|
16455
|
+
const raw = rest[0];
|
|
16456
|
+
if (raw === void 0) {
|
|
16457
|
+
return {
|
|
16458
|
+
message: `${color.amber("Usage:")} /telegram-settings long-tool <ms|off> ${color.dim("(0 or off disables)")}`
|
|
16459
|
+
};
|
|
16460
|
+
}
|
|
16461
|
+
if (raw === "off") {
|
|
16462
|
+
await persistTelegramConfig(persistDeps, (tg) => {
|
|
16463
|
+
tg.longToolThresholdMs = 0;
|
|
16464
|
+
});
|
|
16465
|
+
return {
|
|
16466
|
+
message: `${color.green("\u2713")} long-tool \u2192 ${color.dim("off")}`
|
|
16467
|
+
};
|
|
16468
|
+
}
|
|
16469
|
+
const ms = Number.parseInt(raw, 10);
|
|
16470
|
+
if (Number.isNaN(ms) || ms < 0) {
|
|
16471
|
+
return {
|
|
16472
|
+
message: `${color.red("Invalid number")}: "${raw}". Enter milliseconds, e.g. /telegram-settings long-tool 15000`
|
|
16473
|
+
};
|
|
16474
|
+
}
|
|
16475
|
+
await persistTelegramConfig(persistDeps, (tg) => {
|
|
16476
|
+
tg.longToolThresholdMs = ms;
|
|
16477
|
+
});
|
|
16478
|
+
return {
|
|
16479
|
+
message: `${color.green("\u2713")} long-tool \u2192 ${color.cyan(`${ms}ms`)}`
|
|
16480
|
+
};
|
|
16481
|
+
}
|
|
16482
|
+
if (sub === "poll") {
|
|
16483
|
+
const raw = rest[0];
|
|
16484
|
+
if (raw === void 0) {
|
|
16485
|
+
return { message: `${color.amber("Usage:")} /telegram-settings poll <seconds> ${color.dim("(1\u201360)")}` };
|
|
16486
|
+
}
|
|
16487
|
+
const sec = Number.parseInt(raw, 10);
|
|
16488
|
+
if (Number.isNaN(sec) || sec < 1 || sec > 60) {
|
|
16489
|
+
return {
|
|
16490
|
+
message: `${color.red("Invalid value")}: "${raw}". Enter seconds between 1 and 60.`
|
|
16491
|
+
};
|
|
16492
|
+
}
|
|
16493
|
+
await persistTelegramConfig(persistDeps, (tg) => {
|
|
16494
|
+
tg.pollIntervalSec = sec;
|
|
16495
|
+
});
|
|
16496
|
+
return {
|
|
16497
|
+
message: `${color.green("\u2713")} poll \u2192 ${color.cyan(`${sec}s`)}`
|
|
16498
|
+
};
|
|
16499
|
+
}
|
|
16500
|
+
if (sub === "chat") {
|
|
16501
|
+
const raw = rest[0];
|
|
16502
|
+
if (!raw) {
|
|
16503
|
+
return { message: `${color.amber("Usage:")} /telegram-settings chat <chatId>` };
|
|
16504
|
+
}
|
|
16505
|
+
const chatId = /^\d+$/.test(raw) ? Number(raw) : raw;
|
|
16506
|
+
await persistTelegramConfig(persistDeps, (tg) => {
|
|
16507
|
+
tg.notifyChatId = chatId;
|
|
16508
|
+
});
|
|
16509
|
+
return {
|
|
16510
|
+
message: `${color.green("\u2713")} notify chat \u2192 ${color.cyan(raw)}`
|
|
16511
|
+
};
|
|
16512
|
+
}
|
|
16513
|
+
return {
|
|
16514
|
+
message: `${color.red("Unknown setting")} "${sub}". ${unknownSubcommand(sub, ["session-end", "delegate", "long-tool", "poll", "chat"], "telegram-settings")}`
|
|
16515
|
+
};
|
|
16516
|
+
} catch (err) {
|
|
16517
|
+
return {
|
|
16518
|
+
message: `${color.red("Settings error")}: ${toErrorMessage(err)}`
|
|
16519
|
+
};
|
|
16520
|
+
}
|
|
16521
|
+
}
|
|
16522
|
+
};
|
|
16523
|
+
}
|
|
16129
16524
|
|
|
16130
16525
|
// src/slash-commands/todos.ts
|
|
16131
16526
|
init_helpers();
|
|
@@ -16287,7 +16682,7 @@ function buildWorkingDirCommand(_opts) {
|
|
|
16287
16682
|
ctx.setWorkingDir(resolved);
|
|
16288
16683
|
} catch (err) {
|
|
16289
16684
|
return {
|
|
16290
|
-
message: color.red(
|
|
16685
|
+
message: color.red(toErrorMessage(err))
|
|
16291
16686
|
};
|
|
16292
16687
|
}
|
|
16293
16688
|
const prevRel = path39.relative(ctx.projectRoot, previous) || ".";
|
|
@@ -16434,6 +16829,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
16434
16829
|
buildDirectorCommand(opts),
|
|
16435
16830
|
buildFleetCommand(opts),
|
|
16436
16831
|
buildEnhanceCommand(opts),
|
|
16832
|
+
buildEnsembleCommand(),
|
|
16437
16833
|
buildMemoryCommand(opts),
|
|
16438
16834
|
buildTodosCommand(opts),
|
|
16439
16835
|
buildTasksCommand(),
|
|
@@ -16456,6 +16852,7 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
16456
16852
|
buildWorktreeCommand(opts),
|
|
16457
16853
|
buildSettingsCommand(opts),
|
|
16458
16854
|
buildTelegramSetupCommand(opts),
|
|
16855
|
+
buildTelegramSettingsCommand(opts),
|
|
16459
16856
|
buildSetModelCommand(opts),
|
|
16460
16857
|
buildFallbackCommand(opts),
|
|
16461
16858
|
buildModelCapsCommand(opts),
|
|
@@ -16475,8 +16872,6 @@ function buildBuiltinSlashCommands(opts) {
|
|
|
16475
16872
|
})
|
|
16476
16873
|
];
|
|
16477
16874
|
}
|
|
16478
|
-
|
|
16479
|
-
// src/pre-launch.ts
|
|
16480
16875
|
var MANIFESTS = [
|
|
16481
16876
|
"package.json",
|
|
16482
16877
|
"pyproject.toml",
|
|
@@ -16544,7 +16939,7 @@ async function runProjectCheck(opts) {
|
|
|
16544
16939
|
`);
|
|
16545
16940
|
} catch (err) {
|
|
16546
16941
|
renderer.writeError(
|
|
16547
|
-
`Failed to scaffold AGENTS.md: ${
|
|
16942
|
+
`Failed to scaffold AGENTS.md: ${toErrorMessage(err)}`
|
|
16548
16943
|
);
|
|
16549
16944
|
}
|
|
16550
16945
|
}
|
|
@@ -16589,7 +16984,7 @@ async function runProjectCheck(opts) {
|
|
|
16589
16984
|
`);
|
|
16590
16985
|
} catch (err) {
|
|
16591
16986
|
renderer.writeError(
|
|
16592
|
-
`git init failed: ${
|
|
16987
|
+
`git init failed: ${toErrorMessage(err)}
|
|
16593
16988
|
`
|
|
16594
16989
|
);
|
|
16595
16990
|
}
|
|
@@ -17148,6 +17543,17 @@ function summarize(value, name) {
|
|
|
17148
17543
|
|
|
17149
17544
|
// src/boot.ts
|
|
17150
17545
|
init_project_utils();
|
|
17546
|
+
function resolveCmdFromCatalog(subagentId) {
|
|
17547
|
+
const desc = findAgentDescriptor(subagentId);
|
|
17548
|
+
if (!desc) return null;
|
|
17549
|
+
const out = {
|
|
17550
|
+
command: desc.acp.command,
|
|
17551
|
+
args: [...desc.acp.args ?? []],
|
|
17552
|
+
role: subagentId
|
|
17553
|
+
};
|
|
17554
|
+
if (desc.acp.env) out.env = desc.acp.env;
|
|
17555
|
+
return out;
|
|
17556
|
+
}
|
|
17151
17557
|
var acpCmd = async (args, deps) => {
|
|
17152
17558
|
const sub = args[0];
|
|
17153
17559
|
if (!sub || sub === "server" || sub === "serve") {
|
|
@@ -17162,6 +17568,9 @@ Usage:
|
|
|
17162
17568
|
wstack acp list List available ACP agents
|
|
17163
17569
|
wstack acp spawn <id> <task>
|
|
17164
17570
|
Spawn an ACP agent as a subagent and wait for result
|
|
17571
|
+
wstack acp parallel <agent-id-csv> <task>
|
|
17572
|
+
Fan a task out to multiple ACP agents in parallel
|
|
17573
|
+
and aggregate the results
|
|
17165
17574
|
wstack acp help Show this help
|
|
17166
17575
|
|
|
17167
17576
|
ACP Mode:
|
|
@@ -17171,9 +17580,17 @@ ACP Mode:
|
|
|
17171
17580
|
Press Ctrl+C to stop.
|
|
17172
17581
|
|
|
17173
17582
|
spawn:
|
|
17174
|
-
Spawns a named ACP agent (
|
|
17175
|
-
|
|
17583
|
+
Spawns a named ACP agent (claude-code, gemini-cli, codex-cli, copilot,
|
|
17584
|
+
cline, goose, openhands, qwen-code, kiro-cli, opencode, mistral-vibe,
|
|
17585
|
+
cursor) with the given task and waits for its result.
|
|
17176
17586
|
Example: wstack acp spawn cline "fix the login bug"
|
|
17587
|
+
|
|
17588
|
+
parallel:
|
|
17589
|
+
Runs the same task on a comma-separated list of ACP agents concurrently.
|
|
17590
|
+
Example: wstack acp parallel claude-code,gemini-cli,codex-cli "review this diff"
|
|
17591
|
+
Each agent's result is rendered under a clearly-marked header. Returns 0
|
|
17592
|
+
if at least one agent succeeds, 1 if all fail. Agents that aren't
|
|
17593
|
+
installed are skipped with a warning.
|
|
17177
17594
|
`);
|
|
17178
17595
|
return 0;
|
|
17179
17596
|
}
|
|
@@ -17183,20 +17600,20 @@ spawn:
|
|
|
17183
17600
|
if (sub === "spawn") {
|
|
17184
17601
|
return spawnACPAgent(args.slice(1), deps);
|
|
17185
17602
|
}
|
|
17603
|
+
if (sub === "parallel") {
|
|
17604
|
+
return parallelACPAgents(args.slice(1), deps);
|
|
17605
|
+
}
|
|
17186
17606
|
deps.renderer.writeError(`Unknown acp subcommand: ${sub}
|
|
17187
17607
|
`);
|
|
17188
17608
|
deps.renderer.write("Run `wstack acp help` for usage.\n");
|
|
17189
17609
|
return 1;
|
|
17190
17610
|
};
|
|
17191
17611
|
async function runACPServer(deps) {
|
|
17192
|
-
const toolRegistry = deps.toolRegistry;
|
|
17193
|
-
const tools = toolRegistry?.list() ?? [];
|
|
17194
17612
|
deps.renderer.writeInfo("Starting WrongStack ACP server...\n");
|
|
17195
|
-
deps.renderer.writeInfo(`Exposing ${tools.length} tool(s) via ACP protocol.
|
|
17196
|
-
`);
|
|
17197
17613
|
deps.renderer.writeInfo("Waiting for ACP client connection on stdin/stdout...\n");
|
|
17614
|
+
deps.renderer.writeInfo("(default runTurn is a no-op echo \u2014 wire makeACPServerAgentTurn for a real agent)\n");
|
|
17198
17615
|
deps.renderer.writeInfo("Press Ctrl+C to stop.\n");
|
|
17199
|
-
const server = new WrongStackACPServer({
|
|
17616
|
+
const server = new WrongStackACPServer({});
|
|
17200
17617
|
const shutdown = () => {
|
|
17201
17618
|
deps.renderer.writeWarning("\nShutting down ACP server...");
|
|
17202
17619
|
server.stop();
|
|
@@ -17215,16 +17632,25 @@ async function runACPServer(deps) {
|
|
|
17215
17632
|
}
|
|
17216
17633
|
return 0;
|
|
17217
17634
|
}
|
|
17218
|
-
function listACPAgents(deps) {
|
|
17219
|
-
|
|
17220
|
-
|
|
17221
|
-
|
|
17222
|
-
|
|
17223
|
-
|
|
17224
|
-
|
|
17635
|
+
async function listACPAgents(deps) {
|
|
17636
|
+
const registry = new EnsembleRegistry();
|
|
17637
|
+
const detected = await registry.list();
|
|
17638
|
+
deps.renderer.write("Detected ACP agents:\n\n");
|
|
17639
|
+
const installed = detected.filter((a) => a.installed);
|
|
17640
|
+
const missing = detected.filter((a) => !a.installed);
|
|
17641
|
+
for (const a of installed) {
|
|
17642
|
+
const ver = a.version ? ` (${a.version.split("\n")[0]})` : "";
|
|
17643
|
+
deps.renderer.write(` \u2713 ${a.id.padEnd(16)} ${a.displayName}${ver}
|
|
17644
|
+
`);
|
|
17645
|
+
}
|
|
17646
|
+
for (const a of missing) {
|
|
17647
|
+
deps.renderer.write(` \u2717 ${a.id.padEnd(16)} ${a.displayName} (${a.reason ?? "not installed"})
|
|
17225
17648
|
`);
|
|
17226
17649
|
}
|
|
17227
|
-
deps.renderer.write(
|
|
17650
|
+
deps.renderer.write(`
|
|
17651
|
+
${installed.length} of ${detected.length} agents available.
|
|
17652
|
+
`);
|
|
17653
|
+
deps.renderer.write("Use `wstack acp spawn <agent-id> <task>` to delegate a task.\n");
|
|
17228
17654
|
return 0;
|
|
17229
17655
|
}
|
|
17230
17656
|
async function spawnACPAgent(args, deps) {
|
|
@@ -17240,7 +17666,7 @@ async function spawnACPAgent(args, deps) {
|
|
|
17240
17666
|
deps.renderer.write("Task description is required.\n");
|
|
17241
17667
|
return 1;
|
|
17242
17668
|
}
|
|
17243
|
-
const cmd = ACP_AGENT_COMMANDS[subagentId];
|
|
17669
|
+
const cmd = ACP_AGENT_COMMANDS[subagentId] ?? resolveCmdFromCatalog(subagentId);
|
|
17244
17670
|
if (!cmd) {
|
|
17245
17671
|
deps.renderer.writeError(`Unknown ACP agent: ${subagentId}
|
|
17246
17672
|
`);
|
|
@@ -17294,10 +17720,11 @@ async function spawnACPAgent(args, deps) {
|
|
|
17294
17720
|
);
|
|
17295
17721
|
return 0;
|
|
17296
17722
|
} catch (err) {
|
|
17297
|
-
|
|
17298
|
-
|
|
17299
|
-
|
|
17300
|
-
|
|
17723
|
+
const e = err;
|
|
17724
|
+
const detail = e.kind ? `[${e.kind}] ` : "";
|
|
17725
|
+
const message = e.message ?? (err instanceof Error ? err.message : String(err));
|
|
17726
|
+
deps.renderer.writeError(`ACP agent error: ${detail}${message}
|
|
17727
|
+
`);
|
|
17301
17728
|
return 1;
|
|
17302
17729
|
} finally {
|
|
17303
17730
|
cleanup();
|
|
@@ -17305,6 +17732,94 @@ async function spawnACPAgent(args, deps) {
|
|
|
17305
17732
|
process.off("SIGTERM", cleanup);
|
|
17306
17733
|
}
|
|
17307
17734
|
}
|
|
17735
|
+
async function parallelACPAgents(args, deps) {
|
|
17736
|
+
const [csv, ...taskParts] = args;
|
|
17737
|
+
if (!csv) {
|
|
17738
|
+
deps.renderer.writeError("Usage: wstack acp parallel <agent-id-csv> <task>\n");
|
|
17739
|
+
deps.renderer.write('Example: wstack acp parallel claude-code,gemini-cli "review this diff"\n');
|
|
17740
|
+
return 1;
|
|
17741
|
+
}
|
|
17742
|
+
const task = taskParts.join(" ");
|
|
17743
|
+
if (!task) {
|
|
17744
|
+
deps.renderer.writeError("Usage: wstack acp parallel <agent-id-csv> <task>\n");
|
|
17745
|
+
deps.renderer.writeError("Task description is required.\n");
|
|
17746
|
+
return 1;
|
|
17747
|
+
}
|
|
17748
|
+
const ac = new AbortController();
|
|
17749
|
+
const onSignal = () => ac.abort();
|
|
17750
|
+
process.on("SIGINT", onSignal);
|
|
17751
|
+
process.on("SIGTERM", onSignal);
|
|
17752
|
+
try {
|
|
17753
|
+
const result = await runEnsemble({
|
|
17754
|
+
agentIds: csv,
|
|
17755
|
+
task,
|
|
17756
|
+
resolveCmd: resolveCmdFromCatalog,
|
|
17757
|
+
signal: ac.signal
|
|
17758
|
+
});
|
|
17759
|
+
const skipped = result.results.filter((r) => r.status === "skipped");
|
|
17760
|
+
if (skipped.length > 0) {
|
|
17761
|
+
deps.renderer.writeWarning(
|
|
17762
|
+
`Skipping ${skipped.length} agent(s) not installed: ${skipped.map((s) => `${s.agentId} (${s.reason ?? "not installed"})`).join(", ")}
|
|
17763
|
+
`
|
|
17764
|
+
);
|
|
17765
|
+
}
|
|
17766
|
+
if (result.summary.succeeded + result.summary.failed + result.summary.cancelled === 0) {
|
|
17767
|
+
deps.renderer.writeError("No installed agents to run.\n");
|
|
17768
|
+
deps.renderer.write("Run `wstack acp list` to see what is available.\n");
|
|
17769
|
+
return 1;
|
|
17770
|
+
}
|
|
17771
|
+
const fannedOut = result.results.filter((r) => r.status !== "skipped").map((r) => r.agentId).join(", ");
|
|
17772
|
+
deps.renderer.writeInfo(
|
|
17773
|
+
`Fanning out to ${result.summary.succeeded + result.summary.failed + result.summary.cancelled} agent(s): ${fannedOut}
|
|
17774
|
+
`
|
|
17775
|
+
);
|
|
17776
|
+
deps.renderer.writeInfo(`Task: ${result.task}
|
|
17777
|
+
|
|
17778
|
+
`);
|
|
17779
|
+
for (const r of result.results) {
|
|
17780
|
+
if (r.status === "skipped") continue;
|
|
17781
|
+
deps.renderer.write(`
|
|
17782
|
+
=== ${r.agentId} ===
|
|
17783
|
+
`);
|
|
17784
|
+
if (r.status === "success") {
|
|
17785
|
+
deps.renderer.write(r.result && r.result.length > 0 ? r.result : "(no result)");
|
|
17786
|
+
deps.renderer.write(
|
|
17787
|
+
`
|
|
17788
|
+
[${r.agentId}] success ${r.durationMs}ms iterations=${r.iterations} toolCalls=${r.toolCalls}
|
|
17789
|
+
`
|
|
17790
|
+
);
|
|
17791
|
+
} else if (r.status === "failed") {
|
|
17792
|
+
deps.renderer.writeError(
|
|
17793
|
+
`[${r.error?.kind ?? "unknown"}] ${r.error?.message ?? "failed"}
|
|
17794
|
+
`
|
|
17795
|
+
);
|
|
17796
|
+
deps.renderer.write(
|
|
17797
|
+
`[${r.agentId}] failed ${r.durationMs}ms
|
|
17798
|
+
`
|
|
17799
|
+
);
|
|
17800
|
+
} else {
|
|
17801
|
+
deps.renderer.writeError(
|
|
17802
|
+
`[${r.error?.kind ?? "aborted"}] ${r.error?.message ?? "cancelled"}
|
|
17803
|
+
`
|
|
17804
|
+
);
|
|
17805
|
+
deps.renderer.write(
|
|
17806
|
+
`[${r.agentId}] cancelled ${r.durationMs}ms
|
|
17807
|
+
`
|
|
17808
|
+
);
|
|
17809
|
+
}
|
|
17810
|
+
}
|
|
17811
|
+
const { succeeded, failed, cancelled, skipped: skip } = result.summary;
|
|
17812
|
+
deps.renderer.write(
|
|
17813
|
+
`
|
|
17814
|
+
Parallel summary: ${succeeded} succeeded, ${failed} failed, ${cancelled} cancelled, ${skip} skipped.
|
|
17815
|
+
`
|
|
17816
|
+
);
|
|
17817
|
+
return succeeded > 0 ? 0 : 1;
|
|
17818
|
+
} finally {
|
|
17819
|
+
process.off("SIGINT", onSignal);
|
|
17820
|
+
process.off("SIGTERM", onSignal);
|
|
17821
|
+
}
|
|
17822
|
+
}
|
|
17308
17823
|
var auditCmd = async (args, deps) => {
|
|
17309
17824
|
const wpaths = resolveWstackPaths({
|
|
17310
17825
|
projectRoot: deps.projectRoot,
|
|
@@ -18092,6 +18607,35 @@ ${color.amber("?")} Pick: `)).trim().toLowerCase();
|
|
|
18092
18607
|
}
|
|
18093
18608
|
}
|
|
18094
18609
|
|
|
18610
|
+
// src/auth-menu/local.ts
|
|
18611
|
+
init_provider_config_utils();
|
|
18612
|
+
|
|
18613
|
+
// src/auth-menu/local.ts
|
|
18614
|
+
var LOCAL_LLM_PRESETS = [
|
|
18615
|
+
{
|
|
18616
|
+
id: "ollama",
|
|
18617
|
+
label: "Ollama",
|
|
18618
|
+
defaultBaseUrl: "http://localhost:11434/v1",
|
|
18619
|
+
noAuth: true,
|
|
18620
|
+
hint: "https://ollama.com \u2014 port 11434, no auth"
|
|
18621
|
+
},
|
|
18622
|
+
{
|
|
18623
|
+
id: "vllm",
|
|
18624
|
+
label: "vLLM",
|
|
18625
|
+
defaultBaseUrl: "http://localhost:8000/v1",
|
|
18626
|
+
noAuth: false,
|
|
18627
|
+
hint: "https://docs.vllm.ai \u2014 port 8000, optional Bearer"
|
|
18628
|
+
},
|
|
18629
|
+
{
|
|
18630
|
+
id: "lmstudio",
|
|
18631
|
+
label: "LM Studio",
|
|
18632
|
+
defaultBaseUrl: "http://localhost:1234/v1",
|
|
18633
|
+
noAuth: false,
|
|
18634
|
+
hint: "https://lmstudio.ai \u2014 port 1234, optional Bearer"
|
|
18635
|
+
}
|
|
18636
|
+
];
|
|
18637
|
+
new Map(LOCAL_LLM_PRESETS.map((p) => [p.id, p]));
|
|
18638
|
+
|
|
18095
18639
|
// src/subcommands/handlers/auth.ts
|
|
18096
18640
|
init_provider_config_utils();
|
|
18097
18641
|
var authCmd = async (args, deps) => {
|
|
@@ -18351,7 +18895,7 @@ async function benchRun(_args, deps) {
|
|
|
18351
18895
|
try {
|
|
18352
18896
|
config = await loadBenchConfig(path39.resolve(deps.cwd, modelsPath));
|
|
18353
18897
|
} catch (err) {
|
|
18354
|
-
deps.renderer.writeError(
|
|
18898
|
+
deps.renderer.writeError(toErrorMessage(err));
|
|
18355
18899
|
return 1;
|
|
18356
18900
|
}
|
|
18357
18901
|
const concurrencyRaw = flagStr(deps, "concurrency");
|
|
@@ -18405,7 +18949,7 @@ async function benchRun(_args, deps) {
|
|
|
18405
18949
|
onProgress: (msg) => deps.renderer.write(color.dim(msg) + "\n")
|
|
18406
18950
|
});
|
|
18407
18951
|
} catch (err) {
|
|
18408
|
-
deps.renderer.writeError(
|
|
18952
|
+
deps.renderer.writeError(toErrorMessage(err));
|
|
18409
18953
|
return 1;
|
|
18410
18954
|
}
|
|
18411
18955
|
await writeJsonArtifacts(outDir, report);
|
|
@@ -18438,7 +18982,7 @@ async function benchReport(args, deps) {
|
|
|
18438
18982
|
summary = await readSummary(outDir);
|
|
18439
18983
|
} catch (err) {
|
|
18440
18984
|
deps.renderer.writeError(
|
|
18441
|
-
`cannot read summary.json in ${outDir}: ${
|
|
18985
|
+
`cannot read summary.json in ${outDir}: ${toErrorMessage(err)}`
|
|
18442
18986
|
);
|
|
18443
18987
|
return 1;
|
|
18444
18988
|
}
|
|
@@ -18476,7 +19020,7 @@ async function benchList(_args, deps) {
|
|
|
18476
19020
|
});
|
|
18477
19021
|
deps.renderer.write("\n" + color.dim(`Harness: ${fp}`) + "\n");
|
|
18478
19022
|
} catch (err) {
|
|
18479
|
-
deps.renderer.writeError(
|
|
19023
|
+
deps.renderer.writeError(toErrorMessage(err));
|
|
18480
19024
|
return 1;
|
|
18481
19025
|
}
|
|
18482
19026
|
}
|
|
@@ -18560,7 +19104,7 @@ var doctorCmd = async (_args, deps) => {
|
|
|
18560
19104
|
checks.push({
|
|
18561
19105
|
name: "models cache",
|
|
18562
19106
|
status: "warn",
|
|
18563
|
-
detail: `read failed: ${
|
|
19107
|
+
detail: `read failed: ${toErrorMessage(err)}`
|
|
18564
19108
|
});
|
|
18565
19109
|
}
|
|
18566
19110
|
try {
|
|
@@ -18583,7 +19127,7 @@ var doctorCmd = async (_args, deps) => {
|
|
|
18583
19127
|
checks.push({
|
|
18584
19128
|
name: "sessions writable",
|
|
18585
19129
|
status: "fail",
|
|
18586
|
-
detail: `cannot write to ${deps.paths.projectSessions}: ${
|
|
19130
|
+
detail: `cannot write to ${deps.paths.projectSessions}: ${toErrorMessage(err)}`
|
|
18587
19131
|
});
|
|
18588
19132
|
}
|
|
18589
19133
|
const mcpEntries = Object.entries(cfg.mcpServers ?? {});
|
|
@@ -18674,7 +19218,7 @@ var exportCmd = async (args, deps) => {
|
|
|
18674
19218
|
try {
|
|
18675
19219
|
rendered = await reader.export(sessionId, { format, includeTools, includeDiagnostics });
|
|
18676
19220
|
} catch (err) {
|
|
18677
|
-
deps.renderer.writeError(`Export failed: ${
|
|
19221
|
+
deps.renderer.writeError(`Export failed: ${toErrorMessage(err)}`);
|
|
18678
19222
|
return 1;
|
|
18679
19223
|
}
|
|
18680
19224
|
if (output) {
|
|
@@ -19647,7 +20191,7 @@ var modeldiagCmd = async (args, deps) => {
|
|
|
19647
20191
|
` ${label} ${provColor(modelKey.padEnd(50))} ${scoreBar(c.score, 110).slice(0, 11)} ${color.amber(fmtMs(latency).padEnd(8))} ${color.dim(`in${usage?.input ?? "?"}/out${usage?.output ?? "?"}`.padEnd(12))} ${firstLineClean}`
|
|
19648
20192
|
);
|
|
19649
20193
|
} catch (err) {
|
|
19650
|
-
const errMsg =
|
|
20194
|
+
const errMsg = toErrorMessage(err);
|
|
19651
20195
|
writeLine(
|
|
19652
20196
|
` ${label} ${color.red(modelKey.padEnd(50))} ${scoreBar(c.score, 110).slice(0, 11)} ${color.red("FAILED")} ${color.dim(errMsg.slice(0, 40))}`
|
|
19653
20197
|
);
|
|
@@ -20691,7 +21235,7 @@ ${result.errors.length} error(s):
|
|
|
20691
21235
|
}
|
|
20692
21236
|
return 0;
|
|
20693
21237
|
} catch (err) {
|
|
20694
|
-
deps.renderer.writeError(
|
|
21238
|
+
deps.renderer.writeError(toErrorMessage(err));
|
|
20695
21239
|
return 1;
|
|
20696
21240
|
}
|
|
20697
21241
|
};
|
|
@@ -21230,7 +21774,7 @@ async function boot(argv) {
|
|
|
21230
21774
|
try {
|
|
21231
21775
|
bootResult = await bootConfig(flags);
|
|
21232
21776
|
} catch (err) {
|
|
21233
|
-
writeErr(`Config error: ${
|
|
21777
|
+
writeErr(`Config error: ${toErrorMessage(err)}
|
|
21234
21778
|
`);
|
|
21235
21779
|
return 2;
|
|
21236
21780
|
}
|
|
@@ -21283,7 +21827,7 @@ async function boot(argv) {
|
|
|
21283
21827
|
await modelsRegistry.refresh();
|
|
21284
21828
|
logger.info("models.dev catalog refreshed");
|
|
21285
21829
|
} catch (err) {
|
|
21286
|
-
const msg =
|
|
21830
|
+
const msg = toErrorMessage(err);
|
|
21287
21831
|
logger.warn(`models.dev refresh failed (${msg}); using cached catalog`);
|
|
21288
21832
|
}
|
|
21289
21833
|
}
|
|
@@ -21584,7 +22128,7 @@ async function checkGitInCwd(opts) {
|
|
|
21584
22128
|
hasCwdGit = true;
|
|
21585
22129
|
} catch (err) {
|
|
21586
22130
|
renderer.writeError(
|
|
21587
|
-
`git init failed: ${
|
|
22131
|
+
`git init failed: ${toErrorMessage(err)}
|
|
21588
22132
|
`
|
|
21589
22133
|
);
|
|
21590
22134
|
}
|
|
@@ -22359,7 +22903,7 @@ async function runRepl(opts) {
|
|
|
22359
22903
|
}
|
|
22360
22904
|
} catch (err) {
|
|
22361
22905
|
opts.renderer.writeError(
|
|
22362
|
-
`[eternal] ${
|
|
22906
|
+
`[eternal] ${toErrorMessage(err)}`
|
|
22363
22907
|
);
|
|
22364
22908
|
}
|
|
22365
22909
|
await new Promise((resolve11) => setTimeout(resolve11, 250));
|
|
@@ -22435,7 +22979,7 @@ async function runRepl(opts) {
|
|
|
22435
22979
|
}
|
|
22436
22980
|
} catch (err) {
|
|
22437
22981
|
opts.renderer.writeError(
|
|
22438
|
-
`[parallel] ${
|
|
22982
|
+
`[parallel] ${toErrorMessage(err)}`
|
|
22439
22983
|
);
|
|
22440
22984
|
}
|
|
22441
22985
|
await new Promise((resolve11) => setTimeout(resolve11, 250));
|
|
@@ -22508,7 +23052,7 @@ ${lines.join("\n")}
|
|
|
22508
23052
|
if (res?.message) opts.renderer.write(`${res.message}
|
|
22509
23053
|
`);
|
|
22510
23054
|
} catch (err) {
|
|
22511
|
-
opts.renderer.writeError(
|
|
23055
|
+
opts.renderer.writeError(toErrorMessage(err));
|
|
22512
23056
|
}
|
|
22513
23057
|
continue;
|
|
22514
23058
|
}
|
|
@@ -22597,7 +23141,7 @@ ${color.dim(taskList2)}
|
|
|
22597
23141
|
}
|
|
22598
23142
|
}
|
|
22599
23143
|
} catch (err) {
|
|
22600
|
-
opts.renderer.writeError(
|
|
23144
|
+
opts.renderer.writeError(toErrorMessage(err));
|
|
22601
23145
|
}
|
|
22602
23146
|
continue;
|
|
22603
23147
|
}
|
|
@@ -22786,7 +23330,7 @@ ${color.dim(
|
|
|
22786
23330
|
}
|
|
22787
23331
|
} catch (err) {
|
|
22788
23332
|
opts.renderer.writeError(
|
|
22789
|
-
`[autonomy] ${
|
|
23333
|
+
`[autonomy] ${toErrorMessage(err)}`
|
|
22790
23334
|
);
|
|
22791
23335
|
} finally {
|
|
22792
23336
|
activeCtrl = void 0;
|
|
@@ -22857,7 +23401,7 @@ ${color.dim(lines)}
|
|
|
22857
23401
|
}
|
|
22858
23402
|
}
|
|
22859
23403
|
} catch (err) {
|
|
22860
|
-
opts.renderer.writeError(
|
|
23404
|
+
opts.renderer.writeError(toErrorMessage(err));
|
|
22861
23405
|
} finally {
|
|
22862
23406
|
activeCtrl = void 0;
|
|
22863
23407
|
}
|
|
@@ -22884,7 +23428,7 @@ async function pasteClipboardImage(builder, opts) {
|
|
|
22884
23428
|
`));
|
|
22885
23429
|
} catch (err) {
|
|
22886
23430
|
opts.renderer.writeError(
|
|
22887
|
-
`Clipboard image error: ${
|
|
23431
|
+
`Clipboard image error: ${toErrorMessage(err)}`
|
|
22888
23432
|
);
|
|
22889
23433
|
}
|
|
22890
23434
|
}
|
|
@@ -22922,7 +23466,7 @@ async function renderGoalBanner(opts) {
|
|
|
22922
23466
|
await opts.slashRegistry.dispatch("/autonomy eternal", opts.agent.ctx);
|
|
22923
23467
|
} catch (err) {
|
|
22924
23468
|
opts.renderer.writeError(
|
|
22925
|
-
`Auto-resume failed: ${
|
|
23469
|
+
`Auto-resume failed: ${toErrorMessage(err)}`
|
|
22926
23470
|
);
|
|
22927
23471
|
}
|
|
22928
23472
|
} else {
|
|
@@ -23134,6 +23678,7 @@ async function execute(deps) {
|
|
|
23134
23678
|
effectiveMaxContext,
|
|
23135
23679
|
queueStore,
|
|
23136
23680
|
context,
|
|
23681
|
+
mailbox,
|
|
23137
23682
|
stats,
|
|
23138
23683
|
detachTodosCheckpoint,
|
|
23139
23684
|
savedProviderCfg,
|
|
@@ -23223,8 +23768,8 @@ async function execute(deps) {
|
|
|
23223
23768
|
timeoutMs: 3e5
|
|
23224
23769
|
};
|
|
23225
23770
|
const subagentId = await dir.spawn(cfg);
|
|
23226
|
-
const { randomUUID:
|
|
23227
|
-
const taskId =
|
|
23771
|
+
const { randomUUID: randomUUID7 } = await import('crypto');
|
|
23772
|
+
const taskId = randomUUID7();
|
|
23228
23773
|
await dir.assign({
|
|
23229
23774
|
id: taskId,
|
|
23230
23775
|
description: taskDesc,
|
|
@@ -23437,6 +23982,76 @@ async function execute(deps) {
|
|
|
23437
23982
|
};
|
|
23438
23983
|
const PROJECT_SWITCH_EXIT_CODE = 42;
|
|
23439
23984
|
let pendingProjectSwitch = null;
|
|
23985
|
+
const coordinatorEvents = /* @__PURE__ */ new Set();
|
|
23986
|
+
let autonomousCoordinator = null;
|
|
23987
|
+
const onDirectorReady = (dir) => {
|
|
23988
|
+
if (autonomousCoordinator) return;
|
|
23989
|
+
const transcript = context.session.transcriptPath;
|
|
23990
|
+
const sessionDir = transcript ? path39.dirname(transcript) : wpaths.projectDir;
|
|
23991
|
+
const llmProvider = {
|
|
23992
|
+
decide: async (prompt) => {
|
|
23993
|
+
const sysPrompt = [
|
|
23994
|
+
{
|
|
23995
|
+
type: "text",
|
|
23996
|
+
text: 'You are the autonomous brain of a multi-agent coordination system. Pick the best option for the decision described and reply with JSON: {"optionId":"<id>","rationale":"<short why>"}.'
|
|
23997
|
+
}
|
|
23998
|
+
];
|
|
23999
|
+
const userPrompt = {
|
|
24000
|
+
type: "text",
|
|
24001
|
+
text: `Decision: ${prompt.question}
|
|
24002
|
+
|
|
24003
|
+
Context: ${prompt.context}
|
|
24004
|
+
|
|
24005
|
+
Options:
|
|
24006
|
+
${prompt.options.map((o, i) => ` ${i + 1}. [${o.id}] ${o.label}${o.consequence ? ` \u2014 ${o.consequence}` : ""}`).join("\n")}
|
|
24007
|
+
|
|
24008
|
+
Risk: ${prompt.risk}
|
|
24009
|
+
|
|
24010
|
+
Reply with ONLY the JSON object.`
|
|
24011
|
+
};
|
|
24012
|
+
const resp = await context.provider.complete(
|
|
24013
|
+
{
|
|
24014
|
+
model: context.model,
|
|
24015
|
+
system: sysPrompt,
|
|
24016
|
+
messages: [
|
|
24017
|
+
{
|
|
24018
|
+
role: "user",
|
|
24019
|
+
content: [userPrompt]
|
|
24020
|
+
}
|
|
24021
|
+
],
|
|
24022
|
+
maxTokens: 1024,
|
|
24023
|
+
temperature: 0
|
|
24024
|
+
},
|
|
24025
|
+
{ signal: context.signal }
|
|
24026
|
+
);
|
|
24027
|
+
const text = resp.content.filter((b) => b.type === "text").map((b) => b.text).join("\n").trim();
|
|
24028
|
+
const cleaned = text.replace(/^```(?:json)?\s*/i, "").replace(/```$/, "").trim();
|
|
24029
|
+
try {
|
|
24030
|
+
const parsed = JSON.parse(cleaned);
|
|
24031
|
+
const optId = parsed.optionId ?? prompt.options[0]?.id ?? "";
|
|
24032
|
+
return { optionId: optId, rationale: parsed.rationale ?? "" };
|
|
24033
|
+
} catch {
|
|
24034
|
+
return { optionId: prompt.options[0]?.id ?? "", rationale: text };
|
|
24035
|
+
}
|
|
24036
|
+
}
|
|
24037
|
+
};
|
|
24038
|
+
autonomousCoordinator = new AutonomousCoordinator({
|
|
24039
|
+
sessionDir,
|
|
24040
|
+
fleet: dir.fleet,
|
|
24041
|
+
mailbox,
|
|
24042
|
+
selfAgentId: `leader@${context.session.id ?? "unknown"}`,
|
|
24043
|
+
selfAgentName: "Leader",
|
|
24044
|
+
llmProvider
|
|
24045
|
+
});
|
|
24046
|
+
};
|
|
24047
|
+
if (director) onDirectorReady(director);
|
|
24048
|
+
const offDirectorSpawned = events.onPattern("subagent.spawned", () => {
|
|
24049
|
+
const dir = director;
|
|
24050
|
+
if (dir) {
|
|
24051
|
+
offDirectorSpawned();
|
|
24052
|
+
onDirectorReady(dir);
|
|
24053
|
+
}
|
|
24054
|
+
});
|
|
23440
24055
|
try {
|
|
23441
24056
|
code = await runTui({
|
|
23442
24057
|
agent,
|
|
@@ -23521,6 +24136,7 @@ async function execute(deps) {
|
|
|
23521
24136
|
featureSkills: cfg.features?.skills !== false,
|
|
23522
24137
|
featureModelsRegistry: cfg.features?.modelsRegistry !== false,
|
|
23523
24138
|
featureTokenSaving: cfg.features?.tokenSavingMode ?? false,
|
|
24139
|
+
allowOutsideProjectRoot: cfg.features?.allowOutsideProjectRoot ?? true,
|
|
23524
24140
|
contextAutoCompact: cfg.context?.autoCompact !== false,
|
|
23525
24141
|
contextStrategy: cfg.context?.strategy ?? "hybrid",
|
|
23526
24142
|
logLevel: cfg.log?.level ?? "info",
|
|
@@ -23559,9 +24175,11 @@ async function execute(deps) {
|
|
|
23559
24175
|
if (s.enhanceEnabled !== void 0) a["enhance"] = s.enhanceEnabled;
|
|
23560
24176
|
if (s.enhanceLanguage !== void 0) a["enhanceLanguage"] = s.enhanceLanguage;
|
|
23561
24177
|
if (s.autonomyNextPrompt !== void 0) a["autonomyNextPrompt"] = s.autonomyNextPrompt;
|
|
24178
|
+
if (s.autoProceedMaxIterations !== void 0)
|
|
24179
|
+
a["autoProceedMaxIterations"] = s.autoProceedMaxIterations;
|
|
23562
24180
|
}
|
|
23563
24181
|
);
|
|
23564
|
-
if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0) {
|
|
24182
|
+
if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0 || s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0 || s.logLevel !== void 0 || s.auditLevel !== void 0 || s.indexOnStart !== void 0 || s.maxIterations !== void 0 || s.nextPrediction !== void 0 || s.debugStream !== void 0 || s.configScope !== void 0 || s.enhanceDelayMs !== void 0) {
|
|
23565
24183
|
const configScope = s.configScope ?? configStore.get().configScope ?? "global";
|
|
23566
24184
|
const targetPath = configScope === "project" && wpaths.inProjectConfig ? wpaths.inProjectConfig : wpaths.globalConfig;
|
|
23567
24185
|
let raw;
|
|
@@ -23578,7 +24196,7 @@ async function execute(deps) {
|
|
|
23578
24196
|
if (s.nextPrediction !== void 0) {
|
|
23579
24197
|
decrypted.nextPrediction = s.nextPrediction;
|
|
23580
24198
|
}
|
|
23581
|
-
if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0) {
|
|
24199
|
+
if (s.featureMcp !== void 0 || s.featurePlugins !== void 0 || s.featureMemory !== void 0 || s.featureSkills !== void 0 || s.featureModelsRegistry !== void 0 || s.featureTokenSaving !== void 0 || s.allowOutsideProjectRoot !== void 0) {
|
|
23582
24200
|
const feats = decrypted.features ?? {};
|
|
23583
24201
|
if (s.featureMcp !== void 0) feats.mcp = s.featureMcp;
|
|
23584
24202
|
if (s.featurePlugins !== void 0) feats.plugins = s.featurePlugins;
|
|
@@ -23588,6 +24206,8 @@ async function execute(deps) {
|
|
|
23588
24206
|
feats.modelsRegistry = s.featureModelsRegistry;
|
|
23589
24207
|
if (s.featureTokenSaving !== void 0)
|
|
23590
24208
|
feats.tokenSavingMode = s.featureTokenSaving;
|
|
24209
|
+
if (s.allowOutsideProjectRoot !== void 0)
|
|
24210
|
+
feats.allowOutsideProjectRoot = s.allowOutsideProjectRoot;
|
|
23591
24211
|
decrypted.features = feats;
|
|
23592
24212
|
}
|
|
23593
24213
|
if (s.contextAutoCompact !== void 0 || s.contextStrategy !== void 0) {
|
|
@@ -23673,6 +24293,7 @@ async function execute(deps) {
|
|
|
23673
24293
|
if (s.streamFleet !== void 0) {
|
|
23674
24294
|
fleetStreamController?.setEnabled(s.streamFleet);
|
|
23675
24295
|
}
|
|
24296
|
+
deps.applyLiveSettings?.(s);
|
|
23676
24297
|
return null;
|
|
23677
24298
|
} catch (err) {
|
|
23678
24299
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -23697,6 +24318,17 @@ async function execute(deps) {
|
|
|
23697
24318
|
confirmExit: config.autonomy?.["confirmExit"] ?? true,
|
|
23698
24319
|
director,
|
|
23699
24320
|
fleetRoster,
|
|
24321
|
+
// ── AutonomousCoordinator: project-level multi-session coordination ─────────
|
|
24322
|
+
// The coordinator tracks goals, tasks, knowledge, and consensus across all
|
|
24323
|
+
// active sessions in the same project. It runs independently of the leader
|
|
24324
|
+
// agent and is accessible to any session in the project via the GlobalMailbox.
|
|
24325
|
+
getAutonomousCoordinator: () => autonomousCoordinator,
|
|
24326
|
+
subscribeCoordinatorEvents: (fn) => {
|
|
24327
|
+
coordinatorEvents.add(fn);
|
|
24328
|
+
return () => {
|
|
24329
|
+
coordinatorEvents.delete(fn);
|
|
24330
|
+
};
|
|
24331
|
+
},
|
|
23700
24332
|
// /clear: signal the TUI to wipe entries and reset fleet/leader stats
|
|
23701
24333
|
// AND bump the context chip version — so the display reflects a
|
|
23702
24334
|
// completely fresh session after the backend has been cleared.
|
|
@@ -24080,6 +24712,7 @@ ${parts.join("\n")}
|
|
|
24080
24712
|
}
|
|
24081
24713
|
} finally {
|
|
24082
24714
|
renderer.setSilent(false);
|
|
24715
|
+
offDirectorSpawned();
|
|
24083
24716
|
}
|
|
24084
24717
|
} else if (flags.webui) {
|
|
24085
24718
|
agent.disableInteractiveConfirmation();
|
|
@@ -25486,7 +26119,7 @@ function setupMetrics(params) {
|
|
|
25486
26119
|
});
|
|
25487
26120
|
} catch (err) {
|
|
25488
26121
|
logger.warn(
|
|
25489
|
-
`metrics endpoint failed to start: ${
|
|
26122
|
+
`metrics endpoint failed to start: ${toErrorMessage(err)}`
|
|
25490
26123
|
);
|
|
25491
26124
|
}
|
|
25492
26125
|
}
|
|
@@ -25542,9 +26175,11 @@ async function setupCompaction(params) {
|
|
|
25542
26175
|
context.meta["contextWindowMode"] = initialPolicy.id;
|
|
25543
26176
|
context.meta["contextWindowPolicy"] = initialPolicy;
|
|
25544
26177
|
let autoCompactor;
|
|
25545
|
-
|
|
26178
|
+
let resolvedBridge;
|
|
26179
|
+
if (effectiveMaxContext > 0) {
|
|
25546
26180
|
const auditLevel = resolveAuditLevel(fullConfig ?? config);
|
|
25547
26181
|
const sessionBridge = providedBridge ?? createSessionEventBridge(sessionWriter, auditLevel);
|
|
26182
|
+
resolvedBridge = sessionBridge;
|
|
25548
26183
|
autoCompactor = new AutoCompactionMiddleware(
|
|
25549
26184
|
compactor,
|
|
25550
26185
|
effectiveMaxContext,
|
|
@@ -25568,9 +26203,10 @@ async function setupCompaction(params) {
|
|
|
25568
26203
|
sessionBridge
|
|
25569
26204
|
}
|
|
25570
26205
|
);
|
|
26206
|
+
autoCompactor.setEnabled(config.context.autoCompact !== false);
|
|
25571
26207
|
pipelines.contextWindow.use({ name: "AutoCompaction", handler: autoCompactor.handler() });
|
|
25572
26208
|
}
|
|
25573
|
-
return { effectiveMaxContext, autoCompactor };
|
|
26209
|
+
return { effectiveMaxContext, autoCompactor, sessionBridge: resolvedBridge };
|
|
25574
26210
|
}
|
|
25575
26211
|
function createAgent(params) {
|
|
25576
26212
|
const secretScrubber = params.container.resolve(TOKENS.SecretScrubber);
|
|
@@ -25676,7 +26312,7 @@ async function setupSession(params) {
|
|
|
25676
26312
|
`Resumed session ${resumed.data.metadata.id} \u2014 ${restoredMessages.length} messages, ${restoredToolCalls.length} tool executions, ${resumed.data.usage.input + resumed.data.usage.output} tokens used previously.`
|
|
25677
26313
|
);
|
|
25678
26314
|
} catch (err) {
|
|
25679
|
-
renderer.writeError(`Resume failed: ${
|
|
26315
|
+
renderer.writeError(`Resume failed: ${toErrorMessage(err)}`);
|
|
25680
26316
|
throw Object.assign(new Error("RESUME_FAILED"), { exitCode: 2 });
|
|
25681
26317
|
}
|
|
25682
26318
|
} else {
|
|
@@ -25714,7 +26350,8 @@ async function setupSession(params) {
|
|
|
25714
26350
|
model: config.model,
|
|
25715
26351
|
agentId: "leader",
|
|
25716
26352
|
agentName: "Leader Agent",
|
|
25717
|
-
traceId
|
|
26353
|
+
traceId,
|
|
26354
|
+
allowOutsideProjectRoot: config.features?.allowOutsideProjectRoot ?? true
|
|
25718
26355
|
});
|
|
25719
26356
|
context.meta["packageTrackerOpts"] = {
|
|
25720
26357
|
storageDir: wpaths.projectDir,
|
|
@@ -26034,7 +26671,10 @@ async function main(argv) {
|
|
|
26034
26671
|
const evOn = (event, handler) => {
|
|
26035
26672
|
events.on(event, handler);
|
|
26036
26673
|
teardownHandlers.push(
|
|
26037
|
-
() =>
|
|
26674
|
+
() => (
|
|
26675
|
+
// biome-ignore lint/suspicious/noExplicitAny: dynamic event dispatcher signature
|
|
26676
|
+
events.off(event, handler)
|
|
26677
|
+
)
|
|
26038
26678
|
);
|
|
26039
26679
|
};
|
|
26040
26680
|
evOn("provider.response", (e) => {
|
|
@@ -27553,6 +28193,10 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
27553
28193
|
tokenCounter,
|
|
27554
28194
|
config,
|
|
27555
28195
|
configStore,
|
|
28196
|
+
// Project-scoped mailbox — the AutonomousCoordinator in execution.ts
|
|
28197
|
+
// subscribes to it so goals/tasks/knowledge are shared with other
|
|
28198
|
+
// terminals working on the same project.
|
|
28199
|
+
mailbox: brainMailbox,
|
|
27556
28200
|
renderer,
|
|
27557
28201
|
reader,
|
|
27558
28202
|
session,
|
|
@@ -27592,6 +28236,34 @@ Restart WrongStack to load or unload plugin code in this session.`;
|
|
|
27592
28236
|
return autonomyMode;
|
|
27593
28237
|
},
|
|
27594
28238
|
getNextPredict: () => nextPredictEnabled,
|
|
28239
|
+
applyLiveSettings: (s) => {
|
|
28240
|
+
try {
|
|
28241
|
+
if (s.yolo !== void 0) {
|
|
28242
|
+
container.resolve(TOKENS.PermissionPolicy).setYolo?.(s.yolo);
|
|
28243
|
+
config = patchConfig(config, { yolo: s.yolo });
|
|
28244
|
+
}
|
|
28245
|
+
if (s.nextPrediction !== void 0) {
|
|
28246
|
+
nextPredictEnabled = s.nextPrediction;
|
|
28247
|
+
config = patchConfig(config, { nextPrediction: s.nextPrediction });
|
|
28248
|
+
}
|
|
28249
|
+
if (s.enhanceEnabled !== void 0) {
|
|
28250
|
+
enhanceController?.setEnabled(s.enhanceEnabled);
|
|
28251
|
+
}
|
|
28252
|
+
if (s.maxIterations !== void 0) {
|
|
28253
|
+
agent.maxIterations = s.maxIterations;
|
|
28254
|
+
}
|
|
28255
|
+
if (s.logLevel !== void 0) {
|
|
28256
|
+
container.resolve(TOKENS.Logger).level = s.logLevel;
|
|
28257
|
+
}
|
|
28258
|
+
if (s.auditLevel !== void 0) {
|
|
28259
|
+
sessionBridge.setAuditLevel(s.auditLevel);
|
|
28260
|
+
}
|
|
28261
|
+
if (s.contextAutoCompact !== void 0) {
|
|
28262
|
+
autoCompactor?.setEnabled(s.contextAutoCompact);
|
|
28263
|
+
}
|
|
28264
|
+
} catch {
|
|
28265
|
+
}
|
|
28266
|
+
},
|
|
27595
28267
|
onSuggestionsParsed: (suggestions) => {
|
|
27596
28268
|
currentSuggestions = suggestions ?? [];
|
|
27597
28269
|
setSuggestions(suggestions ?? []);
|
|
@@ -27674,7 +28346,9 @@ Reply YES to auto-proceed, NO to wait for human input.`
|
|
|
27674
28346
|
getBrainLog: () => brainLog,
|
|
27675
28347
|
// Clean up SessionStats event listeners and all EventBus handlers when the REPL exits.
|
|
27676
28348
|
onDestroy: () => {
|
|
27677
|
-
teardownHandlers.forEach((fn) =>
|
|
28349
|
+
teardownHandlers.forEach((fn) => {
|
|
28350
|
+
fn();
|
|
28351
|
+
});
|
|
27678
28352
|
stats.destroy(events);
|
|
27679
28353
|
}
|
|
27680
28354
|
});
|