@wrongstack/webui-server 0.284.0 → 0.285.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.d.ts +11 -2300
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1019 -277
- package/dist/index.js.map +7 -1
- package/dist/server/autophase-routes.d.ts +10 -0
- package/dist/server/autophase-routes.d.ts.map +1 -0
- package/dist/server/autophase-ws-handler.d.ts +87 -0
- package/dist/server/autophase-ws-handler.d.ts.map +1 -0
- package/dist/server/backend-services.d.ts +114 -0
- package/dist/server/backend-services.d.ts.map +1 -0
- package/dist/server/boot.d.ts +19 -0
- package/dist/server/boot.d.ts.map +1 -0
- package/dist/server/brain-routes.d.ts +9 -0
- package/dist/server/brain-routes.d.ts.map +1 -0
- package/dist/server/codebase-indexing.d.ts +15 -0
- package/dist/server/codebase-indexing.d.ts.map +1 -0
- package/dist/server/collaboration-ws-handler.d.ts +159 -0
- package/dist/server/collaboration-ws-handler.d.ts.map +1 -0
- package/dist/server/completion-handlers.d.ts +39 -0
- package/dist/server/completion-handlers.d.ts.map +1 -0
- package/dist/server/connection-handler.d.ts +72 -0
- package/dist/server/connection-handler.d.ts.map +1 -0
- package/dist/server/context-meta.d.ts +28 -0
- package/dist/server/context-meta.d.ts.map +1 -0
- package/dist/server/custom-context-modes.d.ts +43 -0
- package/dist/server/custom-context-modes.d.ts.map +1 -0
- package/dist/server/design-handlers.d.ts +40 -0
- package/dist/server/design-handlers.d.ts.map +1 -0
- package/dist/server/discover-mailbox-bridge.d.ts +26 -0
- package/dist/server/discover-mailbox-bridge.d.ts.map +1 -0
- package/dist/server/entry.d.ts +2 -2
- package/dist/server/entry.d.ts.map +1 -0
- package/dist/server/entry.js +811 -300
- package/dist/server/entry.js.map +7 -1
- package/dist/server/eternal-iteration-broadcast.d.ts +11 -0
- package/dist/server/eternal-iteration-broadcast.d.ts.map +1 -0
- package/dist/server/file-handlers.d.ts +45 -0
- package/dist/server/file-handlers.d.ts.map +1 -0
- package/dist/server/file-picker.d.ts +26 -0
- package/dist/server/file-picker.d.ts.map +1 -0
- package/dist/server/git-handlers.d.ts +55 -0
- package/dist/server/git-handlers.d.ts.map +1 -0
- package/dist/server/goal-handlers.d.ts +19 -0
- package/dist/server/goal-handlers.d.ts.map +1 -0
- package/dist/server/handlers/index.d.ts +12 -0
- package/dist/server/handlers/index.d.ts.map +1 -0
- package/dist/server/handlers/worklist-handlers.d.ts +49 -0
- package/dist/server/handlers/worklist-handlers.d.ts.map +1 -0
- package/dist/server/handlers.d.ts +1 -51
- package/dist/server/handlers.js +17 -8
- package/dist/server/handlers.js.map +7 -1
- package/dist/server/http-server/analytics-handler.d.ts +35 -0
- package/dist/server/http-server/analytics-handler.d.ts.map +1 -0
- package/dist/server/http-server/api-handlers.d.ts +44 -0
- package/dist/server/http-server/api-handlers.d.ts.map +1 -0
- package/dist/server/http-server.d.ts +108 -0
- package/dist/server/http-server.d.ts.map +1 -0
- package/dist/server/index.d.ts +93 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/instance-registry.d.ts +63 -0
- package/dist/server/instance-registry.d.ts.map +1 -0
- package/dist/server/kanban-routes.d.ts +7 -0
- package/dist/server/kanban-routes.d.ts.map +1 -0
- package/dist/server/lifecycle.d.ts +51 -0
- package/dist/server/lifecycle.d.ts.map +1 -0
- package/dist/server/mailbox-handlers.d.ts +51 -0
- package/dist/server/mailbox-handlers.d.ts.map +1 -0
- package/dist/server/mailbox-routes.d.ts +10 -0
- package/dist/server/mailbox-routes.d.ts.map +1 -0
- package/dist/server/mcp-handlers.d.ts +46 -0
- package/dist/server/mcp-handlers.d.ts.map +1 -0
- package/dist/server/mcp-routes.d.ts +37 -0
- package/dist/server/mcp-routes.d.ts.map +1 -0
- package/dist/server/memory-handlers.d.ts +28 -0
- package/dist/server/memory-handlers.d.ts.map +1 -0
- package/dist/server/message-dispatcher.d.ts +41 -0
- package/dist/server/message-dispatcher.d.ts.map +1 -0
- package/dist/server/mode-handlers.d.ts +50 -0
- package/dist/server/mode-handlers.d.ts.map +1 -0
- package/dist/server/mode-routes.d.ts +8 -0
- package/dist/server/mode-routes.d.ts.map +1 -0
- package/dist/server/model-auto-discovery.d.ts +9 -0
- package/dist/server/model-auto-discovery.d.ts.map +1 -0
- package/dist/server/model-catalog.d.ts +16 -0
- package/dist/server/model-catalog.d.ts.map +1 -0
- package/dist/server/open-browser.d.ts +16 -0
- package/dist/server/open-browser.d.ts.map +1 -0
- package/dist/server/path-containment.d.ts +3 -0
- package/dist/server/path-containment.d.ts.map +1 -0
- package/dist/server/pending-confirms.d.ts +14 -0
- package/dist/server/pending-confirms.d.ts.map +1 -0
- package/dist/server/port-utils.d.ts +28 -0
- package/dist/server/port-utils.d.ts.map +1 -0
- package/dist/server/pre-context-services.d.ts +58 -0
- package/dist/server/pre-context-services.d.ts.map +1 -0
- package/dist/server/pref-helpers.d.ts +43 -0
- package/dist/server/pref-helpers.d.ts.map +1 -0
- package/dist/server/prefs-routes.d.ts +27 -0
- package/dist/server/prefs-routes.d.ts.map +1 -0
- package/dist/server/process-handlers.d.ts +20 -0
- package/dist/server/process-handlers.d.ts.map +1 -0
- package/dist/server/project-handlers.d.ts +53 -0
- package/dist/server/project-handlers.d.ts.map +1 -0
- package/dist/server/project-routes.d.ts +10 -0
- package/dist/server/project-routes.d.ts.map +1 -0
- package/dist/server/projects-manifest.d.ts +18 -0
- package/dist/server/projects-manifest.d.ts.map +1 -0
- package/dist/server/prompts-handlers.d.ts +38 -0
- package/dist/server/prompts-handlers.d.ts.map +1 -0
- package/dist/server/provider-config-io.d.ts +15 -0
- package/dist/server/provider-config-io.d.ts.map +1 -0
- package/dist/server/provider-config-standalone.d.ts +13 -0
- package/dist/server/provider-config-standalone.d.ts.map +1 -0
- package/dist/server/provider-handlers.d.ts +74 -0
- package/dist/server/provider-handlers.d.ts.map +1 -0
- package/dist/server/provider-keys.d.ts +53 -0
- package/dist/server/provider-keys.d.ts.map +1 -0
- package/dist/server/provider-routes.d.ts +13 -0
- package/dist/server/provider-routes.d.ts.map +1 -0
- package/dist/server/provider-store.d.ts +26 -0
- package/dist/server/provider-store.d.ts.map +1 -0
- package/dist/server/routes.d.ts +182 -0
- package/dist/server/routes.d.ts.map +1 -0
- package/dist/server/sdd-board-routes.d.ts +11 -0
- package/dist/server/sdd-board-routes.d.ts.map +1 -0
- package/dist/server/sdd-board-ws-handler.d.ts +57 -0
- package/dist/server/sdd-board-ws-handler.d.ts.map +1 -0
- package/dist/server/sdd-wizard-routes.d.ts +16 -0
- package/dist/server/sdd-wizard-routes.d.ts.map +1 -0
- package/dist/server/sdd-wizard-wiring.d.ts +26 -0
- package/dist/server/sdd-wizard-wiring.d.ts.map +1 -0
- package/dist/server/sdd-wizard-ws-handler.d.ts +66 -0
- package/dist/server/sdd-wizard-ws-handler.d.ts.map +1 -0
- package/dist/server/server-runtime.d.ts +118 -0
- package/dist/server/server-runtime.d.ts.map +1 -0
- package/dist/server/session-handlers.d.ts +44 -0
- package/dist/server/session-handlers.d.ts.map +1 -0
- package/dist/server/session-routes.d.ts +23 -0
- package/dist/server/session-routes.d.ts.map +1 -0
- package/dist/server/setup-events.d.ts +67 -0
- package/dist/server/setup-events.d.ts.map +1 -0
- package/dist/server/setup-screen.d.ts +44 -0
- package/dist/server/setup-screen.d.ts.map +1 -0
- package/dist/server/shell-git-routes.d.ts +10 -0
- package/dist/server/shell-git-routes.d.ts.map +1 -0
- package/dist/server/shell-open.d.ts +12 -0
- package/dist/server/shell-open.d.ts.map +1 -0
- package/dist/server/skills-handlers.d.ts +77 -0
- package/dist/server/skills-handlers.d.ts.map +1 -0
- package/dist/server/specs-routes.d.ts +11 -0
- package/dist/server/specs-routes.d.ts.map +1 -0
- package/dist/server/specs-ws-handler.d.ts +34 -0
- package/dist/server/specs-ws-handler.d.ts.map +1 -0
- package/dist/server/start-webui.d.ts +29 -0
- package/dist/server/start-webui.d.ts.map +1 -0
- package/dist/server/terminal-ws-handler.d.ts +70 -0
- package/dist/server/terminal-ws-handler.d.ts.map +1 -0
- package/dist/server/token-estimator.d.ts +66 -0
- package/dist/server/token-estimator.d.ts.map +1 -0
- package/dist/server/types.d.ts +143 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/usage-cost.d.ts +39 -0
- package/dist/server/usage-cost.d.ts.map +1 -0
- package/dist/server/worktree-ws-handler.d.ts +67 -0
- package/dist/server/worktree-ws-handler.d.ts.map +1 -0
- package/dist/server/ws-auth.d.ts +83 -0
- package/dist/server/ws-auth.d.ts.map +1 -0
- package/dist/server/ws-payload-validation.d.ts +122 -0
- package/dist/server/ws-payload-validation.d.ts.map +1 -0
- package/dist/server/ws-utils.d.ts +38 -0
- package/dist/server/ws-utils.d.ts.map +1 -0
- package/dist/server/zip.d.ts +9 -0
- package/dist/server/zip.d.ts.map +1 -0
- package/package.json +11 -12
package/dist/index.js
CHANGED
|
@@ -1,34 +1,14 @@
|
|
|
1
|
-
import { spawn, spawnSync } from 'child_process';
|
|
2
|
-
import { toErrorMessage, wstackGlobalRoot, resolveWstackPaths, atomicWrite as atomicWrite$1 } from '@wrongstack/core/utils';
|
|
3
|
-
import { DefaultSecretScrubber, PhaseStore, PhaseGraphBuilder, WorktreeManager, PhaseOrchestrator, AutoPhasePlanner, assignNickname, getDesignState, getDesignKitLoader, isDesignStack, loadActiveKit, setActiveKit, recordKitChoice, applyTokenOverrides, recordOverrides, setDesignOverrides, materializeTokens, runDesignVerify, ToolValidationError, atomicWrite, allServers, ConfigError, DefaultSecretVault, expectDefined, computeTaskProgress, bootConfig as bootConfig$1, resolveProjectDir, GlobalMailbox, createDefaultPipelines, resolveSessionLoggingConfig, createSessionEventBridge, watchProviderConfig, listContextWindowModes, DefaultModelsRegistry, TOKENS, ProviderRegistry, ToolRegistry, DefaultMemoryStore, EventBus, makeMailboxTool, makeMailSendTool, makeMailInboxTool, makeFleetStatusTool, applyToolDescriptionModes, applyToolResultRenderModes, DefaultSessionStore, getSessionRegistry, DEFAULT_SESSION_PRUNE_DAYS, DefaultSessionReader, AnnotationsStore, FleetNotifier, AgentStatusTracker, DefaultModeStore, DefaultSkillLoader, SkillInstaller, DefaultPromptLoader, PromptUsageStore, DefaultSystemPromptBuilder, Context, resolveContextWindowPolicy, CollaborationBus, collabInjectMiddleware, collabPauseMiddleware, installDesignStudioMiddleware, createStrategyCompactor, AutoCompactionMiddleware, estimateRequestTokensCalibrated, ToolExecutor, DEFAULT_TOOLS_CONFIG, Agent, ObservableBrainArbiter, createTieredBrainArbiter, DefaultBrainArbiter, BrainMonitor, mailboxSessionTag, wstackGlobalRoot as wstackGlobalRoot$1, createAutonomyBrain, DEFAULT_CONTEXT_WINDOW_MODE_ID, repairToolUseAdjacency, resolveWstackPaths as resolveWstackPaths$1, recentTextTurns, gatedEnhancerReasoning, enhanceUserPrompt, resolveProviderModelList, projectSlug, deserializeTaskGraph, serializeTaskGraph } from '@wrongstack/core';
|
|
4
|
-
import * as path5 from 'path';
|
|
5
|
-
import path5__default, { resolve, join, sep, dirname } from 'path';
|
|
6
|
-
import { searchCodebaseIndex } from '@wrongstack/tools/codebase-index/index';
|
|
7
|
-
import { randomBytes, timingSafeEqual, randomUUID } from 'crypto';
|
|
8
|
-
import { WebSocket, WebSocketServer } from 'ws';
|
|
9
|
-
import * as fs4 from 'fs/promises';
|
|
10
|
-
import * as http from 'http';
|
|
11
|
-
import { Buffer } from 'buffer';
|
|
12
|
-
import * as os from 'os';
|
|
13
|
-
import { listMcp, addMcp, updateMcp, removeMcp, enableMcp, disableMcp, restartMcp, discoverMcp, MCPRegistry } from '@wrongstack/mcp';
|
|
14
|
-
import * as net from 'net';
|
|
15
|
-
import { decryptConfigSecrets, encryptConfigSecrets } from '@wrongstack/core/security';
|
|
16
|
-
import { SddBoardStore, applySddLifecycle, SddRunRegistry, SddInterviewDriver, cleanupStaleSddWorktrees, makeCommandVerifier, SddSupervisor, makeLlmSubtaskGenerator, startSddRun, TaskGraphStore, SpecStore } from '@wrongstack/sdd';
|
|
17
|
-
import * as fs12 from 'fs';
|
|
18
|
-
import { promises, watch, existsSync } from 'fs';
|
|
19
|
-
import JSZip from 'jszip';
|
|
20
|
-
import { createRequire } from 'module';
|
|
21
|
-
import { fileURLToPath } from 'url';
|
|
22
|
-
import { capabilitiesFor, makeProviderFromConfig, buildProviderFactoriesFromRegistry, discoverOpenAICompatibleModels, COMPATIBLE_PRESETS } from '@wrongstack/providers';
|
|
23
|
-
import { DefaultTokenCounter } from '@wrongstack/core/infrastructure';
|
|
24
|
-
import { createDefaultContainer, makeLightSubagentFactory } from '@wrongstack/runtime';
|
|
25
|
-
import { runStartupIndex, isIndexableFile, enqueueReindex, cancelPendingReindexes, shutdownCodebaseIndexHost, ensureSessionShell, builtinToolsPack, rememberTool, forgetTool, searchMemoryTool, relatedMemoryTool, configureExecPolicy, configureDangerBypass } from '@wrongstack/tools';
|
|
26
|
-
import { readLiveLock } from '@wrongstack/core/coordination';
|
|
27
|
-
import { removeColumn, addColumn, getTask, removeTask, assignTask, updateGoalMetricOnTask, addGoalMetricToTask, releaseTaskClaim, claimReadyTask, getTaskChain, setTaskChain, copyTaskToBoard, transferTaskToBoard, moveTask, updateTask, mergeTasks, splitTask, addTask, syncBoardFromTaskGraph, exportBoardToTaskGraph, getKanbanOrchestrationSnapshot, listReadyTasks, createBoard, generateBoardFromDescription, parseLinesIntoTasks, getBoard, removeBoard, duplicateBoard, updateBoard, getKanbanQueueHealth, listBoards } from '@wrongstack/kanban';
|
|
28
|
-
import { beginOAuthLogin } from '@wrongstack/providers/oauth';
|
|
29
|
-
import { probeLocalLlm } from '@wrongstack/runtime/probe';
|
|
30
|
-
|
|
31
1
|
// src/server/autophase-ws-handler.ts
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
4
|
+
import {
|
|
5
|
+
assignNickname,
|
|
6
|
+
AutoPhasePlanner,
|
|
7
|
+
PhaseGraphBuilder,
|
|
8
|
+
PhaseOrchestrator,
|
|
9
|
+
PhaseStore,
|
|
10
|
+
WorktreeManager
|
|
11
|
+
} from "@wrongstack/core";
|
|
32
12
|
function deriveTitle(goal) {
|
|
33
13
|
const firstLine = goal.split("\n").map((l) => l.trim()).find(Boolean);
|
|
34
14
|
if (!firstLine) return "AutoPhase";
|
|
@@ -519,6 +499,14 @@ Type: ${task.type}`;
|
|
|
519
499
|
}
|
|
520
500
|
}
|
|
521
501
|
};
|
|
502
|
+
|
|
503
|
+
// src/server/completion-handlers.ts
|
|
504
|
+
import * as path from "node:path";
|
|
505
|
+
import { searchCodebaseIndex } from "@wrongstack/tools/codebase-index/index";
|
|
506
|
+
|
|
507
|
+
// src/server/ws-utils.ts
|
|
508
|
+
import { randomBytes } from "node:crypto";
|
|
509
|
+
import { WebSocket } from "ws";
|
|
522
510
|
function send(ws, msg) {
|
|
523
511
|
if (ws.readyState === WebSocket.OPEN) {
|
|
524
512
|
ws.send(JSON.stringify(msg));
|
|
@@ -650,8 +638,8 @@ async function handleCompletionRequest(ws, msg, opts) {
|
|
|
650
638
|
return;
|
|
651
639
|
}
|
|
652
640
|
const payload = parsed.payload;
|
|
653
|
-
const projectRoot =
|
|
654
|
-
const resolved =
|
|
641
|
+
const projectRoot = path.resolve(opts.projectRoot);
|
|
642
|
+
const resolved = path.resolve(projectRoot, payload.filePath);
|
|
655
643
|
if (!isInside(projectRoot, resolved)) {
|
|
656
644
|
send(ws, {
|
|
657
645
|
type: "completion.result",
|
|
@@ -1050,7 +1038,7 @@ function buildSearchQuery(linePrefix, filePath) {
|
|
|
1050
1038
|
if (memberMatch?.[1]) return memberMatch[1];
|
|
1051
1039
|
const token = linePrefix.match(/([A-Za-z_$][\w$]*)$/)?.[1];
|
|
1052
1040
|
if (token && token.length >= 2) return token;
|
|
1053
|
-
return
|
|
1041
|
+
return path.basename(filePath, path.extname(filePath));
|
|
1054
1042
|
}
|
|
1055
1043
|
function currentLinePrefix(prefix) {
|
|
1056
1044
|
const idx = Math.max(prefix.lastIndexOf("\n"), prefix.lastIndexOf("\r"));
|
|
@@ -1080,11 +1068,16 @@ function head(value, max) {
|
|
|
1080
1068
|
return value.length <= max ? value : value.slice(0, max);
|
|
1081
1069
|
}
|
|
1082
1070
|
function isInside(root, target) {
|
|
1083
|
-
return target === root || target.startsWith(root +
|
|
1071
|
+
return target === root || target.startsWith(root + path.sep);
|
|
1084
1072
|
}
|
|
1073
|
+
|
|
1074
|
+
// src/server/custom-context-modes.ts
|
|
1075
|
+
import { listContextWindowModes, atomicWrite } from "@wrongstack/core";
|
|
1076
|
+
import * as fs from "node:fs/promises";
|
|
1077
|
+
import * as path2 from "node:path";
|
|
1085
1078
|
var STORE_FILENAME = "custom-context-modes.json";
|
|
1086
1079
|
function storePath(wrongstackDir) {
|
|
1087
|
-
return
|
|
1080
|
+
return path2.join(wrongstackDir, STORE_FILENAME);
|
|
1088
1081
|
}
|
|
1089
1082
|
var BUILTIN_IDS = /* @__PURE__ */ new Set(["balanced", "frugal", "deep", "archival"]);
|
|
1090
1083
|
function createCustomModeStore(wrongstackDir) {
|
|
@@ -1092,7 +1085,7 @@ function createCustomModeStore(wrongstackDir) {
|
|
|
1092
1085
|
const load2 = async () => {
|
|
1093
1086
|
modes.clear();
|
|
1094
1087
|
try {
|
|
1095
|
-
const raw = await
|
|
1088
|
+
const raw = await fs.readFile(storePath(wrongstackDir), "utf8");
|
|
1096
1089
|
const parsed = JSON.parse(raw);
|
|
1097
1090
|
if (Array.isArray(parsed.modes)) {
|
|
1098
1091
|
for (const m of parsed.modes) {
|
|
@@ -1197,6 +1190,23 @@ function createCustomModeStore(wrongstackDir) {
|
|
|
1197
1190
|
};
|
|
1198
1191
|
return { modes, load: load2, save: save2, create, update, remove, list };
|
|
1199
1192
|
}
|
|
1193
|
+
|
|
1194
|
+
// src/server/design-handlers.ts
|
|
1195
|
+
import * as fs2 from "node:fs/promises";
|
|
1196
|
+
import * as path3 from "node:path";
|
|
1197
|
+
import {
|
|
1198
|
+
applyTokenOverrides,
|
|
1199
|
+
getDesignKitLoader,
|
|
1200
|
+
getDesignState,
|
|
1201
|
+
isDesignStack,
|
|
1202
|
+
loadActiveKit,
|
|
1203
|
+
materializeTokens,
|
|
1204
|
+
recordKitChoice,
|
|
1205
|
+
recordOverrides,
|
|
1206
|
+
runDesignVerify,
|
|
1207
|
+
setActiveKit,
|
|
1208
|
+
setDesignOverrides
|
|
1209
|
+
} from "@wrongstack/core";
|
|
1200
1210
|
function readOverrides(value) {
|
|
1201
1211
|
const out = {};
|
|
1202
1212
|
if (value && typeof value === "object") {
|
|
@@ -1344,9 +1354,9 @@ async function handleDesignMaterialize(ws, ctx, msg) {
|
|
|
1344
1354
|
kitId: active.kit,
|
|
1345
1355
|
outPath: typeof payload.out === "string" ? payload.out : void 0
|
|
1346
1356
|
});
|
|
1347
|
-
const abs =
|
|
1348
|
-
await
|
|
1349
|
-
await
|
|
1357
|
+
const abs = path3.join(ctx.projectRoot, result.path);
|
|
1358
|
+
await fs2.mkdir(path3.dirname(abs), { recursive: true });
|
|
1359
|
+
await fs2.writeFile(abs, result.content);
|
|
1350
1360
|
send(ws, {
|
|
1351
1361
|
type: "design.materialize",
|
|
1352
1362
|
payload: { ok: true, path: result.path, format: result.format, stack }
|
|
@@ -1405,6 +1415,11 @@ function createEternalSubscription(subscribe, broadcast2, clientsRef) {
|
|
|
1405
1415
|
};
|
|
1406
1416
|
}
|
|
1407
1417
|
|
|
1418
|
+
// src/server/file-handlers.ts
|
|
1419
|
+
import * as fs4 from "node:fs/promises";
|
|
1420
|
+
import * as path5 from "node:path";
|
|
1421
|
+
import { atomicWrite as atomicWrite2, ToolValidationError as ToolValidationError2 } from "@wrongstack/core";
|
|
1422
|
+
|
|
1408
1423
|
// src/server/file-picker.ts
|
|
1409
1424
|
var SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
1410
1425
|
".git",
|
|
@@ -1452,15 +1467,20 @@ function rankFiles(paths, query, limit) {
|
|
|
1452
1467
|
scored.sort((a, b) => b.score - a.score || a.path.localeCompare(b.path));
|
|
1453
1468
|
return scored.slice(0, limit).map((s) => s.path);
|
|
1454
1469
|
}
|
|
1470
|
+
|
|
1471
|
+
// src/server/path-containment.ts
|
|
1472
|
+
import * as fs3 from "node:fs/promises";
|
|
1473
|
+
import * as path4 from "node:path";
|
|
1474
|
+
import { ToolValidationError } from "@wrongstack/core";
|
|
1455
1475
|
function isPathInside(root, target) {
|
|
1456
|
-
const relative4 =
|
|
1457
|
-
return relative4 === "" || !relative4.startsWith("..") && !
|
|
1476
|
+
const relative4 = path4.relative(root, target);
|
|
1477
|
+
return relative4 === "" || !relative4.startsWith("..") && !path4.isAbsolute(relative4);
|
|
1458
1478
|
}
|
|
1459
1479
|
async function resolveWorkingDirInsideProject(projectRoot, inputPath) {
|
|
1460
|
-
const resolved =
|
|
1480
|
+
const resolved = path4.resolve(projectRoot, inputPath);
|
|
1461
1481
|
let stat2;
|
|
1462
1482
|
try {
|
|
1463
|
-
stat2 = await
|
|
1483
|
+
stat2 = await fs3.stat(resolved);
|
|
1464
1484
|
} catch {
|
|
1465
1485
|
throw new ToolValidationError({
|
|
1466
1486
|
message: `Directory not found or not accessible: ${resolved}`,
|
|
@@ -1474,8 +1494,8 @@ async function resolveWorkingDirInsideProject(projectRoot, inputPath) {
|
|
|
1474
1494
|
});
|
|
1475
1495
|
}
|
|
1476
1496
|
const [realProjectRoot, realResolved] = await Promise.all([
|
|
1477
|
-
|
|
1478
|
-
|
|
1497
|
+
fs3.realpath(projectRoot),
|
|
1498
|
+
fs3.realpath(resolved)
|
|
1479
1499
|
]);
|
|
1480
1500
|
if (!isPathInside(realProjectRoot, realResolved)) {
|
|
1481
1501
|
throw new ToolValidationError({
|
|
@@ -1490,14 +1510,14 @@ async function resolveWorkingDirInsideProject(projectRoot, inputPath) {
|
|
|
1490
1510
|
async function resolveFileInsideProject(projectRoot, filePath) {
|
|
1491
1511
|
const resolved = path5.resolve(projectRoot, filePath);
|
|
1492
1512
|
if (!isPathInside(projectRoot, resolved)) {
|
|
1493
|
-
throw new
|
|
1513
|
+
throw new ToolValidationError2({ message: "Path outside project root", field: "path" });
|
|
1494
1514
|
}
|
|
1495
1515
|
const { parent, base } = splitParentAndBase(resolved);
|
|
1496
1516
|
const realProjectRoot = await fs4.realpath(projectRoot);
|
|
1497
1517
|
const realParent = await realpathAllowMissing(parent);
|
|
1498
1518
|
const realFull = path5.join(realParent, base);
|
|
1499
1519
|
if (!isPathInside(realProjectRoot, realFull)) {
|
|
1500
|
-
throw new
|
|
1520
|
+
throw new ToolValidationError2({ message: "Path outside project root", field: "path" });
|
|
1501
1521
|
}
|
|
1502
1522
|
return realFull;
|
|
1503
1523
|
}
|
|
@@ -1517,7 +1537,7 @@ async function realpathAllowMissing(p) {
|
|
|
1517
1537
|
while (true) {
|
|
1518
1538
|
const parent = path5.dirname(cursor);
|
|
1519
1539
|
if (parent === cursor) {
|
|
1520
|
-
throw new
|
|
1540
|
+
throw new ToolValidationError2({ message: "Path outside project root", field: "path" });
|
|
1521
1541
|
}
|
|
1522
1542
|
segments.unshift(path5.basename(cursor));
|
|
1523
1543
|
try {
|
|
@@ -1650,7 +1670,7 @@ async function handleFilesWrite(ws, msg, projectRoot, opts = {}) {
|
|
|
1650
1670
|
return;
|
|
1651
1671
|
}
|
|
1652
1672
|
try {
|
|
1653
|
-
await
|
|
1673
|
+
await atomicWrite2(realResolved, content);
|
|
1654
1674
|
send(ws, { type: "files.written", payload: { filePath, success: true } });
|
|
1655
1675
|
if (opts.onWritten) {
|
|
1656
1676
|
void Promise.resolve(opts.onWritten(realResolved)).catch(() => void 0);
|
|
@@ -1714,10 +1734,13 @@ async function handleFilesList(ws, msg, projectRoot) {
|
|
|
1714
1734
|
payload: { files: rankFiles(results, payload.query ?? "", limit) }
|
|
1715
1735
|
});
|
|
1716
1736
|
}
|
|
1737
|
+
|
|
1738
|
+
// src/server/git-handlers.ts
|
|
1739
|
+
import nodePath from "node:path";
|
|
1717
1740
|
async function handleGitInfo(ws, projectRoot) {
|
|
1718
1741
|
const cwd = projectRoot || void 0;
|
|
1719
1742
|
try {
|
|
1720
|
-
const { execFile: ef } = await import(
|
|
1743
|
+
const { execFile: ef } = await import("node:child_process");
|
|
1721
1744
|
const git = (args) => new Promise((resolve10) => {
|
|
1722
1745
|
ef("git", args, { cwd, timeout: 3e3 }, (err, stdout) => {
|
|
1723
1746
|
resolve10(err ? "" : stdout.trim());
|
|
@@ -1745,7 +1768,7 @@ async function handleGitInfo(ws, projectRoot) {
|
|
|
1745
1768
|
}
|
|
1746
1769
|
function makeGit(cwd) {
|
|
1747
1770
|
return async (args) => {
|
|
1748
|
-
const { execFile: ef } = await import(
|
|
1771
|
+
const { execFile: ef } = await import("node:child_process");
|
|
1749
1772
|
return new Promise((resolve10) => {
|
|
1750
1773
|
ef(
|
|
1751
1774
|
"git",
|
|
@@ -1827,14 +1850,14 @@ var MAX_DIFF_BYTES = 2 * 1024 * 1024;
|
|
|
1827
1850
|
async function handleGitDiff(ws, projectRoot, path23) {
|
|
1828
1851
|
const cwd = projectRoot || void 0;
|
|
1829
1852
|
const reply = (extra) => send(ws, { type: "git.diff", payload: { path: path23, ...extra } });
|
|
1830
|
-
if (!path23 || path23.includes("\0") || path23.includes("..") ||
|
|
1853
|
+
if (!path23 || path23.includes("\0") || path23.includes("..") || nodePath.isAbsolute(path23)) {
|
|
1831
1854
|
reply({ oldText: "", newText: "", error: "invalid path" });
|
|
1832
1855
|
return;
|
|
1833
1856
|
}
|
|
1834
1857
|
try {
|
|
1835
1858
|
const git = makeGit(cwd);
|
|
1836
|
-
const { readFile: readFile11 } = await import(
|
|
1837
|
-
const { join: join15 } = await import(
|
|
1859
|
+
const { readFile: readFile11 } = await import("node:fs/promises");
|
|
1860
|
+
const { join: join15 } = await import("node:path");
|
|
1838
1861
|
const oldText = await git(["show", `HEAD:${path23}`]);
|
|
1839
1862
|
let newText = "";
|
|
1840
1863
|
try {
|
|
@@ -1866,6 +1889,11 @@ async function handleGitDiff(ws, projectRoot, path23) {
|
|
|
1866
1889
|
}
|
|
1867
1890
|
}
|
|
1868
1891
|
|
|
1892
|
+
// src/server/http-server.ts
|
|
1893
|
+
import * as fs5 from "node:fs/promises";
|
|
1894
|
+
import * as http from "node:http";
|
|
1895
|
+
import * as path6 from "node:path";
|
|
1896
|
+
|
|
1869
1897
|
// src/server/http-server/api-handlers.ts
|
|
1870
1898
|
async function handleApiSessions(res, globalRoot) {
|
|
1871
1899
|
if (!globalRoot) {
|
|
@@ -1874,7 +1902,7 @@ async function handleApiSessions(res, globalRoot) {
|
|
|
1874
1902
|
return;
|
|
1875
1903
|
}
|
|
1876
1904
|
try {
|
|
1877
|
-
const { SessionRegistry } = await import(
|
|
1905
|
+
const { SessionRegistry } = await import("@wrongstack/core");
|
|
1878
1906
|
const registry = new SessionRegistry(globalRoot);
|
|
1879
1907
|
const sessions = await registry.list();
|
|
1880
1908
|
const result = sessions.map((s) => ({
|
|
@@ -1912,7 +1940,7 @@ async function handleApiSessionAgents(res, globalRoot, sessionId) {
|
|
|
1912
1940
|
return;
|
|
1913
1941
|
}
|
|
1914
1942
|
try {
|
|
1915
|
-
const { SessionRegistry } = await import(
|
|
1943
|
+
const { SessionRegistry } = await import("@wrongstack/core");
|
|
1916
1944
|
const registry = new SessionRegistry(globalRoot);
|
|
1917
1945
|
const entry = await registry.get(sessionId);
|
|
1918
1946
|
if (!entry) {
|
|
@@ -2052,7 +2080,7 @@ async function handleApiSessionEvents(res, globalRoot, sessionId, limit) {
|
|
|
2052
2080
|
return;
|
|
2053
2081
|
}
|
|
2054
2082
|
try {
|
|
2055
|
-
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, DefaultSessionStore: DefaultSessionStore2, DefaultSessionReader: DefaultSessionReader2 } = await import(
|
|
2083
|
+
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, DefaultSessionStore: DefaultSessionStore2, DefaultSessionReader: DefaultSessionReader2 } = await import("@wrongstack/core");
|
|
2056
2084
|
const registry = new SessionRegistry(globalRoot);
|
|
2057
2085
|
const entry = await registry.get(sessionId);
|
|
2058
2086
|
if (!entry) {
|
|
@@ -2134,7 +2162,7 @@ async function handleApiSessionMessage(res, req, globalRoot, sessionId) {
|
|
|
2134
2162
|
const priority = ["low", "normal", "high"].includes(rawPriority) ? rawPriority : "high";
|
|
2135
2163
|
const subject = typeof body["subject"] === "string" && body["subject"].trim() ? body["subject"].trim() : "Message from Fleet HQ";
|
|
2136
2164
|
try {
|
|
2137
|
-
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, GlobalMailbox: GlobalMailbox4, mailboxSessionTag: mailboxSessionTag2 } = await import(
|
|
2165
|
+
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, GlobalMailbox: GlobalMailbox4, mailboxSessionTag: mailboxSessionTag2 } = await import("@wrongstack/core");
|
|
2138
2166
|
const registry = new SessionRegistry(globalRoot);
|
|
2139
2167
|
const entry = await registry.get(sessionId);
|
|
2140
2168
|
if (!entry) {
|
|
@@ -2160,7 +2188,7 @@ async function handleApiSessionMailbox(res, globalRoot, sessionId) {
|
|
|
2160
2188
|
return;
|
|
2161
2189
|
}
|
|
2162
2190
|
try {
|
|
2163
|
-
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, GlobalMailbox: GlobalMailbox4, mailboxSessionTag: mailboxSessionTag2 } = await import(
|
|
2191
|
+
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, GlobalMailbox: GlobalMailbox4, mailboxSessionTag: mailboxSessionTag2 } = await import("@wrongstack/core");
|
|
2164
2192
|
const registry = new SessionRegistry(globalRoot);
|
|
2165
2193
|
const entry = await registry.get(sessionId);
|
|
2166
2194
|
if (!entry) {
|
|
@@ -2218,7 +2246,7 @@ async function handleApiSessionInterrupt(res, req, globalRoot, sessionId) {
|
|
|
2218
2246
|
const reason = typeof body["reason"] === "string" && body["reason"].trim() ? body["reason"].trim() : "Operator requested stop from Fleet HQ";
|
|
2219
2247
|
const from = typeof body["from"] === "string" && body["from"].trim() ? body["from"].trim() : "human@webui";
|
|
2220
2248
|
try {
|
|
2221
|
-
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, GlobalMailbox: GlobalMailbox4, mailboxSessionTag: mailboxSessionTag2 } = await import(
|
|
2249
|
+
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, GlobalMailbox: GlobalMailbox4, mailboxSessionTag: mailboxSessionTag2 } = await import("@wrongstack/core");
|
|
2222
2250
|
const registry = new SessionRegistry(globalRoot);
|
|
2223
2251
|
const entry = await registry.get(sessionId);
|
|
2224
2252
|
if (!entry) {
|
|
@@ -2266,7 +2294,7 @@ async function handleApiFleetBroadcast(res, req, globalRoot) {
|
|
|
2266
2294
|
}
|
|
2267
2295
|
const from = typeof body["from"] === "string" && body["from"].trim() ? body["from"].trim() : "human@webui";
|
|
2268
2296
|
try {
|
|
2269
|
-
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, GlobalMailbox: GlobalMailbox4, mailboxSessionTag: mailboxSessionTag2 } = await import(
|
|
2297
|
+
const { SessionRegistry, resolveWstackPaths: resolveWstackPaths3, GlobalMailbox: GlobalMailbox4, mailboxSessionTag: mailboxSessionTag2 } = await import("@wrongstack/core");
|
|
2270
2298
|
const registry = new SessionRegistry(globalRoot);
|
|
2271
2299
|
const all = await registry.list();
|
|
2272
2300
|
const mySlug = all.find((s) => s.pid === process.pid)?.projectSlug;
|
|
@@ -2422,6 +2450,10 @@ function clearAnalyticsBuffer() {
|
|
|
2422
2450
|
function getAnalyticsBuffer() {
|
|
2423
2451
|
return [...EVENT_BUFFER];
|
|
2424
2452
|
}
|
|
2453
|
+
|
|
2454
|
+
// src/server/ws-auth.ts
|
|
2455
|
+
import { Buffer as Buffer2 } from "node:buffer";
|
|
2456
|
+
import { timingSafeEqual } from "node:crypto";
|
|
2425
2457
|
function isLoopbackHostname(hostname) {
|
|
2426
2458
|
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
|
|
2427
2459
|
}
|
|
@@ -2450,8 +2482,8 @@ function allowedHostname(hostname, allowedHostnames) {
|
|
|
2450
2482
|
}
|
|
2451
2483
|
function tokenMatches(provided, expected) {
|
|
2452
2484
|
if (!provided) return false;
|
|
2453
|
-
const a =
|
|
2454
|
-
const b =
|
|
2485
|
+
const a = Buffer2.from(provided);
|
|
2486
|
+
const b = Buffer2.from(expected);
|
|
2455
2487
|
if (a.length !== b.length) return false;
|
|
2456
2488
|
return timingSafeEqual(a, b);
|
|
2457
2489
|
}
|
|
@@ -2607,9 +2639,9 @@ function buildCspHeader(wsPort, requestHost, publicWsUrl) {
|
|
|
2607
2639
|
return `default-src 'self'; script-src ${scriptSrc}; style-src 'self' 'unsafe-inline'; connect-src ${Array.from(connect).join(" ")}; img-src 'self' data:; font-src 'self' data:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'; form-action 'self'`;
|
|
2608
2640
|
}
|
|
2609
2641
|
function isInsideDist(candidate, distDir) {
|
|
2610
|
-
const root =
|
|
2611
|
-
const resolved =
|
|
2612
|
-
return resolved === root || resolved.startsWith(root +
|
|
2642
|
+
const root = path6.resolve(distDir);
|
|
2643
|
+
const resolved = path6.resolve(candidate);
|
|
2644
|
+
return resolved === root || resolved.startsWith(root + path6.sep);
|
|
2613
2645
|
}
|
|
2614
2646
|
function decodeSessionId(segment) {
|
|
2615
2647
|
try {
|
|
@@ -2620,7 +2652,7 @@ function decodeSessionId(segment) {
|
|
|
2620
2652
|
}
|
|
2621
2653
|
function createHttpServer(opts) {
|
|
2622
2654
|
const port = opts.port ?? Number.parseInt(process.env["PORT"] ?? "3456", 10);
|
|
2623
|
-
const distDir =
|
|
2655
|
+
const distDir = path6.resolve(opts.distDir);
|
|
2624
2656
|
const wsPort = opts.wsPort;
|
|
2625
2657
|
const requireAccessToken = Boolean(opts.requireToken) || !isLoopbackBind(opts.host);
|
|
2626
2658
|
return http.createServer(async (req, res) => {
|
|
@@ -2797,21 +2829,21 @@ function createHttpServer(opts) {
|
|
|
2797
2829
|
}
|
|
2798
2830
|
let filePath;
|
|
2799
2831
|
if (url.pathname === "/" || url.pathname === "") {
|
|
2800
|
-
filePath =
|
|
2832
|
+
filePath = path6.join(distDir, "index.html");
|
|
2801
2833
|
} else if (url.pathname.startsWith("/assets/")) {
|
|
2802
|
-
filePath =
|
|
2834
|
+
filePath = path6.join(distDir, url.pathname);
|
|
2803
2835
|
} else if (url.pathname.startsWith("/")) {
|
|
2804
|
-
filePath =
|
|
2836
|
+
filePath = path6.join(distDir, url.pathname);
|
|
2805
2837
|
} else {
|
|
2806
|
-
filePath =
|
|
2838
|
+
filePath = path6.join(distDir, "index.html");
|
|
2807
2839
|
}
|
|
2808
|
-
const resolvedPath =
|
|
2840
|
+
const resolvedPath = path6.resolve(filePath);
|
|
2809
2841
|
if (!isInsideDist(resolvedPath, distDir)) {
|
|
2810
2842
|
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
2811
2843
|
res.end("Forbidden");
|
|
2812
2844
|
return;
|
|
2813
2845
|
}
|
|
2814
|
-
const ext =
|
|
2846
|
+
const ext = path6.extname(resolvedPath);
|
|
2815
2847
|
const contentType = MIME_TYPES[ext] ?? "application/octet-stream";
|
|
2816
2848
|
res.setHeader("Content-Type", contentType);
|
|
2817
2849
|
res.setHeader("X-Content-Type-Options", "nosniff");
|
|
@@ -2823,18 +2855,18 @@ function createHttpServer(opts) {
|
|
|
2823
2855
|
"Content-Security-Policy",
|
|
2824
2856
|
buildCspHeader(wsPort, requestHostForCsp(req.headers.host), opts.publicWsUrl)
|
|
2825
2857
|
);
|
|
2826
|
-
const html = await
|
|
2858
|
+
const html = await fs5.readFile(resolvedPath, "utf8");
|
|
2827
2859
|
res.writeHead(200);
|
|
2828
2860
|
res.end(injectWsConfig(html, { wsPort, publicWsUrl: opts.publicWsUrl }));
|
|
2829
2861
|
return;
|
|
2830
2862
|
}
|
|
2831
|
-
const fileContent = await
|
|
2863
|
+
const fileContent = await fs5.readFile(resolvedPath);
|
|
2832
2864
|
res.writeHead(200);
|
|
2833
2865
|
res.end(fileContent);
|
|
2834
2866
|
} catch (err) {
|
|
2835
2867
|
if (err.code === "ENOENT") {
|
|
2836
2868
|
try {
|
|
2837
|
-
const html = await
|
|
2869
|
+
const html = await fs5.readFile(path6.join(distDir, "index.html"), "utf8");
|
|
2838
2870
|
res.writeHead(200, {
|
|
2839
2871
|
"Content-Type": "text/html",
|
|
2840
2872
|
"X-Content-Type-Options": "nosniff",
|
|
@@ -2858,11 +2890,17 @@ function createHttpServer(opts) {
|
|
|
2858
2890
|
}
|
|
2859
2891
|
});
|
|
2860
2892
|
}
|
|
2893
|
+
|
|
2894
|
+
// src/server/instance-registry.ts
|
|
2895
|
+
import * as os from "node:os";
|
|
2896
|
+
import * as path7 from "node:path";
|
|
2897
|
+
import * as fs6 from "node:fs/promises";
|
|
2898
|
+
import { atomicWrite as atomicWrite3 } from "@wrongstack/core";
|
|
2861
2899
|
function defaultBaseDir() {
|
|
2862
|
-
return
|
|
2900
|
+
return path7.join(os.homedir(), ".wrongstack");
|
|
2863
2901
|
}
|
|
2864
2902
|
function registryPath(baseDir = defaultBaseDir()) {
|
|
2865
|
-
return
|
|
2903
|
+
return path7.join(baseDir, "webui-instances.json");
|
|
2866
2904
|
}
|
|
2867
2905
|
function isPidAlive(pid) {
|
|
2868
2906
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
@@ -2875,7 +2913,7 @@ function isPidAlive(pid) {
|
|
|
2875
2913
|
}
|
|
2876
2914
|
async function load(file) {
|
|
2877
2915
|
try {
|
|
2878
|
-
const raw = await
|
|
2916
|
+
const raw = await fs6.readFile(file, "utf8");
|
|
2879
2917
|
const parsed = JSON.parse(raw);
|
|
2880
2918
|
if (parsed?.version === 1 && Array.isArray(parsed.instances)) {
|
|
2881
2919
|
return parsed;
|
|
@@ -2885,7 +2923,7 @@ async function load(file) {
|
|
|
2885
2923
|
return { version: 1, instances: [] };
|
|
2886
2924
|
}
|
|
2887
2925
|
async function save(file, instances) {
|
|
2888
|
-
await
|
|
2926
|
+
await atomicWrite3(file, `${JSON.stringify({ version: 1, instances }, null, 2)}
|
|
2889
2927
|
`, {
|
|
2890
2928
|
mode: 384
|
|
2891
2929
|
});
|
|
@@ -2930,6 +2968,19 @@ function formatInstances(instances) {
|
|
|
2930
2968
|
}
|
|
2931
2969
|
return lines.join("\n");
|
|
2932
2970
|
}
|
|
2971
|
+
|
|
2972
|
+
// src/server/mcp-handlers.ts
|
|
2973
|
+
import { allServers } from "@wrongstack/core";
|
|
2974
|
+
import {
|
|
2975
|
+
addMcp,
|
|
2976
|
+
disableMcp,
|
|
2977
|
+
discoverMcp,
|
|
2978
|
+
enableMcp,
|
|
2979
|
+
listMcp,
|
|
2980
|
+
removeMcp,
|
|
2981
|
+
restartMcp,
|
|
2982
|
+
updateMcp
|
|
2983
|
+
} from "@wrongstack/mcp";
|
|
2933
2984
|
function mapStatus(raw) {
|
|
2934
2985
|
switch (raw) {
|
|
2935
2986
|
case "connected":
|
|
@@ -3167,6 +3218,9 @@ async function handleMemoryForget(ws, msg, memoryStore) {
|
|
|
3167
3218
|
sendResult(ws, false, errMessage(err));
|
|
3168
3219
|
}
|
|
3169
3220
|
}
|
|
3221
|
+
|
|
3222
|
+
// src/server/open-browser.ts
|
|
3223
|
+
import { spawn } from "node:child_process";
|
|
3170
3224
|
function browserOpenCommand(url, platform = process.platform) {
|
|
3171
3225
|
if (platform === "win32") {
|
|
3172
3226
|
return { command: "cmd", args: ["/c", "start", "", url] };
|
|
@@ -3185,7 +3239,7 @@ function openBrowser(url, platform = process.platform) {
|
|
|
3185
3239
|
child.unref();
|
|
3186
3240
|
if (child.pid) {
|
|
3187
3241
|
try {
|
|
3188
|
-
import(
|
|
3242
|
+
import("@wrongstack/tools").then(({ getProcessRegistry }) => {
|
|
3189
3243
|
const pid = child.pid;
|
|
3190
3244
|
if (pid === void 0) return;
|
|
3191
3245
|
getProcessRegistry().register({
|
|
@@ -3207,6 +3261,10 @@ function openBrowser(url, platform = process.platform) {
|
|
|
3207
3261
|
} catch {
|
|
3208
3262
|
}
|
|
3209
3263
|
}
|
|
3264
|
+
|
|
3265
|
+
// src/server/port-utils.ts
|
|
3266
|
+
import * as net from "node:net";
|
|
3267
|
+
import { ToolValidationError as ToolValidationError3 } from "@wrongstack/core";
|
|
3210
3268
|
function isPortFree(host, port) {
|
|
3211
3269
|
return new Promise((resolve10) => {
|
|
3212
3270
|
const srv = net.createServer();
|
|
@@ -3232,7 +3290,7 @@ async function findFreePort(host, startPort, opts = {}) {
|
|
|
3232
3290
|
}
|
|
3233
3291
|
port++;
|
|
3234
3292
|
}
|
|
3235
|
-
throw new
|
|
3293
|
+
throw new ToolValidationError3({
|
|
3236
3294
|
message: `No free port found near ${startPort} on ${host} after ${maxTries} attempts.`,
|
|
3237
3295
|
field: "port"
|
|
3238
3296
|
});
|
|
@@ -3442,10 +3500,19 @@ async function handlePromptsRecent(ws, ctx) {
|
|
|
3442
3500
|
send(ws, { type: "prompts.recent", payload: { slugs: [], error: errMessage(err) } });
|
|
3443
3501
|
}
|
|
3444
3502
|
}
|
|
3503
|
+
|
|
3504
|
+
// src/server/provider-config-standalone.ts
|
|
3505
|
+
import * as path8 from "node:path";
|
|
3506
|
+
import { DefaultSecretVault } from "@wrongstack/core";
|
|
3507
|
+
|
|
3508
|
+
// src/server/provider-config-io.ts
|
|
3509
|
+
import * as fs7 from "node:fs/promises";
|
|
3510
|
+
import { ConfigError, atomicWrite as atomicWrite4 } from "@wrongstack/core";
|
|
3511
|
+
import { decryptConfigSecrets, encryptConfigSecrets } from "@wrongstack/core/security";
|
|
3445
3512
|
async function loadSavedProviders(configPath, vault) {
|
|
3446
3513
|
let raw;
|
|
3447
3514
|
try {
|
|
3448
|
-
raw = await
|
|
3515
|
+
raw = await fs7.readFile(configPath, "utf8");
|
|
3449
3516
|
} catch {
|
|
3450
3517
|
return {};
|
|
3451
3518
|
}
|
|
@@ -3462,7 +3529,7 @@ async function saveProviders(configPath, vault, providers) {
|
|
|
3462
3529
|
let raw;
|
|
3463
3530
|
let fileExists = true;
|
|
3464
3531
|
try {
|
|
3465
|
-
raw = await
|
|
3532
|
+
raw = await fs7.readFile(configPath, "utf8");
|
|
3466
3533
|
} catch (err) {
|
|
3467
3534
|
if (err.code !== "ENOENT") {
|
|
3468
3535
|
throw new ConfigError({
|
|
@@ -3491,16 +3558,21 @@ async function saveProviders(configPath, vault, providers) {
|
|
|
3491
3558
|
}
|
|
3492
3559
|
parsed.providers = providers;
|
|
3493
3560
|
const encrypted = encryptConfigSecrets(parsed, vault);
|
|
3494
|
-
await
|
|
3561
|
+
await atomicWrite4(configPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
3495
3562
|
}
|
|
3563
|
+
|
|
3564
|
+
// src/server/provider-config-standalone.ts
|
|
3496
3565
|
function createProviderConfigIO(configPath) {
|
|
3497
|
-
const keyFile =
|
|
3566
|
+
const keyFile = path8.join(path8.dirname(configPath), ".key");
|
|
3498
3567
|
const vault = new DefaultSecretVault({ keyFile });
|
|
3499
3568
|
return {
|
|
3500
3569
|
load: () => loadSavedProviders(configPath, vault),
|
|
3501
3570
|
save: (providers) => saveProviders(configPath, vault, providers)
|
|
3502
3571
|
};
|
|
3503
3572
|
}
|
|
3573
|
+
|
|
3574
|
+
// src/server/provider-keys.ts
|
|
3575
|
+
import { expectDefined } from "@wrongstack/core";
|
|
3504
3576
|
function normalizeKeys(cfg) {
|
|
3505
3577
|
if (Array.isArray(cfg.apiKeys) && cfg.apiKeys.length > 0) {
|
|
3506
3578
|
return cfg.apiKeys.map((k) => ({ ...k }));
|
|
@@ -3594,6 +3666,12 @@ function removeProvider(providers, providerId) {
|
|
|
3594
3666
|
delete providers[providerId];
|
|
3595
3667
|
return { ok: true, message: `Provider "${providerId}" removed` };
|
|
3596
3668
|
}
|
|
3669
|
+
|
|
3670
|
+
// src/server/sdd-board-ws-handler.ts
|
|
3671
|
+
import {
|
|
3672
|
+
applySddLifecycle,
|
|
3673
|
+
SddBoardStore
|
|
3674
|
+
} from "@wrongstack/sdd";
|
|
3597
3675
|
var CONTROL_TYPES = /* @__PURE__ */ new Set([
|
|
3598
3676
|
"pause",
|
|
3599
3677
|
"resume",
|
|
@@ -3738,6 +3816,26 @@ var SddBoardWebSocketHandler = class {
|
|
|
3738
3816
|
if (client.ws.readyState === 1) client.ws.send(JSON.stringify(msg));
|
|
3739
3817
|
}
|
|
3740
3818
|
};
|
|
3819
|
+
|
|
3820
|
+
// src/server/sdd-wizard-wiring.ts
|
|
3821
|
+
import * as path9 from "node:path";
|
|
3822
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
3823
|
+
import {
|
|
3824
|
+
WorktreeManager as WorktreeManager2,
|
|
3825
|
+
ToolValidationError as ToolValidationError4
|
|
3826
|
+
} from "@wrongstack/core";
|
|
3827
|
+
import {
|
|
3828
|
+
cleanupStaleSddWorktrees,
|
|
3829
|
+
makeCommandVerifier,
|
|
3830
|
+
makeLlmSubtaskGenerator,
|
|
3831
|
+
SddBoardStore as SddBoardStore2,
|
|
3832
|
+
SddInterviewDriver,
|
|
3833
|
+
SddRunRegistry,
|
|
3834
|
+
SddSupervisor,
|
|
3835
|
+
SpecStore,
|
|
3836
|
+
startSddRun,
|
|
3837
|
+
TaskGraphStore
|
|
3838
|
+
} from "@wrongstack/sdd";
|
|
3741
3839
|
var PLANNING_ONLY_GUARD = "SYSTEM: You are running a PLANNING-ONLY specification interview. Do NOT write, create, or edit any files, and do NOT run shell/terminal commands or use any code-editing tools \u2014 they are disabled here and any attempt will fail and waste the turn. Respond with TEXT ONLY: ask your question, or emit the requested spec / plan / task JSON. All code is written later, automatically, once the plan is approved and the multi-agent run starts.\n\n---\n\n";
|
|
3742
3840
|
function buildSddWizardDeps(opts) {
|
|
3743
3841
|
const registry = new SddRunRegistry();
|
|
@@ -3761,14 +3859,14 @@ function buildSddWizardDeps(opts) {
|
|
|
3761
3859
|
makeDriver: () => new SddInterviewDriver({
|
|
3762
3860
|
specStore: new SpecStore({ baseDir: opts.paths.projectSpecs }),
|
|
3763
3861
|
graphStore: new TaskGraphStore({ baseDir: opts.paths.projectTaskGraphs }),
|
|
3764
|
-
sessionPath:
|
|
3862
|
+
sessionPath: path9.join(opts.paths.projectDir, "sdd-wizard-session.json")
|
|
3765
3863
|
}),
|
|
3766
3864
|
runInterviewTurn: (prompt) => runIsolatedTurn(prompt, "Spec Architect"),
|
|
3767
3865
|
startRun: async (driver, { parallelSlots, defaultModel, defaultProvider, fallbackModels, worktrees: useWorktrees }) => {
|
|
3768
3866
|
const graph = driver.getGraph();
|
|
3769
3867
|
const tracker = driver.getTracker();
|
|
3770
3868
|
if (!graph || !tracker) {
|
|
3771
|
-
throw new
|
|
3869
|
+
throw new ToolValidationError4({
|
|
3772
3870
|
message: "No task graph to run \u2014 finish the interview first.",
|
|
3773
3871
|
field: "taskGraph"
|
|
3774
3872
|
});
|
|
@@ -3776,7 +3874,7 @@ function buildSddWizardDeps(opts) {
|
|
|
3776
3874
|
const worktreesEnabled = useWorktrees ?? process.env["WRONGSTACK_SDD_WORKTREES"] !== "0";
|
|
3777
3875
|
let worktrees;
|
|
3778
3876
|
if (worktreesEnabled) {
|
|
3779
|
-
const inGit =
|
|
3877
|
+
const inGit = spawnSync2("git", ["rev-parse", "--is-inside-work-tree"], {
|
|
3780
3878
|
cwd: opts.projectRoot,
|
|
3781
3879
|
encoding: "utf8",
|
|
3782
3880
|
windowsHide: true
|
|
@@ -3786,14 +3884,14 @@ function buildSddWizardDeps(opts) {
|
|
|
3786
3884
|
projectRoot: opts.projectRoot,
|
|
3787
3885
|
boardsDir: opts.paths.projectSddBoards
|
|
3788
3886
|
}).catch(() => void 0);
|
|
3789
|
-
worktrees = new
|
|
3887
|
+
worktrees = new WorktreeManager2({
|
|
3790
3888
|
projectRoot: opts.projectRoot,
|
|
3791
3889
|
events: opts.events,
|
|
3792
3890
|
sessionId: () => opts.agent.ctx.session?.id
|
|
3793
3891
|
});
|
|
3794
3892
|
}
|
|
3795
3893
|
}
|
|
3796
|
-
const boardStore = new
|
|
3894
|
+
const boardStore = new SddBoardStore2({ baseDir: opts.paths.projectSddBoards });
|
|
3797
3895
|
const verifyTask = makeCommandVerifier();
|
|
3798
3896
|
const superviseFailure = opts.brain ? new SddSupervisor({
|
|
3799
3897
|
brain: opts.brain,
|
|
@@ -3973,20 +4071,25 @@ var SddWizardWebSocketHandler = class {
|
|
|
3973
4071
|
if (client.ws.readyState === 1) client.ws.send(JSON.stringify(msg));
|
|
3974
4072
|
}
|
|
3975
4073
|
};
|
|
4074
|
+
|
|
4075
|
+
// src/server/shell-open.ts
|
|
4076
|
+
import * as fs8 from "node:fs/promises";
|
|
4077
|
+
import * as path10 from "node:path";
|
|
4078
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
3976
4079
|
var METACHAR_REGEX = /[&|<>^"'`'\n\r]/;
|
|
3977
4080
|
function shellQuote(s) {
|
|
3978
4081
|
return s.replaceAll("'", `'"'"'`);
|
|
3979
4082
|
}
|
|
3980
4083
|
async function handleShellOpen(req, logger) {
|
|
3981
4084
|
try {
|
|
3982
|
-
const resolved =
|
|
3983
|
-
await
|
|
4085
|
+
const resolved = path10.resolve(req.path);
|
|
4086
|
+
await fs8.access(resolved);
|
|
3984
4087
|
if (METACHAR_REGEX.test(resolved)) {
|
|
3985
4088
|
return { success: false, message: "Path contains unsupported characters." };
|
|
3986
4089
|
}
|
|
3987
4090
|
const platform = process.platform;
|
|
3988
4091
|
const launch = (cmd, args, onError) => {
|
|
3989
|
-
const child =
|
|
4092
|
+
const child = spawn2(cmd, args, {
|
|
3990
4093
|
detached: true,
|
|
3991
4094
|
stdio: "ignore",
|
|
3992
4095
|
windowsHide: true
|
|
@@ -4030,6 +4133,12 @@ async function handleShellOpen(req, logger) {
|
|
|
4030
4133
|
}
|
|
4031
4134
|
}
|
|
4032
4135
|
|
|
4136
|
+
// src/server/skills-handlers.ts
|
|
4137
|
+
import { promises as fs9 } from "node:fs";
|
|
4138
|
+
import path11 from "node:path";
|
|
4139
|
+
import { atomicWrite as atomicWrite5 } from "@wrongstack/core";
|
|
4140
|
+
import { wstackGlobalRoot } from "@wrongstack/core/utils";
|
|
4141
|
+
|
|
4033
4142
|
// src/server/ws-payload-validation.ts
|
|
4034
4143
|
function isRecord(value) {
|
|
4035
4144
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -4624,6 +4733,123 @@ function validateProjectsSelectPayload(payload) {
|
|
|
4624
4733
|
};
|
|
4625
4734
|
}
|
|
4626
4735
|
|
|
4736
|
+
// src/server/zip.ts
|
|
4737
|
+
import { deflateRawSync, inflateRawSync } from "node:zlib";
|
|
4738
|
+
function createZipBuffer(entries) {
|
|
4739
|
+
const localParts = [];
|
|
4740
|
+
const centralParts = [];
|
|
4741
|
+
let offset = 0;
|
|
4742
|
+
const { date, time } = dosDateTime(/* @__PURE__ */ new Date());
|
|
4743
|
+
for (const entry of entries) {
|
|
4744
|
+
const name2 = Buffer.from(normalizeZipPath(entry.name), "utf8");
|
|
4745
|
+
const data = typeof entry.data === "string" ? Buffer.from(entry.data, "utf8") : Buffer.from(entry.data);
|
|
4746
|
+
const compressed = deflateRawSync(data);
|
|
4747
|
+
const crc = crc32(data);
|
|
4748
|
+
const local = Buffer.alloc(30);
|
|
4749
|
+
local.writeUInt32LE(67324752, 0);
|
|
4750
|
+
local.writeUInt16LE(20, 4);
|
|
4751
|
+
local.writeUInt16LE(2048, 6);
|
|
4752
|
+
local.writeUInt16LE(8, 8);
|
|
4753
|
+
local.writeUInt16LE(time, 10);
|
|
4754
|
+
local.writeUInt16LE(date, 12);
|
|
4755
|
+
local.writeUInt32LE(crc, 14);
|
|
4756
|
+
local.writeUInt32LE(compressed.length, 18);
|
|
4757
|
+
local.writeUInt32LE(data.length, 22);
|
|
4758
|
+
local.writeUInt16LE(name2.length, 26);
|
|
4759
|
+
localParts.push(local, name2, compressed);
|
|
4760
|
+
const central = Buffer.alloc(46);
|
|
4761
|
+
central.writeUInt32LE(33639248, 0);
|
|
4762
|
+
central.writeUInt16LE(798, 4);
|
|
4763
|
+
central.writeUInt16LE(20, 6);
|
|
4764
|
+
central.writeUInt16LE(2048, 8);
|
|
4765
|
+
central.writeUInt16LE(8, 10);
|
|
4766
|
+
central.writeUInt16LE(time, 12);
|
|
4767
|
+
central.writeUInt16LE(date, 14);
|
|
4768
|
+
central.writeUInt32LE(crc, 16);
|
|
4769
|
+
central.writeUInt32LE(compressed.length, 20);
|
|
4770
|
+
central.writeUInt32LE(data.length, 24);
|
|
4771
|
+
central.writeUInt16LE(name2.length, 28);
|
|
4772
|
+
central.writeUInt32LE(offset, 42);
|
|
4773
|
+
centralParts.push(central, name2);
|
|
4774
|
+
offset += local.length + name2.length + compressed.length;
|
|
4775
|
+
}
|
|
4776
|
+
const centralDirectory = Buffer.concat(centralParts);
|
|
4777
|
+
const end = Buffer.alloc(22);
|
|
4778
|
+
end.writeUInt32LE(101010256, 0);
|
|
4779
|
+
end.writeUInt16LE(entries.length, 8);
|
|
4780
|
+
end.writeUInt16LE(entries.length, 10);
|
|
4781
|
+
end.writeUInt32LE(centralDirectory.length, 12);
|
|
4782
|
+
end.writeUInt32LE(offset, 16);
|
|
4783
|
+
return Buffer.concat([...localParts, centralDirectory, end]);
|
|
4784
|
+
}
|
|
4785
|
+
function readZipEntries(archive) {
|
|
4786
|
+
const maxEntries = 1e3;
|
|
4787
|
+
const maxEntryBytes = 64 * 1024 * 1024;
|
|
4788
|
+
const maxTotalBytes = 128 * 1024 * 1024;
|
|
4789
|
+
const buffer = Buffer.from(archive);
|
|
4790
|
+
const result = /* @__PURE__ */ new Map();
|
|
4791
|
+
let totalBytes = 0;
|
|
4792
|
+
let offset = 0;
|
|
4793
|
+
while (offset + 4 <= buffer.length && buffer.readUInt32LE(offset) === 67324752) {
|
|
4794
|
+
if (offset + 30 > buffer.length) throw new Error("Truncated ZIP local header.");
|
|
4795
|
+
const flags = buffer.readUInt16LE(offset + 6);
|
|
4796
|
+
const method = buffer.readUInt16LE(offset + 8);
|
|
4797
|
+
if ((flags & 1) !== 0) throw new Error("Encrypted ZIP entries are not supported.");
|
|
4798
|
+
if ((flags & 8) !== 0) throw new Error("ZIP data descriptors are not supported.");
|
|
4799
|
+
const compressedSize = buffer.readUInt32LE(offset + 18);
|
|
4800
|
+
const expectedSize = buffer.readUInt32LE(offset + 22);
|
|
4801
|
+
if (result.size >= maxEntries) throw new Error("ZIP contains too many entries.");
|
|
4802
|
+
if (expectedSize > maxEntryBytes || totalBytes + expectedSize > maxTotalBytes) {
|
|
4803
|
+
throw new Error("ZIP expands beyond the configured size limit.");
|
|
4804
|
+
}
|
|
4805
|
+
if (compressedSize > 0 && expectedSize / compressedSize > 1e3) {
|
|
4806
|
+
throw new Error("ZIP entry has a suspicious compression ratio.");
|
|
4807
|
+
}
|
|
4808
|
+
const nameLength = buffer.readUInt16LE(offset + 26);
|
|
4809
|
+
const extraLength = buffer.readUInt16LE(offset + 28);
|
|
4810
|
+
const nameStart = offset + 30;
|
|
4811
|
+
const dataStart = nameStart + nameLength + extraLength;
|
|
4812
|
+
const dataEnd = dataStart + compressedSize;
|
|
4813
|
+
if (dataEnd > buffer.length) throw new Error("Truncated ZIP entry.");
|
|
4814
|
+
const name2 = buffer.subarray(nameStart, nameStart + nameLength).toString("utf8");
|
|
4815
|
+
if (!isSafeZipPath(name2)) throw new Error(`Unsafe ZIP entry path: ${name2}`);
|
|
4816
|
+
const compressed = buffer.subarray(dataStart, dataEnd);
|
|
4817
|
+
const data = method === 0 ? Buffer.from(compressed) : method === 8 ? inflateRawSync(compressed) : void 0;
|
|
4818
|
+
if (!data) throw new Error(`Unsupported ZIP compression method: ${method}`);
|
|
4819
|
+
if (data.length !== expectedSize) throw new Error(`ZIP size mismatch for ${name2}`);
|
|
4820
|
+
if (crc32(data) !== buffer.readUInt32LE(offset + 14)) throw new Error(`ZIP CRC mismatch for ${name2}`);
|
|
4821
|
+
result.set(name2, data);
|
|
4822
|
+
totalBytes += data.length;
|
|
4823
|
+
offset = dataEnd;
|
|
4824
|
+
}
|
|
4825
|
+
return result;
|
|
4826
|
+
}
|
|
4827
|
+
function normalizeZipPath(value) {
|
|
4828
|
+
const normalized = value.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
4829
|
+
if (!isSafeZipPath(normalized)) throw new Error(`Unsafe ZIP entry path: ${value}`);
|
|
4830
|
+
return normalized;
|
|
4831
|
+
}
|
|
4832
|
+
function isSafeZipPath(value) {
|
|
4833
|
+
return value.length > 0 && !value.includes("\0") && !value.startsWith("/") && !/^[a-z]:/i.test(value) && !value.split("/").includes("..");
|
|
4834
|
+
}
|
|
4835
|
+
function dosDateTime(value) {
|
|
4836
|
+
const year = Math.max(1980, Math.min(2107, value.getFullYear()));
|
|
4837
|
+
return {
|
|
4838
|
+
date: year - 1980 << 9 | value.getMonth() + 1 << 5 | value.getDate(),
|
|
4839
|
+
time: value.getHours() << 11 | value.getMinutes() << 5 | Math.floor(value.getSeconds() / 2)
|
|
4840
|
+
};
|
|
4841
|
+
}
|
|
4842
|
+
var CRC_TABLE = Array.from({ length: 256 }, (_, index) => {
|
|
4843
|
+
let crc = index;
|
|
4844
|
+
for (let bit = 0; bit < 8; bit++) crc = (crc & 1) !== 0 ? 3988292384 ^ crc >>> 1 : crc >>> 1;
|
|
4845
|
+
return crc >>> 0;
|
|
4846
|
+
});
|
|
4847
|
+
function crc32(data) {
|
|
4848
|
+
let crc = 4294967295;
|
|
4849
|
+
for (const byte of data) crc = crc >>> 8 ^ (CRC_TABLE[(crc ^ byte) & 255] ?? 0);
|
|
4850
|
+
return (crc ^ 4294967295) >>> 0;
|
|
4851
|
+
}
|
|
4852
|
+
|
|
4627
4853
|
// src/server/skills-handlers.ts
|
|
4628
4854
|
async function handleSkillsList(ws, ctx) {
|
|
4629
4855
|
if (!ctx.skillLoader) {
|
|
@@ -4692,19 +4918,19 @@ async function handleSkillsContent(ws, ctx, msg) {
|
|
|
4692
4918
|
send(ws, { type: "skills.content", payload: { name: name2, body: "", path: "", source, relatedFiles: [], references: [], error: `Skill "${name2}" not found` } });
|
|
4693
4919
|
return;
|
|
4694
4920
|
}
|
|
4695
|
-
const body = await
|
|
4696
|
-
const skillDir =
|
|
4921
|
+
const body = await fs9.readFile(entry.path, "utf8");
|
|
4922
|
+
const skillDir = path11.dirname(entry.path);
|
|
4697
4923
|
let relatedFiles = [];
|
|
4698
4924
|
try {
|
|
4699
|
-
const files = await
|
|
4700
|
-
relatedFiles = files.filter((f) => f !==
|
|
4925
|
+
const files = await fs9.readdir(skillDir);
|
|
4926
|
+
relatedFiles = files.filter((f) => f !== path11.basename(entry.path)).map((f) => path11.join(skillDir, f));
|
|
4701
4927
|
} catch {
|
|
4702
4928
|
}
|
|
4703
4929
|
const nameLower = name2.toLowerCase();
|
|
4704
4930
|
const refResults = await Promise.all(
|
|
4705
4931
|
entries.filter((e) => e.name.toLowerCase() !== nameLower).map(async (e) => {
|
|
4706
4932
|
try {
|
|
4707
|
-
const content = await
|
|
4933
|
+
const content = await fs9.readFile(e.path, "utf8");
|
|
4708
4934
|
return [e.name, content.toLowerCase().includes(nameLower)];
|
|
4709
4935
|
} catch {
|
|
4710
4936
|
return [e.name, false];
|
|
@@ -4794,20 +5020,20 @@ async function handleSkillsCreate(ws, ctx, msg) {
|
|
|
4794
5020
|
}
|
|
4795
5021
|
const createPayload = parsed.value;
|
|
4796
5022
|
try {
|
|
4797
|
-
const targetDir = createPayload.scope === "global" ?
|
|
4798
|
-
ctx.globalSkillsDir ??
|
|
5023
|
+
const targetDir = createPayload.scope === "global" ? path11.join(
|
|
5024
|
+
ctx.globalSkillsDir ?? path11.join(wstackGlobalRoot(), "skills"),
|
|
4799
5025
|
createPayload.name.trim()
|
|
4800
|
-
) :
|
|
4801
|
-
ctx.projectSkillsDir ??
|
|
5026
|
+
) : path11.join(
|
|
5027
|
+
ctx.projectSkillsDir ?? path11.join(ctx.projectRoot, ".wrongstack", "skills"),
|
|
4802
5028
|
createPayload.name.trim()
|
|
4803
5029
|
);
|
|
4804
5030
|
try {
|
|
4805
|
-
await
|
|
5031
|
+
await fs9.access(targetDir);
|
|
4806
5032
|
send(ws, { type: "skills.created", payload: { success: false, error: `Skill "${createPayload.name}" already exists` } });
|
|
4807
5033
|
return;
|
|
4808
5034
|
} catch {
|
|
4809
5035
|
}
|
|
4810
|
-
await
|
|
5036
|
+
await fs9.mkdir(targetDir, { recursive: true });
|
|
4811
5037
|
const lines = createPayload.description.trim().split("\n");
|
|
4812
5038
|
const firstLine = (lines[0] ?? "").trim();
|
|
4813
5039
|
const bodyLines = lines.slice(1).map((l) => l.trim()).filter(Boolean);
|
|
@@ -4855,13 +5081,13 @@ ${trigger}
|
|
|
4855
5081
|
"- `bug-hunter` \u2014 for systematic bug detection patterns",
|
|
4856
5082
|
"- `output-standards` \u2014 for standardized `<nextsteps>` formatting"
|
|
4857
5083
|
].join("\n");
|
|
4858
|
-
await
|
|
5084
|
+
await atomicWrite5(path11.join(targetDir, "SKILL.md"), skillContent);
|
|
4859
5085
|
send(ws, {
|
|
4860
5086
|
type: "skills.created",
|
|
4861
5087
|
payload: {
|
|
4862
5088
|
success: true,
|
|
4863
5089
|
error: null,
|
|
4864
|
-
skill: { name: createPayload.name.trim(), path:
|
|
5090
|
+
skill: { name: createPayload.name.trim(), path: path11.join(targetDir, "SKILL.md"), scope: createPayload.scope }
|
|
4865
5091
|
}
|
|
4866
5092
|
});
|
|
4867
5093
|
} catch (err) {
|
|
@@ -4891,7 +5117,7 @@ async function handleSkillsEdit(ws, ctx, msg) {
|
|
|
4891
5117
|
send(ws, { type: "skills.edited", payload: { success: false, error: `${label} skills cannot be edited` } });
|
|
4892
5118
|
return;
|
|
4893
5119
|
}
|
|
4894
|
-
await
|
|
5120
|
+
await atomicWrite5(entry.path, editPayload.body);
|
|
4895
5121
|
send(ws, { type: "skills.edited", payload: { success: true, error: null } });
|
|
4896
5122
|
} catch (err) {
|
|
4897
5123
|
send(ws, { type: "skills.edited", payload: { success: false, error: errMessage(err) } });
|
|
@@ -4904,29 +5130,35 @@ async function handleSkillsExport(ws, ctx) {
|
|
|
4904
5130
|
}
|
|
4905
5131
|
try {
|
|
4906
5132
|
const entries = await ctx.skillLoader.listEntries();
|
|
4907
|
-
const
|
|
5133
|
+
const zipEntries = [];
|
|
4908
5134
|
for (const entry of entries) {
|
|
4909
5135
|
try {
|
|
4910
5136
|
const body = await ctx.skillLoader.readBody(entry.name);
|
|
4911
5137
|
const safeName = entry.name.replace(/\//g, "_");
|
|
4912
|
-
|
|
5138
|
+
zipEntries.push({ name: `${safeName}/SKILL.md`, data: body });
|
|
4913
5139
|
} catch {
|
|
4914
5140
|
}
|
|
4915
5141
|
}
|
|
4916
|
-
const zipBuffer =
|
|
5142
|
+
const zipBuffer = createZipBuffer(zipEntries);
|
|
4917
5143
|
const zipBase64 = zipBuffer.toString("base64");
|
|
4918
5144
|
send(ws, { type: "skills.exported", payload: { zipBase64, skillCount: entries.length, error: void 0 } });
|
|
4919
5145
|
} catch (err) {
|
|
4920
5146
|
send(ws, { type: "skills.exported", payload: { zipBase64: "", skillCount: 0, error: errMessage(err) } });
|
|
4921
5147
|
}
|
|
4922
5148
|
}
|
|
5149
|
+
|
|
5150
|
+
// src/server/specs-ws-handler.ts
|
|
5151
|
+
import {
|
|
5152
|
+
computeTaskProgress
|
|
5153
|
+
} from "@wrongstack/core";
|
|
5154
|
+
import { SpecStore as SpecStore2, TaskGraphStore as TaskGraphStore2 } from "@wrongstack/sdd";
|
|
4923
5155
|
var SpecsWebSocketHandler = class {
|
|
4924
5156
|
specStore;
|
|
4925
5157
|
graphStore;
|
|
4926
5158
|
clients = /* @__PURE__ */ new Set();
|
|
4927
5159
|
constructor(specsDir, taskGraphsDir) {
|
|
4928
|
-
this.specStore = new
|
|
4929
|
-
this.graphStore = new
|
|
5160
|
+
this.specStore = new SpecStore2({ baseDir: specsDir });
|
|
5161
|
+
this.graphStore = new TaskGraphStore2({ baseDir: taskGraphsDir });
|
|
4930
5162
|
}
|
|
4931
5163
|
addClient(ws) {
|
|
4932
5164
|
const client = { ws, id: crypto.randomUUID() };
|
|
@@ -5130,6 +5362,13 @@ function estimateContextBreakdown(input) {
|
|
|
5130
5362
|
messages: { total: msgTokens, count: input.messages.length, breakdown: messageBreakdown }
|
|
5131
5363
|
};
|
|
5132
5364
|
}
|
|
5365
|
+
|
|
5366
|
+
// src/server/worktree-ws-handler.ts
|
|
5367
|
+
import { join as join8, resolve as resolve6, sep as sep3 } from "node:path";
|
|
5368
|
+
import { WorktreeManager as WorktreeManager3 } from "@wrongstack/core";
|
|
5369
|
+
import { cleanupStaleSddWorktrees as cleanupStaleSddWorktrees2 } from "@wrongstack/sdd";
|
|
5370
|
+
import { toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
|
|
5371
|
+
var MAX_ACTIVITY = 6;
|
|
5133
5372
|
var ACTIVE_STATUSES = /* @__PURE__ */ new Set(["allocating", "active", "committing", "merging"]);
|
|
5134
5373
|
var MANAGED_BRANCH_RE = /^wstack\/ap\/[A-Za-z0-9._/-]+$/;
|
|
5135
5374
|
var WorktreeWebSocketHandler = class {
|
|
@@ -5186,13 +5425,13 @@ var WorktreeWebSocketHandler = class {
|
|
|
5186
5425
|
// ── orphan management ─────────────────────────────────────────────────────
|
|
5187
5426
|
/** Absolute managed-worktrees root for this project. */
|
|
5188
5427
|
worktreesRoot() {
|
|
5189
|
-
return
|
|
5428
|
+
return resolve6(join8(this.management.projectRoot, ".wrongstack", "worktrees"));
|
|
5190
5429
|
}
|
|
5191
5430
|
/** True iff `dir` resolves strictly inside the managed worktrees root. */
|
|
5192
5431
|
underRoot(dir) {
|
|
5193
|
-
const abs =
|
|
5432
|
+
const abs = resolve6(dir);
|
|
5194
5433
|
const root = this.worktreesRoot();
|
|
5195
|
-
return abs !== root && abs.startsWith(root +
|
|
5434
|
+
return abs !== root && abs.startsWith(root + sep3);
|
|
5196
5435
|
}
|
|
5197
5436
|
/** Branches of worktrees a live in-session run currently owns. */
|
|
5198
5437
|
liveActiveBranches() {
|
|
@@ -5213,7 +5452,7 @@ var WorktreeWebSocketHandler = class {
|
|
|
5213
5452
|
return;
|
|
5214
5453
|
}
|
|
5215
5454
|
try {
|
|
5216
|
-
const wt = new
|
|
5455
|
+
const wt = new WorktreeManager3({ projectRoot: this.management.projectRoot });
|
|
5217
5456
|
const { worktrees, branches } = await wt.listManaged();
|
|
5218
5457
|
const live = this.liveActiveBranches();
|
|
5219
5458
|
const orphans = [];
|
|
@@ -5237,7 +5476,7 @@ var WorktreeWebSocketHandler = class {
|
|
|
5237
5476
|
}
|
|
5238
5477
|
});
|
|
5239
5478
|
} catch (err) {
|
|
5240
|
-
this.logger.debug?.(`worktree orphan scan failed: ${
|
|
5479
|
+
this.logger.debug?.(`worktree orphan scan failed: ${toErrorMessage2(err)}`);
|
|
5241
5480
|
this.broadcast({ type: "worktree.orphans", payload: { orphans: [], canClean: false } });
|
|
5242
5481
|
}
|
|
5243
5482
|
}
|
|
@@ -5261,7 +5500,7 @@ var WorktreeWebSocketHandler = class {
|
|
|
5261
5500
|
});
|
|
5262
5501
|
return;
|
|
5263
5502
|
}
|
|
5264
|
-
const res = await
|
|
5503
|
+
const res = await cleanupStaleSddWorktrees2({
|
|
5265
5504
|
projectRoot: this.management.projectRoot,
|
|
5266
5505
|
boardsDir: this.management.boardsDir
|
|
5267
5506
|
});
|
|
@@ -5300,7 +5539,7 @@ var WorktreeWebSocketHandler = class {
|
|
|
5300
5539
|
}
|
|
5301
5540
|
let removed = false;
|
|
5302
5541
|
if (dir) {
|
|
5303
|
-
const wt = new
|
|
5542
|
+
const wt = new WorktreeManager3({ projectRoot: this.management.projectRoot });
|
|
5304
5543
|
({ removed } = await wt.removeOne(dir, branch));
|
|
5305
5544
|
}
|
|
5306
5545
|
for (const [id, h] of [...this.handles]) {
|
|
@@ -5324,7 +5563,7 @@ var WorktreeWebSocketHandler = class {
|
|
|
5324
5563
|
this.broadcast({ type: "worktree.merge_result", payload: { ok: false, branch, reason: "a run is live on this worktree \u2014 stop it first" } });
|
|
5325
5564
|
return;
|
|
5326
5565
|
}
|
|
5327
|
-
const wt = new
|
|
5566
|
+
const wt = new WorktreeManager3({ projectRoot: this.management.projectRoot });
|
|
5328
5567
|
const res = await wt.mergeBranch(branch);
|
|
5329
5568
|
this.broadcast({
|
|
5330
5569
|
type: "worktree.merge_result",
|
|
@@ -5339,8 +5578,8 @@ var WorktreeWebSocketHandler = class {
|
|
|
5339
5578
|
return;
|
|
5340
5579
|
}
|
|
5341
5580
|
const base = baseBranch && MANAGED_BRANCH_RE.test(baseBranch) ? baseBranch : void 0;
|
|
5342
|
-
const wt = new
|
|
5343
|
-
const summary = await wt.diffSummary(
|
|
5581
|
+
const wt = new WorktreeManager3({ projectRoot: this.management.projectRoot });
|
|
5582
|
+
const summary = await wt.diffSummary(resolve6(dir), base);
|
|
5344
5583
|
this.broadcast({ type: "worktree.diff_result", payload: { dir, summary } });
|
|
5345
5584
|
}
|
|
5346
5585
|
// ── internals ───────────────────────────────────────────────────────────
|
|
@@ -5412,7 +5651,7 @@ var WorktreeWebSocketHandler = class {
|
|
|
5412
5651
|
activity(id, kind, text) {
|
|
5413
5652
|
const cur = this.handles.get(id);
|
|
5414
5653
|
if (cur) {
|
|
5415
|
-
const recentActivity = [...cur.recentActivity, { kind, text, at: Date.now() }].slice(-
|
|
5654
|
+
const recentActivity = [...cur.recentActivity, { kind, text, at: Date.now() }].slice(-MAX_ACTIVITY);
|
|
5416
5655
|
this.handles.set(id, { ...cur, recentActivity });
|
|
5417
5656
|
}
|
|
5418
5657
|
this.broadcast({ type: "worktree.event", payload: { kind, handleId: id, text, at: Date.now() } });
|
|
@@ -5444,7 +5683,7 @@ var WorktreeWebSocketHandler = class {
|
|
|
5444
5683
|
try {
|
|
5445
5684
|
if (ws.readyState === 1) ws.send(data);
|
|
5446
5685
|
} catch (err) {
|
|
5447
|
-
this.logger.debug?.(`worktree broadcast failed: ${
|
|
5686
|
+
this.logger.debug?.(`worktree broadcast failed: ${toErrorMessage2(err)}`);
|
|
5448
5687
|
}
|
|
5449
5688
|
}
|
|
5450
5689
|
}
|
|
@@ -5456,6 +5695,12 @@ var WorktreeWebSocketHandler = class {
|
|
|
5456
5695
|
}
|
|
5457
5696
|
};
|
|
5458
5697
|
|
|
5698
|
+
// src/server/server-runtime.ts
|
|
5699
|
+
import * as path13 from "node:path";
|
|
5700
|
+
import { createRequire } from "node:module";
|
|
5701
|
+
import { fileURLToPath } from "node:url";
|
|
5702
|
+
import { WebSocketServer } from "ws";
|
|
5703
|
+
|
|
5459
5704
|
// src/server/lifecycle.ts
|
|
5460
5705
|
function createShutdown(res) {
|
|
5461
5706
|
const log = res.log ?? ((m) => console.log(m));
|
|
@@ -5491,9 +5736,14 @@ function registerShutdownHandlers(res) {
|
|
|
5491
5736
|
process.off("SIGTERM", shutdown);
|
|
5492
5737
|
};
|
|
5493
5738
|
}
|
|
5739
|
+
|
|
5740
|
+
// src/server/setup-events.ts
|
|
5741
|
+
import * as fs10 from "node:fs/promises";
|
|
5742
|
+
import { watch as fsWatch } from "node:fs";
|
|
5743
|
+
import * as path12 from "node:path";
|
|
5494
5744
|
function statusProjectHashFromWatchFilename(projectsDir, filename) {
|
|
5495
5745
|
const raw = String(filename);
|
|
5496
|
-
const relative4 =
|
|
5746
|
+
const relative4 = path12.isAbsolute(raw) ? path12.relative(projectsDir, raw) : raw;
|
|
5497
5747
|
const parts = relative4.split(/[\\/]+/).filter(Boolean);
|
|
5498
5748
|
if (parts.length < 2) return null;
|
|
5499
5749
|
if (parts[parts.length - 1] !== "status.json") return null;
|
|
@@ -5630,7 +5880,7 @@ function setupEvents(deps2) {
|
|
|
5630
5880
|
try {
|
|
5631
5881
|
const taskPath = context.meta["task.path"];
|
|
5632
5882
|
if (typeof taskPath === "string" && taskPath) {
|
|
5633
|
-
const { loadTasks } = await import(
|
|
5883
|
+
const { loadTasks } = await import("@wrongstack/core");
|
|
5634
5884
|
const file = await loadTasks(taskPath);
|
|
5635
5885
|
broadcast2(clients, { type: "tasks.updated", payload: sessionPayload2({ sessionId: e.sessionId, tasks: file?.tasks ?? [] }) });
|
|
5636
5886
|
}
|
|
@@ -5639,7 +5889,7 @@ function setupEvents(deps2) {
|
|
|
5639
5889
|
try {
|
|
5640
5890
|
const planPath = context.meta["plan.path"];
|
|
5641
5891
|
if (typeof planPath === "string" && planPath) {
|
|
5642
|
-
const { loadPlan } = await import(
|
|
5892
|
+
const { loadPlan } = await import("@wrongstack/core");
|
|
5643
5893
|
const plan = await loadPlan(planPath);
|
|
5644
5894
|
broadcast2(clients, { type: "plan.updated", payload: sessionPayload2({ sessionId: e.sessionId, plan: plan ?? { version: 1, sessionId: e.sessionId ?? context.session?.id ?? "", updatedAt: (/* @__PURE__ */ new Date()).toISOString(), items: [] } }) });
|
|
5645
5895
|
}
|
|
@@ -5936,6 +6186,7 @@ function setupEvents(deps2) {
|
|
|
5936
6186
|
events.on("subagent.budget_extended", (e) => forwardSubagent("budget_extended", { sessionId: e.sessionId, subagentId: e.subagentId, budgetKind: e.kind, newLimit: e.newLimit, totalExtensions: e.totalExtensions }));
|
|
5937
6187
|
events.on("subagent.ctx_pct", (e) => forwardSubagent("ctx_pct", { sessionId: e.sessionId, subagentId: e.subagentId, load: e.load, tokens: e.tokens, maxContext: e.maxContext }));
|
|
5938
6188
|
events.on("subagent.task_completed", (e) => forwardSubagent("task_completed", { sessionId: e.sessionId, subagentId: e.subagentId, status: e.status, iterations: e.iterations, toolCalls: e.toolCalls, finalText: e.finalText, failureReason: e.error?.kind, error: e.error ? { kind: e.error.kind, message: e.error.message } : void 0 }));
|
|
6189
|
+
events.on("subagent.removed", (e) => forwardSubagent("removed", { sessionId: e.sessionId, subagentId: e.subagentId, reason: e.reason }));
|
|
5939
6190
|
events.on("agent.timeline.message", (e) => {
|
|
5940
6191
|
broadcast2(clients, {
|
|
5941
6192
|
type: "agent.timeline.message",
|
|
@@ -6033,14 +6284,20 @@ function setupEvents(deps2) {
|
|
|
6033
6284
|
payload: sessionPayload2({ event: eventName, ...payload })
|
|
6034
6285
|
});
|
|
6035
6286
|
});
|
|
6287
|
+
events.onPattern("memory.*", (eventName, payload) => {
|
|
6288
|
+
broadcast2(clients, {
|
|
6289
|
+
type: "memory.event",
|
|
6290
|
+
payload: sessionPayload2({ event: eventName, ...payload })
|
|
6291
|
+
});
|
|
6292
|
+
});
|
|
6036
6293
|
events.on("client.status", async (e) => {
|
|
6037
6294
|
broadcast2(clients, { type: "client.status_update", payload: e });
|
|
6038
6295
|
if (wpaths?.projectStatus) {
|
|
6039
6296
|
try {
|
|
6040
6297
|
const statusFile = wpaths.projectStatus(e.projectHash);
|
|
6041
|
-
const dir =
|
|
6042
|
-
await
|
|
6043
|
-
await
|
|
6298
|
+
const dir = path12.dirname(statusFile);
|
|
6299
|
+
await fs10.mkdir(dir, { recursive: true });
|
|
6300
|
+
await fs10.writeFile(statusFile, JSON.stringify(e, null, 2), "utf-8");
|
|
6044
6301
|
} catch (err) {
|
|
6045
6302
|
console.error(
|
|
6046
6303
|
JSON.stringify({
|
|
@@ -6054,7 +6311,7 @@ function setupEvents(deps2) {
|
|
|
6054
6311
|
}
|
|
6055
6312
|
});
|
|
6056
6313
|
if (wpaths?.projectStatus && wpaths.configDir) {
|
|
6057
|
-
const projectsDir =
|
|
6314
|
+
const projectsDir = path12.join(wpaths.configDir, "projects");
|
|
6058
6315
|
const knownProjectHashes = /* @__PURE__ */ new Set();
|
|
6059
6316
|
const debounceTimers = /* @__PURE__ */ new Map();
|
|
6060
6317
|
const DEBOUNCE_MS = 150;
|
|
@@ -6118,8 +6375,8 @@ function setupEvents(deps2) {
|
|
|
6118
6375
|
let watcher;
|
|
6119
6376
|
const startWatcher = async () => {
|
|
6120
6377
|
try {
|
|
6121
|
-
await
|
|
6122
|
-
watcher =
|
|
6378
|
+
await fs10.mkdir(projectsDir, { recursive: true });
|
|
6379
|
+
watcher = fsWatch(projectsDir, { persistent: true, recursive: true }, async (eventType, filename) => {
|
|
6123
6380
|
if (eventType !== "change" && eventType !== "rename") return;
|
|
6124
6381
|
if (filename == null) return;
|
|
6125
6382
|
const projectHash = statusProjectHashFromWatchFilename(projectsDir, filename);
|
|
@@ -6128,8 +6385,8 @@ function setupEvents(deps2) {
|
|
|
6128
6385
|
if (!knownProjectHashes.has(projectHash)) return;
|
|
6129
6386
|
if (watcherMetrics) watcherMetrics.filesProcessed++;
|
|
6130
6387
|
try {
|
|
6131
|
-
const targetFile =
|
|
6132
|
-
const content = await
|
|
6388
|
+
const targetFile = path12.join(projectsDir, projectHash, "status.json");
|
|
6389
|
+
const content = await fs10.readFile(targetFile, "utf-8");
|
|
6133
6390
|
const statusData = JSON.parse(content);
|
|
6134
6391
|
scheduleBroadcast(projectHash, statusData);
|
|
6135
6392
|
} catch {
|
|
@@ -6181,11 +6438,11 @@ function setupEvents(deps2) {
|
|
|
6181
6438
|
}
|
|
6182
6439
|
});
|
|
6183
6440
|
}
|
|
6184
|
-
const globalRoot = globalConfigPath ?
|
|
6441
|
+
const globalRoot = globalConfigPath ? path12.dirname(globalConfigPath) : void 0;
|
|
6185
6442
|
if (globalRoot) {
|
|
6186
6443
|
const broadcastSessions = async () => {
|
|
6187
6444
|
try {
|
|
6188
|
-
const { SessionRegistry } = await import(
|
|
6445
|
+
const { SessionRegistry } = await import("@wrongstack/core");
|
|
6189
6446
|
const registry = new SessionRegistry(globalRoot);
|
|
6190
6447
|
const sessions = await registry.list();
|
|
6191
6448
|
const mySlug = sessions.find((s) => s.pid === process.pid)?.projectSlug;
|
|
@@ -6228,7 +6485,7 @@ function setupEvents(deps2) {
|
|
|
6228
6485
|
disposers.push(() => clearInterval(statusInterval));
|
|
6229
6486
|
let regDebounce;
|
|
6230
6487
|
try {
|
|
6231
|
-
const regWatcher =
|
|
6488
|
+
const regWatcher = fsWatch(globalRoot, { persistent: false }, (_event, filename) => {
|
|
6232
6489
|
const name2 = filename ? String(filename) : "";
|
|
6233
6490
|
if (!name2.startsWith("session-registry.json") || name2.endsWith(".lock")) return;
|
|
6234
6491
|
if (regDebounce) clearTimeout(regDebounce);
|
|
@@ -6264,6 +6521,9 @@ function getCostRates(model) {
|
|
|
6264
6521
|
function computeUsageCost(usage, rates) {
|
|
6265
6522
|
return (usage.input * rates.input + usage.output * rates.output + (usage.cacheRead ?? 0) * rates.cacheRead) / 1e6;
|
|
6266
6523
|
}
|
|
6524
|
+
|
|
6525
|
+
// src/server/model-catalog.ts
|
|
6526
|
+
import { capabilitiesFor } from "@wrongstack/providers";
|
|
6267
6527
|
var SIBLING_CATALOG = {
|
|
6268
6528
|
"anthropic-oauth": "anthropic",
|
|
6269
6529
|
"openai-codex": "openai",
|
|
@@ -6370,6 +6630,9 @@ function readConfiguredBool(providerConfig, key) {
|
|
|
6370
6630
|
function positiveNumber(value) {
|
|
6371
6631
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
6372
6632
|
}
|
|
6633
|
+
|
|
6634
|
+
// src/server/server-runtime.ts
|
|
6635
|
+
import { toErrorMessage as toErrorMessage3 } from "@wrongstack/core/utils";
|
|
6373
6636
|
async function resolvePorts(opts) {
|
|
6374
6637
|
const requestedWsPort = opts.wsPort ?? 3457;
|
|
6375
6638
|
const wsHost = opts.wsHost ?? process.env["WEBUI_HOST"] ?? process.env["WS_HOST"] ?? "127.0.0.1";
|
|
@@ -6430,7 +6693,7 @@ function createSessionStartPayload(g) {
|
|
|
6430
6693
|
inputCost,
|
|
6431
6694
|
outputCost,
|
|
6432
6695
|
cacheReadCost,
|
|
6433
|
-
projectName:
|
|
6696
|
+
projectName: path13.basename(projectRoot) || projectRoot,
|
|
6434
6697
|
projectRoot,
|
|
6435
6698
|
cwd: g.getWorkingDir(),
|
|
6436
6699
|
mode: g.getModeId(),
|
|
@@ -6468,13 +6731,26 @@ function createWsServers(ports, accessToken) {
|
|
|
6468
6731
|
port: ports.wsPort,
|
|
6469
6732
|
host: ports.wsHost,
|
|
6470
6733
|
verifyClient: verifyClient2,
|
|
6471
|
-
maxPayload: WS_MAX_PAYLOAD
|
|
6734
|
+
maxPayload: WS_MAX_PAYLOAD,
|
|
6735
|
+
// Send a ping every 15s to keep idle connections alive. Without this,
|
|
6736
|
+
// network equipment (routers, proxies, NAT gateways) may drop idle TCP
|
|
6737
|
+
// connections, causing the browser to see a close event and show the
|
|
6738
|
+
// "reconnecting" banner. The browser responds with a pong automatically
|
|
6739
|
+
// (the WebSocket API handles this at the transport level).
|
|
6740
|
+
pingInterval: 15e3,
|
|
6741
|
+
// Wait 5s for a pong before considering the connection dead. A client
|
|
6742
|
+
// that hasn't responded to 3 consecutive pings in a row (45s total
|
|
6743
|
+
// quiet) is almost certainly unreachable — close the socket so the
|
|
6744
|
+
// client can reconnect cleanly rather than hanging indefinitely.
|
|
6745
|
+
pingTimeout: 5e3
|
|
6472
6746
|
});
|
|
6473
6747
|
const wssSecondary = ports.wsHost === "127.0.0.1" ? new WebSocketServer({
|
|
6474
6748
|
port: ports.wsPort,
|
|
6475
6749
|
host: "::1",
|
|
6476
6750
|
verifyClient: verifyClient2,
|
|
6477
|
-
maxPayload: WS_MAX_PAYLOAD
|
|
6751
|
+
maxPayload: WS_MAX_PAYLOAD,
|
|
6752
|
+
pingInterval: 15e3,
|
|
6753
|
+
pingTimeout: 5e3
|
|
6478
6754
|
}) : null;
|
|
6479
6755
|
const clients = /* @__PURE__ */ new Map();
|
|
6480
6756
|
console.log(
|
|
@@ -6496,7 +6772,7 @@ function armEvents(wssPrimary, wssSecondary, wsHost, wsPort, setupInput, watcher
|
|
|
6496
6772
|
};
|
|
6497
6773
|
wssPrimary.on("listening", () => arm(`${wsHost}:${wsPort}`));
|
|
6498
6774
|
wssPrimary.on("error", (err) => {
|
|
6499
|
-
console.error(JSON.stringify({ level: "error", event: "webui.ws_server_error", host: wsHost, message:
|
|
6775
|
+
console.error(JSON.stringify({ level: "error", event: "webui.ws_server_error", host: wsHost, message: toErrorMessage3(err), timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
6500
6776
|
});
|
|
6501
6777
|
if (wssSecondary) {
|
|
6502
6778
|
wssSecondary.on("listening", () => arm(`::1:${wsPort}`));
|
|
@@ -6515,13 +6791,13 @@ function armEvents(wssPrimary, wssSecondary, wsHost, wsPort, setupInput, watcher
|
|
|
6515
6791
|
};
|
|
6516
6792
|
}
|
|
6517
6793
|
function resolveWebuiDistDir(fromUrl, explicitDistDir) {
|
|
6518
|
-
if (explicitDistDir) return
|
|
6794
|
+
if (explicitDistDir) return path13.resolve(explicitDistDir);
|
|
6519
6795
|
try {
|
|
6520
6796
|
const requireFromHere2 = createRequire(fromUrl);
|
|
6521
6797
|
const serverEntry = requireFromHere2.resolve("@wrongstack/webui/server");
|
|
6522
|
-
return
|
|
6798
|
+
return path13.resolve(path13.dirname(serverEntry), "..");
|
|
6523
6799
|
} catch {
|
|
6524
|
-
return
|
|
6800
|
+
return path13.resolve(path13.dirname(fileURLToPath(fromUrl)), "..", "..", "dist");
|
|
6525
6801
|
}
|
|
6526
6802
|
}
|
|
6527
6803
|
function startHttpServer(opts) {
|
|
@@ -6536,13 +6812,13 @@ function startHttpServer(opts) {
|
|
|
6536
6812
|
watcherMetrics: opts.watcherMetrics,
|
|
6537
6813
|
onFleetPing: opts.onFleetPing
|
|
6538
6814
|
});
|
|
6539
|
-
const registryBaseDir =
|
|
6815
|
+
const registryBaseDir = path13.dirname(opts.globalConfigPath);
|
|
6540
6816
|
httpServer.listen(opts.httpPort, opts.wsHost, () => {
|
|
6541
6817
|
const openUrl = buildWebUIAccessUrl({ host: opts.wsHost, port: opts.httpPort, token: opts.wsToken, publicUrl: opts.publicUrl });
|
|
6542
6818
|
console.log(`[WebUI] HTTP server running on ${openUrl}`);
|
|
6543
6819
|
if (opts.openBrowser) openBrowser(openUrl);
|
|
6544
6820
|
void registerInstance(
|
|
6545
|
-
{ pid: process.pid, httpPort: opts.httpPort, wsPort: opts.wsPort, host: opts.wsHost, projectRoot: opts.projectRoot, projectName:
|
|
6821
|
+
{ pid: process.pid, httpPort: opts.httpPort, wsPort: opts.wsPort, host: opts.wsHost, projectRoot: opts.projectRoot, projectName: path13.basename(opts.projectRoot) || opts.projectRoot, startedAt: (/* @__PURE__ */ new Date()).toISOString(), url: buildWebUIAccessUrl({ host: opts.wsHost, port: opts.httpPort, publicUrl: opts.publicUrl }) },
|
|
6546
6822
|
registryBaseDir
|
|
6547
6823
|
).catch((err) => console.warn(JSON.stringify({ level: "warn", event: "webui.instance_record_failed", message: errMessage(err), timestamp: (/* @__PURE__ */ new Date()).toISOString() })));
|
|
6548
6824
|
});
|
|
@@ -6556,6 +6832,63 @@ function registerShutdown(deps2) {
|
|
|
6556
6832
|
onShutdown: deps2.onShutdown
|
|
6557
6833
|
});
|
|
6558
6834
|
}
|
|
6835
|
+
|
|
6836
|
+
// src/server/pre-context-services.ts
|
|
6837
|
+
import * as path15 from "node:path";
|
|
6838
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
6839
|
+
import { WebSocket as WebSocket2 } from "ws";
|
|
6840
|
+
import { DefaultTokenCounter } from "@wrongstack/core/infrastructure";
|
|
6841
|
+
import {
|
|
6842
|
+
AgentStatusTracker,
|
|
6843
|
+
AnnotationsStore,
|
|
6844
|
+
DEFAULT_SESSION_PRUNE_DAYS,
|
|
6845
|
+
DefaultModelsRegistry,
|
|
6846
|
+
DefaultModeStore,
|
|
6847
|
+
DefaultPromptLoader,
|
|
6848
|
+
DefaultSessionReader,
|
|
6849
|
+
DefaultSessionStore,
|
|
6850
|
+
DefaultSkillLoader,
|
|
6851
|
+
DefaultSystemPromptBuilder,
|
|
6852
|
+
EventBus,
|
|
6853
|
+
FleetNotifier,
|
|
6854
|
+
GlobalMailbox,
|
|
6855
|
+
PromptUsageStore,
|
|
6856
|
+
ProviderRegistry,
|
|
6857
|
+
SkillInstaller,
|
|
6858
|
+
TOKENS,
|
|
6859
|
+
ToolRegistry,
|
|
6860
|
+
Context,
|
|
6861
|
+
applyToolDescriptionModes,
|
|
6862
|
+
applyToolResultRenderModes,
|
|
6863
|
+
configureChildEnvGitIdentity,
|
|
6864
|
+
resolveContextWindowPolicy,
|
|
6865
|
+
getSessionRegistry,
|
|
6866
|
+
makeMailboxTool,
|
|
6867
|
+
makeMailInboxTool,
|
|
6868
|
+
makeFleetStatusTool,
|
|
6869
|
+
makeMailSendTool
|
|
6870
|
+
} from "@wrongstack/core";
|
|
6871
|
+
import {
|
|
6872
|
+
createSuperMemoryTools
|
|
6873
|
+
} from "@wrongstack/super-memory";
|
|
6874
|
+
import { MCPRegistry } from "@wrongstack/mcp";
|
|
6875
|
+
import { buildProviderFactoriesFromRegistry } from "@wrongstack/providers";
|
|
6876
|
+
import { createDefaultContainer } from "@wrongstack/runtime";
|
|
6877
|
+
import {
|
|
6878
|
+
builtinToolsPack,
|
|
6879
|
+
configureDangerBypass,
|
|
6880
|
+
configureExecPolicy,
|
|
6881
|
+
forgetTool,
|
|
6882
|
+
relatedMemoryTool,
|
|
6883
|
+
rememberTool,
|
|
6884
|
+
searchMemoryTool
|
|
6885
|
+
} from "@wrongstack/tools";
|
|
6886
|
+
import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
|
|
6887
|
+
|
|
6888
|
+
// src/server/setup-screen.ts
|
|
6889
|
+
import { expectDefined as expectDefined2 } from "@wrongstack/core";
|
|
6890
|
+
import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
|
|
6891
|
+
import { makeProviderFromConfig } from "@wrongstack/providers";
|
|
6559
6892
|
var UNCONFIGURED_CAPABILITIES = {
|
|
6560
6893
|
tools: false,
|
|
6561
6894
|
parallelTools: false,
|
|
@@ -6595,7 +6928,7 @@ function logCreateFailure(event, err) {
|
|
|
6595
6928
|
JSON.stringify({
|
|
6596
6929
|
level: "error",
|
|
6597
6930
|
event,
|
|
6598
|
-
message:
|
|
6931
|
+
message: toErrorMessage4(err),
|
|
6599
6932
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6600
6933
|
})
|
|
6601
6934
|
);
|
|
@@ -6620,7 +6953,7 @@ function resolveSetupProvider(opts) {
|
|
|
6620
6953
|
const savedProviders = config.providers ?? {};
|
|
6621
6954
|
const firstKey = Object.keys(savedProviders)[0];
|
|
6622
6955
|
if (firstKey) {
|
|
6623
|
-
const firstProvider =
|
|
6956
|
+
const firstProvider = expectDefined2(savedProviders[firstKey]);
|
|
6624
6957
|
try {
|
|
6625
6958
|
const provider2 = makeProviderFromConfig(firstKey, {
|
|
6626
6959
|
...firstProvider,
|
|
@@ -6700,6 +7033,11 @@ function seedContextMeta(config, context) {
|
|
|
6700
7033
|
const tgMs = tgExt?.["longToolThresholdMs"];
|
|
6701
7034
|
meta["tgLongToolMs"] = typeof tgMs === "number" ? tgMs : 3e4;
|
|
6702
7035
|
}
|
|
7036
|
+
|
|
7037
|
+
// src/server/model-auto-discovery.ts
|
|
7038
|
+
import * as fs11 from "node:fs/promises";
|
|
7039
|
+
import * as path14 from "node:path";
|
|
7040
|
+
import { COMPATIBLE_PRESETS, discoverOpenAICompatibleModels } from "@wrongstack/providers";
|
|
6703
7041
|
function isOverlayRegistry(value) {
|
|
6704
7042
|
return !!value && typeof value === "object" && typeof value.mergeOverlay === "function";
|
|
6705
7043
|
}
|
|
@@ -6724,7 +7062,7 @@ function eligibleProviders(config) {
|
|
|
6724
7062
|
}
|
|
6725
7063
|
async function readCache(file) {
|
|
6726
7064
|
try {
|
|
6727
|
-
return JSON.parse(await
|
|
7065
|
+
return JSON.parse(await fs11.readFile(file, "utf8"));
|
|
6728
7066
|
} catch {
|
|
6729
7067
|
return {};
|
|
6730
7068
|
}
|
|
@@ -6734,7 +7072,7 @@ async function discoverAndMergeWebuiProviders(opts) {
|
|
|
6734
7072
|
if (!isOverlayRegistry(registry)) return;
|
|
6735
7073
|
const targets = eligibleProviders(opts.config);
|
|
6736
7074
|
if (targets.length === 0) return;
|
|
6737
|
-
const cacheFile =
|
|
7075
|
+
const cacheFile = path14.join(opts.cacheDir, "discovered-models-cache.json");
|
|
6738
7076
|
const cache = await readCache(cacheFile);
|
|
6739
7077
|
let cacheDirty = false;
|
|
6740
7078
|
await Promise.all(
|
|
@@ -6771,8 +7109,8 @@ async function discoverAndMergeWebuiProviders(opts) {
|
|
|
6771
7109
|
);
|
|
6772
7110
|
if (cacheDirty) {
|
|
6773
7111
|
try {
|
|
6774
|
-
await
|
|
6775
|
-
await
|
|
7112
|
+
await fs11.mkdir(path14.dirname(cacheFile), { recursive: true });
|
|
7113
|
+
await fs11.writeFile(cacheFile, JSON.stringify(cache), "utf8");
|
|
6776
7114
|
} catch {
|
|
6777
7115
|
opts.logger?.debug?.("provider auto-discovery cache write failed");
|
|
6778
7116
|
}
|
|
@@ -6794,20 +7132,22 @@ async function createPreContextServices(input) {
|
|
|
6794
7132
|
await modelsRegistry.refresh();
|
|
6795
7133
|
logger.info("models.dev catalog refreshed");
|
|
6796
7134
|
} catch (err) {
|
|
6797
|
-
logger.warn(`models.dev refresh failed (${
|
|
7135
|
+
logger.warn(`models.dev refresh failed (${toErrorMessage5(err)}); using cached catalog`);
|
|
6798
7136
|
}
|
|
6799
7137
|
}
|
|
6800
7138
|
try {
|
|
6801
7139
|
await discoverAndMergeWebuiProviders({
|
|
6802
7140
|
config,
|
|
6803
7141
|
registry: modelsRegistry,
|
|
6804
|
-
cacheDir:
|
|
7142
|
+
cacheDir: path15.dirname(wpaths.modelsCache),
|
|
6805
7143
|
logger
|
|
6806
7144
|
});
|
|
6807
7145
|
} catch (err) {
|
|
6808
|
-
logger.debug(`provider auto-discovery skipped: ${
|
|
7146
|
+
logger.debug(`provider auto-discovery skipped: ${toErrorMessage5(err)}`);
|
|
6809
7147
|
}
|
|
6810
|
-
const
|
|
7148
|
+
const events = opts.services?.events ?? new EventBus();
|
|
7149
|
+
events.setLogger(logger);
|
|
7150
|
+
const container = createDefaultContainer({ config, wpaths, logger, modelsRegistry, events });
|
|
6811
7151
|
const configStore = opts.services?.configStore ?? container.resolve(TOKENS.ConfigStore);
|
|
6812
7152
|
const providerRegistry = new ProviderRegistry();
|
|
6813
7153
|
try {
|
|
@@ -6815,22 +7155,23 @@ async function createPreContextServices(input) {
|
|
|
6815
7155
|
for (const f of factories) providerRegistry.register(f);
|
|
6816
7156
|
console.log("[WebUI] Provider registry loaded:", providerRegistry.list().length, "providers");
|
|
6817
7157
|
} catch (err) {
|
|
6818
|
-
console.warn(JSON.stringify({ level: "warn", event: "webui.provider_registry_load_failed", message:
|
|
7158
|
+
console.warn(JSON.stringify({ level: "warn", event: "webui.provider_registry_load_failed", message: toErrorMessage5(err), timestamp: (/* @__PURE__ */ new Date()).toISOString() }));
|
|
6819
7159
|
}
|
|
6820
7160
|
const toolRegistry = opts.services?.toolRegistry ?? (() => {
|
|
6821
7161
|
const r = new ToolRegistry();
|
|
6822
7162
|
r.registerAllOrThrow([...builtinToolsPack.tools ?? []], builtinToolsPack.name);
|
|
6823
7163
|
return r;
|
|
6824
7164
|
})();
|
|
6825
|
-
const memoryStore =
|
|
7165
|
+
const memoryStore = container.resolve(TOKENS.MemoryStore);
|
|
6826
7166
|
if (config.features.memory) {
|
|
6827
7167
|
toolRegistry.register(rememberTool(memoryStore));
|
|
6828
7168
|
toolRegistry.register(forgetTool(memoryStore));
|
|
6829
7169
|
toolRegistry.register(searchMemoryTool(memoryStore));
|
|
6830
7170
|
toolRegistry.register(relatedMemoryTool(memoryStore));
|
|
7171
|
+
if (isSuperMemoryService(memoryStore)) {
|
|
7172
|
+
for (const tool of createSuperMemoryTools(memoryStore)) toolRegistry.register(tool);
|
|
7173
|
+
}
|
|
6831
7174
|
}
|
|
6832
|
-
const events = opts.services?.events ?? new EventBus();
|
|
6833
|
-
events.setLogger(logger);
|
|
6834
7175
|
toolRegistry.register(makeMailboxTool({ projectDir: wpaths.projectDir, events }));
|
|
6835
7176
|
toolRegistry.register(makeMailSendTool({ projectDir: wpaths.projectDir, events }));
|
|
6836
7177
|
toolRegistry.register(makeMailInboxTool({ projectDir: wpaths.projectDir, events }));
|
|
@@ -6839,6 +7180,7 @@ async function createPreContextServices(input) {
|
|
|
6839
7180
|
applyToolResultRenderModes(toolRegistry, config.tools?.resultRenderMode);
|
|
6840
7181
|
configureExecPolicy(config.tools?.exec ?? {});
|
|
6841
7182
|
configureDangerBypass(config.tools?.exec?.danger ?? {});
|
|
7183
|
+
configureChildEnvGitIdentity(config.git?.identity ?? null);
|
|
6842
7184
|
console.log("[WebUI] Tool registry loaded:", toolRegistry.list().length, "tools");
|
|
6843
7185
|
const mcpRegistry = new MCPRegistry({ toolRegistry, events, log: logger, cacheDir: wpaths.cacheDir });
|
|
6844
7186
|
if (config.features.mcp && config.mcpServers) {
|
|
@@ -6890,7 +7232,7 @@ async function createPreContextServices(input) {
|
|
|
6890
7232
|
sessionId: session.id,
|
|
6891
7233
|
projectSlug: wpaths.projectSlug,
|
|
6892
7234
|
projectRoot,
|
|
6893
|
-
projectName:
|
|
7235
|
+
projectName: path15.basename(projectRoot),
|
|
6894
7236
|
workingDir,
|
|
6895
7237
|
clientType: "webui",
|
|
6896
7238
|
pid: process.pid,
|
|
@@ -6916,13 +7258,13 @@ async function createPreContextServices(input) {
|
|
|
6916
7258
|
startWorktreeTelemetryBridge,
|
|
6917
7259
|
startToolTelemetryBridge,
|
|
6918
7260
|
startCostTelemetryBridge
|
|
6919
|
-
} = await import(
|
|
7261
|
+
} = await import("@wrongstack/core");
|
|
6920
7262
|
const hqTelemetry = createHqPublisherFromEnv({
|
|
6921
7263
|
clientKind: "webui",
|
|
6922
7264
|
projectRoot,
|
|
6923
|
-
projectName:
|
|
7265
|
+
projectName: path15.basename(projectRoot),
|
|
6924
7266
|
appConfig: config,
|
|
6925
|
-
socketFactory: (url) => new
|
|
7267
|
+
socketFactory: (url) => new WebSocket2(url)
|
|
6926
7268
|
});
|
|
6927
7269
|
if (hqTelemetry) {
|
|
6928
7270
|
hqTelemetry.connect();
|
|
@@ -6932,7 +7274,7 @@ async function createPreContextServices(input) {
|
|
|
6932
7274
|
events,
|
|
6933
7275
|
sessionId: session.id,
|
|
6934
7276
|
projectRoot,
|
|
6935
|
-
projectName:
|
|
7277
|
+
projectName: path15.basename(projectRoot),
|
|
6936
7278
|
globalRoot: wpaths.globalRoot,
|
|
6937
7279
|
initialAgents: statusTracker?.getAgents(),
|
|
6938
7280
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -7021,7 +7363,7 @@ async function createPreContextServices(input) {
|
|
|
7021
7363
|
const modelCapabilitiesRef = { current: modelCapabilities };
|
|
7022
7364
|
const skillLoader = config.features.skills ? new DefaultSkillLoader({ paths: wpaths }) : void 0;
|
|
7023
7365
|
const skillInstaller = config.features.skills ? new SkillInstaller({
|
|
7024
|
-
manifestPath:
|
|
7366
|
+
manifestPath: path15.join(wpaths.globalRoot, "installed-skills.json"),
|
|
7025
7367
|
projectSkillsDir: wpaths.inProjectSkills,
|
|
7026
7368
|
globalSkillsDir: wpaths.globalSkills,
|
|
7027
7369
|
projectHash: wpaths.projectHash,
|
|
@@ -7030,8 +7372,8 @@ async function createPreContextServices(input) {
|
|
|
7030
7372
|
const promptsEnabled = config.features.prompts !== false;
|
|
7031
7373
|
const bundledPromptsDir = promptsEnabled ? (() => {
|
|
7032
7374
|
try {
|
|
7033
|
-
const req =
|
|
7034
|
-
return
|
|
7375
|
+
const req = createRequire2(import.meta.url);
|
|
7376
|
+
return path15.join(path15.dirname(req.resolve("@wrongstack/core/package.json")), "data", "prompts");
|
|
7035
7377
|
} catch {
|
|
7036
7378
|
return void 0;
|
|
7037
7379
|
}
|
|
@@ -7112,8 +7454,33 @@ async function createPreContextServices(input) {
|
|
|
7112
7454
|
needsSetup
|
|
7113
7455
|
};
|
|
7114
7456
|
}
|
|
7457
|
+
function isSuperMemoryService(memoryStore) {
|
|
7458
|
+
const value = memoryStore;
|
|
7459
|
+
return typeof value["retrieveForPath"] === "function" && typeof value["searchSuper"] === "function" && typeof value["graphFor"] === "function" && typeof value["verify"] === "function" && typeof value["hygiene"] === "function" && typeof value["listCandidates"] === "function";
|
|
7460
|
+
}
|
|
7461
|
+
|
|
7462
|
+
// src/server/start-webui.ts
|
|
7463
|
+
import * as path22 from "node:path";
|
|
7464
|
+
import {
|
|
7465
|
+
createDefaultPipelines,
|
|
7466
|
+
createSessionEventBridge,
|
|
7467
|
+
DEFAULT_CONTEXT_WINDOW_MODE_ID as DEFAULT_CONTEXT_WINDOW_MODE_ID2,
|
|
7468
|
+
expectDefined as expectDefined3,
|
|
7469
|
+
resolveSessionLoggingConfig,
|
|
7470
|
+
watchProviderConfig
|
|
7471
|
+
} from "@wrongstack/core";
|
|
7472
|
+
import { toErrorMessage as toErrorMessage10 } from "@wrongstack/core/utils";
|
|
7473
|
+
import { makeProviderFromConfig as makeProviderFromConfig3 } from "@wrongstack/providers";
|
|
7474
|
+
import {
|
|
7475
|
+
ensureSessionShell
|
|
7476
|
+
} from "@wrongstack/tools";
|
|
7477
|
+
|
|
7478
|
+
// src/server/boot.ts
|
|
7479
|
+
import {
|
|
7480
|
+
bootConfig as coreBootConfig
|
|
7481
|
+
} from "@wrongstack/core";
|
|
7115
7482
|
async function bootConfig() {
|
|
7116
|
-
const { config, vault, globalConfigPath, projectRoot, wpaths, logger } = await
|
|
7483
|
+
const { config, vault, globalConfigPath, projectRoot, wpaths, logger } = await coreBootConfig({
|
|
7117
7484
|
appLabel: "WebUI"
|
|
7118
7485
|
});
|
|
7119
7486
|
return { config, vault, globalConfigPath, projectRoot, wpaths, logger };
|
|
@@ -7121,6 +7488,35 @@ async function bootConfig() {
|
|
|
7121
7488
|
function patchConfig(config, updates) {
|
|
7122
7489
|
return Object.freeze({ ...config, ...updates });
|
|
7123
7490
|
}
|
|
7491
|
+
|
|
7492
|
+
// src/server/backend-services.ts
|
|
7493
|
+
import {
|
|
7494
|
+
Agent,
|
|
7495
|
+
AutoCompactionMiddleware as AutoCompactionMiddlewareCtor,
|
|
7496
|
+
BrainMonitor,
|
|
7497
|
+
CollaborationBus as CollaborationBusCtor,
|
|
7498
|
+
DEFAULT_TOOLS_CONFIG,
|
|
7499
|
+
createStrategyCompactor,
|
|
7500
|
+
collabInjectMiddleware,
|
|
7501
|
+
collabPauseMiddleware,
|
|
7502
|
+
estimateRequestTokensCalibrated,
|
|
7503
|
+
installDesignStudioMiddleware,
|
|
7504
|
+
ObservableBrainArbiter as ObservableBrainArbiterCtor,
|
|
7505
|
+
resolveContextWindowPolicy as resolveContextWindowPolicy2,
|
|
7506
|
+
createAutonomyBrain,
|
|
7507
|
+
createTieredBrainArbiter,
|
|
7508
|
+
DefaultBrainArbiter,
|
|
7509
|
+
GlobalMailbox as GlobalMailbox2,
|
|
7510
|
+
mailboxSessionTag,
|
|
7511
|
+
SessionMemoryConsolidator,
|
|
7512
|
+
TOKENS as TOKENS2,
|
|
7513
|
+
ToolExecutor
|
|
7514
|
+
} from "@wrongstack/core";
|
|
7515
|
+
|
|
7516
|
+
// src/server/collaboration-ws-handler.ts
|
|
7517
|
+
import { randomUUID } from "node:crypto";
|
|
7518
|
+
import { toErrorMessage as toErrorMessage6 } from "@wrongstack/core/utils";
|
|
7519
|
+
var REPLAY_LIMIT = 50;
|
|
7124
7520
|
var PAUSE_TIMEOUT_MS = 6e4;
|
|
7125
7521
|
var CollaborationWebSocketHandler = class {
|
|
7126
7522
|
constructor(events, logger, reader, annotations, bus) {
|
|
@@ -7248,7 +7644,7 @@ var CollaborationWebSocketHandler = class {
|
|
|
7248
7644
|
if (this.reader) {
|
|
7249
7645
|
this.replayHistory(ws, sessionId).catch((err) => {
|
|
7250
7646
|
this.logger.debug?.(
|
|
7251
|
-
`collab: replay failed for ${sessionId}: ${
|
|
7647
|
+
`collab: replay failed for ${sessionId}: ${toErrorMessage6(err)}`
|
|
7252
7648
|
);
|
|
7253
7649
|
});
|
|
7254
7650
|
}
|
|
@@ -7366,7 +7762,7 @@ var CollaborationWebSocketHandler = class {
|
|
|
7366
7762
|
this.send(
|
|
7367
7763
|
ws,
|
|
7368
7764
|
this.errorMessage(
|
|
7369
|
-
`annotation rejected: ${
|
|
7765
|
+
`annotation rejected: ${toErrorMessage6(err)}`
|
|
7370
7766
|
)
|
|
7371
7767
|
);
|
|
7372
7768
|
}
|
|
@@ -7433,7 +7829,7 @@ var CollaborationWebSocketHandler = class {
|
|
|
7433
7829
|
this.send(
|
|
7434
7830
|
ws,
|
|
7435
7831
|
this.errorMessage(
|
|
7436
|
-
`resolve failed: ${
|
|
7832
|
+
`resolve failed: ${toErrorMessage6(err)}`
|
|
7437
7833
|
)
|
|
7438
7834
|
);
|
|
7439
7835
|
}
|
|
@@ -7481,7 +7877,7 @@ var CollaborationWebSocketHandler = class {
|
|
|
7481
7877
|
if (p.ws.readyState === 1) p.ws.send(data);
|
|
7482
7878
|
} catch (err) {
|
|
7483
7879
|
this.logger.debug?.(
|
|
7484
|
-
`collab broadcast failed: ${
|
|
7880
|
+
`collab broadcast failed: ${toErrorMessage6(err)}`
|
|
7485
7881
|
);
|
|
7486
7882
|
}
|
|
7487
7883
|
}
|
|
@@ -7508,11 +7904,11 @@ var CollaborationWebSocketHandler = class {
|
|
|
7508
7904
|
}
|
|
7509
7905
|
} catch (err) {
|
|
7510
7906
|
this.logger.debug?.(
|
|
7511
|
-
`collab: session reader rejected ${sessionId}: ${
|
|
7907
|
+
`collab: session reader rejected ${sessionId}: ${toErrorMessage6(err)}`
|
|
7512
7908
|
);
|
|
7513
7909
|
return;
|
|
7514
7910
|
}
|
|
7515
|
-
const tail2 = all.slice(-
|
|
7911
|
+
const tail2 = all.slice(-REPLAY_LIMIT);
|
|
7516
7912
|
if (tail2.length === 0) return;
|
|
7517
7913
|
for (const raw of tail2) {
|
|
7518
7914
|
const ev = raw;
|
|
@@ -7589,7 +7985,7 @@ var CollaborationWebSocketHandler = class {
|
|
|
7589
7985
|
if (p.ws.readyState === 1) p.ws.send(data);
|
|
7590
7986
|
} catch (err) {
|
|
7591
7987
|
this.logger.debug?.(
|
|
7592
|
-
`collab broadcast failed: ${
|
|
7988
|
+
`collab broadcast failed: ${toErrorMessage6(err)}`
|
|
7593
7989
|
);
|
|
7594
7990
|
}
|
|
7595
7991
|
}
|
|
@@ -7841,6 +8237,17 @@ var CollaborationWebSocketHandler = class {
|
|
|
7841
8237
|
}
|
|
7842
8238
|
}
|
|
7843
8239
|
};
|
|
8240
|
+
|
|
8241
|
+
// src/server/codebase-indexing.ts
|
|
8242
|
+
import * as fs12 from "node:fs";
|
|
8243
|
+
import * as path16 from "node:path";
|
|
8244
|
+
import {
|
|
8245
|
+
cancelPendingReindexes,
|
|
8246
|
+
enqueueReindex,
|
|
8247
|
+
isIndexableFile,
|
|
8248
|
+
runStartupIndex,
|
|
8249
|
+
shutdownCodebaseIndexHost
|
|
8250
|
+
} from "@wrongstack/tools";
|
|
7844
8251
|
var IGNORE_DIRS = /* @__PURE__ */ new Set([
|
|
7845
8252
|
"node_modules",
|
|
7846
8253
|
".git",
|
|
@@ -7886,7 +8293,7 @@ function setupWebUICodebaseIndexing(deps2) {
|
|
|
7886
8293
|
if (!filename) return;
|
|
7887
8294
|
const rel = filename.toString();
|
|
7888
8295
|
if (isIgnored(rel)) return;
|
|
7889
|
-
const abs =
|
|
8296
|
+
const abs = path16.resolve(deps2.projectRoot, rel);
|
|
7890
8297
|
enqueueFile(abs);
|
|
7891
8298
|
});
|
|
7892
8299
|
watcher.on("error", (err) => deps2.logger.debug(`webui codebase index watcher error: ${err}`));
|
|
@@ -7899,7 +8306,7 @@ function setupWebUICodebaseIndexing(deps2) {
|
|
|
7899
8306
|
}
|
|
7900
8307
|
function enqueueFile(filePath) {
|
|
7901
8308
|
if (!idx.onEdit && !idx.watchExternal) return;
|
|
7902
|
-
const abs =
|
|
8309
|
+
const abs = path16.isAbsolute(filePath) ? path16.normalize(filePath) : path16.resolve(deps2.projectRoot, filePath);
|
|
7903
8310
|
if (!isInside2(deps2.projectRoot, abs) || !isIndexableFile(abs)) return;
|
|
7904
8311
|
enqueueReindex({
|
|
7905
8312
|
projectRoot: deps2.projectRoot,
|
|
@@ -7936,15 +8343,23 @@ function isIgnored(rel) {
|
|
|
7936
8343
|
return rel.split(/[/\\]/).some((seg) => IGNORE_DIRS.has(seg));
|
|
7937
8344
|
}
|
|
7938
8345
|
function isInside2(root, target) {
|
|
7939
|
-
const normalizedRoot =
|
|
7940
|
-
const normalizedTarget =
|
|
7941
|
-
return normalizedTarget === normalizedRoot || normalizedTarget.startsWith(normalizedRoot +
|
|
8346
|
+
const normalizedRoot = path16.resolve(root);
|
|
8347
|
+
const normalizedTarget = path16.resolve(target);
|
|
8348
|
+
return normalizedTarget === normalizedRoot || normalizedTarget.startsWith(normalizedRoot + path16.sep);
|
|
7942
8349
|
}
|
|
8350
|
+
|
|
8351
|
+
// src/server/discover-mailbox-bridge.ts
|
|
8352
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
8353
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
8354
|
+
import { existsSync } from "node:fs";
|
|
8355
|
+
import { dirname as dirname8, join as join12 } from "node:path";
|
|
8356
|
+
import { resolveProjectDir, wstackGlobalRoot as wstackGlobalRoot2 } from "@wrongstack/core";
|
|
8357
|
+
import { readLiveLock } from "@wrongstack/core/coordination";
|
|
7943
8358
|
var MAILBOX_BRIDGE_BOOT_TIMEOUT_MS = 5e3;
|
|
7944
8359
|
async function discoverMailboxBridgeForWebui(params) {
|
|
7945
8360
|
const mode = params.config?.features?.mailboxBridge ?? "auto";
|
|
7946
8361
|
if (mode === "off") return;
|
|
7947
|
-
const projectDir = resolveProjectDir(params.projectRoot,
|
|
8362
|
+
const projectDir = resolveProjectDir(params.projectRoot, wstackGlobalRoot2());
|
|
7948
8363
|
let result = await readLiveLock(projectDir);
|
|
7949
8364
|
let spawnedPid = null;
|
|
7950
8365
|
if (result.kind !== "live") {
|
|
@@ -8010,7 +8425,7 @@ async function waitForLiveMailboxBridge(projectDir, timeoutMs) {
|
|
|
8010
8425
|
function spawnMailboxBridge(projectRoot, logger) {
|
|
8011
8426
|
const invocation = mailboxServeInvocation(projectRoot);
|
|
8012
8427
|
try {
|
|
8013
|
-
const child =
|
|
8428
|
+
const child = spawn3(invocation.command, invocation.args, {
|
|
8014
8429
|
cwd: projectRoot,
|
|
8015
8430
|
detached: process.platform !== "win32" && !invocation.useShell,
|
|
8016
8431
|
env: process.env,
|
|
@@ -8041,7 +8456,7 @@ function mailboxServeInvocation(projectRoot) {
|
|
|
8041
8456
|
return { command: process.execPath, args: [explicitCliEntry, "mailbox", "serve"] };
|
|
8042
8457
|
}
|
|
8043
8458
|
try {
|
|
8044
|
-
const require2 =
|
|
8459
|
+
const require2 = createRequire3(import.meta.url);
|
|
8045
8460
|
const cliEntry = require2.resolve("@wrongstack/cli");
|
|
8046
8461
|
return { command: process.execPath, args: [cliEntry, "mailbox", "serve"] };
|
|
8047
8462
|
} catch {
|
|
@@ -8065,9 +8480,9 @@ function mailboxServeInvocation(projectRoot) {
|
|
|
8065
8480
|
function findWorkspaceCliEntry(projectRoot) {
|
|
8066
8481
|
let dir = projectRoot;
|
|
8067
8482
|
for (let i = 0; i < 6; i++) {
|
|
8068
|
-
const candidate =
|
|
8483
|
+
const candidate = join12(dir, "packages", "cli", "dist", "index.js");
|
|
8069
8484
|
if (existsSync(candidate)) return candidate;
|
|
8070
|
-
const parent =
|
|
8485
|
+
const parent = dirname8(dir);
|
|
8071
8486
|
if (parent === dir) return null;
|
|
8072
8487
|
dir = parent;
|
|
8073
8488
|
}
|
|
@@ -8076,10 +8491,15 @@ function findWorkspaceCliEntry(projectRoot) {
|
|
|
8076
8491
|
function sleep(ms) {
|
|
8077
8492
|
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
8078
8493
|
}
|
|
8494
|
+
|
|
8495
|
+
// src/server/terminal-ws-handler.ts
|
|
8496
|
+
import { spawn as spawnChild } from "node:child_process";
|
|
8497
|
+
import { createRequire as createRequire4 } from "node:module";
|
|
8498
|
+
import { toErrorMessage as toErrorMessage7 } from "@wrongstack/core/utils";
|
|
8079
8499
|
var MAX_SESSIONS_PER_CLIENT = 8;
|
|
8080
8500
|
var DEFAULT_COLS = 80;
|
|
8081
8501
|
var DEFAULT_ROWS = 24;
|
|
8082
|
-
var requireFromHere =
|
|
8502
|
+
var requireFromHere = createRequire4(import.meta.url);
|
|
8083
8503
|
var cachedNodePty;
|
|
8084
8504
|
var TerminalWebSocketHandler = class {
|
|
8085
8505
|
constructor(getCwd, logger, loadNodePty = defaultLoadNodePty, killProcessTree = defaultKillProcessTree) {
|
|
@@ -8157,8 +8577,8 @@ var TerminalWebSocketHandler = class {
|
|
|
8157
8577
|
...windowsPtyOptions()
|
|
8158
8578
|
});
|
|
8159
8579
|
} catch (err) {
|
|
8160
|
-
const msg = `Integrated terminal failed to start: ${
|
|
8161
|
-
this.logger.warn?.(`terminal spawn failed: ${
|
|
8580
|
+
const msg = `Integrated terminal failed to start: ${toErrorMessage7(err)}`;
|
|
8581
|
+
this.logger.warn?.(`terminal spawn failed: ${toErrorMessage7(err)}`);
|
|
8162
8582
|
this.send(ws, { type: "terminal.output", payload: { id: payload.id, data: `${msg}\r
|
|
8163
8583
|
` } });
|
|
8164
8584
|
this.send(ws, { type: "terminal.exit", payload: { id: payload.id, exitCode: -1 } });
|
|
@@ -8211,7 +8631,7 @@ var TerminalWebSocketHandler = class {
|
|
|
8211
8631
|
try {
|
|
8212
8632
|
pty.kill();
|
|
8213
8633
|
} catch (err) {
|
|
8214
|
-
this.logger.warn?.(`${reason} failed: ${
|
|
8634
|
+
this.logger.warn?.(`${reason} failed: ${toErrorMessage7(err)}`);
|
|
8215
8635
|
}
|
|
8216
8636
|
}
|
|
8217
8637
|
killWindowsProcessTree(pty, reason) {
|
|
@@ -8223,7 +8643,7 @@ var TerminalWebSocketHandler = class {
|
|
|
8223
8643
|
} catch {
|
|
8224
8644
|
}
|
|
8225
8645
|
} catch (err) {
|
|
8226
|
-
this.logger.warn?.(`${reason} taskkill failed: ${
|
|
8646
|
+
this.logger.warn?.(`${reason} taskkill failed: ${toErrorMessage7(err)}`);
|
|
8227
8647
|
}
|
|
8228
8648
|
}
|
|
8229
8649
|
send(ws, msg) {
|
|
@@ -8254,7 +8674,7 @@ function windowsPtyOptions() {
|
|
|
8254
8674
|
return { useConptyDll: true };
|
|
8255
8675
|
}
|
|
8256
8676
|
function defaultKillProcessTree(pid) {
|
|
8257
|
-
const child =
|
|
8677
|
+
const child = spawnChild("taskkill", ["/PID", String(pid), "/T", "/F"], {
|
|
8258
8678
|
stdio: "ignore",
|
|
8259
8679
|
windowsHide: true
|
|
8260
8680
|
});
|
|
@@ -8267,6 +8687,14 @@ function clampDim(value, fallback) {
|
|
|
8267
8687
|
if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
|
|
8268
8688
|
return Math.max(1, Math.min(1e3, Math.floor(value)));
|
|
8269
8689
|
}
|
|
8690
|
+
|
|
8691
|
+
// src/server/backend-services.ts
|
|
8692
|
+
import { makeLightSubagentFactory } from "@wrongstack/runtime";
|
|
8693
|
+
import {
|
|
8694
|
+
createSuperMemoryToolCallMiddleware,
|
|
8695
|
+
createSuperMemoryTurnMiddleware
|
|
8696
|
+
} from "@wrongstack/super-memory";
|
|
8697
|
+
import { toErrorMessage as toErrorMessage8 } from "@wrongstack/core/utils";
|
|
8270
8698
|
async function createAgentServices(input) {
|
|
8271
8699
|
const {
|
|
8272
8700
|
config,
|
|
@@ -8281,15 +8709,37 @@ async function createAgentServices(input) {
|
|
|
8281
8709
|
providerRegistry,
|
|
8282
8710
|
modelsRegistry,
|
|
8283
8711
|
events,
|
|
8712
|
+
memoryStore,
|
|
8284
8713
|
modelCapabilitiesRef
|
|
8285
8714
|
} = input;
|
|
8286
|
-
const collabBus = new
|
|
8715
|
+
const collabBus = new CollaborationBusCtor();
|
|
8287
8716
|
const pipelines = input.pipelines;
|
|
8288
8717
|
const collabInject = collabInjectMiddleware(collabBus, { logger });
|
|
8289
8718
|
pipelines.toolCall.prepend(collabInject);
|
|
8290
8719
|
const collabPause = collabPauseMiddleware(collabBus, { logger });
|
|
8291
8720
|
pipelines.toolCall.prepend(collabPause);
|
|
8292
8721
|
installDesignStudioMiddleware({ pipelines, ctx: context });
|
|
8722
|
+
if (config.features.memory !== false && config.superMemory?.enabled !== false && isSuperMemoryRetriever(memoryStore)) {
|
|
8723
|
+
if (config.superMemory?.inject?.toolResults !== false) {
|
|
8724
|
+
pipelines.toolCall.use(createSuperMemoryToolCallMiddleware({
|
|
8725
|
+
memory: memoryStore,
|
|
8726
|
+
maxHintsPerTool: config.superMemory?.inject?.maxHintsPerTool,
|
|
8727
|
+
maxCharsPerTool: config.superMemory?.inject?.maxCharsPerTool,
|
|
8728
|
+
minScore: config.superMemory?.inject?.minScore,
|
|
8729
|
+
repeatCooldownMs: config.superMemory?.inject?.repeatCooldownMs,
|
|
8730
|
+
verifyOnMutation: config.superMemory?.hygiene?.autoOnFileChange,
|
|
8731
|
+
triggers: config.superMemory?.inject?.triggers
|
|
8732
|
+
}));
|
|
8733
|
+
}
|
|
8734
|
+
if (config.superMemory?.inject?.turnContext !== false) {
|
|
8735
|
+
pipelines.request.use(createSuperMemoryTurnMiddleware({
|
|
8736
|
+
memory: memoryStore,
|
|
8737
|
+
maxMemories: config.superMemory?.inject?.maxTurnMemories,
|
|
8738
|
+
maxChars: config.superMemory?.inject?.maxCharsPerTurn,
|
|
8739
|
+
minScore: config.superMemory?.inject?.minScore
|
|
8740
|
+
}));
|
|
8741
|
+
}
|
|
8742
|
+
}
|
|
8293
8743
|
const codebaseIndexing = setupWebUICodebaseIndexing({
|
|
8294
8744
|
config,
|
|
8295
8745
|
context,
|
|
@@ -8303,7 +8753,7 @@ async function createAgentServices(input) {
|
|
|
8303
8753
|
summarizerModel: config.context?.summarizerModel,
|
|
8304
8754
|
llmSelector: config.context?.llmSelector
|
|
8305
8755
|
});
|
|
8306
|
-
const initialContextPolicy =
|
|
8756
|
+
const initialContextPolicy = resolveContextWindowPolicy2(config.context);
|
|
8307
8757
|
let autoCompactor;
|
|
8308
8758
|
if (config.context?.autoCompact !== false) {
|
|
8309
8759
|
let effectiveMaxContext = config.context?.effectiveMaxContext ?? 0;
|
|
@@ -8320,7 +8770,7 @@ async function createAgentServices(input) {
|
|
|
8320
8770
|
}
|
|
8321
8771
|
}
|
|
8322
8772
|
if (!effectiveMaxContext) effectiveMaxContext = provider.capabilities.maxContext;
|
|
8323
|
-
autoCompactor = new
|
|
8773
|
+
autoCompactor = new AutoCompactionMiddlewareCtor(
|
|
8324
8774
|
compactor,
|
|
8325
8775
|
effectiveMaxContext,
|
|
8326
8776
|
(ctx) => estimateRequestTokensCalibrated(
|
|
@@ -8348,7 +8798,7 @@ async function createAgentServices(input) {
|
|
|
8348
8798
|
const updateAutoCompactionMaxContext = async (newProvider, providerId = newProvider.id, providerCfg) => {
|
|
8349
8799
|
await modelsRegistry.refresh().catch((err) => {
|
|
8350
8800
|
logger.warn(
|
|
8351
|
-
`models.dev refresh failed for ${providerId}/${context.model}: ${
|
|
8801
|
+
`models.dev refresh failed for ${providerId}/${context.model}: ${toErrorMessage8(err)}; using cached catalog`
|
|
8352
8802
|
);
|
|
8353
8803
|
});
|
|
8354
8804
|
const currentConfig = input.config;
|
|
@@ -8385,9 +8835,9 @@ async function createAgentServices(input) {
|
|
|
8385
8835
|
maxContext: newMaxContext
|
|
8386
8836
|
});
|
|
8387
8837
|
};
|
|
8388
|
-
const secretScrubber = container.resolve(
|
|
8389
|
-
const renderer = container.has(
|
|
8390
|
-
const permissionPolicy = container.resolve(
|
|
8838
|
+
const secretScrubber = container.resolve(TOKENS2.SecretScrubber);
|
|
8839
|
+
const renderer = container.has(TOKENS2.Renderer) ? container.resolve(TOKENS2.Renderer) : void 0;
|
|
8840
|
+
const permissionPolicy = container.resolve(TOKENS2.PermissionPolicy);
|
|
8391
8841
|
const toolExecutor = new ToolExecutor(toolRegistry, {
|
|
8392
8842
|
permissionPolicy,
|
|
8393
8843
|
secretScrubber,
|
|
@@ -8398,7 +8848,7 @@ async function createAgentServices(input) {
|
|
|
8398
8848
|
perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,
|
|
8399
8849
|
tracer: void 0
|
|
8400
8850
|
});
|
|
8401
|
-
const webuiLogger = container.resolve(
|
|
8851
|
+
const webuiLogger = container.resolve(TOKENS2.Logger);
|
|
8402
8852
|
void discoverMailboxBridgeForWebui({
|
|
8403
8853
|
projectRoot,
|
|
8404
8854
|
config,
|
|
@@ -8424,6 +8874,9 @@ async function createAgentServices(input) {
|
|
|
8424
8874
|
confirmAwaiter: void 0,
|
|
8425
8875
|
toolExecutor
|
|
8426
8876
|
});
|
|
8877
|
+
if (config.features.memory && config.features.memoryConsolidation !== false) {
|
|
8878
|
+
agent.extensions.register(new SessionMemoryConsolidator({ memoryStore }));
|
|
8879
|
+
}
|
|
8427
8880
|
console.log("[WebUI] Agent initialized");
|
|
8428
8881
|
const brainSettings = { maxAutoRisk: "medium" };
|
|
8429
8882
|
const autonomousBrain = {
|
|
@@ -8434,7 +8887,7 @@ async function createAgentServices(input) {
|
|
|
8434
8887
|
// the tiered ceiling gates risk — keep inner permissive
|
|
8435
8888
|
}).decide(request)
|
|
8436
8889
|
};
|
|
8437
|
-
const brain = new
|
|
8890
|
+
const brain = new ObservableBrainArbiterCtor(
|
|
8438
8891
|
createTieredBrainArbiter({
|
|
8439
8892
|
policy: new DefaultBrainArbiter(),
|
|
8440
8893
|
autonomous: autonomousBrain,
|
|
@@ -8442,7 +8895,7 @@ async function createAgentServices(input) {
|
|
|
8442
8895
|
}),
|
|
8443
8896
|
events
|
|
8444
8897
|
);
|
|
8445
|
-
container.bind(
|
|
8898
|
+
container.bind(TOKENS2.BrainArbiter, () => brain);
|
|
8446
8899
|
const brainLog = [];
|
|
8447
8900
|
const pushBrainLog = (entry) => {
|
|
8448
8901
|
brainLog.push(entry);
|
|
@@ -8475,7 +8928,7 @@ async function createAgentServices(input) {
|
|
|
8475
8928
|
outcome: e.decision.type === "deny" ? e.decision.reason : ""
|
|
8476
8929
|
})
|
|
8477
8930
|
);
|
|
8478
|
-
const brainMailbox = new
|
|
8931
|
+
const brainMailbox = new GlobalMailbox2(wpaths.projectDir, events);
|
|
8479
8932
|
const brainMonitor = new BrainMonitor({
|
|
8480
8933
|
events,
|
|
8481
8934
|
brain,
|
|
@@ -8568,14 +9021,14 @@ async function createAgentServices(input) {
|
|
|
8568
9021
|
updateAutoCompactionMaxContext
|
|
8569
9022
|
};
|
|
8570
9023
|
}
|
|
9024
|
+
function isSuperMemoryRetriever(memoryStore) {
|
|
9025
|
+
const value = memoryStore;
|
|
9026
|
+
return typeof value["retrieveForPath"] === "function" && typeof value["searchSuper"] === "function";
|
|
9027
|
+
}
|
|
8571
9028
|
|
|
8572
9029
|
// src/server/pending-confirms.ts
|
|
8573
|
-
function isDestructivePendingConfirm(confirm) {
|
|
8574
|
-
return confirm.riskTier === "destructive" || confirm.decisionSource === "yolo_destructive";
|
|
8575
|
-
}
|
|
8576
9030
|
function resolveYoloEligiblePendingConfirms(pendingConfirms) {
|
|
8577
9031
|
for (const [id, confirm] of pendingConfirms) {
|
|
8578
|
-
if (isDestructivePendingConfirm(confirm)) continue;
|
|
8579
9032
|
pendingConfirms.delete(id);
|
|
8580
9033
|
confirm.resolve("yes");
|
|
8581
9034
|
}
|
|
@@ -8731,6 +9184,9 @@ function createConnectionHandler(opts) {
|
|
|
8731
9184
|
};
|
|
8732
9185
|
}
|
|
8733
9186
|
|
|
9187
|
+
// src/server/message-dispatcher.ts
|
|
9188
|
+
import path17 from "node:path";
|
|
9189
|
+
|
|
8734
9190
|
// src/server/autophase-routes.ts
|
|
8735
9191
|
async function handleAutoPhaseRoute(_ws, msg, handlers) {
|
|
8736
9192
|
if (!msg.type.startsWith("autophase.")) return false;
|
|
@@ -8754,10 +9210,13 @@ async function handleBrainRoute(ws, msg, handlers) {
|
|
|
8754
9210
|
return false;
|
|
8755
9211
|
}
|
|
8756
9212
|
}
|
|
9213
|
+
|
|
9214
|
+
// src/server/goal-handlers.ts
|
|
9215
|
+
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
8757
9216
|
async function handleGoalGet(projectRoot, broadcast2) {
|
|
8758
9217
|
try {
|
|
8759
9218
|
const goalPath = resolveWstackPaths({ projectRoot }).projectGoal;
|
|
8760
|
-
const { readFile: readFile11 } = await import(
|
|
9219
|
+
const { readFile: readFile11 } = await import("node:fs/promises");
|
|
8761
9220
|
const raw = await readFile11(goalPath, "utf8");
|
|
8762
9221
|
const goal = JSON.parse(raw);
|
|
8763
9222
|
broadcast2({ type: "goal.updated", payload: goal });
|
|
@@ -8811,7 +9270,7 @@ async function handleTasksGet(ctx, ws) {
|
|
|
8811
9270
|
const taskPath = ctx.context.meta["task.path"];
|
|
8812
9271
|
if (typeof taskPath === "string" && taskPath) {
|
|
8813
9272
|
try {
|
|
8814
|
-
const { loadTasks } = await import(
|
|
9273
|
+
const { loadTasks } = await import("@wrongstack/core");
|
|
8815
9274
|
const file = await loadTasks(taskPath);
|
|
8816
9275
|
ctx.send(ws, { type: "tasks.updated", payload: sessionPayload(ctx, { tasks: file?.tasks ?? [] }) });
|
|
8817
9276
|
} catch {
|
|
@@ -8831,7 +9290,7 @@ async function handleTaskUpdate(ctx, ws, payload) {
|
|
|
8831
9290
|
return;
|
|
8832
9291
|
}
|
|
8833
9292
|
try {
|
|
8834
|
-
const { loadTasks, saveTasks } = await import(
|
|
9293
|
+
const { loadTasks, saveTasks } = await import("@wrongstack/core");
|
|
8835
9294
|
const file = await loadTasks(taskPath);
|
|
8836
9295
|
if (!file) {
|
|
8837
9296
|
sendResult2(ws, ctx, false, "No task file found.");
|
|
@@ -8860,7 +9319,7 @@ async function handlePlanGet(ctx, ws) {
|
|
|
8860
9319
|
const sessionId = ctx.context.session?.id ?? "";
|
|
8861
9320
|
if (typeof planPath === "string" && planPath) {
|
|
8862
9321
|
try {
|
|
8863
|
-
const { loadPlan } = await import(
|
|
9322
|
+
const { loadPlan } = await import("@wrongstack/core");
|
|
8864
9323
|
const plan = await loadPlan(planPath);
|
|
8865
9324
|
ctx.send(ws, {
|
|
8866
9325
|
type: "plan.updated",
|
|
@@ -8901,7 +9360,7 @@ async function handlePlanTemplateUse(ctx, ws, template) {
|
|
|
8901
9360
|
return;
|
|
8902
9361
|
}
|
|
8903
9362
|
try {
|
|
8904
|
-
const { getPlanTemplate, loadPlan, savePlan, emptyPlan, addPlanItem } = await import(
|
|
9363
|
+
const { getPlanTemplate, loadPlan, savePlan, emptyPlan, addPlanItem } = await import("@wrongstack/core");
|
|
8905
9364
|
const tpl = getPlanTemplate(template);
|
|
8906
9365
|
if (!tpl) {
|
|
8907
9366
|
sendResult2(ws, ctx, false, `Unknown template "${template}".`);
|
|
@@ -8926,7 +9385,7 @@ async function handlePlanItemUpdate(ctx, ws, payload) {
|
|
|
8926
9385
|
return;
|
|
8927
9386
|
}
|
|
8928
9387
|
try {
|
|
8929
|
-
const { mutatePlan, setPlanItemStatus } = await import(
|
|
9388
|
+
const { mutatePlan, setPlanItemStatus } = await import("@wrongstack/core");
|
|
8930
9389
|
let changed = false;
|
|
8931
9390
|
const plan = await mutatePlan(planPath, sessionId, async (p) => {
|
|
8932
9391
|
const before = p.updatedAt;
|
|
@@ -8993,6 +9452,45 @@ async function handleWorklistMessage(ctx, ws, msg) {
|
|
|
8993
9452
|
return;
|
|
8994
9453
|
}
|
|
8995
9454
|
}
|
|
9455
|
+
|
|
9456
|
+
// src/server/kanban-routes.ts
|
|
9457
|
+
import {
|
|
9458
|
+
deserializeTaskGraph,
|
|
9459
|
+
serializeTaskGraph
|
|
9460
|
+
} from "@wrongstack/core";
|
|
9461
|
+
import {
|
|
9462
|
+
addColumn,
|
|
9463
|
+
addGoalMetricToTask,
|
|
9464
|
+
addTask,
|
|
9465
|
+
assignTask,
|
|
9466
|
+
claimReadyTask,
|
|
9467
|
+
copyTaskToBoard,
|
|
9468
|
+
createBoard,
|
|
9469
|
+
duplicateBoard,
|
|
9470
|
+
exportBoardToTaskGraph,
|
|
9471
|
+
generateBoardFromDescription,
|
|
9472
|
+
getBoard,
|
|
9473
|
+
getKanbanOrchestrationSnapshot,
|
|
9474
|
+
getKanbanQueueHealth,
|
|
9475
|
+
getTask,
|
|
9476
|
+
getTaskChain,
|
|
9477
|
+
listReadyTasks,
|
|
9478
|
+
listBoards,
|
|
9479
|
+
mergeTasks,
|
|
9480
|
+
moveTask,
|
|
9481
|
+
parseLinesIntoTasks,
|
|
9482
|
+
removeBoard,
|
|
9483
|
+
removeColumn,
|
|
9484
|
+
removeTask,
|
|
9485
|
+
releaseTaskClaim,
|
|
9486
|
+
setTaskChain,
|
|
9487
|
+
splitTask,
|
|
9488
|
+
syncBoardFromTaskGraph,
|
|
9489
|
+
transferTaskToBoard,
|
|
9490
|
+
updateBoard,
|
|
9491
|
+
updateGoalMetricOnTask,
|
|
9492
|
+
updateTask
|
|
9493
|
+
} from "@wrongstack/kanban";
|
|
8996
9494
|
function ok(ws, type, data) {
|
|
8997
9495
|
send(ws, { type, payload: { success: true, data: data ?? null } });
|
|
8998
9496
|
}
|
|
@@ -9593,7 +10091,7 @@ async function handlePrefsRoute(ws, msg, handlers) {
|
|
|
9593
10091
|
// src/server/process-handlers.ts
|
|
9594
10092
|
async function handleProcessList(ws) {
|
|
9595
10093
|
try {
|
|
9596
|
-
const { getProcessRegistry } = await import(
|
|
10094
|
+
const { getProcessRegistry } = await import("@wrongstack/tools");
|
|
9597
10095
|
const procs = getProcessRegistry().list();
|
|
9598
10096
|
send(ws, {
|
|
9599
10097
|
type: "process.list",
|
|
@@ -9620,7 +10118,7 @@ async function handleProcessKill(ws, payload) {
|
|
|
9620
10118
|
}
|
|
9621
10119
|
const { pid } = parsed.value;
|
|
9622
10120
|
try {
|
|
9623
|
-
const { getProcessRegistry } = await import(
|
|
10121
|
+
const { getProcessRegistry } = await import("@wrongstack/tools");
|
|
9624
10122
|
const proc = getProcessRegistry().get(pid);
|
|
9625
10123
|
if (proc?.protected) {
|
|
9626
10124
|
sendResult(ws, false, `Cannot kill protected process (PID ${pid})`);
|
|
@@ -9634,7 +10132,7 @@ async function handleProcessKill(ws, payload) {
|
|
|
9634
10132
|
}
|
|
9635
10133
|
async function handleProcessKillAll(ws) {
|
|
9636
10134
|
try {
|
|
9637
|
-
const { getProcessRegistry } = await import(
|
|
10135
|
+
const { getProcessRegistry } = await import("@wrongstack/tools");
|
|
9638
10136
|
getProcessRegistry().killAll();
|
|
9639
10137
|
sendResult(ws, true, "All processes killed");
|
|
9640
10138
|
} catch (err) {
|
|
@@ -9944,7 +10442,7 @@ function createMessageDispatcher(opts) {
|
|
|
9944
10442
|
skillLoader: deps2.skillLoader,
|
|
9945
10443
|
skillInstaller: deps2.skillInstaller,
|
|
9946
10444
|
projectRoot,
|
|
9947
|
-
projectSkillsDir:
|
|
10445
|
+
projectSkillsDir: path17.join(projectRoot, ".wrongstack", "skills"),
|
|
9948
10446
|
globalSkillsDir: deps2.wpaths.globalSkills
|
|
9949
10447
|
};
|
|
9950
10448
|
}
|
|
@@ -10399,6 +10897,7 @@ function createMessageDispatcher(opts) {
|
|
|
10399
10897
|
break;
|
|
10400
10898
|
}
|
|
10401
10899
|
case "prefs.update": {
|
|
10900
|
+
void ws;
|
|
10402
10901
|
throw new Error("handlePrefsRoute did not claim prefs.update \u2014 check chain order");
|
|
10403
10902
|
}
|
|
10404
10903
|
case "prefs.get": {
|
|
@@ -10412,6 +10911,11 @@ function createMessageDispatcher(opts) {
|
|
|
10412
10911
|
}
|
|
10413
10912
|
};
|
|
10414
10913
|
}
|
|
10914
|
+
|
|
10915
|
+
// src/server/pref-helpers.ts
|
|
10916
|
+
import { atomicWrite as atomicWrite6 } from "@wrongstack/core/utils";
|
|
10917
|
+
import { decryptConfigSecrets as decryptConfigSecrets2, encryptConfigSecrets as encryptConfigSecrets2 } from "@wrongstack/core/security";
|
|
10918
|
+
import * as fs13 from "node:fs/promises";
|
|
10415
10919
|
var PREF_KEYS = [
|
|
10416
10920
|
"autonomy",
|
|
10417
10921
|
"autonomyDelayMs",
|
|
@@ -10471,7 +10975,7 @@ async function updateGlobalConfig(deps2, holder, mutate, errorLabel) {
|
|
|
10471
10975
|
const write = async () => {
|
|
10472
10976
|
let raw;
|
|
10473
10977
|
try {
|
|
10474
|
-
raw = await
|
|
10978
|
+
raw = await fs13.readFile(globalConfigPath, "utf8");
|
|
10475
10979
|
} catch {
|
|
10476
10980
|
raw = "{}";
|
|
10477
10981
|
}
|
|
@@ -10482,10 +10986,10 @@ async function updateGlobalConfig(deps2, holder, mutate, errorLabel) {
|
|
|
10482
10986
|
logger.warn(`${errorLabel}: refusing to overwrite corrupt config at ${globalConfigPath}`);
|
|
10483
10987
|
return;
|
|
10484
10988
|
}
|
|
10485
|
-
const decrypted =
|
|
10989
|
+
const decrypted = decryptConfigSecrets2(parsed, vault);
|
|
10486
10990
|
mutate(decrypted);
|
|
10487
|
-
const encrypted =
|
|
10488
|
-
await
|
|
10991
|
+
const encrypted = encryptConfigSecrets2(decrypted, vault);
|
|
10992
|
+
await atomicWrite6(globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
10489
10993
|
};
|
|
10490
10994
|
const next = holder.lock.then(write);
|
|
10491
10995
|
holder.lock = next.then(
|
|
@@ -10647,13 +11151,18 @@ async function persistPrefsToConfig(deps2, holder, payload) {
|
|
|
10647
11151
|
}
|
|
10648
11152
|
}, "prefs");
|
|
10649
11153
|
}
|
|
11154
|
+
|
|
11155
|
+
// src/server/projects-manifest.ts
|
|
11156
|
+
import * as fs14 from "node:fs/promises";
|
|
11157
|
+
import * as path18 from "node:path";
|
|
11158
|
+
import { projectSlug } from "@wrongstack/core";
|
|
10650
11159
|
function projectsJsonPath(globalConfigPath) {
|
|
10651
|
-
const base =
|
|
10652
|
-
return
|
|
11160
|
+
const base = path18.dirname(globalConfigPath);
|
|
11161
|
+
return path18.join(base, "projects.json");
|
|
10653
11162
|
}
|
|
10654
11163
|
async function loadManifest(globalConfigPath) {
|
|
10655
11164
|
try {
|
|
10656
|
-
const raw = await
|
|
11165
|
+
const raw = await fs14.readFile(projectsJsonPath(globalConfigPath), "utf8");
|
|
10657
11166
|
const parsed = JSON.parse(raw);
|
|
10658
11167
|
return { projects: parsed.projects ?? [] };
|
|
10659
11168
|
} catch {
|
|
@@ -10662,18 +11171,26 @@ async function loadManifest(globalConfigPath) {
|
|
|
10662
11171
|
}
|
|
10663
11172
|
async function saveManifest(manifest, globalConfigPath) {
|
|
10664
11173
|
const file = projectsJsonPath(globalConfigPath);
|
|
10665
|
-
await
|
|
10666
|
-
await
|
|
11174
|
+
await fs14.mkdir(path18.dirname(file), { recursive: true });
|
|
11175
|
+
await fs14.writeFile(file, JSON.stringify(manifest, null, 2), "utf8");
|
|
10667
11176
|
}
|
|
10668
11177
|
function generateProjectSlug(rootPath) {
|
|
10669
11178
|
return projectSlug(rootPath);
|
|
10670
11179
|
}
|
|
10671
11180
|
async function ensureProjectDataDir(slug, globalConfigPath) {
|
|
10672
|
-
const base =
|
|
10673
|
-
const dir =
|
|
10674
|
-
await
|
|
11181
|
+
const base = path18.dirname(globalConfigPath);
|
|
11182
|
+
const dir = path18.join(base, "projects", slug);
|
|
11183
|
+
await fs14.mkdir(dir, { recursive: true });
|
|
10675
11184
|
return dir;
|
|
10676
11185
|
}
|
|
11186
|
+
|
|
11187
|
+
// src/server/provider-handlers.ts
|
|
11188
|
+
import { DefaultSecretScrubber } from "@wrongstack/core";
|
|
11189
|
+
import {
|
|
11190
|
+
beginOAuthLogin
|
|
11191
|
+
} from "@wrongstack/providers/oauth";
|
|
11192
|
+
import { probeLocalLlm } from "@wrongstack/runtime/probe";
|
|
11193
|
+
import { toErrorMessage as toErrorMessage9 } from "@wrongstack/core/utils";
|
|
10677
11194
|
function projectSavedProviders(providers) {
|
|
10678
11195
|
return Object.entries(providers).map(([id, cfg]) => {
|
|
10679
11196
|
const keys = normalizeKeys(cfg);
|
|
@@ -10704,7 +11221,7 @@ function createProviderHandlers(deps2) {
|
|
|
10704
11221
|
}
|
|
10705
11222
|
async function saveConfigProviders(providers) {
|
|
10706
11223
|
const next = configWriteLock.then(() => saveProviders(globalConfigPath, vault, providers)).catch((err) => {
|
|
10707
|
-
const msg =
|
|
11224
|
+
const msg = toErrorMessage9(err);
|
|
10708
11225
|
console.error(JSON.stringify({
|
|
10709
11226
|
level: "error",
|
|
10710
11227
|
event: "webui.provider_save_failed",
|
|
@@ -10976,10 +11493,23 @@ function createProviderHandlers(deps2) {
|
|
|
10976
11493
|
loadConfigProviders
|
|
10977
11494
|
};
|
|
10978
11495
|
}
|
|
11496
|
+
|
|
11497
|
+
// src/server/routes.ts
|
|
11498
|
+
import path21 from "node:path";
|
|
11499
|
+
import {
|
|
11500
|
+
enhanceUserPrompt,
|
|
11501
|
+
gatedEnhancerReasoning,
|
|
11502
|
+
recentTextTurns,
|
|
11503
|
+
resolveProviderModelList
|
|
11504
|
+
} from "@wrongstack/core";
|
|
11505
|
+
import { makeProviderFromConfig as makeProviderFromConfig2 } from "@wrongstack/providers";
|
|
11506
|
+
|
|
11507
|
+
// src/server/mailbox-handlers.ts
|
|
11508
|
+
import { GlobalMailbox as GlobalMailbox3, resolveProjectDir as resolveProjectDir2 } from "@wrongstack/core";
|
|
10979
11509
|
async function handleMailboxMessages(ws, deps2, payload) {
|
|
10980
11510
|
try {
|
|
10981
|
-
const dir =
|
|
10982
|
-
const mb = new
|
|
11511
|
+
const dir = resolveProjectDir2(deps2.projectRoot, deps2.globalRoot);
|
|
11512
|
+
const mb = new GlobalMailbox3(dir);
|
|
10983
11513
|
const limit = payload?.limit ?? 30;
|
|
10984
11514
|
const unreadForAgent = payload?.unreadOnly === true && payload.agentId !== void 0;
|
|
10985
11515
|
const messages = await mb.query({
|
|
@@ -11019,8 +11549,8 @@ async function handleMailboxMessages(ws, deps2, payload) {
|
|
|
11019
11549
|
}
|
|
11020
11550
|
async function handleMailboxAgents(ws, deps2, payload) {
|
|
11021
11551
|
try {
|
|
11022
|
-
const dir =
|
|
11023
|
-
const mb = new
|
|
11552
|
+
const dir = resolveProjectDir2(deps2.projectRoot, deps2.globalRoot);
|
|
11553
|
+
const mb = new GlobalMailbox3(dir);
|
|
11024
11554
|
const agents = payload?.onlineOnly ? await mb.getOnlineAgents() : await mb.getAgentStatuses();
|
|
11025
11555
|
send(ws, {
|
|
11026
11556
|
type: "mailbox.agents",
|
|
@@ -11048,8 +11578,8 @@ async function handleMailboxAgents(ws, deps2, payload) {
|
|
|
11048
11578
|
}
|
|
11049
11579
|
async function handleMailboxClear(ws, deps2) {
|
|
11050
11580
|
try {
|
|
11051
|
-
const dir =
|
|
11052
|
-
const mb = new
|
|
11581
|
+
const dir = resolveProjectDir2(deps2.projectRoot, deps2.globalRoot);
|
|
11582
|
+
const mb = new GlobalMailbox3(dir);
|
|
11053
11583
|
await mb.clearAll();
|
|
11054
11584
|
send(ws, { type: "mailbox.cleared", payload: {} });
|
|
11055
11585
|
} catch (err) {
|
|
@@ -11058,14 +11588,21 @@ async function handleMailboxClear(ws, deps2) {
|
|
|
11058
11588
|
}
|
|
11059
11589
|
async function handleMailboxPurge(ws, deps2, opts) {
|
|
11060
11590
|
try {
|
|
11061
|
-
const dir =
|
|
11062
|
-
const mb = new
|
|
11591
|
+
const dir = resolveProjectDir2(deps2.projectRoot, deps2.globalRoot);
|
|
11592
|
+
const mb = new GlobalMailbox3(dir);
|
|
11063
11593
|
const result = await mb.purgeStale(opts);
|
|
11064
11594
|
send(ws, { type: "mailbox.purged", payload: result });
|
|
11065
11595
|
} catch (err) {
|
|
11066
11596
|
send(ws, { type: "mailbox.purged", payload: { error: errMessage(err) } });
|
|
11067
11597
|
}
|
|
11068
11598
|
}
|
|
11599
|
+
|
|
11600
|
+
// src/server/mode-handlers.ts
|
|
11601
|
+
import {
|
|
11602
|
+
DefaultSystemPromptBuilder as DefaultSystemPromptBuilder2,
|
|
11603
|
+
resolveWstackPaths as resolveWstackPaths2,
|
|
11604
|
+
ToolValidationError as ToolValidationError5
|
|
11605
|
+
} from "@wrongstack/core";
|
|
11069
11606
|
function createModeHandlers(ctx) {
|
|
11070
11607
|
return {
|
|
11071
11608
|
listModes: async (ws) => {
|
|
@@ -11108,14 +11645,14 @@ function createModeHandlers(ctx) {
|
|
|
11108
11645
|
} else {
|
|
11109
11646
|
const found = await ctx.modeStore.getMode(id);
|
|
11110
11647
|
if (!found) {
|
|
11111
|
-
throw new
|
|
11648
|
+
throw new ToolValidationError5({ message: `Unknown mode "${id}"`, field: "modeId" });
|
|
11112
11649
|
}
|
|
11113
11650
|
await ctx.modeStore.setActiveMode(id);
|
|
11114
11651
|
}
|
|
11115
11652
|
ctx.setModeId(id);
|
|
11116
11653
|
const modePrompt = id === "default" ? "" : (await ctx.modeStore.getMode(id))?.prompt ?? "";
|
|
11117
|
-
const paths =
|
|
11118
|
-
const freshBuilder = new
|
|
11654
|
+
const paths = resolveWstackPaths2({ projectRoot: ctx.projectRoot, globalRoot: ctx.globalRoot });
|
|
11655
|
+
const freshBuilder = new DefaultSystemPromptBuilder2({
|
|
11119
11656
|
memoryStore: ctx.memoryStore,
|
|
11120
11657
|
skillLoader: ctx.skillLoader,
|
|
11121
11658
|
modeStore: ctx.modeStore,
|
|
@@ -11145,6 +11682,9 @@ function createModeHandlers(ctx) {
|
|
|
11145
11682
|
}
|
|
11146
11683
|
};
|
|
11147
11684
|
}
|
|
11685
|
+
|
|
11686
|
+
// src/server/project-handlers.ts
|
|
11687
|
+
import * as path19 from "node:path";
|
|
11148
11688
|
function createProjectHandlers(ctx) {
|
|
11149
11689
|
return {
|
|
11150
11690
|
listProjects: async (ws) => {
|
|
@@ -11170,7 +11710,7 @@ function createProjectHandlers(ctx) {
|
|
|
11170
11710
|
selectProject: async (ws, msg) => {
|
|
11171
11711
|
const payload = msg.payload;
|
|
11172
11712
|
const root = typeof payload?.root === "string" ? payload.root : "";
|
|
11173
|
-
const name2 = typeof payload?.name === "string" ? payload.name : root ?
|
|
11713
|
+
const name2 = typeof payload?.name === "string" ? payload.name : root ? path19.basename(root) : "";
|
|
11174
11714
|
send(ws, {
|
|
11175
11715
|
type: "projects.selected",
|
|
11176
11716
|
payload: {
|
|
@@ -11203,6 +11743,14 @@ function createProjectHandlers(ctx) {
|
|
|
11203
11743
|
}
|
|
11204
11744
|
};
|
|
11205
11745
|
}
|
|
11746
|
+
|
|
11747
|
+
// src/server/session-handlers.ts
|
|
11748
|
+
import * as path20 from "node:path";
|
|
11749
|
+
import {
|
|
11750
|
+
DEFAULT_CONTEXT_WINDOW_MODE_ID,
|
|
11751
|
+
repairToolUseAdjacency,
|
|
11752
|
+
resolveContextWindowPolicy as resolveContextWindowPolicy3
|
|
11753
|
+
} from "@wrongstack/core";
|
|
11206
11754
|
function createSessionHandlers(ctx) {
|
|
11207
11755
|
const currentSessionId = () => ctx.getSession().id;
|
|
11208
11756
|
const sessionPayload2 = (payload) => {
|
|
@@ -11356,7 +11904,7 @@ function createSessionHandlers(ctx) {
|
|
|
11356
11904
|
return;
|
|
11357
11905
|
}
|
|
11358
11906
|
const { id } = parsed.value;
|
|
11359
|
-
let policy =
|
|
11907
|
+
let policy = resolveContextWindowPolicy3({}, id);
|
|
11360
11908
|
if (policy.id !== id) {
|
|
11361
11909
|
const customModes = ctx.customModeStore.list().filter((m) => m.custom === true);
|
|
11362
11910
|
const custom = customModes.find((m) => m.id === id);
|
|
@@ -11428,7 +11976,7 @@ function createSessionHandlers(ctx) {
|
|
|
11428
11976
|
const { id } = parsed.value;
|
|
11429
11977
|
if (String(ctx.context.meta["contextWindowMode"] ?? "") === id) {
|
|
11430
11978
|
ctx.context.meta["contextWindowMode"] = DEFAULT_CONTEXT_WINDOW_MODE_ID;
|
|
11431
|
-
ctx.context.meta["contextWindowPolicy"] =
|
|
11979
|
+
ctx.context.meta["contextWindowPolicy"] = resolveContextWindowPolicy3({}, DEFAULT_CONTEXT_WINDOW_MODE_ID);
|
|
11432
11980
|
}
|
|
11433
11981
|
const result = ctx.customModeStore.remove(id);
|
|
11434
11982
|
sendResult(ws, result.ok, result.error ?? `Mode "${id}" deleted`);
|
|
@@ -11548,10 +12096,10 @@ function createSessionHandlers(ctx) {
|
|
|
11548
12096
|
listCheckpoints: async (ws, msg) => {
|
|
11549
12097
|
if (!ensureCurrentSession(ws, msg, "session.checkpoints")) return;
|
|
11550
12098
|
try {
|
|
11551
|
-
const { DefaultSessionRewinder } = await import(
|
|
12099
|
+
const { DefaultSessionRewinder } = await import("@wrongstack/core");
|
|
11552
12100
|
const projectRoot = ctx.getProjectRoot();
|
|
11553
12101
|
const rewinder = new DefaultSessionRewinder(
|
|
11554
|
-
|
|
12102
|
+
path20.join(projectRoot, ".wrongstack", "sessions"),
|
|
11555
12103
|
projectRoot
|
|
11556
12104
|
);
|
|
11557
12105
|
const checkpoints = await rewinder.listCheckpoints(ctx.getSession().id);
|
|
@@ -11564,10 +12112,10 @@ function createSessionHandlers(ctx) {
|
|
|
11564
12112
|
if (!ensureCurrentSession(ws, msg, "session.rewind")) return;
|
|
11565
12113
|
const { checkpointIndex } = msg.payload;
|
|
11566
12114
|
try {
|
|
11567
|
-
const { DefaultSessionRewinder } = await import(
|
|
12115
|
+
const { DefaultSessionRewinder } = await import("@wrongstack/core");
|
|
11568
12116
|
const projectRoot = ctx.getProjectRoot();
|
|
11569
12117
|
const rewinder = new DefaultSessionRewinder(
|
|
11570
|
-
|
|
12118
|
+
path20.join(projectRoot, ".wrongstack", "sessions"),
|
|
11571
12119
|
projectRoot
|
|
11572
12120
|
);
|
|
11573
12121
|
await rewinder.rewindToCheckpoint(ctx.getSession().id, checkpointIndex);
|
|
@@ -11652,11 +12200,13 @@ function buildRoutes(state, deps2, cb) {
|
|
|
11652
12200
|
const saved = await providerHandlers.loadConfigProviders();
|
|
11653
12201
|
const cfg = saved[providerId];
|
|
11654
12202
|
const provider = await resolveProviderCatalogForModels(deps2.modelsRegistry, providerId, cfg);
|
|
12203
|
+
const siblingId = SIBLING_CATALOG[providerId];
|
|
12204
|
+
const siblingCatalog = siblingId && siblingId !== providerId ? await deps2.modelsRegistry.getProvider(siblingId).catch(() => void 0) : void 0;
|
|
11655
12205
|
const models = await enrichProviderModelDescriptors(
|
|
11656
12206
|
deps2.modelsRegistry,
|
|
11657
12207
|
providerId,
|
|
11658
12208
|
cfg,
|
|
11659
|
-
resolveProviderModelList(cfg?.models, provider, cfg?.type ?? providerId)
|
|
12209
|
+
resolveProviderModelList(cfg?.models, provider, cfg?.type ?? providerId, siblingCatalog)
|
|
11660
12210
|
);
|
|
11661
12211
|
send(ws, {
|
|
11662
12212
|
type: "provider.models",
|
|
@@ -11682,7 +12232,7 @@ function buildRoutes(state, deps2, cb) {
|
|
|
11682
12232
|
const providerCfg = newCfg.providers?.[newProvider] ?? {
|
|
11683
12233
|
type: newProvider
|
|
11684
12234
|
};
|
|
11685
|
-
const newProv = deps2.providerRegistry.has(newProvider) ? deps2.providerRegistry.create({ ...providerCfg, type: newProvider }) :
|
|
12235
|
+
const newProv = deps2.providerRegistry.has(newProvider) ? deps2.providerRegistry.create({ ...providerCfg, type: newProvider }) : makeProviderFromConfig2(newProvider, providerCfg);
|
|
11686
12236
|
deps2.context.provider = newProv;
|
|
11687
12237
|
await cb.updateAutoCompactionMaxContext(newProv, newProvider, providerCfg);
|
|
11688
12238
|
await cb.updateGlobalConfig((config) => {
|
|
@@ -11925,7 +12475,7 @@ function buildRoutes(state, deps2, cb) {
|
|
|
11925
12475
|
}
|
|
11926
12476
|
return handleMailboxMessages(
|
|
11927
12477
|
ws,
|
|
11928
|
-
{ projectRoot: state.getProjectRoot(), globalRoot:
|
|
12478
|
+
{ projectRoot: state.getProjectRoot(), globalRoot: path21.dirname(deps2.globalConfigPath) },
|
|
11929
12479
|
parsed.value
|
|
11930
12480
|
);
|
|
11931
12481
|
},
|
|
@@ -11937,13 +12487,13 @@ function buildRoutes(state, deps2, cb) {
|
|
|
11937
12487
|
}
|
|
11938
12488
|
return handleMailboxAgents(
|
|
11939
12489
|
ws,
|
|
11940
|
-
{ projectRoot: state.getProjectRoot(), globalRoot:
|
|
12490
|
+
{ projectRoot: state.getProjectRoot(), globalRoot: path21.dirname(deps2.globalConfigPath) },
|
|
11941
12491
|
parsed.value
|
|
11942
12492
|
);
|
|
11943
12493
|
},
|
|
11944
12494
|
clear: (ws) => handleMailboxClear(ws, {
|
|
11945
12495
|
projectRoot: state.getProjectRoot(),
|
|
11946
|
-
globalRoot:
|
|
12496
|
+
globalRoot: path21.dirname(deps2.globalConfigPath)
|
|
11947
12497
|
}),
|
|
11948
12498
|
purge: (ws, msg) => {
|
|
11949
12499
|
const parsed = validateMailboxPurgePayload(msg.payload);
|
|
@@ -11953,7 +12503,7 @@ function buildRoutes(state, deps2, cb) {
|
|
|
11953
12503
|
}
|
|
11954
12504
|
return handleMailboxPurge(
|
|
11955
12505
|
ws,
|
|
11956
|
-
{ projectRoot: state.getProjectRoot(), globalRoot:
|
|
12506
|
+
{ projectRoot: state.getProjectRoot(), globalRoot: path21.dirname(deps2.globalConfigPath) },
|
|
11957
12507
|
parsed.value
|
|
11958
12508
|
);
|
|
11959
12509
|
}
|
|
@@ -12061,7 +12611,7 @@ async function startWebUI(opts = {}) {
|
|
|
12061
12611
|
const updateGlobalConfig2 = async (mutate, errorLabel) => updateGlobalConfig(prefHelperDeps, configWriteLock, mutate, errorLabel);
|
|
12062
12612
|
console.log("[WebUI] Config loaded:", config.provider ?? "(none)", "/", config.model ?? "(none)");
|
|
12063
12613
|
if (!config.provider && config.providers && typeof config.providers === "object" && config.providers !== null && !Array.isArray(config.providers) && Object.keys(config.providers).length > 0) {
|
|
12064
|
-
const firstKey =
|
|
12614
|
+
const firstKey = expectDefined3(Object.keys(config.providers)[0]);
|
|
12065
12615
|
config = patchConfig(config, { provider: firstKey });
|
|
12066
12616
|
console.log("[WebUI] No active provider \u2014 auto-selected:", firstKey);
|
|
12067
12617
|
}
|
|
@@ -12161,7 +12711,7 @@ async function startWebUI(opts = {}) {
|
|
|
12161
12711
|
getProjectRoot: () => projectRoot,
|
|
12162
12712
|
getWorkingDir: () => workingDir,
|
|
12163
12713
|
getModeId: () => modeId,
|
|
12164
|
-
getContextMode: () => String(context.meta["contextWindowMode"] ??
|
|
12714
|
+
getContextMode: () => String(context.meta["contextWindowMode"] ?? DEFAULT_CONTEXT_WINDOW_MODE_ID2),
|
|
12165
12715
|
getNeedsSetup: () => needsSetup,
|
|
12166
12716
|
modelsRegistry
|
|
12167
12717
|
});
|
|
@@ -12204,21 +12754,21 @@ async function startWebUI(opts = {}) {
|
|
|
12204
12754
|
wpaths
|
|
12205
12755
|
}, watcherMetricsRef);
|
|
12206
12756
|
async function touchProjectEntry(root, workDir) {
|
|
12207
|
-
const resolved =
|
|
12757
|
+
const resolved = path22.resolve(root);
|
|
12208
12758
|
const manifest = await loadManifest(globalConfigPath);
|
|
12209
12759
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
12210
|
-
const existing = manifest.projects.find((p) =>
|
|
12760
|
+
const existing = manifest.projects.find((p) => path22.resolve(p.root) === resolved);
|
|
12211
12761
|
if (existing) {
|
|
12212
12762
|
existing.lastSeen = now;
|
|
12213
|
-
if (workDir) existing.lastWorkingDir =
|
|
12763
|
+
if (workDir) existing.lastWorkingDir = path22.resolve(workDir);
|
|
12214
12764
|
} else {
|
|
12215
12765
|
manifest.projects.push({
|
|
12216
|
-
name:
|
|
12766
|
+
name: path22.basename(resolved),
|
|
12217
12767
|
root: resolved,
|
|
12218
12768
|
slug: generateProjectSlug(resolved),
|
|
12219
12769
|
createdAt: now,
|
|
12220
12770
|
lastSeen: now,
|
|
12221
|
-
lastWorkingDir: workDir ?
|
|
12771
|
+
lastWorkingDir: workDir ? path22.resolve(workDir) : void 0
|
|
12222
12772
|
});
|
|
12223
12773
|
}
|
|
12224
12774
|
await saveManifest(manifest, globalConfigPath);
|
|
@@ -12363,13 +12913,13 @@ async function startWebUI(opts = {}) {
|
|
|
12363
12913
|
...snapshot.apiKey !== void 0 ? { apiKey: snapshot.apiKey } : {},
|
|
12364
12914
|
...snapshot.baseUrl !== void 0 ? { baseUrl: snapshot.baseUrl } : {}
|
|
12365
12915
|
};
|
|
12366
|
-
const newProv = deps2.providerRegistry.has(activeId) ? deps2.providerRegistry.create({ ...providerCfg, type: activeId }) :
|
|
12916
|
+
const newProv = deps2.providerRegistry.has(activeId) ? deps2.providerRegistry.create({ ...providerCfg, type: activeId }) : makeProviderFromConfig3(activeId, { ...providerCfg, type: activeId });
|
|
12367
12917
|
deps2.context.provider = newProv;
|
|
12368
12918
|
void updateAutoCompactionMaxContext(newProv).catch(() => void 0);
|
|
12369
12919
|
console.log(`[WebUI] Provider credentials reloaded from config.json (${activeId})`);
|
|
12370
12920
|
} catch (err) {
|
|
12371
12921
|
console.warn(
|
|
12372
|
-
`[WebUI] Credential hot-reload failed for ${activeId}: ${
|
|
12922
|
+
`[WebUI] Credential hot-reload failed for ${activeId}: ${toErrorMessage10(err)}`
|
|
12373
12923
|
);
|
|
12374
12924
|
}
|
|
12375
12925
|
},
|
|
@@ -12436,20 +12986,33 @@ async function startWebUI(opts = {}) {
|
|
|
12436
12986
|
},
|
|
12437
12987
|
clients: () => clients.keys(),
|
|
12438
12988
|
servers: [httpServer, wssPrimary, ...wssSecondary ? [wssSecondary] : []],
|
|
12439
|
-
onShutdown: () => {
|
|
12989
|
+
onShutdown: async () => {
|
|
12440
12990
|
credentialWatcherClose?.();
|
|
12441
12991
|
brainMonitor.stop();
|
|
12442
|
-
|
|
12992
|
+
await mcpRegistry.stopAll().catch(() => void 0);
|
|
12443
12993
|
eventArming.getDispose()?.();
|
|
12444
12994
|
if (eternalSubscription) {
|
|
12445
12995
|
eternalSubscription.dispose();
|
|
12446
12996
|
eternalSubscription = null;
|
|
12447
12997
|
}
|
|
12448
12998
|
codebaseIndexing.dispose();
|
|
12449
|
-
|
|
12999
|
+
if (config.superMemory?.enabled !== false && config.superMemory?.hygiene?.autoAfterSession !== false) {
|
|
13000
|
+
const candidate = memoryStore;
|
|
13001
|
+
await candidate.hygiene?.({
|
|
13002
|
+
retentionDays: config.superMemory?.hygiene?.retentionDays,
|
|
13003
|
+
archiveLowConfidenceAfterDays: config.superMemory?.hygiene?.archiveLowConfidenceAfterDays
|
|
13004
|
+
}).catch((err) => logger.warn(`super-memory session hygiene failed: ${toErrorMessage10(err)}`));
|
|
13005
|
+
}
|
|
13006
|
+
await unregisterInstance(process.pid, path22.dirname(globalConfigPath));
|
|
12450
13007
|
}
|
|
12451
13008
|
});
|
|
12452
13009
|
}
|
|
13010
|
+
|
|
13011
|
+
// src/server/provider-store.ts
|
|
13012
|
+
import { expectDefined as expectDefined4 } from "@wrongstack/core";
|
|
13013
|
+
import * as fs15 from "node:fs/promises";
|
|
13014
|
+
import { decryptConfigSecrets as decryptConfigSecrets3, encryptConfigSecrets as encryptConfigSecrets3 } from "@wrongstack/core/security";
|
|
13015
|
+
import { atomicWrite as atomicWrite7 } from "@wrongstack/core";
|
|
12453
13016
|
function createConfigWriteLock() {
|
|
12454
13017
|
let lock = Promise.resolve();
|
|
12455
13018
|
return {
|
|
@@ -12471,10 +13034,10 @@ function createProviderStore(deps2) {
|
|
|
12471
13034
|
const configWriteLock = createConfigWriteLock();
|
|
12472
13035
|
async function loadSavedProviders2() {
|
|
12473
13036
|
try {
|
|
12474
|
-
const raw = await
|
|
13037
|
+
const raw = await fs15.readFile(globalConfigPath, "utf8");
|
|
12475
13038
|
const parsed = JSON.parse(raw);
|
|
12476
13039
|
if (!parsed.providers) return {};
|
|
12477
|
-
return
|
|
13040
|
+
return decryptConfigSecrets3(parsed.providers, vault);
|
|
12478
13041
|
} catch {
|
|
12479
13042
|
return {};
|
|
12480
13043
|
}
|
|
@@ -12485,14 +13048,14 @@ function createProviderStore(deps2) {
|
|
|
12485
13048
|
await prev;
|
|
12486
13049
|
let parsed;
|
|
12487
13050
|
try {
|
|
12488
|
-
const raw = await
|
|
13051
|
+
const raw = await fs15.readFile(globalConfigPath, "utf8");
|
|
12489
13052
|
parsed = JSON.parse(raw);
|
|
12490
13053
|
} catch {
|
|
12491
13054
|
parsed = {};
|
|
12492
13055
|
}
|
|
12493
13056
|
parsed["providers"] = providers;
|
|
12494
|
-
const encrypted =
|
|
12495
|
-
await
|
|
13057
|
+
const encrypted = encryptConfigSecrets3(parsed, vault);
|
|
13058
|
+
await atomicWrite7(globalConfigPath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
12496
13059
|
} finally {
|
|
12497
13060
|
release();
|
|
12498
13061
|
}
|
|
@@ -12514,7 +13077,7 @@ function createProviderStore(deps2) {
|
|
|
12514
13077
|
return;
|
|
12515
13078
|
}
|
|
12516
13079
|
cfg.apiKeys = keys;
|
|
12517
|
-
const active = keys.find((k) => k.label === cfg.activeKey) ??
|
|
13080
|
+
const active = keys.find((k) => k.label === cfg.activeKey) ?? expectDefined4(keys[0]);
|
|
12518
13081
|
delete cfg.apiKey;
|
|
12519
13082
|
if (!cfg.activeKey || !keys.some((k) => k.label === cfg.activeKey)) {
|
|
12520
13083
|
cfg.activeKey = active.label;
|
|
@@ -12533,7 +13096,186 @@ function createProviderStore(deps2) {
|
|
|
12533
13096
|
maskedKey: maskedKey2
|
|
12534
13097
|
};
|
|
12535
13098
|
}
|
|
12536
|
-
|
|
12537
|
-
|
|
13099
|
+
export {
|
|
13100
|
+
AutoPhaseWebSocketHandler,
|
|
13101
|
+
CollaborationWebSocketHandler,
|
|
13102
|
+
SKIP_DIRS,
|
|
13103
|
+
SddBoardWebSocketHandler,
|
|
13104
|
+
SddWizardWebSocketHandler,
|
|
13105
|
+
SpecsWebSocketHandler,
|
|
13106
|
+
TerminalWebSocketHandler,
|
|
13107
|
+
WorktreeWebSocketHandler,
|
|
13108
|
+
addProvider,
|
|
13109
|
+
bootConfig,
|
|
13110
|
+
broadcast,
|
|
13111
|
+
browserOpenCommand,
|
|
13112
|
+
buildCspHeader,
|
|
13113
|
+
buildSddWizardDeps,
|
|
13114
|
+
buildWebUIAccessUrl,
|
|
13115
|
+
clearAnalyticsBuffer,
|
|
13116
|
+
computeUsageCost,
|
|
13117
|
+
createConfigWriteLock,
|
|
13118
|
+
createCustomModeStore,
|
|
13119
|
+
createEternalSubscription,
|
|
13120
|
+
createHttpServer,
|
|
13121
|
+
createProviderConfigIO,
|
|
13122
|
+
createProviderHandlers,
|
|
13123
|
+
createProviderStore,
|
|
13124
|
+
createShutdown,
|
|
13125
|
+
createToolLspCompletionSource,
|
|
13126
|
+
createZipBuffer,
|
|
13127
|
+
decodeSessionId,
|
|
13128
|
+
defaultBaseDir,
|
|
13129
|
+
deleteKey,
|
|
13130
|
+
ensureProjectDataDir,
|
|
13131
|
+
envFlag,
|
|
13132
|
+
errMessage,
|
|
13133
|
+
estimateContextBreakdown,
|
|
13134
|
+
estimateTokens,
|
|
13135
|
+
extractToken,
|
|
13136
|
+
extractTokenFromCookie,
|
|
13137
|
+
findFreePort,
|
|
13138
|
+
formatInstances,
|
|
13139
|
+
generateAuthToken,
|
|
13140
|
+
getAnalyticsBuffer,
|
|
13141
|
+
getCostRates,
|
|
13142
|
+
handleApiAnalyticsGet,
|
|
13143
|
+
handleApiAnalyticsPost,
|
|
13144
|
+
handleApiAnalyticsSummary,
|
|
13145
|
+
handleAutoPhaseRoute,
|
|
13146
|
+
handleBrainRoute,
|
|
13147
|
+
handleCompletionRequest,
|
|
13148
|
+
handleDesignList,
|
|
13149
|
+
handleDesignMaterialize,
|
|
13150
|
+
handleDesignSet,
|
|
13151
|
+
handleDesignState,
|
|
13152
|
+
handleDesignUse,
|
|
13153
|
+
handleDesignVerify,
|
|
13154
|
+
handleFilesList,
|
|
13155
|
+
handleFilesRead,
|
|
13156
|
+
handleFilesTree,
|
|
13157
|
+
handleFilesWrite,
|
|
13158
|
+
handleGitChanges,
|
|
13159
|
+
handleGitDiff,
|
|
13160
|
+
handleGitInfo,
|
|
13161
|
+
handleGoalGet,
|
|
13162
|
+
handleMailboxMessages,
|
|
13163
|
+
handleMailboxRoute,
|
|
13164
|
+
handleMcpAdd,
|
|
13165
|
+
handleMcpDisable,
|
|
13166
|
+
handleMcpDiscover,
|
|
13167
|
+
handleMcpEnable,
|
|
13168
|
+
handleMcpList,
|
|
13169
|
+
handleMcpRemove,
|
|
13170
|
+
handleMcpRestart,
|
|
13171
|
+
handleMcpRoute,
|
|
13172
|
+
handleMcpSleep,
|
|
13173
|
+
handleMcpUpdate,
|
|
13174
|
+
handleMcpWake,
|
|
13175
|
+
handleMemoryForget,
|
|
13176
|
+
handleMemoryList,
|
|
13177
|
+
handleMemoryRemember,
|
|
13178
|
+
handleModeRoute,
|
|
13179
|
+
handlePrefsRoute,
|
|
13180
|
+
handleProcessKill,
|
|
13181
|
+
handleProcessKillAll,
|
|
13182
|
+
handleProcessList,
|
|
13183
|
+
handleProjectRoute,
|
|
13184
|
+
handlePromptsContent,
|
|
13185
|
+
handlePromptsCreate,
|
|
13186
|
+
handlePromptsFavorite,
|
|
13187
|
+
handlePromptsList,
|
|
13188
|
+
handlePromptsRecent,
|
|
13189
|
+
handlePromptsSearch,
|
|
13190
|
+
handlePromptsUsed,
|
|
13191
|
+
handleProviderRoute,
|
|
13192
|
+
handleSddBoardRoute,
|
|
13193
|
+
handleSddWizardRoute,
|
|
13194
|
+
handleSessionRoute,
|
|
13195
|
+
handleShellGitRoute,
|
|
13196
|
+
handleShellOpen,
|
|
13197
|
+
handleSkillsContent,
|
|
13198
|
+
handleSkillsCreate,
|
|
13199
|
+
handleSkillsEdit,
|
|
13200
|
+
handleSkillsExport,
|
|
13201
|
+
handleSkillsInstall,
|
|
13202
|
+
handleSkillsList,
|
|
13203
|
+
handleSkillsUninstall,
|
|
13204
|
+
handleSkillsUpdate,
|
|
13205
|
+
handleSpecsRoute,
|
|
13206
|
+
handleWorklistMessage,
|
|
13207
|
+
hostForBrowserUrl,
|
|
13208
|
+
hostHeaderOk,
|
|
13209
|
+
injectWsConfig,
|
|
13210
|
+
injectWsPort,
|
|
13211
|
+
isHiddenEntry,
|
|
13212
|
+
isInsideDist,
|
|
13213
|
+
isLoopbackBind,
|
|
13214
|
+
isLoopbackHostname,
|
|
13215
|
+
isPathInside,
|
|
13216
|
+
isPidAlive,
|
|
13217
|
+
isPortFree,
|
|
13218
|
+
isWildcardBind,
|
|
13219
|
+
listInstances,
|
|
13220
|
+
loadManifest,
|
|
13221
|
+
loadSavedProviders,
|
|
13222
|
+
maskedKey,
|
|
13223
|
+
messagePreview,
|
|
13224
|
+
messageTokens,
|
|
13225
|
+
normalizeKeys,
|
|
13226
|
+
openBrowser,
|
|
13227
|
+
patchConfig,
|
|
13228
|
+
persistPrefsToConfig,
|
|
13229
|
+
projectSavedProviders,
|
|
13230
|
+
projectsJsonPath,
|
|
13231
|
+
rankFiles,
|
|
13232
|
+
readZipEntries,
|
|
13233
|
+
registerInstance,
|
|
13234
|
+
registerShutdownHandlers,
|
|
13235
|
+
registryPath,
|
|
13236
|
+
removeProvider,
|
|
13237
|
+
resolveAllPendingConfirms,
|
|
13238
|
+
resolveAuthToken,
|
|
13239
|
+
resolveProviderCatalogForModels,
|
|
13240
|
+
resolveProviderModelMetadata,
|
|
13241
|
+
resolveWorkingDirInsideProject,
|
|
13242
|
+
resolveYoloEligiblePendingConfirms,
|
|
13243
|
+
saveManifest,
|
|
13244
|
+
saveProviders,
|
|
13245
|
+
send,
|
|
13246
|
+
sendResult,
|
|
13247
|
+
setActiveKey,
|
|
13248
|
+
setupEvents,
|
|
13249
|
+
setupWebUICodebaseIndexing,
|
|
13250
|
+
startWebUI,
|
|
13251
|
+
statusProjectHashFromWatchFilename,
|
|
13252
|
+
stringifyContent,
|
|
13253
|
+
tokenMatches,
|
|
13254
|
+
unregisterInstance,
|
|
13255
|
+
upsertKey,
|
|
13256
|
+
validateAutonomySwitchPayload,
|
|
13257
|
+
validateBrainAskPayload,
|
|
13258
|
+
validateBrainRiskPayload,
|
|
13259
|
+
validateContextModeCreatePayload,
|
|
13260
|
+
validateContextModeDeletePayload,
|
|
13261
|
+
validateContextModeSwitchPayload,
|
|
13262
|
+
validateContextModeUpdatePayload,
|
|
13263
|
+
validateGitDiffPayload,
|
|
13264
|
+
validateMailboxAgentsPayload,
|
|
13265
|
+
validateMailboxMessagesPayload,
|
|
13266
|
+
validateMailboxPurgePayload,
|
|
13267
|
+
validateModeSwitchPayload,
|
|
13268
|
+
validateModelSwitchPayload,
|
|
13269
|
+
validatePlanTemplateUsePayload,
|
|
13270
|
+
validatePrefsUpdatePayload,
|
|
13271
|
+
validateProcessKillPayload,
|
|
13272
|
+
validateProjectsAddPayload,
|
|
13273
|
+
validateProjectsSelectPayload,
|
|
13274
|
+
validateShellOpenPayload,
|
|
13275
|
+
validateSkillsCreatePayload,
|
|
13276
|
+
validateSkillsEditPayload,
|
|
13277
|
+
validateWorkingDirSetPayload,
|
|
13278
|
+
verifyClient,
|
|
13279
|
+
writeKeysBack
|
|
13280
|
+
};
|
|
12538
13281
|
//# sourceMappingURL=index.js.map
|
|
12539
|
-
//# sourceMappingURL=index.js.map
|