@wrongstack/webui-server 0.298.0 → 0.298.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +187 -78
- package/dist/protocol/client-workspace.d.ts +1 -1
- package/dist/protocol/index.js +3 -0
- package/dist/protocol/registry.d.ts +2 -2
- package/dist/protocol/server-conversation.d.ts +1 -1
- package/dist/server/embedded-host-adapters.d.ts +2 -0
- package/dist/server/entry.js +187 -78
- package/dist/server/http-server.d.ts +3 -1
- package/dist/server/provider-handlers.d.ts +4 -0
- package/dist/server/provider-routes.d.ts +2 -0
- package/package.json +11 -11
package/dist/index.js
CHANGED
|
@@ -73,8 +73,7 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
73
73
|
// Display-only toggles (purely visual, persisted in localStorage via Zustand).
|
|
74
74
|
"groupToolCalls",
|
|
75
75
|
"showThinkingLogs",
|
|
76
|
-
// v11 Display parity:
|
|
77
|
-
"showAgentSwarmPanel",
|
|
76
|
+
// v11 Display parity: inverse fsAccess flag.
|
|
78
77
|
"allowOutsideProjectRoot",
|
|
79
78
|
// v13 Display parity (TUI SettingsPicker fields 42 & 43): the read tool
|
|
80
79
|
// includes codebase-index symbols, and SAGE memory-inject blocks are
|
|
@@ -169,7 +168,8 @@ var ENUM_PREF_KEYS = {
|
|
|
169
168
|
// Chimera autoFix + auto-review cascade threshold
|
|
170
169
|
chimeraAutoFix: /* @__PURE__ */ new Set(["off", "ask", "auto"]),
|
|
171
170
|
autoReviewCascadeOn: /* @__PURE__ */ new Set(["off", "critical", "high"]),
|
|
172
|
-
fleetChatVerbosity: /* @__PURE__ */ new Set(["off", "full"])
|
|
171
|
+
fleetChatVerbosity: /* @__PURE__ */ new Set(["off", "full"]),
|
|
172
|
+
showAgentSwarmPanel: /* @__PURE__ */ new Set(["bottom", "sidebar", "off"])
|
|
173
173
|
};
|
|
174
174
|
function validateModelRuntimeValue(modelRuntime, path35) {
|
|
175
175
|
const reasoning = modelRuntime["reasoning"];
|
|
@@ -8978,7 +8978,7 @@ function buildCspHeader(publicWsUrl, host, port) {
|
|
|
8978
8978
|
if (host && isLoopbackHostname(host)) {
|
|
8979
8979
|
const p = port ?? 3456;
|
|
8980
8980
|
if (p > 0 && p <= 65535) {
|
|
8981
|
-
for (const h of ["127.0.0.1", "localhost"
|
|
8981
|
+
for (const h of ["127.0.0.1", "localhost"]) {
|
|
8982
8982
|
connect.add(`ws://${h}:${p}`);
|
|
8983
8983
|
connect.add(`wss://${h}:${p}`);
|
|
8984
8984
|
}
|
|
@@ -15665,7 +15665,8 @@ function createProviderOperations(deps2) {
|
|
|
15665
15665
|
providerId,
|
|
15666
15666
|
config
|
|
15667
15667
|
);
|
|
15668
|
-
const
|
|
15668
|
+
const siblingCatalogKey = config?.family ?? providerId;
|
|
15669
|
+
const siblingId = SIBLING_CATALOG[siblingCatalogKey];
|
|
15669
15670
|
const sibling = siblingId && siblingId !== providerId ? await deps2.modelsRegistry.getProvider(siblingId).catch(() => void 0) : void 0;
|
|
15670
15671
|
let models = resolveProviderModelList(
|
|
15671
15672
|
config?.models,
|
|
@@ -15820,6 +15821,50 @@ function createProviderOperations(deps2) {
|
|
|
15820
15821
|
sendOperationResult(ws, false, errMessage(err));
|
|
15821
15822
|
}
|
|
15822
15823
|
}
|
|
15824
|
+
async function handleCustomModelSet(ws, providerId, modelId, definition) {
|
|
15825
|
+
try {
|
|
15826
|
+
const providers = await loadConfigProviders();
|
|
15827
|
+
const cfg = Object.hasOwn(providers, providerId) ? providers[providerId] : void 0;
|
|
15828
|
+
if (!cfg) {
|
|
15829
|
+
sendOperationResult(ws, false, `Unknown provider "${providerId}"`);
|
|
15830
|
+
return;
|
|
15831
|
+
}
|
|
15832
|
+
if (!cfg.customModels) cfg.customModels = {};
|
|
15833
|
+
cfg.customModels[modelId] = definition;
|
|
15834
|
+
if (!cfg.models) cfg.models = [];
|
|
15835
|
+
if (!cfg.models.includes(modelId)) cfg.models.push(modelId);
|
|
15836
|
+
await saveConfigProviders(providers);
|
|
15837
|
+
sendOperationResult(ws, true, `Saved model "${modelId}" for ${providerId}`);
|
|
15838
|
+
broadcastSaved(providers);
|
|
15839
|
+
} catch (err) {
|
|
15840
|
+
sendOperationResult(ws, false, errMessage(err));
|
|
15841
|
+
}
|
|
15842
|
+
}
|
|
15843
|
+
async function handleCustomModelRemove(ws, providerId, modelId) {
|
|
15844
|
+
try {
|
|
15845
|
+
const providers = await loadConfigProviders();
|
|
15846
|
+
const cfg = Object.hasOwn(providers, providerId) ? providers[providerId] : void 0;
|
|
15847
|
+
if (!cfg) {
|
|
15848
|
+
sendOperationResult(ws, false, `Unknown provider "${providerId}"`);
|
|
15849
|
+
return;
|
|
15850
|
+
}
|
|
15851
|
+
if (cfg.customModels && Object.hasOwn(cfg.customModels, modelId)) {
|
|
15852
|
+
delete cfg.customModels[modelId];
|
|
15853
|
+
if (Object.keys(cfg.customModels).length === 0) delete cfg.customModels;
|
|
15854
|
+
if (cfg.models) {
|
|
15855
|
+
cfg.models = cfg.models.filter((m) => m !== modelId);
|
|
15856
|
+
if (cfg.models.length === 0) delete cfg.models;
|
|
15857
|
+
}
|
|
15858
|
+
await saveConfigProviders(providers);
|
|
15859
|
+
sendOperationResult(ws, true, `Removed model "${modelId}" from ${providerId}`);
|
|
15860
|
+
broadcastSaved(providers);
|
|
15861
|
+
} else {
|
|
15862
|
+
sendOperationResult(ws, false, `Model "${modelId}" not found in ${providerId}`);
|
|
15863
|
+
}
|
|
15864
|
+
} catch (err) {
|
|
15865
|
+
sendOperationResult(ws, false, errMessage(err));
|
|
15866
|
+
}
|
|
15867
|
+
}
|
|
15823
15868
|
async function handleProviderUndoClear(ws, providerId, previousModels) {
|
|
15824
15869
|
try {
|
|
15825
15870
|
const providers = await loadConfigProviders();
|
|
@@ -15895,7 +15940,7 @@ function createProviderOperations(deps2) {
|
|
|
15895
15940
|
const p = existing ? { ...existing } : { type: providerId };
|
|
15896
15941
|
p.family = outcome.family;
|
|
15897
15942
|
if (!p.baseUrl) p.baseUrl = outcome.baseUrl;
|
|
15898
|
-
p.models = [...outcome.models];
|
|
15943
|
+
if (outcome.models.length > 0) p.models = [...outcome.models];
|
|
15899
15944
|
const keys = normalizeKeys(p).filter((k) => k.label !== outcome.apiKey.label);
|
|
15900
15945
|
keys.push(outcome.apiKey);
|
|
15901
15946
|
writeKeysBack(p, keys);
|
|
@@ -16003,6 +16048,8 @@ function createProviderOperations(deps2) {
|
|
|
16003
16048
|
handleProviderAdd,
|
|
16004
16049
|
handleProviderRemove,
|
|
16005
16050
|
handleProviderClearModels,
|
|
16051
|
+
handleCustomModelSet,
|
|
16052
|
+
handleCustomModelRemove,
|
|
16006
16053
|
handleProviderUndoClear,
|
|
16007
16054
|
handleProviderUpdate,
|
|
16008
16055
|
handleProviderProbe,
|
|
@@ -16339,6 +16386,8 @@ var CLIENT_CONFIGURATION_MESSAGE_TYPES = [
|
|
|
16339
16386
|
"prefs.update",
|
|
16340
16387
|
"provider.add",
|
|
16341
16388
|
"provider.clear_models",
|
|
16389
|
+
"provider.custom_models.remove",
|
|
16390
|
+
"provider.custom_models.set",
|
|
16342
16391
|
"provider.models",
|
|
16343
16392
|
"provider.models.search",
|
|
16344
16393
|
"provider.probe",
|
|
@@ -16365,6 +16414,7 @@ var SERVER_CONVERSATION_MESSAGE_TYPES = [
|
|
|
16365
16414
|
"agent.status_changed",
|
|
16366
16415
|
"agent.timeline.message",
|
|
16367
16416
|
"client.status_update",
|
|
16417
|
+
"chimera.report_available",
|
|
16368
16418
|
"compaction.failed",
|
|
16369
16419
|
"completion.result",
|
|
16370
16420
|
"context.compacted",
|
|
@@ -18201,10 +18251,14 @@ async function handleProjectRoute(ws, msg, handlers) {
|
|
|
18201
18251
|
}
|
|
18202
18252
|
|
|
18203
18253
|
// src/server/provider-routes.ts
|
|
18254
|
+
import { modelsDevModelSchema } from "@wrongstack/core/models";
|
|
18204
18255
|
function asPayloadRecord(msg) {
|
|
18205
18256
|
const payload = msg.payload;
|
|
18206
18257
|
return typeof payload === "object" && payload !== null && !Array.isArray(payload) ? payload : null;
|
|
18207
18258
|
}
|
|
18259
|
+
function isRecord4(value) {
|
|
18260
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18261
|
+
}
|
|
18208
18262
|
function requiredString(payload, key) {
|
|
18209
18263
|
const value = payload[key];
|
|
18210
18264
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
@@ -18227,7 +18281,7 @@ var CUSTOM_MODEL_BOOLEAN_CAPS = /* @__PURE__ */ new Set([
|
|
|
18227
18281
|
"streaming",
|
|
18228
18282
|
"jsonMode"
|
|
18229
18283
|
]);
|
|
18230
|
-
var INLINE_DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "maxOutput", "capabilities", "provider"]);
|
|
18284
|
+
var INLINE_DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "maxOutput", "capabilities", "provider", "modelsDev"]);
|
|
18231
18285
|
function optionalCustomModels(payload) {
|
|
18232
18286
|
const value = payload["customModels"];
|
|
18233
18287
|
if (value === void 0) return void 0;
|
|
@@ -18266,11 +18320,21 @@ function optionalCustomModels(payload) {
|
|
|
18266
18320
|
}
|
|
18267
18321
|
capabilities = built;
|
|
18268
18322
|
}
|
|
18323
|
+
const rawMd = definition["modelsDev"];
|
|
18324
|
+
let validatedModelsDev;
|
|
18325
|
+
if (rawMd !== void 0) {
|
|
18326
|
+
if (!isRecord4(rawMd)) return null;
|
|
18327
|
+
const parsed = modelsDevModelSchema.safeParse({ ...rawMd, id: modelId });
|
|
18328
|
+
if (!parsed.success) return null;
|
|
18329
|
+
const { id: _parsedId, ...validMd } = parsed.data;
|
|
18330
|
+
validatedModelsDev = validMd;
|
|
18331
|
+
}
|
|
18269
18332
|
out[modelId] = {
|
|
18270
18333
|
...typeof definition["name"] === "string" ? { name: definition["name"] } : {},
|
|
18271
18334
|
...typeof definition["provider"] === "string" ? { provider: definition["provider"] } : {},
|
|
18272
18335
|
...typeof definition["maxOutput"] === "number" ? { maxOutput: definition["maxOutput"] } : {},
|
|
18273
|
-
...capabilities ? { capabilities } : {}
|
|
18336
|
+
...capabilities ? { capabilities } : {},
|
|
18337
|
+
...validatedModelsDev ? { modelsDev: validatedModelsDev } : {}
|
|
18274
18338
|
};
|
|
18275
18339
|
}
|
|
18276
18340
|
return out;
|
|
@@ -18374,6 +18438,30 @@ async function handleProviderRoute(ws, msg, routes) {
|
|
|
18374
18438
|
await routes.providerHandlers.handleProviderClearModels(ws, providerId);
|
|
18375
18439
|
return true;
|
|
18376
18440
|
}
|
|
18441
|
+
case "provider.custom_models.set": {
|
|
18442
|
+
const payload = asPayloadRecord(msg);
|
|
18443
|
+
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
18444
|
+
const modelId = payload ? requiredString(payload, "modelId") : null;
|
|
18445
|
+
if (!payload || !providerId || !SAFE_CONFIG_KEY.test(providerId) || !modelId || !SAFE_CONFIG_KEY.test(modelId)) {
|
|
18446
|
+
return invalidPayload(ws, msg.type);
|
|
18447
|
+
}
|
|
18448
|
+
const customModelRaw = payload["customModel"];
|
|
18449
|
+
if (!isRecord4(customModelRaw)) return invalidPayload(ws, msg.type);
|
|
18450
|
+
const cm = optionalCustomModels({ customModels: { [modelId]: customModelRaw } });
|
|
18451
|
+
if (!cm || !cm[modelId]) return invalidPayload(ws, msg.type);
|
|
18452
|
+
await routes.providerHandlers.handleCustomModelSet(ws, providerId, modelId, cm[modelId]);
|
|
18453
|
+
return true;
|
|
18454
|
+
}
|
|
18455
|
+
case "provider.custom_models.remove": {
|
|
18456
|
+
const payload = asPayloadRecord(msg);
|
|
18457
|
+
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
18458
|
+
const modelId = payload ? requiredString(payload, "modelId") : null;
|
|
18459
|
+
if (!payload || !providerId || !SAFE_CONFIG_KEY.test(providerId) || !modelId || !SAFE_CONFIG_KEY.test(modelId)) {
|
|
18460
|
+
return invalidPayload(ws, msg.type);
|
|
18461
|
+
}
|
|
18462
|
+
await routes.providerHandlers.handleCustomModelRemove(ws, providerId, modelId);
|
|
18463
|
+
return true;
|
|
18464
|
+
}
|
|
18377
18465
|
case "provider.undo_clear": {
|
|
18378
18466
|
const payload = asPayloadRecord(msg);
|
|
18379
18467
|
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
@@ -20053,12 +20141,67 @@ var SddWizardWebSocketHandler = class {
|
|
|
20053
20141
|
// src/server/setup-events.ts
|
|
20054
20142
|
import { recordTaskFileActivity } from "@wrongstack/kanban";
|
|
20055
20143
|
|
|
20144
|
+
// src/server/setup-events-core-watchers.ts
|
|
20145
|
+
import * as fs19 from "node:fs/promises";
|
|
20146
|
+
import * as path24 from "node:path";
|
|
20147
|
+
function registerSetupEventsCoreWatchers(deps2) {
|
|
20148
|
+
const { broadcast: broadcast2, clients, context } = deps2;
|
|
20149
|
+
const disposers = [];
|
|
20150
|
+
const conversationState = context.state;
|
|
20151
|
+
if (typeof conversationState?.onChange === "function") {
|
|
20152
|
+
disposers.push(
|
|
20153
|
+
conversationState.onChange((change) => {
|
|
20154
|
+
if (change.kind !== "todos_replaced") return;
|
|
20155
|
+
broadcast2(clients, {
|
|
20156
|
+
type: "todos.updated",
|
|
20157
|
+
payload: {
|
|
20158
|
+
sessionId: context.session?.id ?? "",
|
|
20159
|
+
todos: [...change.todos],
|
|
20160
|
+
revision: conversationState.revision
|
|
20161
|
+
}
|
|
20162
|
+
});
|
|
20163
|
+
})
|
|
20164
|
+
);
|
|
20165
|
+
}
|
|
20166
|
+
const projectRoot = context.projectRoot;
|
|
20167
|
+
if (projectRoot) {
|
|
20168
|
+
disposers.push(
|
|
20169
|
+
subscribeKanbanDaemonEvents(projectRoot, (message) => broadcast2(clients, message))
|
|
20170
|
+
);
|
|
20171
|
+
}
|
|
20172
|
+
return disposers;
|
|
20173
|
+
}
|
|
20174
|
+
function registerSetupEventsClientStatusWriter(deps2) {
|
|
20175
|
+
const { broadcast: broadcast2, clients, events, wpaths } = deps2;
|
|
20176
|
+
const on = (event, listener) => events.on(event, listener);
|
|
20177
|
+
return on("client.status", async (e) => {
|
|
20178
|
+
broadcast2(clients, { type: "client.status_update", payload: e });
|
|
20179
|
+
if (wpaths?.projectStatus) {
|
|
20180
|
+
try {
|
|
20181
|
+
const statusFile = wpaths.projectStatus(e.projectHash);
|
|
20182
|
+
const dir = path24.dirname(statusFile);
|
|
20183
|
+
await fs19.mkdir(dir, { recursive: true });
|
|
20184
|
+
await fs19.writeFile(statusFile, JSON.stringify(e, null, 2), "utf-8");
|
|
20185
|
+
} catch (err) {
|
|
20186
|
+
console.error(
|
|
20187
|
+
JSON.stringify({
|
|
20188
|
+
level: "error",
|
|
20189
|
+
event: "setup_events.status_write_failed",
|
|
20190
|
+
message: err instanceof Error ? err.message : String(err),
|
|
20191
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
20192
|
+
})
|
|
20193
|
+
);
|
|
20194
|
+
}
|
|
20195
|
+
}
|
|
20196
|
+
});
|
|
20197
|
+
}
|
|
20198
|
+
|
|
20056
20199
|
// src/server/setup-events-fleet-broadcaster.ts
|
|
20057
20200
|
import { watch as fsWatch } from "node:fs";
|
|
20058
|
-
import * as
|
|
20201
|
+
import * as path25 from "node:path";
|
|
20059
20202
|
function registerSetupEventsFleetBroadcaster(deps2) {
|
|
20060
20203
|
const { globalConfigPath, wpaths, context, clients, broadcast: broadcast2, onFleetBroadcaster, isDisposed } = deps2;
|
|
20061
|
-
const globalRoot = globalConfigPath ?
|
|
20204
|
+
const globalRoot = globalConfigPath ? path25.dirname(globalConfigPath) : void 0;
|
|
20062
20205
|
if (!globalRoot) return void 0;
|
|
20063
20206
|
const disposers = [];
|
|
20064
20207
|
const broadcastSessions = async () => {
|
|
@@ -20068,8 +20211,8 @@ function registerSetupEventsFleetBroadcaster(deps2) {
|
|
|
20068
20211
|
const sessions = await registry.list();
|
|
20069
20212
|
const ownEntry = sessions.find((s) => s.pid === process.pid);
|
|
20070
20213
|
const mySlug = ownEntry?.projectSlug ?? wpaths?.projectSlug;
|
|
20071
|
-
const myRoot =
|
|
20072
|
-
const live = sessions.filter((s) => s.status === "active" || s.status === "idle").filter((s) => mySlug ? s.projectSlug === mySlug :
|
|
20214
|
+
const myRoot = path25.resolve(context.projectRoot);
|
|
20215
|
+
const live = sessions.filter((s) => s.status === "active" || s.status === "idle").filter((s) => mySlug ? s.projectSlug === mySlug : path25.resolve(s.projectRoot) === myRoot).map((s) => ({
|
|
20073
20216
|
sessionId: s.sessionId,
|
|
20074
20217
|
projectName: s.projectName,
|
|
20075
20218
|
projectSlug: s.projectSlug,
|
|
@@ -20259,14 +20402,14 @@ function createSetupEventSessionHelpers(context, sessionBridge) {
|
|
|
20259
20402
|
|
|
20260
20403
|
// src/server/setup-events-status-watcher.ts
|
|
20261
20404
|
import { watch as fsWatch2 } from "node:fs";
|
|
20262
|
-
import * as
|
|
20263
|
-
import * as
|
|
20405
|
+
import * as fs20 from "node:fs/promises";
|
|
20406
|
+
import * as path27 from "node:path";
|
|
20264
20407
|
|
|
20265
20408
|
// src/server/setup-events-watcher.ts
|
|
20266
|
-
import * as
|
|
20409
|
+
import * as path26 from "node:path";
|
|
20267
20410
|
function statusProjectHashFromWatchFilename(projectsDir, filename) {
|
|
20268
20411
|
const raw = String(filename);
|
|
20269
|
-
const relative5 =
|
|
20412
|
+
const relative5 = path26.isAbsolute(raw) ? path26.relative(projectsDir, raw) : raw;
|
|
20270
20413
|
const parts = relative5.split(/[\\/]+/).filter(Boolean);
|
|
20271
20414
|
if (parts.length < 2 || parts.at(-1) !== "status.json") return null;
|
|
20272
20415
|
return parts.at(-2) ?? null;
|
|
@@ -20301,7 +20444,7 @@ function logFileWatcherMetrics(metrics) {
|
|
|
20301
20444
|
function registerSetupEventsStatusWatcher(deps2) {
|
|
20302
20445
|
const { wpaths, watcherMetrics, clients, broadcast: broadcast2, on, isDisposed } = deps2;
|
|
20303
20446
|
if (!wpaths?.projectStatus || !wpaths.globalRoot) return void 0;
|
|
20304
|
-
const projectsDir =
|
|
20447
|
+
const projectsDir = path27.join(wpaths.globalRoot, "projects");
|
|
20305
20448
|
const knownProjectHashes = /* @__PURE__ */ new Set();
|
|
20306
20449
|
const debounceTimers = /* @__PURE__ */ new Map();
|
|
20307
20450
|
const DEBOUNCE_MS2 = 150;
|
|
@@ -20346,7 +20489,7 @@ function registerSetupEventsStatusWatcher(deps2) {
|
|
|
20346
20489
|
let watcher;
|
|
20347
20490
|
const startWatcher = async () => {
|
|
20348
20491
|
try {
|
|
20349
|
-
await
|
|
20492
|
+
await fs20.mkdir(projectsDir, { recursive: true });
|
|
20350
20493
|
if (isDisposed()) return;
|
|
20351
20494
|
watcher = fsWatch2(
|
|
20352
20495
|
projectsDir,
|
|
@@ -20360,8 +20503,8 @@ function registerSetupEventsStatusWatcher(deps2) {
|
|
|
20360
20503
|
if (!knownProjectHashes.has(projectHash)) return;
|
|
20361
20504
|
if (watcherMetrics) watcherMetrics.filesProcessed++;
|
|
20362
20505
|
try {
|
|
20363
|
-
const targetFile =
|
|
20364
|
-
const content = await
|
|
20506
|
+
const targetFile = path27.join(projectsDir, projectHash, "status.json");
|
|
20507
|
+
const content = await fs20.readFile(targetFile, "utf-8");
|
|
20365
20508
|
const statusData = JSON.parse(content);
|
|
20366
20509
|
scheduleBroadcast(projectHash, statusData);
|
|
20367
20510
|
} catch {
|
|
@@ -20417,61 +20560,6 @@ function registerSetupEventsStatusWatcher(deps2) {
|
|
|
20417
20560
|
};
|
|
20418
20561
|
}
|
|
20419
20562
|
|
|
20420
|
-
// src/server/setup-events-core-watchers.ts
|
|
20421
|
-
import * as fs20 from "node:fs/promises";
|
|
20422
|
-
import * as path27 from "node:path";
|
|
20423
|
-
function registerSetupEventsCoreWatchers(deps2) {
|
|
20424
|
-
const { broadcast: broadcast2, clients, context } = deps2;
|
|
20425
|
-
const disposers = [];
|
|
20426
|
-
const conversationState = context.state;
|
|
20427
|
-
if (typeof conversationState?.onChange === "function") {
|
|
20428
|
-
disposers.push(
|
|
20429
|
-
conversationState.onChange((change) => {
|
|
20430
|
-
if (change.kind !== "todos_replaced") return;
|
|
20431
|
-
broadcast2(clients, {
|
|
20432
|
-
type: "todos.updated",
|
|
20433
|
-
payload: {
|
|
20434
|
-
sessionId: context.session?.id ?? "",
|
|
20435
|
-
todos: [...change.todos],
|
|
20436
|
-
revision: conversationState.revision
|
|
20437
|
-
}
|
|
20438
|
-
});
|
|
20439
|
-
})
|
|
20440
|
-
);
|
|
20441
|
-
}
|
|
20442
|
-
const projectRoot = context.projectRoot;
|
|
20443
|
-
if (projectRoot) {
|
|
20444
|
-
disposers.push(
|
|
20445
|
-
subscribeKanbanDaemonEvents(projectRoot, (message) => broadcast2(clients, message))
|
|
20446
|
-
);
|
|
20447
|
-
}
|
|
20448
|
-
return disposers;
|
|
20449
|
-
}
|
|
20450
|
-
function registerSetupEventsClientStatusWriter(deps2) {
|
|
20451
|
-
const { broadcast: broadcast2, clients, events, wpaths } = deps2;
|
|
20452
|
-
const on = (event, listener) => events.on(event, listener);
|
|
20453
|
-
return on("client.status", async (e) => {
|
|
20454
|
-
broadcast2(clients, { type: "client.status_update", payload: e });
|
|
20455
|
-
if (wpaths?.projectStatus) {
|
|
20456
|
-
try {
|
|
20457
|
-
const statusFile = wpaths.projectStatus(e.projectHash);
|
|
20458
|
-
const dir = path27.dirname(statusFile);
|
|
20459
|
-
await fs20.mkdir(dir, { recursive: true });
|
|
20460
|
-
await fs20.writeFile(statusFile, JSON.stringify(e, null, 2), "utf-8");
|
|
20461
|
-
} catch (err) {
|
|
20462
|
-
console.error(
|
|
20463
|
-
JSON.stringify({
|
|
20464
|
-
level: "error",
|
|
20465
|
-
event: "setup_events.status_write_failed",
|
|
20466
|
-
message: err instanceof Error ? err.message : String(err),
|
|
20467
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
20468
|
-
})
|
|
20469
|
-
);
|
|
20470
|
-
}
|
|
20471
|
-
}
|
|
20472
|
-
});
|
|
20473
|
-
}
|
|
20474
|
-
|
|
20475
20563
|
// src/server/setup-events.ts
|
|
20476
20564
|
function setupEvents(deps2) {
|
|
20477
20565
|
const {
|
|
@@ -21027,6 +21115,12 @@ function setupEvents(deps2) {
|
|
|
21027
21115
|
});
|
|
21028
21116
|
});
|
|
21029
21117
|
disposers.push(
|
|
21118
|
+
events.onPattern("chimera.report_available", (_event, payload) => {
|
|
21119
|
+
broadcast2(clients, {
|
|
21120
|
+
type: "chimera.report_available",
|
|
21121
|
+
payload
|
|
21122
|
+
});
|
|
21123
|
+
}),
|
|
21030
21124
|
events.onPattern("mailbox.received", (_e, payload) => {
|
|
21031
21125
|
broadcast2(clients, { type: "mailbox.received", payload });
|
|
21032
21126
|
}),
|
|
@@ -21543,10 +21637,12 @@ import {
|
|
|
21543
21637
|
} from "@wrongstack/core/utils";
|
|
21544
21638
|
import { makeLightSubagentFactory } from "@wrongstack/runtime";
|
|
21545
21639
|
import {
|
|
21640
|
+
createSageContextMonitorMiddleware,
|
|
21546
21641
|
createSageToolCallMiddleware,
|
|
21547
21642
|
createSageTurnMiddleware,
|
|
21548
21643
|
getSageRetrieval,
|
|
21549
|
-
getSageService
|
|
21644
|
+
getSageService,
|
|
21645
|
+
InjectionTracker
|
|
21550
21646
|
} from "@wrongstack/sage";
|
|
21551
21647
|
|
|
21552
21648
|
// src/server/discover-mailbox-bridge.ts
|
|
@@ -22394,6 +22490,8 @@ async function createAgentServices(input) {
|
|
|
22394
22490
|
installDesignStudioMiddleware({ pipelines, ctx: context });
|
|
22395
22491
|
const memoryRetrieval = getSageRetrieval(memoryStore);
|
|
22396
22492
|
if (config.features.memory !== false && config.Sage?.enabled !== false && memoryRetrieval) {
|
|
22493
|
+
const sageInjectionTracker = new InjectionTracker();
|
|
22494
|
+
const getSageSessionId = () => input.sessionGetter().id;
|
|
22397
22495
|
if (config.Sage?.inject?.toolResults !== false) {
|
|
22398
22496
|
pipelines.toolCall.use(
|
|
22399
22497
|
createSageToolCallMiddleware({
|
|
@@ -22411,7 +22509,9 @@ async function createAgentServices(input) {
|
|
|
22411
22509
|
// middleware falls back to ctx.session.id for cooldown but passes
|
|
22412
22510
|
// undefined to retrieval, causing owned session-scoped memories to be
|
|
22413
22511
|
// silently excluded from tool-call injection.
|
|
22414
|
-
getSessionId:
|
|
22512
|
+
getSessionId: getSageSessionId,
|
|
22513
|
+
tracker: sageInjectionTracker,
|
|
22514
|
+
events
|
|
22415
22515
|
})
|
|
22416
22516
|
);
|
|
22417
22517
|
}
|
|
@@ -22421,10 +22521,19 @@ async function createAgentServices(input) {
|
|
|
22421
22521
|
memory: memoryRetrieval,
|
|
22422
22522
|
maxMemories: config.Sage?.inject?.maxTurnMemories,
|
|
22423
22523
|
maxChars: config.Sage?.inject?.maxCharsPerTurn,
|
|
22424
|
-
minScore: config.Sage?.inject?.minScore
|
|
22524
|
+
minScore: config.Sage?.inject?.minScore,
|
|
22525
|
+
getSessionId: getSageSessionId,
|
|
22526
|
+
tracker: sageInjectionTracker
|
|
22425
22527
|
})
|
|
22426
22528
|
);
|
|
22427
22529
|
}
|
|
22530
|
+
pipelines.request.use(
|
|
22531
|
+
createSageContextMonitorMiddleware({
|
|
22532
|
+
tracker: sageInjectionTracker,
|
|
22533
|
+
events,
|
|
22534
|
+
getSessionId: getSageSessionId
|
|
22535
|
+
})
|
|
22536
|
+
);
|
|
22428
22537
|
}
|
|
22429
22538
|
const codebaseIndexing = setupWebUICodebaseIndexing({
|
|
22430
22539
|
config,
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare const CLIENT_WORKSPACE_MESSAGE_TYPES: readonly ['files.list', 'files.read', 'files.tree', 'files.write', 'git.changes', 'git.diff', 'git.info', 'projects.add', 'projects.list', 'projects.select', 'working_dir.set', 'worktree.cleanup', 'worktree.diff', 'worktree.merge', 'worktree.remove', 'worktree.scan', 'shell.open', 'process.kill', 'process.killAll', 'process.list', 'terminal.close', 'terminal.create', 'terminal.input', 'terminal.resize'];
|
|
2
|
-
export declare const CLIENT_CONFIGURATION_MESSAGE_TYPES: readonly ['codebase.index.server.shutdown', 'connections.health', 'connections.service_action', 'diag.get', 'key.add', 'key.delete', 'key.set_active', 'key.update', 'prefs.get', 'prefs.update', 'provider.add', 'provider.clear_models', 'provider.models', 'provider.models.search', 'provider.probe', 'provider.remove', 'provider.status.clear', 'provider.status.get', 'provider.status.retry', 'provider.undo_clear', 'provider.update', 'providers.list', 'providers.saved', 'tool.disable', 'tool.enable', 'tools.list', 'webui.shutdown'];
|
|
2
|
+
export declare const CLIENT_CONFIGURATION_MESSAGE_TYPES: readonly ['codebase.index.server.shutdown', 'connections.health', 'connections.service_action', 'diag.get', 'key.add', 'key.delete', 'key.set_active', 'key.update', 'prefs.get', 'prefs.update', 'provider.add', 'provider.clear_models', 'provider.custom_models.remove', 'provider.custom_models.set', 'provider.models', 'provider.models.search', 'provider.probe', 'provider.remove', 'provider.status.clear', 'provider.status.get', 'provider.status.retry', 'provider.undo_clear', 'provider.update', 'providers.list', 'providers.saved', 'tool.disable', 'tool.enable', 'tools.list', 'webui.shutdown'];
|
|
3
3
|
//# sourceMappingURL=client-workspace.d.ts.map
|
package/dist/protocol/index.js
CHANGED
|
@@ -289,6 +289,8 @@ var CLIENT_CONFIGURATION_MESSAGE_TYPES = [
|
|
|
289
289
|
"prefs.update",
|
|
290
290
|
"provider.add",
|
|
291
291
|
"provider.clear_models",
|
|
292
|
+
"provider.custom_models.remove",
|
|
293
|
+
"provider.custom_models.set",
|
|
292
294
|
"provider.models",
|
|
293
295
|
"provider.models.search",
|
|
294
296
|
"provider.probe",
|
|
@@ -315,6 +317,7 @@ var SERVER_CONVERSATION_MESSAGE_TYPES = [
|
|
|
315
317
|
"agent.status_changed",
|
|
316
318
|
"agent.timeline.message",
|
|
317
319
|
"client.status_update",
|
|
320
|
+
"chimera.report_available",
|
|
318
321
|
"compaction.failed",
|
|
319
322
|
"completion.result",
|
|
320
323
|
"context.compacted",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare const CLIENT_MESSAGE_TYPES: readonly ["abort", "ping", "user_message", "tool.confirm_result", "completion.request", "model.switch", "model.refine", "autonomy.switch", "context.clear", "context.compact", "context.debug", "context.editor.open", "context.editor.validate", "context.editor.apply", "context.mode.create", "context.mode.delete", "context.mode.switch", "context.mode.update", "context.modes.list", "context.repair", "mode.switch", "modes.list", "session.checkpoints", "session.delete", "session.new", "session.rename", "session.resume", "session.rewind", "session.save", "sessions.list", "side_effects.list", "stats.get", "todo.update", "todos.clear", "todos.get", "todos.remove", "collab.join", "collab.leave", "collab.annotate", "collab.resolve", "collab.request_pause", "collab.resume", "collab.grant_control", "collab.inject_tool", "mailbox.action", "mailbox.agents", "mailbox.clear", "mailbox.compact", "mailbox.messages", "mailbox.purge", "mailbox.send", "files.list", "files.read", "files.tree", "files.write", "git.changes", "git.diff", "git.info", "projects.add", "projects.list", "projects.select", "working_dir.set", "worktree.cleanup", "worktree.diff", "worktree.merge", "worktree.remove", "worktree.scan", "shell.open", "process.kill", "process.killAll", "process.list", "terminal.close", "terminal.create", "terminal.input", "terminal.resize", "codebase.index.server.shutdown", "connections.health", "connections.service_action", "diag.get", "key.add", "key.delete", "key.set_active", "key.update", "prefs.get", "prefs.update", "provider.add", "provider.clear_models", "provider.models", "provider.models.search", "provider.probe", "provider.remove", "provider.status.clear", "provider.status.get", "provider.status.retry", "provider.undo_clear", "provider.update", "providers.list", "providers.saved", "tool.disable", "tool.enable", "tools.list", "webui.shutdown", "goal-state.get", "goal.addTask", "goal.assess", "goal.assignTask", "goal.clear", "goal.get", "goal.list", "goal.load", "goal.moveTask", "goal.pause", "goal.resume", "goal.retryTask", "goal.revert", "goal.runTask", "goal.save", "goal.selectPhase", "goal.start", "goal.state", "goal.status", "goal.stop", "goal.taskStatus", "goal.toggleAutonomous", "plan.get", "plan.item.update", "plan.template_use", "task.update", "tasks.get", "sdd.board.cancel_task", "sdd.board.cleanup_worktrees", "sdd.board.delete_task", "sdd.board.destroy", "sdd.board.get", "sdd.board.list", "sdd.board.pause", "sdd.board.reassign", "sdd.board.resume", "sdd.board.retry", "sdd.board.retry_all_failed", "sdd.board.rollback", "sdd.board.set_task_fallbacks", "sdd.board.set_task_model", "sdd.board.set_task_verification", "sdd.board.split_task", "sdd.board.stop", "sdd.run.from_graph", "sdd.run.from_spec", "sdd.run.start", "sdd.spec.approve", "sdd.spec.discard", "sdd.spec.get", "sdd.spec.message", "sdd.spec.start", "specs.get", "specs.list", "specs.taskStatus", "brain.ask", "brain.config.get", "brain.config.set", "brain.risk", "brain.status", "chronicle.facet", "chronicle.facets", "chronicle.graph", "chronicle.metrics", "chronicle.query", "chronicle.status", "config.doctor", "design.list", "design.materialize", "design.set", "design.state", "design.swap", "design.tune", "design.use", "design.verify", "memory.list", "memory.sage.backfillRecoverable", "memory.sage.candidateResolve", "memory.sage.delete", "memory.sage.forFile", "memory.sage.get", "memory.sage.graph", "memory.sage.list", "memory.sage.listPage", "memory.sage.recover", "memory.sage.remember", "memory.sage.update", "auth.oauth.cancel", "auth.oauth.code", "auth.oauth.start", "mcp.add", "mcp.disable", "mcp.discover", "mcp.enable", "mcp.list", "mcp.prompt.get", "mcp.prompts", "mcp.remove", "mcp.resource.read", "mcp.resources", "mcp.restart", "mcp.sleep", "mcp.update", "mcp.wake", "prompts.content", "prompts.create", "prompts.favorite", "prompts.list", "prompts.recent", "prompts.search", "prompts.used", "skills.content", "skills.create", "skills.edit", "skills.export", "skills.install", "skills.list", "skills.uninstall", "skills.update"];
|
|
2
|
-
export declare const SERVER_MESSAGE_TYPES: readonly ["error", "log", "pong", "side_effects", "agent.status_changed", "agent.timeline.message", "client.status_update", "compaction.failed", "completion.result", "context.compacted", "context.debug", "context.editor.snapshot", "context.editor.validation", "context.editor.applied", "context.mode.changed", "context.modes.list", "context.repaired", "ctx.max_context", "ctx.pct", "delegate.completed", "delegate.started", "iteration.completed", "iteration.limit_reached", "iteration.started", "model.refine_result", "modes.list", "provider.active_blocked", "provider.error", "provider.fallback", "provider.response", "provider.retry", "provider.status_changed", "provider.stream_error", "provider.text_delta", "provider.thinking_delta", "run.result", "session.checkpoints", "session.damaged", "session.end", "session.rewound", "session.start", "session.stats", "sessions.list", "sessions.status_update", "stats.get", "token.cost_estimate_unavailable", "token.threshold", "tool.confirm_needed", "tool.disabled", "tool.enabled", "tool.executed", "tool.loop_detected", "tool.progress", "tool.started", "tools.list", "trust.persisted", "collab.annotation.added", "collab.annotation.resolved", "collab.event", "collab.injection.granted", "collab.participant.joined", "collab.participant.left", "collab.pause.granted", "collab.pause.released", "collab.state", "mailbox.action_result", "mailbox.agent_registered", "mailbox.agents", "mailbox.cleared", "mailbox.compacted", "mailbox.event", "mailbox.messages", "mailbox.sent", "mailbox.purged", "mailbox.received", "subagent.budget_extended", "subagent.event", "checkpoint.written", "codemap.file_event", "codemap.index_updated", "codemap.tool_executed", "codemap.tool_started", "file.saved", "files.list", "files.read", "files.tree", "files.written", "git.changes", "git.diff", "git.info", "process.list", "projects.added", "projects.list", "projects.selected", "terminal.exit", "terminal.output", "working_dir.changed", "worktree.cleanup_result", "worktree.diff_result", "worktree.event", "worktree.merge_result", "worktree.orphans", "worktree.state", "auth.oauth.status", "codebase.index.server.shutdown_result", "connections.health_error", "connections.health_result", "connections.service_action_result", "diag.get", "key.operation_result", "model.switch_result", "prefs.updated", "provider.catalog", "provider.models", "provider.models.search_result", "provider.probe", "provider.status.snapshot", "providers.saved", "budget.decision", "budget.threshold_reached", "coordinator.stats", "coordinator.status", "eternal.iteration", "fleet.concurrency_update", "goal-state.updated", "goal.assess.result", "goal.list", "goal.paused", "goal.resumed", "goal.saved", "goal.error", "goal.stopped", "goal.failed", "goal.completed", "goal.cleared", "goal.reverted", "goal.progress", "goal.state", "in_flight.ended", "in_flight.started", "plan.updated", "task.completed", "task.failed", "task.pending", "task.started", "tasks.updated", "todos.cleared", "todos.updated", "kanban.task.activity", "sdd.board.lifecycle_result", "sdd.board.list", "sdd.board.snapshot", "sdd.run.started", "sdd.spec.agent_text", "sdd.spec.error", "sdd.spec.snapshot", "specs.detail", "specs.list", "consensus.vote_cast", "consensus.vote_initiated", "consensus.vote_resolved", "cron.job_fired", "cron.snapshot", "techstack.job.cancelled", "techstack.job.failed", "techstack.job.progress", "techstack.job.started", "techstack.report.delivered", "techstack.report.ready", "techstack.snapshot.updated", "techstack.workspace.completed", "brain.answer", "brain.config", "brain.event", "brain.status", "chronicle.error", "chronicle.facet_result", "chronicle.facets_result", "chronicle.graph_result", "chronicle.metrics_result", "chronicle.query_result", "chronicle.status_result", "config.doctor.result", "design.list", "design.materialize", "design.set", "design.state", "design.swap", "design.tune", "design.use", "design.verify", "memory.event", "memory.list", "memory.sage.backfillRecoverable", "memory.sage.candidateResolve", "memory.sage.delete", "memory.sage.forFile", "memory.sage.get", "memory.sage.graph", "memory.sage.list", "memory.sage.listPage", "memory.sage.recover", "memory.sage.remember", "memory.sage.update", "mcp.content.error", "mcp.content.selected", "mcp.list", "mcp.operation_result", "mcp.prompts", "mcp.resources", "mcp.server.added", "mcp.server.connected", "mcp.server.disconnected", "mcp.server.discovered", "mcp.server.error", "mcp.server.reconnected", "mcp.server.removed", "mcp.server.sleeping", "mcp.server.updated", "mcp.server.waking", "prompts.content", "prompts.created", "prompts.favorite", "prompts.list", "prompts.recent", "prompts.search", "prompts.used", "skills.content", "skills.created", "skills.edited", "skills.exported", "skills.installed", "skills.list", "skills.uninstalled", "skills.updated"];
|
|
1
|
+
export declare const CLIENT_MESSAGE_TYPES: readonly ["abort", "ping", "user_message", "tool.confirm_result", "completion.request", "model.switch", "model.refine", "autonomy.switch", "context.clear", "context.compact", "context.debug", "context.editor.open", "context.editor.validate", "context.editor.apply", "context.mode.create", "context.mode.delete", "context.mode.switch", "context.mode.update", "context.modes.list", "context.repair", "mode.switch", "modes.list", "session.checkpoints", "session.delete", "session.new", "session.rename", "session.resume", "session.rewind", "session.save", "sessions.list", "side_effects.list", "stats.get", "todo.update", "todos.clear", "todos.get", "todos.remove", "collab.join", "collab.leave", "collab.annotate", "collab.resolve", "collab.request_pause", "collab.resume", "collab.grant_control", "collab.inject_tool", "mailbox.action", "mailbox.agents", "mailbox.clear", "mailbox.compact", "mailbox.messages", "mailbox.purge", "mailbox.send", "files.list", "files.read", "files.tree", "files.write", "git.changes", "git.diff", "git.info", "projects.add", "projects.list", "projects.select", "working_dir.set", "worktree.cleanup", "worktree.diff", "worktree.merge", "worktree.remove", "worktree.scan", "shell.open", "process.kill", "process.killAll", "process.list", "terminal.close", "terminal.create", "terminal.input", "terminal.resize", "codebase.index.server.shutdown", "connections.health", "connections.service_action", "diag.get", "key.add", "key.delete", "key.set_active", "key.update", "prefs.get", "prefs.update", "provider.add", "provider.clear_models", "provider.custom_models.remove", "provider.custom_models.set", "provider.models", "provider.models.search", "provider.probe", "provider.remove", "provider.status.clear", "provider.status.get", "provider.status.retry", "provider.undo_clear", "provider.update", "providers.list", "providers.saved", "tool.disable", "tool.enable", "tools.list", "webui.shutdown", "goal-state.get", "goal.addTask", "goal.assess", "goal.assignTask", "goal.clear", "goal.get", "goal.list", "goal.load", "goal.moveTask", "goal.pause", "goal.resume", "goal.retryTask", "goal.revert", "goal.runTask", "goal.save", "goal.selectPhase", "goal.start", "goal.state", "goal.status", "goal.stop", "goal.taskStatus", "goal.toggleAutonomous", "plan.get", "plan.item.update", "plan.template_use", "task.update", "tasks.get", "sdd.board.cancel_task", "sdd.board.cleanup_worktrees", "sdd.board.delete_task", "sdd.board.destroy", "sdd.board.get", "sdd.board.list", "sdd.board.pause", "sdd.board.reassign", "sdd.board.resume", "sdd.board.retry", "sdd.board.retry_all_failed", "sdd.board.rollback", "sdd.board.set_task_fallbacks", "sdd.board.set_task_model", "sdd.board.set_task_verification", "sdd.board.split_task", "sdd.board.stop", "sdd.run.from_graph", "sdd.run.from_spec", "sdd.run.start", "sdd.spec.approve", "sdd.spec.discard", "sdd.spec.get", "sdd.spec.message", "sdd.spec.start", "specs.get", "specs.list", "specs.taskStatus", "brain.ask", "brain.config.get", "brain.config.set", "brain.risk", "brain.status", "chronicle.facet", "chronicle.facets", "chronicle.graph", "chronicle.metrics", "chronicle.query", "chronicle.status", "config.doctor", "design.list", "design.materialize", "design.set", "design.state", "design.swap", "design.tune", "design.use", "design.verify", "memory.list", "memory.sage.backfillRecoverable", "memory.sage.candidateResolve", "memory.sage.delete", "memory.sage.forFile", "memory.sage.get", "memory.sage.graph", "memory.sage.list", "memory.sage.listPage", "memory.sage.recover", "memory.sage.remember", "memory.sage.update", "auth.oauth.cancel", "auth.oauth.code", "auth.oauth.start", "mcp.add", "mcp.disable", "mcp.discover", "mcp.enable", "mcp.list", "mcp.prompt.get", "mcp.prompts", "mcp.remove", "mcp.resource.read", "mcp.resources", "mcp.restart", "mcp.sleep", "mcp.update", "mcp.wake", "prompts.content", "prompts.create", "prompts.favorite", "prompts.list", "prompts.recent", "prompts.search", "prompts.used", "skills.content", "skills.create", "skills.edit", "skills.export", "skills.install", "skills.list", "skills.uninstall", "skills.update"];
|
|
2
|
+
export declare const SERVER_MESSAGE_TYPES: readonly ["error", "log", "pong", "side_effects", "agent.status_changed", "agent.timeline.message", "client.status_update", "chimera.report_available", "compaction.failed", "completion.result", "context.compacted", "context.debug", "context.editor.snapshot", "context.editor.validation", "context.editor.applied", "context.mode.changed", "context.modes.list", "context.repaired", "ctx.max_context", "ctx.pct", "delegate.completed", "delegate.started", "iteration.completed", "iteration.limit_reached", "iteration.started", "model.refine_result", "modes.list", "provider.active_blocked", "provider.error", "provider.fallback", "provider.response", "provider.retry", "provider.status_changed", "provider.stream_error", "provider.text_delta", "provider.thinking_delta", "run.result", "session.checkpoints", "session.damaged", "session.end", "session.rewound", "session.start", "session.stats", "sessions.list", "sessions.status_update", "stats.get", "token.cost_estimate_unavailable", "token.threshold", "tool.confirm_needed", "tool.disabled", "tool.enabled", "tool.executed", "tool.loop_detected", "tool.progress", "tool.started", "tools.list", "trust.persisted", "collab.annotation.added", "collab.annotation.resolved", "collab.event", "collab.injection.granted", "collab.participant.joined", "collab.participant.left", "collab.pause.granted", "collab.pause.released", "collab.state", "mailbox.action_result", "mailbox.agent_registered", "mailbox.agents", "mailbox.cleared", "mailbox.compacted", "mailbox.event", "mailbox.messages", "mailbox.sent", "mailbox.purged", "mailbox.received", "subagent.budget_extended", "subagent.event", "checkpoint.written", "codemap.file_event", "codemap.index_updated", "codemap.tool_executed", "codemap.tool_started", "file.saved", "files.list", "files.read", "files.tree", "files.written", "git.changes", "git.diff", "git.info", "process.list", "projects.added", "projects.list", "projects.selected", "terminal.exit", "terminal.output", "working_dir.changed", "worktree.cleanup_result", "worktree.diff_result", "worktree.event", "worktree.merge_result", "worktree.orphans", "worktree.state", "auth.oauth.status", "codebase.index.server.shutdown_result", "connections.health_error", "connections.health_result", "connections.service_action_result", "diag.get", "key.operation_result", "model.switch_result", "prefs.updated", "provider.catalog", "provider.models", "provider.models.search_result", "provider.probe", "provider.status.snapshot", "providers.saved", "budget.decision", "budget.threshold_reached", "coordinator.stats", "coordinator.status", "eternal.iteration", "fleet.concurrency_update", "goal-state.updated", "goal.assess.result", "goal.list", "goal.paused", "goal.resumed", "goal.saved", "goal.error", "goal.stopped", "goal.failed", "goal.completed", "goal.cleared", "goal.reverted", "goal.progress", "goal.state", "in_flight.ended", "in_flight.started", "plan.updated", "task.completed", "task.failed", "task.pending", "task.started", "tasks.updated", "todos.cleared", "todos.updated", "kanban.task.activity", "sdd.board.lifecycle_result", "sdd.board.list", "sdd.board.snapshot", "sdd.run.started", "sdd.spec.agent_text", "sdd.spec.error", "sdd.spec.snapshot", "specs.detail", "specs.list", "consensus.vote_cast", "consensus.vote_initiated", "consensus.vote_resolved", "cron.job_fired", "cron.snapshot", "techstack.job.cancelled", "techstack.job.failed", "techstack.job.progress", "techstack.job.started", "techstack.report.delivered", "techstack.report.ready", "techstack.snapshot.updated", "techstack.workspace.completed", "brain.answer", "brain.config", "brain.event", "brain.status", "chronicle.error", "chronicle.facet_result", "chronicle.facets_result", "chronicle.graph_result", "chronicle.metrics_result", "chronicle.query_result", "chronicle.status_result", "config.doctor.result", "design.list", "design.materialize", "design.set", "design.state", "design.swap", "design.tune", "design.use", "design.verify", "memory.event", "memory.list", "memory.sage.backfillRecoverable", "memory.sage.candidateResolve", "memory.sage.delete", "memory.sage.forFile", "memory.sage.get", "memory.sage.graph", "memory.sage.list", "memory.sage.listPage", "memory.sage.recover", "memory.sage.remember", "memory.sage.update", "mcp.content.error", "mcp.content.selected", "mcp.list", "mcp.operation_result", "mcp.prompts", "mcp.resources", "mcp.server.added", "mcp.server.connected", "mcp.server.disconnected", "mcp.server.discovered", "mcp.server.error", "mcp.server.reconnected", "mcp.server.removed", "mcp.server.sleeping", "mcp.server.updated", "mcp.server.waking", "prompts.content", "prompts.created", "prompts.favorite", "prompts.list", "prompts.recent", "prompts.search", "prompts.used", "skills.content", "skills.created", "skills.edited", "skills.exported", "skills.installed", "skills.list", "skills.uninstalled", "skills.updated"];
|
|
3
3
|
export type ExactClientMessageType = (typeof CLIENT_MESSAGE_TYPES)[number];
|
|
4
4
|
export type ExactServerMessageType = (typeof SERVER_MESSAGE_TYPES)[number];
|
|
5
5
|
export declare function isRegisteredMessageType(type: string, direction: 'client' | 'server'): boolean;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const SERVER_CONVERSATION_MESSAGE_TYPES: readonly ['error', 'log', 'pong', 'side_effects', 'agent.status_changed', 'agent.timeline.message', 'client.status_update', 'compaction.failed', 'completion.result', 'context.compacted', 'context.debug', 'context.editor.snapshot', 'context.editor.validation', 'context.editor.applied', 'context.mode.changed', 'context.modes.list', 'context.repaired', 'ctx.max_context', 'ctx.pct', 'delegate.completed', 'delegate.started', 'iteration.completed', 'iteration.limit_reached', 'iteration.started', 'model.refine_result', 'modes.list', 'provider.active_blocked', 'provider.error', 'provider.fallback', 'provider.response', 'provider.retry', 'provider.status_changed', 'provider.stream_error', 'provider.text_delta', 'provider.thinking_delta', 'run.result', 'session.checkpoints', 'session.damaged', 'session.end', 'session.rewound', 'session.start', 'session.stats', 'sessions.list', 'sessions.status_update', 'stats.get', 'token.cost_estimate_unavailable', 'token.threshold', 'tool.confirm_needed', 'tool.disabled', 'tool.enabled', 'tool.executed', 'tool.loop_detected', 'tool.progress', 'tool.started', 'tools.list', 'trust.persisted'];
|
|
1
|
+
export declare const SERVER_CONVERSATION_MESSAGE_TYPES: readonly ['error', 'log', 'pong', 'side_effects', 'agent.status_changed', 'agent.timeline.message', 'client.status_update', 'chimera.report_available', 'compaction.failed', 'completion.result', 'context.compacted', 'context.debug', 'context.editor.snapshot', 'context.editor.validation', 'context.editor.applied', 'context.mode.changed', 'context.modes.list', 'context.repaired', 'ctx.max_context', 'ctx.pct', 'delegate.completed', 'delegate.started', 'iteration.completed', 'iteration.limit_reached', 'iteration.started', 'model.refine_result', 'modes.list', 'provider.active_blocked', 'provider.error', 'provider.fallback', 'provider.response', 'provider.retry', 'provider.status_changed', 'provider.stream_error', 'provider.text_delta', 'provider.thinking_delta', 'run.result', 'session.checkpoints', 'session.damaged', 'session.end', 'session.rewound', 'session.start', 'session.stats', 'sessions.list', 'sessions.status_update', 'stats.get', 'token.cost_estimate_unavailable', 'token.threshold', 'tool.confirm_needed', 'tool.disabled', 'tool.enabled', 'tool.executed', 'tool.loop_detected', 'tool.progress', 'tool.started', 'tools.list', 'trust.persisted'];
|
|
2
2
|
export declare const SERVER_COLLABORATION_MESSAGE_TYPES: readonly ['collab.annotation.added', 'collab.annotation.resolved', 'collab.event', 'collab.injection.granted', 'collab.participant.joined', 'collab.participant.left', 'collab.pause.granted', 'collab.pause.released', 'collab.state', 'mailbox.action_result', 'mailbox.agent_registered', 'mailbox.agents', 'mailbox.cleared', 'mailbox.compacted', 'mailbox.event', 'mailbox.messages', 'mailbox.sent', 'mailbox.purged', 'mailbox.received', 'subagent.budget_extended', 'subagent.event'];
|
|
3
3
|
//# sourceMappingURL=server-conversation.d.ts.map
|
|
@@ -54,6 +54,8 @@ export declare function createEmbeddedProviderOperations(ctx: EmbeddedProviderCo
|
|
|
54
54
|
}) => Promise<void>;
|
|
55
55
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
56
56
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
57
|
+
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
58
|
+
handleCustomModelRemove: (ws: WebSocket, providerId: string, modelId: string) => Promise<void>;
|
|
57
59
|
handleProviderUndoClear: (ws: WebSocket, providerId: string, previousModels: string[]) => Promise<void>;
|
|
58
60
|
handleProviderUpdate: (ws: WebSocket, payload: {
|
|
59
61
|
id: string;
|
package/dist/server/entry.js
CHANGED
|
@@ -77,8 +77,7 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
77
77
|
// Display-only toggles (purely visual, persisted in localStorage via Zustand).
|
|
78
78
|
"groupToolCalls",
|
|
79
79
|
"showThinkingLogs",
|
|
80
|
-
// v11 Display parity:
|
|
81
|
-
"showAgentSwarmPanel",
|
|
80
|
+
// v11 Display parity: inverse fsAccess flag.
|
|
82
81
|
"allowOutsideProjectRoot",
|
|
83
82
|
// v13 Display parity (TUI SettingsPicker fields 42 & 43): the read tool
|
|
84
83
|
// includes codebase-index symbols, and SAGE memory-inject blocks are
|
|
@@ -173,7 +172,8 @@ var ENUM_PREF_KEYS = {
|
|
|
173
172
|
// Chimera autoFix + auto-review cascade threshold
|
|
174
173
|
chimeraAutoFix: /* @__PURE__ */ new Set(["off", "ask", "auto"]),
|
|
175
174
|
autoReviewCascadeOn: /* @__PURE__ */ new Set(["off", "critical", "high"]),
|
|
176
|
-
fleetChatVerbosity: /* @__PURE__ */ new Set(["off", "full"])
|
|
175
|
+
fleetChatVerbosity: /* @__PURE__ */ new Set(["off", "full"]),
|
|
176
|
+
showAgentSwarmPanel: /* @__PURE__ */ new Set(["bottom", "sidebar", "off"])
|
|
177
177
|
};
|
|
178
178
|
function validateModelRuntimeValue(modelRuntime, path30) {
|
|
179
179
|
const reasoning = modelRuntime["reasoning"];
|
|
@@ -8381,7 +8381,7 @@ function buildCspHeader(publicWsUrl, host, port) {
|
|
|
8381
8381
|
if (host && isLoopbackHostname(host)) {
|
|
8382
8382
|
const p = port ?? 3456;
|
|
8383
8383
|
if (p > 0 && p <= 65535) {
|
|
8384
|
-
for (const h of ["127.0.0.1", "localhost"
|
|
8384
|
+
for (const h of ["127.0.0.1", "localhost"]) {
|
|
8385
8385
|
connect.add(`ws://${h}:${p}`);
|
|
8386
8386
|
connect.add(`wss://${h}:${p}`);
|
|
8387
8387
|
}
|
|
@@ -13762,7 +13762,8 @@ function createProviderOperations(deps2) {
|
|
|
13762
13762
|
providerId,
|
|
13763
13763
|
config
|
|
13764
13764
|
);
|
|
13765
|
-
const
|
|
13765
|
+
const siblingCatalogKey = config?.family ?? providerId;
|
|
13766
|
+
const siblingId = SIBLING_CATALOG[siblingCatalogKey];
|
|
13766
13767
|
const sibling = siblingId && siblingId !== providerId ? await deps2.modelsRegistry.getProvider(siblingId).catch(() => void 0) : void 0;
|
|
13767
13768
|
let models = resolveProviderModelList(
|
|
13768
13769
|
config?.models,
|
|
@@ -13917,6 +13918,50 @@ function createProviderOperations(deps2) {
|
|
|
13917
13918
|
sendOperationResult(ws, false, errMessage(err));
|
|
13918
13919
|
}
|
|
13919
13920
|
}
|
|
13921
|
+
async function handleCustomModelSet(ws, providerId, modelId, definition) {
|
|
13922
|
+
try {
|
|
13923
|
+
const providers = await loadConfigProviders();
|
|
13924
|
+
const cfg = Object.hasOwn(providers, providerId) ? providers[providerId] : void 0;
|
|
13925
|
+
if (!cfg) {
|
|
13926
|
+
sendOperationResult(ws, false, `Unknown provider "${providerId}"`);
|
|
13927
|
+
return;
|
|
13928
|
+
}
|
|
13929
|
+
if (!cfg.customModels) cfg.customModels = {};
|
|
13930
|
+
cfg.customModels[modelId] = definition;
|
|
13931
|
+
if (!cfg.models) cfg.models = [];
|
|
13932
|
+
if (!cfg.models.includes(modelId)) cfg.models.push(modelId);
|
|
13933
|
+
await saveConfigProviders(providers);
|
|
13934
|
+
sendOperationResult(ws, true, `Saved model "${modelId}" for ${providerId}`);
|
|
13935
|
+
broadcastSaved(providers);
|
|
13936
|
+
} catch (err) {
|
|
13937
|
+
sendOperationResult(ws, false, errMessage(err));
|
|
13938
|
+
}
|
|
13939
|
+
}
|
|
13940
|
+
async function handleCustomModelRemove(ws, providerId, modelId) {
|
|
13941
|
+
try {
|
|
13942
|
+
const providers = await loadConfigProviders();
|
|
13943
|
+
const cfg = Object.hasOwn(providers, providerId) ? providers[providerId] : void 0;
|
|
13944
|
+
if (!cfg) {
|
|
13945
|
+
sendOperationResult(ws, false, `Unknown provider "${providerId}"`);
|
|
13946
|
+
return;
|
|
13947
|
+
}
|
|
13948
|
+
if (cfg.customModels && Object.hasOwn(cfg.customModels, modelId)) {
|
|
13949
|
+
delete cfg.customModels[modelId];
|
|
13950
|
+
if (Object.keys(cfg.customModels).length === 0) delete cfg.customModels;
|
|
13951
|
+
if (cfg.models) {
|
|
13952
|
+
cfg.models = cfg.models.filter((m) => m !== modelId);
|
|
13953
|
+
if (cfg.models.length === 0) delete cfg.models;
|
|
13954
|
+
}
|
|
13955
|
+
await saveConfigProviders(providers);
|
|
13956
|
+
sendOperationResult(ws, true, `Removed model "${modelId}" from ${providerId}`);
|
|
13957
|
+
broadcastSaved(providers);
|
|
13958
|
+
} else {
|
|
13959
|
+
sendOperationResult(ws, false, `Model "${modelId}" not found in ${providerId}`);
|
|
13960
|
+
}
|
|
13961
|
+
} catch (err) {
|
|
13962
|
+
sendOperationResult(ws, false, errMessage(err));
|
|
13963
|
+
}
|
|
13964
|
+
}
|
|
13920
13965
|
async function handleProviderUndoClear(ws, providerId, previousModels) {
|
|
13921
13966
|
try {
|
|
13922
13967
|
const providers = await loadConfigProviders();
|
|
@@ -13992,7 +14037,7 @@ function createProviderOperations(deps2) {
|
|
|
13992
14037
|
const p = existing ? { ...existing } : { type: providerId };
|
|
13993
14038
|
p.family = outcome.family;
|
|
13994
14039
|
if (!p.baseUrl) p.baseUrl = outcome.baseUrl;
|
|
13995
|
-
p.models = [...outcome.models];
|
|
14040
|
+
if (outcome.models.length > 0) p.models = [...outcome.models];
|
|
13996
14041
|
const keys = normalizeKeys(p).filter((k) => k.label !== outcome.apiKey.label);
|
|
13997
14042
|
keys.push(outcome.apiKey);
|
|
13998
14043
|
writeKeysBack(p, keys);
|
|
@@ -14100,6 +14145,8 @@ function createProviderOperations(deps2) {
|
|
|
14100
14145
|
handleProviderAdd,
|
|
14101
14146
|
handleProviderRemove,
|
|
14102
14147
|
handleProviderClearModels,
|
|
14148
|
+
handleCustomModelSet,
|
|
14149
|
+
handleCustomModelRemove,
|
|
14103
14150
|
handleProviderUndoClear,
|
|
14104
14151
|
handleProviderUpdate,
|
|
14105
14152
|
handleProviderProbe,
|
|
@@ -14373,6 +14420,8 @@ var CLIENT_CONFIGURATION_MESSAGE_TYPES = [
|
|
|
14373
14420
|
"prefs.update",
|
|
14374
14421
|
"provider.add",
|
|
14375
14422
|
"provider.clear_models",
|
|
14423
|
+
"provider.custom_models.remove",
|
|
14424
|
+
"provider.custom_models.set",
|
|
14376
14425
|
"provider.models",
|
|
14377
14426
|
"provider.models.search",
|
|
14378
14427
|
"provider.probe",
|
|
@@ -14399,6 +14448,7 @@ var SERVER_CONVERSATION_MESSAGE_TYPES = [
|
|
|
14399
14448
|
"agent.status_changed",
|
|
14400
14449
|
"agent.timeline.message",
|
|
14401
14450
|
"client.status_update",
|
|
14451
|
+
"chimera.report_available",
|
|
14402
14452
|
"compaction.failed",
|
|
14403
14453
|
"completion.result",
|
|
14404
14454
|
"context.compacted",
|
|
@@ -15897,10 +15947,14 @@ async function handleProjectRoute(ws, msg, handlers) {
|
|
|
15897
15947
|
}
|
|
15898
15948
|
|
|
15899
15949
|
// src/server/provider-routes.ts
|
|
15950
|
+
import { modelsDevModelSchema } from "@wrongstack/core/models";
|
|
15900
15951
|
function asPayloadRecord(msg) {
|
|
15901
15952
|
const payload = msg.payload;
|
|
15902
15953
|
return typeof payload === "object" && payload !== null && !Array.isArray(payload) ? payload : null;
|
|
15903
15954
|
}
|
|
15955
|
+
function isRecord4(value) {
|
|
15956
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15957
|
+
}
|
|
15904
15958
|
function requiredString(payload, key) {
|
|
15905
15959
|
const value = payload[key];
|
|
15906
15960
|
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
@@ -15923,7 +15977,7 @@ var CUSTOM_MODEL_BOOLEAN_CAPS = /* @__PURE__ */ new Set([
|
|
|
15923
15977
|
"streaming",
|
|
15924
15978
|
"jsonMode"
|
|
15925
15979
|
]);
|
|
15926
|
-
var INLINE_DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "maxOutput", "capabilities", "provider"]);
|
|
15980
|
+
var INLINE_DEFINITION_KEYS = /* @__PURE__ */ new Set(["name", "maxOutput", "capabilities", "provider", "modelsDev"]);
|
|
15927
15981
|
function optionalCustomModels(payload) {
|
|
15928
15982
|
const value = payload["customModels"];
|
|
15929
15983
|
if (value === void 0) return void 0;
|
|
@@ -15962,11 +16016,21 @@ function optionalCustomModels(payload) {
|
|
|
15962
16016
|
}
|
|
15963
16017
|
capabilities = built;
|
|
15964
16018
|
}
|
|
16019
|
+
const rawMd = definition["modelsDev"];
|
|
16020
|
+
let validatedModelsDev;
|
|
16021
|
+
if (rawMd !== void 0) {
|
|
16022
|
+
if (!isRecord4(rawMd)) return null;
|
|
16023
|
+
const parsed = modelsDevModelSchema.safeParse({ ...rawMd, id: modelId });
|
|
16024
|
+
if (!parsed.success) return null;
|
|
16025
|
+
const { id: _parsedId, ...validMd } = parsed.data;
|
|
16026
|
+
validatedModelsDev = validMd;
|
|
16027
|
+
}
|
|
15965
16028
|
out[modelId] = {
|
|
15966
16029
|
...typeof definition["name"] === "string" ? { name: definition["name"] } : {},
|
|
15967
16030
|
...typeof definition["provider"] === "string" ? { provider: definition["provider"] } : {},
|
|
15968
16031
|
...typeof definition["maxOutput"] === "number" ? { maxOutput: definition["maxOutput"] } : {},
|
|
15969
|
-
...capabilities ? { capabilities } : {}
|
|
16032
|
+
...capabilities ? { capabilities } : {},
|
|
16033
|
+
...validatedModelsDev ? { modelsDev: validatedModelsDev } : {}
|
|
15970
16034
|
};
|
|
15971
16035
|
}
|
|
15972
16036
|
return out;
|
|
@@ -16070,6 +16134,30 @@ async function handleProviderRoute(ws, msg, routes) {
|
|
|
16070
16134
|
await routes.providerHandlers.handleProviderClearModels(ws, providerId);
|
|
16071
16135
|
return true;
|
|
16072
16136
|
}
|
|
16137
|
+
case "provider.custom_models.set": {
|
|
16138
|
+
const payload = asPayloadRecord(msg);
|
|
16139
|
+
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
16140
|
+
const modelId = payload ? requiredString(payload, "modelId") : null;
|
|
16141
|
+
if (!payload || !providerId || !SAFE_CONFIG_KEY.test(providerId) || !modelId || !SAFE_CONFIG_KEY.test(modelId)) {
|
|
16142
|
+
return invalidPayload(ws, msg.type);
|
|
16143
|
+
}
|
|
16144
|
+
const customModelRaw = payload["customModel"];
|
|
16145
|
+
if (!isRecord4(customModelRaw)) return invalidPayload(ws, msg.type);
|
|
16146
|
+
const cm = optionalCustomModels({ customModels: { [modelId]: customModelRaw } });
|
|
16147
|
+
if (!cm || !cm[modelId]) return invalidPayload(ws, msg.type);
|
|
16148
|
+
await routes.providerHandlers.handleCustomModelSet(ws, providerId, modelId, cm[modelId]);
|
|
16149
|
+
return true;
|
|
16150
|
+
}
|
|
16151
|
+
case "provider.custom_models.remove": {
|
|
16152
|
+
const payload = asPayloadRecord(msg);
|
|
16153
|
+
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
16154
|
+
const modelId = payload ? requiredString(payload, "modelId") : null;
|
|
16155
|
+
if (!payload || !providerId || !SAFE_CONFIG_KEY.test(providerId) || !modelId || !SAFE_CONFIG_KEY.test(modelId)) {
|
|
16156
|
+
return invalidPayload(ws, msg.type);
|
|
16157
|
+
}
|
|
16158
|
+
await routes.providerHandlers.handleCustomModelRemove(ws, providerId, modelId);
|
|
16159
|
+
return true;
|
|
16160
|
+
}
|
|
16073
16161
|
case "provider.undo_clear": {
|
|
16074
16162
|
const payload = asPayloadRecord(msg);
|
|
16075
16163
|
const providerId = payload ? requiredString(payload, "providerId") : null;
|
|
@@ -17289,12 +17377,67 @@ var SddWizardWebSocketHandler = class {
|
|
|
17289
17377
|
// src/server/setup-events.ts
|
|
17290
17378
|
import { recordTaskFileActivity } from "@wrongstack/kanban";
|
|
17291
17379
|
|
|
17380
|
+
// src/server/setup-events-core-watchers.ts
|
|
17381
|
+
import * as fs17 from "node:fs/promises";
|
|
17382
|
+
import * as path19 from "node:path";
|
|
17383
|
+
function registerSetupEventsCoreWatchers(deps2) {
|
|
17384
|
+
const { broadcast: broadcast2, clients, context } = deps2;
|
|
17385
|
+
const disposers = [];
|
|
17386
|
+
const conversationState = context.state;
|
|
17387
|
+
if (typeof conversationState?.onChange === "function") {
|
|
17388
|
+
disposers.push(
|
|
17389
|
+
conversationState.onChange((change) => {
|
|
17390
|
+
if (change.kind !== "todos_replaced") return;
|
|
17391
|
+
broadcast2(clients, {
|
|
17392
|
+
type: "todos.updated",
|
|
17393
|
+
payload: {
|
|
17394
|
+
sessionId: context.session?.id ?? "",
|
|
17395
|
+
todos: [...change.todos],
|
|
17396
|
+
revision: conversationState.revision
|
|
17397
|
+
}
|
|
17398
|
+
});
|
|
17399
|
+
})
|
|
17400
|
+
);
|
|
17401
|
+
}
|
|
17402
|
+
const projectRoot = context.projectRoot;
|
|
17403
|
+
if (projectRoot) {
|
|
17404
|
+
disposers.push(
|
|
17405
|
+
subscribeKanbanDaemonEvents(projectRoot, (message) => broadcast2(clients, message))
|
|
17406
|
+
);
|
|
17407
|
+
}
|
|
17408
|
+
return disposers;
|
|
17409
|
+
}
|
|
17410
|
+
function registerSetupEventsClientStatusWriter(deps2) {
|
|
17411
|
+
const { broadcast: broadcast2, clients, events, wpaths } = deps2;
|
|
17412
|
+
const on = (event, listener) => events.on(event, listener);
|
|
17413
|
+
return on("client.status", async (e) => {
|
|
17414
|
+
broadcast2(clients, { type: "client.status_update", payload: e });
|
|
17415
|
+
if (wpaths?.projectStatus) {
|
|
17416
|
+
try {
|
|
17417
|
+
const statusFile = wpaths.projectStatus(e.projectHash);
|
|
17418
|
+
const dir = path19.dirname(statusFile);
|
|
17419
|
+
await fs17.mkdir(dir, { recursive: true });
|
|
17420
|
+
await fs17.writeFile(statusFile, JSON.stringify(e, null, 2), "utf-8");
|
|
17421
|
+
} catch (err) {
|
|
17422
|
+
console.error(
|
|
17423
|
+
JSON.stringify({
|
|
17424
|
+
level: "error",
|
|
17425
|
+
event: "setup_events.status_write_failed",
|
|
17426
|
+
message: err instanceof Error ? err.message : String(err),
|
|
17427
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17428
|
+
})
|
|
17429
|
+
);
|
|
17430
|
+
}
|
|
17431
|
+
}
|
|
17432
|
+
});
|
|
17433
|
+
}
|
|
17434
|
+
|
|
17292
17435
|
// src/server/setup-events-fleet-broadcaster.ts
|
|
17293
17436
|
import { watch as fsWatch } from "node:fs";
|
|
17294
|
-
import * as
|
|
17437
|
+
import * as path20 from "node:path";
|
|
17295
17438
|
function registerSetupEventsFleetBroadcaster(deps2) {
|
|
17296
17439
|
const { globalConfigPath, wpaths, context, clients, broadcast: broadcast2, onFleetBroadcaster, isDisposed } = deps2;
|
|
17297
|
-
const globalRoot = globalConfigPath ?
|
|
17440
|
+
const globalRoot = globalConfigPath ? path20.dirname(globalConfigPath) : void 0;
|
|
17298
17441
|
if (!globalRoot) return void 0;
|
|
17299
17442
|
const disposers = [];
|
|
17300
17443
|
const broadcastSessions = async () => {
|
|
@@ -17304,8 +17447,8 @@ function registerSetupEventsFleetBroadcaster(deps2) {
|
|
|
17304
17447
|
const sessions = await registry.list();
|
|
17305
17448
|
const ownEntry = sessions.find((s) => s.pid === process.pid);
|
|
17306
17449
|
const mySlug = ownEntry?.projectSlug ?? wpaths?.projectSlug;
|
|
17307
|
-
const myRoot =
|
|
17308
|
-
const live = sessions.filter((s) => s.status === "active" || s.status === "idle").filter((s) => mySlug ? s.projectSlug === mySlug :
|
|
17450
|
+
const myRoot = path20.resolve(context.projectRoot);
|
|
17451
|
+
const live = sessions.filter((s) => s.status === "active" || s.status === "idle").filter((s) => mySlug ? s.projectSlug === mySlug : path20.resolve(s.projectRoot) === myRoot).map((s) => ({
|
|
17309
17452
|
sessionId: s.sessionId,
|
|
17310
17453
|
projectName: s.projectName,
|
|
17311
17454
|
projectSlug: s.projectSlug,
|
|
@@ -17495,14 +17638,14 @@ function createSetupEventSessionHelpers(context, sessionBridge) {
|
|
|
17495
17638
|
|
|
17496
17639
|
// src/server/setup-events-status-watcher.ts
|
|
17497
17640
|
import { watch as fsWatch2 } from "node:fs";
|
|
17498
|
-
import * as
|
|
17499
|
-
import * as
|
|
17641
|
+
import * as fs18 from "node:fs/promises";
|
|
17642
|
+
import * as path22 from "node:path";
|
|
17500
17643
|
|
|
17501
17644
|
// src/server/setup-events-watcher.ts
|
|
17502
|
-
import * as
|
|
17645
|
+
import * as path21 from "node:path";
|
|
17503
17646
|
function statusProjectHashFromWatchFilename(projectsDir, filename) {
|
|
17504
17647
|
const raw = String(filename);
|
|
17505
|
-
const relative5 =
|
|
17648
|
+
const relative5 = path21.isAbsolute(raw) ? path21.relative(projectsDir, raw) : raw;
|
|
17506
17649
|
const parts = relative5.split(/[\\/]+/).filter(Boolean);
|
|
17507
17650
|
if (parts.length < 2 || parts.at(-1) !== "status.json") return null;
|
|
17508
17651
|
return parts.at(-2) ?? null;
|
|
@@ -17537,7 +17680,7 @@ function logFileWatcherMetrics(metrics) {
|
|
|
17537
17680
|
function registerSetupEventsStatusWatcher(deps2) {
|
|
17538
17681
|
const { wpaths, watcherMetrics, clients, broadcast: broadcast2, on, isDisposed } = deps2;
|
|
17539
17682
|
if (!wpaths?.projectStatus || !wpaths.globalRoot) return void 0;
|
|
17540
|
-
const projectsDir =
|
|
17683
|
+
const projectsDir = path22.join(wpaths.globalRoot, "projects");
|
|
17541
17684
|
const knownProjectHashes = /* @__PURE__ */ new Set();
|
|
17542
17685
|
const debounceTimers = /* @__PURE__ */ new Map();
|
|
17543
17686
|
const DEBOUNCE_MS = 150;
|
|
@@ -17582,7 +17725,7 @@ function registerSetupEventsStatusWatcher(deps2) {
|
|
|
17582
17725
|
let watcher;
|
|
17583
17726
|
const startWatcher = async () => {
|
|
17584
17727
|
try {
|
|
17585
|
-
await
|
|
17728
|
+
await fs18.mkdir(projectsDir, { recursive: true });
|
|
17586
17729
|
if (isDisposed()) return;
|
|
17587
17730
|
watcher = fsWatch2(
|
|
17588
17731
|
projectsDir,
|
|
@@ -17596,8 +17739,8 @@ function registerSetupEventsStatusWatcher(deps2) {
|
|
|
17596
17739
|
if (!knownProjectHashes.has(projectHash)) return;
|
|
17597
17740
|
if (watcherMetrics) watcherMetrics.filesProcessed++;
|
|
17598
17741
|
try {
|
|
17599
|
-
const targetFile =
|
|
17600
|
-
const content = await
|
|
17742
|
+
const targetFile = path22.join(projectsDir, projectHash, "status.json");
|
|
17743
|
+
const content = await fs18.readFile(targetFile, "utf-8");
|
|
17601
17744
|
const statusData = JSON.parse(content);
|
|
17602
17745
|
scheduleBroadcast(projectHash, statusData);
|
|
17603
17746
|
} catch {
|
|
@@ -17653,61 +17796,6 @@ function registerSetupEventsStatusWatcher(deps2) {
|
|
|
17653
17796
|
};
|
|
17654
17797
|
}
|
|
17655
17798
|
|
|
17656
|
-
// src/server/setup-events-core-watchers.ts
|
|
17657
|
-
import * as fs18 from "node:fs/promises";
|
|
17658
|
-
import * as path22 from "node:path";
|
|
17659
|
-
function registerSetupEventsCoreWatchers(deps2) {
|
|
17660
|
-
const { broadcast: broadcast2, clients, context } = deps2;
|
|
17661
|
-
const disposers = [];
|
|
17662
|
-
const conversationState = context.state;
|
|
17663
|
-
if (typeof conversationState?.onChange === "function") {
|
|
17664
|
-
disposers.push(
|
|
17665
|
-
conversationState.onChange((change) => {
|
|
17666
|
-
if (change.kind !== "todos_replaced") return;
|
|
17667
|
-
broadcast2(clients, {
|
|
17668
|
-
type: "todos.updated",
|
|
17669
|
-
payload: {
|
|
17670
|
-
sessionId: context.session?.id ?? "",
|
|
17671
|
-
todos: [...change.todos],
|
|
17672
|
-
revision: conversationState.revision
|
|
17673
|
-
}
|
|
17674
|
-
});
|
|
17675
|
-
})
|
|
17676
|
-
);
|
|
17677
|
-
}
|
|
17678
|
-
const projectRoot = context.projectRoot;
|
|
17679
|
-
if (projectRoot) {
|
|
17680
|
-
disposers.push(
|
|
17681
|
-
subscribeKanbanDaemonEvents(projectRoot, (message) => broadcast2(clients, message))
|
|
17682
|
-
);
|
|
17683
|
-
}
|
|
17684
|
-
return disposers;
|
|
17685
|
-
}
|
|
17686
|
-
function registerSetupEventsClientStatusWriter(deps2) {
|
|
17687
|
-
const { broadcast: broadcast2, clients, events, wpaths } = deps2;
|
|
17688
|
-
const on = (event, listener) => events.on(event, listener);
|
|
17689
|
-
return on("client.status", async (e) => {
|
|
17690
|
-
broadcast2(clients, { type: "client.status_update", payload: e });
|
|
17691
|
-
if (wpaths?.projectStatus) {
|
|
17692
|
-
try {
|
|
17693
|
-
const statusFile = wpaths.projectStatus(e.projectHash);
|
|
17694
|
-
const dir = path22.dirname(statusFile);
|
|
17695
|
-
await fs18.mkdir(dir, { recursive: true });
|
|
17696
|
-
await fs18.writeFile(statusFile, JSON.stringify(e, null, 2), "utf-8");
|
|
17697
|
-
} catch (err) {
|
|
17698
|
-
console.error(
|
|
17699
|
-
JSON.stringify({
|
|
17700
|
-
level: "error",
|
|
17701
|
-
event: "setup_events.status_write_failed",
|
|
17702
|
-
message: err instanceof Error ? err.message : String(err),
|
|
17703
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
17704
|
-
})
|
|
17705
|
-
);
|
|
17706
|
-
}
|
|
17707
|
-
}
|
|
17708
|
-
});
|
|
17709
|
-
}
|
|
17710
|
-
|
|
17711
17799
|
// src/server/setup-events.ts
|
|
17712
17800
|
function setupEvents(deps2) {
|
|
17713
17801
|
const {
|
|
@@ -18263,6 +18351,12 @@ function setupEvents(deps2) {
|
|
|
18263
18351
|
});
|
|
18264
18352
|
});
|
|
18265
18353
|
disposers.push(
|
|
18354
|
+
events.onPattern("chimera.report_available", (_event, payload) => {
|
|
18355
|
+
broadcast2(clients, {
|
|
18356
|
+
type: "chimera.report_available",
|
|
18357
|
+
payload
|
|
18358
|
+
});
|
|
18359
|
+
}),
|
|
18266
18360
|
events.onPattern("mailbox.received", (_e, payload) => {
|
|
18267
18361
|
broadcast2(clients, { type: "mailbox.received", payload });
|
|
18268
18362
|
}),
|
|
@@ -18779,10 +18873,12 @@ import {
|
|
|
18779
18873
|
} from "@wrongstack/core/utils";
|
|
18780
18874
|
import { makeLightSubagentFactory } from "@wrongstack/runtime";
|
|
18781
18875
|
import {
|
|
18876
|
+
createSageContextMonitorMiddleware,
|
|
18782
18877
|
createSageToolCallMiddleware,
|
|
18783
18878
|
createSageTurnMiddleware,
|
|
18784
18879
|
getSageRetrieval,
|
|
18785
|
-
getSageService
|
|
18880
|
+
getSageService,
|
|
18881
|
+
InjectionTracker
|
|
18786
18882
|
} from "@wrongstack/sage";
|
|
18787
18883
|
|
|
18788
18884
|
// src/server/discover-mailbox-bridge.ts
|
|
@@ -19630,6 +19726,8 @@ async function createAgentServices(input) {
|
|
|
19630
19726
|
installDesignStudioMiddleware({ pipelines, ctx: context });
|
|
19631
19727
|
const memoryRetrieval = getSageRetrieval(memoryStore);
|
|
19632
19728
|
if (config.features.memory !== false && config.Sage?.enabled !== false && memoryRetrieval) {
|
|
19729
|
+
const sageInjectionTracker = new InjectionTracker();
|
|
19730
|
+
const getSageSessionId = () => input.sessionGetter().id;
|
|
19633
19731
|
if (config.Sage?.inject?.toolResults !== false) {
|
|
19634
19732
|
pipelines.toolCall.use(
|
|
19635
19733
|
createSageToolCallMiddleware({
|
|
@@ -19647,7 +19745,9 @@ async function createAgentServices(input) {
|
|
|
19647
19745
|
// middleware falls back to ctx.session.id for cooldown but passes
|
|
19648
19746
|
// undefined to retrieval, causing owned session-scoped memories to be
|
|
19649
19747
|
// silently excluded from tool-call injection.
|
|
19650
|
-
getSessionId:
|
|
19748
|
+
getSessionId: getSageSessionId,
|
|
19749
|
+
tracker: sageInjectionTracker,
|
|
19750
|
+
events
|
|
19651
19751
|
})
|
|
19652
19752
|
);
|
|
19653
19753
|
}
|
|
@@ -19657,10 +19757,19 @@ async function createAgentServices(input) {
|
|
|
19657
19757
|
memory: memoryRetrieval,
|
|
19658
19758
|
maxMemories: config.Sage?.inject?.maxTurnMemories,
|
|
19659
19759
|
maxChars: config.Sage?.inject?.maxCharsPerTurn,
|
|
19660
|
-
minScore: config.Sage?.inject?.minScore
|
|
19760
|
+
minScore: config.Sage?.inject?.minScore,
|
|
19761
|
+
getSessionId: getSageSessionId,
|
|
19762
|
+
tracker: sageInjectionTracker
|
|
19661
19763
|
})
|
|
19662
19764
|
);
|
|
19663
19765
|
}
|
|
19766
|
+
pipelines.request.use(
|
|
19767
|
+
createSageContextMonitorMiddleware({
|
|
19768
|
+
tracker: sageInjectionTracker,
|
|
19769
|
+
events,
|
|
19770
|
+
getSessionId: getSageSessionId
|
|
19771
|
+
})
|
|
19772
|
+
);
|
|
19664
19773
|
}
|
|
19665
19774
|
const codebaseIndexing = setupWebUICodebaseIndexing({
|
|
19666
19775
|
config,
|
|
@@ -89,7 +89,9 @@ export declare function injectWsConfig(html: string, opts: {
|
|
|
89
89
|
* When set, this origin is added to `connect-src` as a `ws://`/`wss://` entry.
|
|
90
90
|
* @param host - The server bind host. When it matches a known loopback address
|
|
91
91
|
* (`127.0.0.1`, `::1`, `[::1]`, or `localhost`), explicit `ws://`/`wss://`
|
|
92
|
-
* entries for
|
|
92
|
+
* entries for `127.0.0.1` and `localhost` are added to `connect-src`.
|
|
93
|
+
* IPv6 loopback (`[::1]`) is excluded — it produces an invalid CSP source
|
|
94
|
+
* and is covered by `'self'` (CSP maps ws:→http:, wss:→https:).
|
|
93
95
|
* @param port - The server listen port. Defaults to `3456`. Unnecessary when
|
|
94
96
|
* only publicWsUrl is used (no loopback branch).
|
|
95
97
|
*/
|
|
@@ -98,6 +98,8 @@ export declare function createProviderOperations(deps: ProviderOperationsDeps):
|
|
|
98
98
|
}) => Promise<void>;
|
|
99
99
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
100
100
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
101
|
+
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
102
|
+
handleCustomModelRemove: (ws: WebSocket, providerId: string, modelId: string) => Promise<void>;
|
|
101
103
|
handleProviderUndoClear: (ws: WebSocket, providerId: string, previousModels: string[]) => Promise<void>;
|
|
102
104
|
handleProviderUpdate: (ws: WebSocket, payload: {
|
|
103
105
|
id: string;
|
|
@@ -138,6 +140,8 @@ export declare function createProviderHandlers(deps: ProviderHandlerDeps): {
|
|
|
138
140
|
}) => Promise<void>;
|
|
139
141
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
140
142
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
143
|
+
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
144
|
+
handleCustomModelRemove: (ws: WebSocket, providerId: string, modelId: string) => Promise<void>;
|
|
141
145
|
handleProviderUndoClear: (ws: WebSocket, providerId: string, previousModels: string[]) => Promise<void>;
|
|
142
146
|
handleProviderUpdate: (ws: WebSocket, payload: {
|
|
143
147
|
id: string;
|
|
@@ -17,6 +17,8 @@ export interface ProviderMutationHandlers {
|
|
|
17
17
|
}) => Promise<void>;
|
|
18
18
|
handleProviderRemove: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
19
19
|
handleProviderClearModels: (ws: WebSocket, providerId: string) => Promise<void>;
|
|
20
|
+
handleCustomModelSet: (ws: WebSocket, providerId: string, modelId: string, definition: NonNullable<ProviderConfig['customModels']>[string]) => Promise<void>;
|
|
21
|
+
handleCustomModelRemove: (ws: WebSocket, providerId: string, modelId: string) => Promise<void>;
|
|
20
22
|
handleProviderUndoClear: (ws: WebSocket, providerId: string, previousModels: string[]) => Promise<void>;
|
|
21
23
|
handleProviderUpdate: (ws: WebSocket, payload: {
|
|
22
24
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/webui-server",
|
|
3
|
-
"version": "0.298.
|
|
3
|
+
"version": "0.298.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack WebUI HTTP/WebSocket server module — extracted from @wrongstack/webui in PR #243/244 to remove the CLI -> @wrongstack/webui/server cross-package edge (audit §3.1.1). Pure backend: HTTP routes, WebSocket handlers, MCP tool wrappers, HTML serving. The web frontend lives in @wrongstack/webui; this package is the standalone server it can run on.",
|
|
6
6
|
"keywords": [
|
|
@@ -40,18 +40,18 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"ws": "^8.21.1",
|
|
43
|
-
"@wrongstack/core": "0.298.
|
|
44
|
-
"@wrongstack/
|
|
45
|
-
"@wrongstack/
|
|
46
|
-
"@wrongstack/kanban": "0.298.
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/
|
|
51
|
-
"@wrongstack/
|
|
43
|
+
"@wrongstack/core": "0.298.2",
|
|
44
|
+
"@wrongstack/sdd": "0.298.2",
|
|
45
|
+
"@wrongstack/runtime": "0.298.2",
|
|
46
|
+
"@wrongstack/kanban": "0.298.2",
|
|
47
|
+
"@wrongstack/sage": "0.298.2",
|
|
48
|
+
"@wrongstack/providers": "0.298.2",
|
|
49
|
+
"@wrongstack/techstack": "0.298.2",
|
|
50
|
+
"@wrongstack/tools": "0.298.2",
|
|
51
|
+
"@wrongstack/mcp": "0.298.2"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@types/node": "^26.1.
|
|
54
|
+
"@types/node": "^26.1.2",
|
|
55
55
|
"@types/ws": "^8.18.1",
|
|
56
56
|
"typescript": "^7.0.2"
|
|
57
57
|
},
|