@wrongstack/webui-server 0.310.1 → 0.313.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js
CHANGED
|
@@ -100,7 +100,7 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
100
100
|
"showSageMemoryInject",
|
|
101
101
|
// WrongProxy / WrongTrace master switch. When on, the CLI rewrites every
|
|
102
102
|
// provider's base URL through the configured proxy URL (default
|
|
103
|
-
// http://localhost:
|
|
103
|
+
// http://localhost:3444 → http://localhost:3444/proxy/<host><path>).
|
|
104
104
|
// Excluded providers (openai-codex) flow through unchanged.
|
|
105
105
|
"wrongProxyEnabled"
|
|
106
106
|
]);
|
|
@@ -171,7 +171,7 @@ var STRING_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
171
171
|
"autoReviewModel",
|
|
172
172
|
"autoReviewFallbackProfile",
|
|
173
173
|
// WrongProxy / WrongTrace URL. Empty = unset. Default lives in
|
|
174
|
-
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:
|
|
174
|
+
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:3444'); users
|
|
175
175
|
// can override here for non-default daemon ports / paths.
|
|
176
176
|
"wrongProxyUrl"
|
|
177
177
|
]);
|
|
@@ -187,7 +187,7 @@ var ENUM_PREF_KEYS = {
|
|
|
187
187
|
reasoningEffort: REASONING_EFFORT_VALUES,
|
|
188
188
|
cacheTtl: CACHE_TTL_VALUES,
|
|
189
189
|
statuslineMode: /* @__PURE__ */ new Set(["minimum", "detailed", "no-color"]),
|
|
190
|
-
animationStyle: /* @__PURE__ */ new Set(["rainbow", "wave", "pulse", "dots", "breathe", "cycle"]),
|
|
190
|
+
animationStyle: /* @__PURE__ */ new Set(["rainbow", "wave", "pulse", "dots", "breathe", "static", "cycle"]),
|
|
191
191
|
fsAccess: /* @__PURE__ */ new Set(["unrestricted", "project"]),
|
|
192
192
|
// Chimera autoFix + auto-review cascade threshold
|
|
193
193
|
chimeraAutoFix: /* @__PURE__ */ new Set(["off", "ask", "auto"]),
|
|
@@ -6376,7 +6376,8 @@ function estimateTokens(s) {
|
|
|
6376
6376
|
function stringifyContent(c) {
|
|
6377
6377
|
if (typeof c === "string") return c;
|
|
6378
6378
|
try {
|
|
6379
|
-
|
|
6379
|
+
const serialized = JSON.stringify(c);
|
|
6380
|
+
return serialized === void 0 ? String(c) : serialized;
|
|
6380
6381
|
} catch {
|
|
6381
6382
|
return String(c);
|
|
6382
6383
|
}
|
|
@@ -21211,7 +21212,7 @@ var PREF_KEYS = [
|
|
|
21211
21212
|
// Fleet chat verbosity: off | full (migrated from streamFleet boolean).
|
|
21212
21213
|
"fleetChatVerbosity",
|
|
21213
21214
|
// WrongProxy / WrongTrace: master switch + configurable URL (default
|
|
21214
|
-
// http://localhost:
|
|
21215
|
+
// http://localhost:3444). When `wrongProxyEnabled` is true and the daemon
|
|
21215
21216
|
// is reachable, every provider's base URL flows through
|
|
21216
21217
|
// `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is excluded by spec.
|
|
21217
21218
|
"wrongProxyEnabled",
|
|
@@ -24257,6 +24258,8 @@ import {
|
|
|
24257
24258
|
// src/server/backend-services.ts
|
|
24258
24259
|
import { join as join15 } from "node:path";
|
|
24259
24260
|
import { Agent } from "@wrongstack/core/agent";
|
|
24261
|
+
import { HookRegistry, HookRunner } from "@wrongstack/core/hooks";
|
|
24262
|
+
import { createWrongTraceHookPair, recordGateDecision, snapshotGateDecisions, persistWrongTraceGateCounters } from "@wrongstack/wrongtrace";
|
|
24260
24263
|
import {
|
|
24261
24264
|
BrainDecisionLedger,
|
|
24262
24265
|
BrainMonitor,
|
|
@@ -25298,6 +25301,33 @@ async function createAgentServices(input) {
|
|
|
25298
25301
|
const secretScrubber = container.resolve(TOKENS2.SecretScrubber);
|
|
25299
25302
|
const renderer = container.has(TOKENS2.Renderer) ? container.resolve(TOKENS2.Renderer) : void 0;
|
|
25300
25303
|
const permissionPolicy = container.resolve(TOKENS2.PermissionPolicy);
|
|
25304
|
+
const wrongTraceHookRegistry = new HookRegistry();
|
|
25305
|
+
const wrongTraceHooks = createWrongTraceHookPair(() => context.session.id, {
|
|
25306
|
+
emit: (event) => {
|
|
25307
|
+
events.emit("wrongtrace.gate.decision", event);
|
|
25308
|
+
recordGateDecision(event);
|
|
25309
|
+
void persistWrongTraceGateCounters(projectRoot, snapshotGateDecisions());
|
|
25310
|
+
}
|
|
25311
|
+
});
|
|
25312
|
+
wrongTraceHookRegistry.registerInProcess(
|
|
25313
|
+
"PreToolUse",
|
|
25314
|
+
"edit|write|replace|patch|codebase-ast-replace",
|
|
25315
|
+
wrongTraceHooks.preToolUse,
|
|
25316
|
+
"wrongtrace-gate"
|
|
25317
|
+
);
|
|
25318
|
+
wrongTraceHookRegistry.registerInProcess(
|
|
25319
|
+
"PostToolUse",
|
|
25320
|
+
"edit|write|replace|patch|codebase-ast-replace",
|
|
25321
|
+
wrongTraceHooks.postToolUse,
|
|
25322
|
+
"wrongtrace-gate"
|
|
25323
|
+
);
|
|
25324
|
+
const wrongTraceHookRunner = new HookRunner({
|
|
25325
|
+
registry: wrongTraceHookRegistry,
|
|
25326
|
+
sessionId: () => context.session.id,
|
|
25327
|
+
// Coordination, not enforcement: these hooks are fail-open by
|
|
25328
|
+
// construction and must run regardless of shell-hook gating.
|
|
25329
|
+
allowNonPolicy: true
|
|
25330
|
+
});
|
|
25301
25331
|
const toolExecutor = new ToolExecutor(toolRegistry, {
|
|
25302
25332
|
permissionPolicy,
|
|
25303
25333
|
secretScrubber,
|
|
@@ -25307,6 +25337,7 @@ async function createAgentServices(input) {
|
|
|
25307
25337
|
iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,
|
|
25308
25338
|
perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,
|
|
25309
25339
|
tracer: void 0,
|
|
25340
|
+
hookRunner: wrongTraceHookRunner,
|
|
25310
25341
|
// Off unless the operator opts in. The WebUI drives the same agent as the
|
|
25311
25342
|
// CLI, so it must resolve this identically — a surface-dependent gate
|
|
25312
25343
|
// would mean the same repo governs under `wstack` and not in the browser.
|
|
@@ -25528,6 +25559,12 @@ async function createAgentServices(input) {
|
|
|
25528
25559
|
// round-robin keeps reassigning the doomed model. Mirrors the CLI
|
|
25529
25560
|
// factory wiring at host-subagent-factory.ts:337.
|
|
25530
25561
|
statusTracker: container.safeResolve(TOKENS2.ProviderModelStatusTracker),
|
|
25562
|
+
// WrongTrace lock gate for SDD-wizard workers: the standalone server
|
|
25563
|
+
// already built a dedicated WrongTrace-only HookRunner for its own
|
|
25564
|
+
// executor above; handing the same runner to the runtime factory
|
|
25565
|
+
// makes every worker edit honor peer locks with one process-wide
|
|
25566
|
+
// owner identity (context.session.id).
|
|
25567
|
+
hookRunner: wrongTraceHookRunner,
|
|
25531
25568
|
...input.installToolBoundary ? { installToolBoundary: input.installToolBoundary } : {}
|
|
25532
25569
|
}),
|
|
25533
25570
|
paths: {
|
|
@@ -27597,6 +27634,40 @@ function setupWebuiCredentialWatcher(options) {
|
|
|
27597
27634
|
return credentialWatcher.close;
|
|
27598
27635
|
}
|
|
27599
27636
|
|
|
27637
|
+
// src/server/start-webui-proxy-apply.ts
|
|
27638
|
+
import { createProxyInstantApply } from "@wrongstack/core/wiring/proxy-rewrite";
|
|
27639
|
+
import { makeProviderFromConfig as makeProviderFromConfig6, withCatalogCapabilities as withCatalogCapabilities2 } from "@wrongstack/providers";
|
|
27640
|
+
function setupWebuiProxyInstantApply(options) {
|
|
27641
|
+
const { state, deps: deps2, updateAutoCompactionMaxContext } = options;
|
|
27642
|
+
const instantApply = createProxyInstantApply({
|
|
27643
|
+
// Prefer the LIVE provider id over the config's — mirrors the CLI
|
|
27644
|
+
// wiring; the context is the source of truth once the session boots.
|
|
27645
|
+
getActiveProviderId: () => deps2.context.provider?.id ?? state.getConfig().provider ?? "",
|
|
27646
|
+
// Same raw-read rule as every other WebUI provider-build site:
|
|
27647
|
+
// savedCfg.baseUrl ?? top-level config.baseUrl.
|
|
27648
|
+
getRawBaseUrl: (providerId) => state.getConfig().providers?.[providerId]?.baseUrl ?? state.getConfig().baseUrl,
|
|
27649
|
+
rebuildProvider: async (providerId) => {
|
|
27650
|
+
await deps2.context.runModelTransition(async () => {
|
|
27651
|
+
if (deps2.context.provider?.id !== providerId) return;
|
|
27652
|
+
const cur = state.getConfig();
|
|
27653
|
+
const providerCfg = cur.providers?.[providerId] ?? { type: providerId };
|
|
27654
|
+
const routedCfg = routeProviderCfgThroughProxy(providerCfg, cur.baseUrl, providerId);
|
|
27655
|
+
const built = deps2.providerRegistry.has(providerId) ? deps2.providerRegistry.create({ ...routedCfg, type: providerId }) : makeProviderFromConfig6(providerId, routedCfg);
|
|
27656
|
+
const model = deps2.context.model ?? cur.model ?? "";
|
|
27657
|
+
const newProv = deps2.modelsRegistry ? await withCatalogCapabilities2(deps2.modelsRegistry, providerId, built, {
|
|
27658
|
+
...routedCfg,
|
|
27659
|
+
type: providerId,
|
|
27660
|
+
model
|
|
27661
|
+
}) : built;
|
|
27662
|
+
deps2.context.provider = newProv;
|
|
27663
|
+
void updateAutoCompactionMaxContext(newProv, providerId).catch(() => void 0);
|
|
27664
|
+
});
|
|
27665
|
+
},
|
|
27666
|
+
logger: deps2.logger
|
|
27667
|
+
});
|
|
27668
|
+
return () => instantApply.dispose();
|
|
27669
|
+
}
|
|
27670
|
+
|
|
27600
27671
|
// src/server/start-webui-remediation.ts
|
|
27601
27672
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
27602
27673
|
import { toLanguagePackageInput } from "@wrongstack/techstack";
|
|
@@ -27686,6 +27757,7 @@ function setupWebuiShutdown(options) {
|
|
|
27686
27757
|
await options.todosCheckpoint.detach();
|
|
27687
27758
|
await options.stopHeapWatchdog();
|
|
27688
27759
|
options.getCredentialWatcherClose()?.();
|
|
27760
|
+
options.getProxyInstantApplyDispose()();
|
|
27689
27761
|
options.disposeRealtimeHandlers();
|
|
27690
27762
|
const governanceCleanup = await options.governanceHandle?.close();
|
|
27691
27763
|
if (governanceCleanup && !governanceCleanup.ok) {
|
|
@@ -28232,6 +28304,11 @@ async function startWebUI(opts = {}) {
|
|
|
28232
28304
|
clients,
|
|
28233
28305
|
updateAutoCompactionMaxContext
|
|
28234
28306
|
});
|
|
28307
|
+
const proxyInstantApplyDispose = setupWebuiProxyInstantApply({
|
|
28308
|
+
state,
|
|
28309
|
+
deps: deps2,
|
|
28310
|
+
updateAutoCompactionMaxContext
|
|
28311
|
+
});
|
|
28235
28312
|
const stopHeapWatchdog = startSharedHeapWatchdog({
|
|
28236
28313
|
collectStats: () => ({
|
|
28237
28314
|
surface: opts.surface ?? "webui",
|
|
@@ -28339,6 +28416,7 @@ projectRoot: ${ev.projectRoot ?? "?"}`,
|
|
|
28339
28416
|
todosCheckpoint,
|
|
28340
28417
|
stopHeapWatchdog,
|
|
28341
28418
|
getCredentialWatcherClose: () => credentialWatcherClose,
|
|
28419
|
+
getProxyInstantApplyDispose: () => proxyInstantApplyDispose,
|
|
28342
28420
|
disposeRealtimeHandlers,
|
|
28343
28421
|
governanceHandle,
|
|
28344
28422
|
logger,
|
package/dist/server/entry.js
CHANGED
|
@@ -101,7 +101,7 @@ var BOOLEAN_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
101
101
|
"showSageMemoryInject",
|
|
102
102
|
// WrongProxy / WrongTrace master switch. When on, the CLI rewrites every
|
|
103
103
|
// provider's base URL through the configured proxy URL (default
|
|
104
|
-
// http://localhost:
|
|
104
|
+
// http://localhost:3444 → http://localhost:3444/proxy/<host><path>).
|
|
105
105
|
// Excluded providers (openai-codex) flow through unchanged.
|
|
106
106
|
"wrongProxyEnabled"
|
|
107
107
|
]);
|
|
@@ -172,7 +172,7 @@ var STRING_PREF_KEYS = /* @__PURE__ */ new Set([
|
|
|
172
172
|
"autoReviewModel",
|
|
173
173
|
"autoReviewFallbackProfile",
|
|
174
174
|
// WrongProxy / WrongTrace URL. Empty = unset. Default lives in
|
|
175
|
-
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:
|
|
175
|
+
// `LocalPrefs.DEFAULTS.wrongProxyUrl` ('http://localhost:3444'); users
|
|
176
176
|
// can override here for non-default daemon ports / paths.
|
|
177
177
|
"wrongProxyUrl"
|
|
178
178
|
]);
|
|
@@ -188,7 +188,7 @@ var ENUM_PREF_KEYS = {
|
|
|
188
188
|
reasoningEffort: REASONING_EFFORT_VALUES,
|
|
189
189
|
cacheTtl: CACHE_TTL_VALUES,
|
|
190
190
|
statuslineMode: /* @__PURE__ */ new Set(["minimum", "detailed", "no-color"]),
|
|
191
|
-
animationStyle: /* @__PURE__ */ new Set(["rainbow", "wave", "pulse", "dots", "breathe", "cycle"]),
|
|
191
|
+
animationStyle: /* @__PURE__ */ new Set(["rainbow", "wave", "pulse", "dots", "breathe", "static", "cycle"]),
|
|
192
192
|
fsAccess: /* @__PURE__ */ new Set(["unrestricted", "project"]),
|
|
193
193
|
// Chimera autoFix + auto-review cascade threshold
|
|
194
194
|
chimeraAutoFix: /* @__PURE__ */ new Set(["off", "ask", "auto"]),
|
|
@@ -6191,7 +6191,8 @@ function estimateTokens(s) {
|
|
|
6191
6191
|
function stringifyContent(c) {
|
|
6192
6192
|
if (typeof c === "string") return c;
|
|
6193
6193
|
try {
|
|
6194
|
-
|
|
6194
|
+
const serialized = JSON.stringify(c);
|
|
6195
|
+
return serialized === void 0 ? String(c) : serialized;
|
|
6195
6196
|
} catch {
|
|
6196
6197
|
return String(c);
|
|
6197
6198
|
}
|
|
@@ -19497,7 +19498,7 @@ var PREF_KEYS = [
|
|
|
19497
19498
|
// Fleet chat verbosity: off | full (migrated from streamFleet boolean).
|
|
19498
19499
|
"fleetChatVerbosity",
|
|
19499
19500
|
// WrongProxy / WrongTrace: master switch + configurable URL (default
|
|
19500
|
-
// http://localhost:
|
|
19501
|
+
// http://localhost:3444). When `wrongProxyEnabled` is true and the daemon
|
|
19501
19502
|
// is reachable, every provider's base URL flows through
|
|
19502
19503
|
// `${wrongProxyUrl}/proxy/<host><path>`. openai-codex is excluded by spec.
|
|
19503
19504
|
"wrongProxyEnabled",
|
|
@@ -22441,6 +22442,8 @@ import {
|
|
|
22441
22442
|
// src/server/backend-services.ts
|
|
22442
22443
|
import { join as join12 } from "node:path";
|
|
22443
22444
|
import { Agent } from "@wrongstack/core/agent";
|
|
22445
|
+
import { HookRegistry, HookRunner } from "@wrongstack/core/hooks";
|
|
22446
|
+
import { createWrongTraceHookPair, recordGateDecision, snapshotGateDecisions, persistWrongTraceGateCounters } from "@wrongstack/wrongtrace";
|
|
22444
22447
|
import {
|
|
22445
22448
|
BrainDecisionLedger,
|
|
22446
22449
|
BrainMonitor,
|
|
@@ -23482,6 +23485,33 @@ async function createAgentServices(input) {
|
|
|
23482
23485
|
const secretScrubber = container.resolve(TOKENS.SecretScrubber);
|
|
23483
23486
|
const renderer = container.has(TOKENS.Renderer) ? container.resolve(TOKENS.Renderer) : void 0;
|
|
23484
23487
|
const permissionPolicy = container.resolve(TOKENS.PermissionPolicy);
|
|
23488
|
+
const wrongTraceHookRegistry = new HookRegistry();
|
|
23489
|
+
const wrongTraceHooks = createWrongTraceHookPair(() => context.session.id, {
|
|
23490
|
+
emit: (event) => {
|
|
23491
|
+
events.emit("wrongtrace.gate.decision", event);
|
|
23492
|
+
recordGateDecision(event);
|
|
23493
|
+
void persistWrongTraceGateCounters(projectRoot, snapshotGateDecisions());
|
|
23494
|
+
}
|
|
23495
|
+
});
|
|
23496
|
+
wrongTraceHookRegistry.registerInProcess(
|
|
23497
|
+
"PreToolUse",
|
|
23498
|
+
"edit|write|replace|patch|codebase-ast-replace",
|
|
23499
|
+
wrongTraceHooks.preToolUse,
|
|
23500
|
+
"wrongtrace-gate"
|
|
23501
|
+
);
|
|
23502
|
+
wrongTraceHookRegistry.registerInProcess(
|
|
23503
|
+
"PostToolUse",
|
|
23504
|
+
"edit|write|replace|patch|codebase-ast-replace",
|
|
23505
|
+
wrongTraceHooks.postToolUse,
|
|
23506
|
+
"wrongtrace-gate"
|
|
23507
|
+
);
|
|
23508
|
+
const wrongTraceHookRunner = new HookRunner({
|
|
23509
|
+
registry: wrongTraceHookRegistry,
|
|
23510
|
+
sessionId: () => context.session.id,
|
|
23511
|
+
// Coordination, not enforcement: these hooks are fail-open by
|
|
23512
|
+
// construction and must run regardless of shell-hook gating.
|
|
23513
|
+
allowNonPolicy: true
|
|
23514
|
+
});
|
|
23485
23515
|
const toolExecutor = new ToolExecutor(toolRegistry, {
|
|
23486
23516
|
permissionPolicy,
|
|
23487
23517
|
secretScrubber,
|
|
@@ -23491,6 +23521,7 @@ async function createAgentServices(input) {
|
|
|
23491
23521
|
iterationTimeoutMs: config.tools?.iterationTimeoutMs ?? DEFAULT_TOOLS_CONFIG.iterationTimeoutMs,
|
|
23492
23522
|
perIterationOutputCapBytes: config.tools?.perIterationOutputCapBytes ?? DEFAULT_TOOLS_CONFIG.perIterationOutputCapBytes,
|
|
23493
23523
|
tracer: void 0,
|
|
23524
|
+
hookRunner: wrongTraceHookRunner,
|
|
23494
23525
|
// Off unless the operator opts in. The WebUI drives the same agent as the
|
|
23495
23526
|
// CLI, so it must resolve this identically — a surface-dependent gate
|
|
23496
23527
|
// would mean the same repo governs under `wstack` and not in the browser.
|
|
@@ -23712,6 +23743,12 @@ async function createAgentServices(input) {
|
|
|
23712
23743
|
// round-robin keeps reassigning the doomed model. Mirrors the CLI
|
|
23713
23744
|
// factory wiring at host-subagent-factory.ts:337.
|
|
23714
23745
|
statusTracker: container.safeResolve(TOKENS.ProviderModelStatusTracker),
|
|
23746
|
+
// WrongTrace lock gate for SDD-wizard workers: the standalone server
|
|
23747
|
+
// already built a dedicated WrongTrace-only HookRunner for its own
|
|
23748
|
+
// executor above; handing the same runner to the runtime factory
|
|
23749
|
+
// makes every worker edit honor peer locks with one process-wide
|
|
23750
|
+
// owner identity (context.session.id).
|
|
23751
|
+
hookRunner: wrongTraceHookRunner,
|
|
23715
23752
|
...input.installToolBoundary ? { installToolBoundary: input.installToolBoundary } : {}
|
|
23716
23753
|
}),
|
|
23717
23754
|
paths: {
|
|
@@ -25781,6 +25818,40 @@ function setupWebuiCredentialWatcher(options) {
|
|
|
25781
25818
|
return credentialWatcher.close;
|
|
25782
25819
|
}
|
|
25783
25820
|
|
|
25821
|
+
// src/server/start-webui-proxy-apply.ts
|
|
25822
|
+
import { createProxyInstantApply } from "@wrongstack/core/wiring/proxy-rewrite";
|
|
25823
|
+
import { makeProviderFromConfig as makeProviderFromConfig4, withCatalogCapabilities as withCatalogCapabilities2 } from "@wrongstack/providers";
|
|
25824
|
+
function setupWebuiProxyInstantApply(options) {
|
|
25825
|
+
const { state, deps: deps2, updateAutoCompactionMaxContext } = options;
|
|
25826
|
+
const instantApply = createProxyInstantApply({
|
|
25827
|
+
// Prefer the LIVE provider id over the config's — mirrors the CLI
|
|
25828
|
+
// wiring; the context is the source of truth once the session boots.
|
|
25829
|
+
getActiveProviderId: () => deps2.context.provider?.id ?? state.getConfig().provider ?? "",
|
|
25830
|
+
// Same raw-read rule as every other WebUI provider-build site:
|
|
25831
|
+
// savedCfg.baseUrl ?? top-level config.baseUrl.
|
|
25832
|
+
getRawBaseUrl: (providerId) => state.getConfig().providers?.[providerId]?.baseUrl ?? state.getConfig().baseUrl,
|
|
25833
|
+
rebuildProvider: async (providerId) => {
|
|
25834
|
+
await deps2.context.runModelTransition(async () => {
|
|
25835
|
+
if (deps2.context.provider?.id !== providerId) return;
|
|
25836
|
+
const cur = state.getConfig();
|
|
25837
|
+
const providerCfg = cur.providers?.[providerId] ?? { type: providerId };
|
|
25838
|
+
const routedCfg = routeProviderCfgThroughProxy(providerCfg, cur.baseUrl, providerId);
|
|
25839
|
+
const built = deps2.providerRegistry.has(providerId) ? deps2.providerRegistry.create({ ...routedCfg, type: providerId }) : makeProviderFromConfig4(providerId, routedCfg);
|
|
25840
|
+
const model = deps2.context.model ?? cur.model ?? "";
|
|
25841
|
+
const newProv = deps2.modelsRegistry ? await withCatalogCapabilities2(deps2.modelsRegistry, providerId, built, {
|
|
25842
|
+
...routedCfg,
|
|
25843
|
+
type: providerId,
|
|
25844
|
+
model
|
|
25845
|
+
}) : built;
|
|
25846
|
+
deps2.context.provider = newProv;
|
|
25847
|
+
void updateAutoCompactionMaxContext(newProv, providerId).catch(() => void 0);
|
|
25848
|
+
});
|
|
25849
|
+
},
|
|
25850
|
+
logger: deps2.logger
|
|
25851
|
+
});
|
|
25852
|
+
return () => instantApply.dispose();
|
|
25853
|
+
}
|
|
25854
|
+
|
|
25784
25855
|
// src/server/start-webui-remediation.ts
|
|
25785
25856
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
25786
25857
|
import { toLanguagePackageInput } from "@wrongstack/techstack";
|
|
@@ -25870,6 +25941,7 @@ function setupWebuiShutdown(options) {
|
|
|
25870
25941
|
await options.todosCheckpoint.detach();
|
|
25871
25942
|
await options.stopHeapWatchdog();
|
|
25872
25943
|
options.getCredentialWatcherClose()?.();
|
|
25944
|
+
options.getProxyInstantApplyDispose()();
|
|
25873
25945
|
options.disposeRealtimeHandlers();
|
|
25874
25946
|
const governanceCleanup = await options.governanceHandle?.close();
|
|
25875
25947
|
if (governanceCleanup && !governanceCleanup.ok) {
|
|
@@ -26416,6 +26488,11 @@ async function startWebUI(opts = {}) {
|
|
|
26416
26488
|
clients,
|
|
26417
26489
|
updateAutoCompactionMaxContext
|
|
26418
26490
|
});
|
|
26491
|
+
const proxyInstantApplyDispose = setupWebuiProxyInstantApply({
|
|
26492
|
+
state,
|
|
26493
|
+
deps: deps2,
|
|
26494
|
+
updateAutoCompactionMaxContext
|
|
26495
|
+
});
|
|
26419
26496
|
const stopHeapWatchdog = startSharedHeapWatchdog({
|
|
26420
26497
|
collectStats: () => ({
|
|
26421
26498
|
surface: opts.surface ?? "webui",
|
|
@@ -26523,6 +26600,7 @@ projectRoot: ${ev.projectRoot ?? "?"}`,
|
|
|
26523
26600
|
todosCheckpoint,
|
|
26524
26601
|
stopHeapWatchdog,
|
|
26525
26602
|
getCredentialWatcherClose: () => credentialWatcherClose,
|
|
26603
|
+
getProxyInstantApplyDispose: () => proxyInstantApplyDispose,
|
|
26526
26604
|
disposeRealtimeHandlers,
|
|
26527
26605
|
governanceHandle,
|
|
26528
26606
|
logger,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WrongProxy instant-apply for the standalone WebUI server.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the CLI-side wiring in `setupProviderRuntime` (packages/cli/src/
|
|
5
|
+
* wiring/provider-runtime-setup.ts): subscribe to material proxy-config
|
|
6
|
+
* changes via `createProxyInstantApply` and rebuild the LIVE provider when
|
|
7
|
+
* the routing verdict for the active provider flips, so a Settings toggle
|
|
8
|
+
* or probe deactivation takes effect immediately instead of on the next
|
|
9
|
+
* incidental provider build.
|
|
10
|
+
*
|
|
11
|
+
* The rebuild sequence mirrors `applyModelSwitchCore` (routes.ts) — route
|
|
12
|
+
* the cfg through `routeProviderCfgThroughProxy`, build via registry or
|
|
13
|
+
* `makeProviderFromConfig`, overlay the live model's catalog capabilities
|
|
14
|
+
* — minus the parts that don't apply when provider+model are unchanged
|
|
15
|
+
* (no config persist, no session.start spam). The swap itself runs inside
|
|
16
|
+
* `runModelTransition` with a superseded-check so a queued rebuild can
|
|
17
|
+
* never overwrite a newer /model switch.
|
|
18
|
+
*
|
|
19
|
+
* In the CLI-hosted path this server module is NOT wired (the CLI's own
|
|
20
|
+
* `setupProviderRuntime` instant-apply covers the shared agent context),
|
|
21
|
+
* so there is exactly one rebuilder per process.
|
|
22
|
+
*/
|
|
23
|
+
import type { Provider, ProviderConfig } from '@wrongstack/core/types';
|
|
24
|
+
import type { WebuiDeps, WebuiMutableState } from './routes.js';
|
|
25
|
+
export interface WebuiProxyApplyOptions {
|
|
26
|
+
state: WebuiMutableState;
|
|
27
|
+
deps: WebuiDeps;
|
|
28
|
+
/** Mirrors `cb.updateAutoCompactionMaxContext` in start-webui.ts. */
|
|
29
|
+
updateAutoCompactionMaxContext: (provider: Provider, providerId?: string, providerCfg?: ProviderConfig | undefined) => Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Wire the standalone server's WrongProxy instant-apply. Returns the
|
|
33
|
+
* dispose function for shutdown wiring. The helper itself lives in
|
|
34
|
+
* `@wrongstack/core` so both hosts share the identical change-detection
|
|
35
|
+
* semantics (effective-URL comparison, serialized rebuilds).
|
|
36
|
+
*/
|
|
37
|
+
export declare function setupWebuiProxyInstantApply(options: WebuiProxyApplyOptions): () => void;
|
|
38
|
+
//# sourceMappingURL=start-webui-proxy-apply.d.ts.map
|
|
@@ -18,6 +18,7 @@ export declare function setupWebuiShutdown(options: {
|
|
|
18
18
|
};
|
|
19
19
|
stopHeapWatchdog: () => Promise<void>;
|
|
20
20
|
getCredentialWatcherClose: () => (() => void) | undefined;
|
|
21
|
+
getProxyInstantApplyDispose: () => () => void;
|
|
21
22
|
disposeRealtimeHandlers: () => void;
|
|
22
23
|
governanceHandle?: {
|
|
23
24
|
close: () => Promise<{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/webui-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.313.0",
|
|
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": [
|
|
@@ -36,18 +36,19 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"ws": "^8.21.3",
|
|
39
|
-
"@wrongstack/core": "0.
|
|
40
|
-
"@wrongstack/
|
|
41
|
-
"@wrongstack/
|
|
42
|
-
"@wrongstack/sage": "0.
|
|
43
|
-
"@wrongstack/runtime": "0.
|
|
44
|
-
"@wrongstack/providers": "0.
|
|
45
|
-
"@wrongstack/sdd": "0.
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/
|
|
39
|
+
"@wrongstack/core": "0.313.0",
|
|
40
|
+
"@wrongstack/mcp": "0.313.0",
|
|
41
|
+
"@wrongstack/kanban": "0.313.0",
|
|
42
|
+
"@wrongstack/sage": "0.313.0",
|
|
43
|
+
"@wrongstack/runtime": "0.313.0",
|
|
44
|
+
"@wrongstack/providers": "0.313.0",
|
|
45
|
+
"@wrongstack/sdd": "0.313.0",
|
|
46
|
+
"@wrongstack/requirement-intake": "0.313.0",
|
|
47
|
+
"@wrongstack/techstack": "0.313.0",
|
|
48
|
+
"@wrongstack/tools": "0.313.0",
|
|
49
|
+
"@wrongstack/vector-memory": "0.313.0",
|
|
50
|
+
"@wrongstack/wrongtrace": "0.313.0",
|
|
51
|
+
"@wrongstack/webui-protocol": "0.313.0"
|
|
51
52
|
},
|
|
52
53
|
"devDependencies": {
|
|
53
54
|
"@types/node": "^26.2.0",
|