@jsonstudio/rcc 0.89.2239 → 0.90.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/dist/build-info.js +2 -2
- package/dist/build-info.js.map +1 -1
- package/dist/cli/commands/claude.js +1 -0
- package/dist/cli/commands/claude.js.map +1 -1
- package/dist/cli/commands/codex.js +1 -0
- package/dist/cli/commands/codex.js.map +1 -1
- package/dist/cli/commands/guardian-daemon.d.ts +2 -0
- package/dist/cli/commands/guardian-daemon.js +299 -0
- package/dist/cli/commands/guardian-daemon.js.map +1 -0
- package/dist/cli/commands/init/camoufox.js +1 -1
- package/dist/cli/commands/init/camoufox.js.map +1 -1
- package/dist/cli/commands/launcher/types.d.ts +6 -0
- package/dist/cli/commands/launcher-kernel.js +456 -109
- package/dist/cli/commands/launcher-kernel.js.map +1 -1
- package/dist/cli/commands/port.js +28 -8
- package/dist/cli/commands/port.js.map +1 -1
- package/dist/cli/commands/restart.d.ts +4 -0
- package/dist/cli/commands/restart.js +91 -42
- package/dist/cli/commands/restart.js.map +1 -1
- package/dist/cli/commands/start-types.d.ts +4 -0
- package/dist/cli/commands/start.js +108 -65
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/stop.d.ts +3 -0
- package/dist/cli/commands/stop.js +30 -63
- package/dist/cli/commands/stop.js.map +1 -1
- package/dist/cli/config/init-provider-catalog.js +8 -3
- package/dist/cli/config/init-provider-catalog.js.map +1 -1
- package/dist/cli/guardian/client.d.ts +38 -0
- package/dist/cli/guardian/client.js +237 -0
- package/dist/cli/guardian/client.js.map +1 -0
- package/dist/cli/guardian/paths.d.ts +7 -0
- package/dist/cli/guardian/paths.js +13 -0
- package/dist/cli/guardian/paths.js.map +1 -0
- package/dist/cli/guardian/types.d.ts +30 -0
- package/dist/cli/guardian/types.js +2 -0
- package/dist/cli/guardian/types.js.map +1 -0
- package/dist/cli/register/guardian-daemon-command.d.ts +2 -0
- package/dist/cli/register/guardian-daemon-command.js +5 -0
- package/dist/cli/register/guardian-daemon-command.js.map +1 -0
- package/dist/cli/server/port-utils.js +57 -1
- package/dist/cli/server/port-utils.js.map +1 -1
- package/dist/cli.js +48 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/oauth.js +6 -6
- package/dist/commands/oauth.js.map +1 -1
- package/dist/config/routecodex-config-loader.js +66 -1
- package/dist/config/routecodex-config-loader.js.map +1 -1
- package/dist/config/virtual-router-builder.js +18 -0
- package/dist/config/virtual-router-builder.js.map +1 -1
- package/dist/config/virtual-router-types.js +20 -5
- package/dist/config/virtual-router-types.js.map +1 -1
- package/dist/daemon-admin-ui/assets/index-C8vP_c5E.js +15 -0
- package/dist/daemon-admin-ui/assets/index-DjIoHmNv.css +1 -0
- package/dist/daemon-admin-ui/index.html +13 -0
- package/dist/docs/daemon-admin-ui.html +328 -57
- package/dist/index.d.ts +9 -0
- package/dist/index.js +268 -10
- package/dist/index.js.map +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.error-helpers.d.ts +1 -0
- package/dist/manager/modules/quota/provider-quota-daemon.error-helpers.js +36 -0
- package/dist/manager/modules/quota/provider-quota-daemon.error-helpers.js.map +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.events.js +50 -1
- package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -1
- package/dist/providers/auth/antigravity-user-agent.js +78 -31
- package/dist/providers/auth/antigravity-user-agent.js.map +1 -1
- package/dist/providers/auth/gemini-cli-userinfo-helper.js +94 -63
- package/dist/providers/auth/gemini-cli-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/iflow-userinfo-helper.js +1 -1
- package/dist/providers/auth/iflow-userinfo-helper.js.map +1 -1
- package/dist/providers/auth/oauth-error-message.d.ts +1 -0
- package/dist/providers/auth/oauth-error-message.js +44 -0
- package/dist/providers/auth/oauth-error-message.js.map +1 -0
- package/dist/providers/auth/oauth-lifecycle/error-detection.js +42 -8
- package/dist/providers/auth/oauth-lifecycle/error-detection.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle/token-io.d.ts +1 -0
- package/dist/providers/auth/oauth-lifecycle/token-io.js +12 -0
- package/dist/providers/auth/oauth-lifecycle/token-io.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle.js +502 -87
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/auth/oauth-repair-cooldown.js +2 -7
- package/dist/providers/auth/oauth-repair-cooldown.js.map +1 -1
- package/dist/providers/auth/oauth-repair-env.js +3 -5
- package/dist/providers/auth/oauth-repair-env.js.map +1 -1
- package/dist/providers/auth/oauth-utils/error-extraction.js +42 -8
- package/dist/providers/auth/oauth-utils/error-extraction.js.map +1 -1
- package/dist/providers/core/config/camoufox-actions.d.ts +31 -0
- package/dist/providers/core/config/camoufox-actions.js +461 -0
- package/dist/providers/core/config/camoufox-actions.js.map +1 -0
- package/dist/providers/core/config/camoufox-launcher.d.ts +3 -0
- package/dist/providers/core/config/camoufox-launcher.js +518 -160
- package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
- package/dist/providers/core/config/oauth-flows.js +6 -44
- package/dist/providers/core/config/oauth-flows.js.map +1 -1
- package/dist/providers/core/config/provider-oauth-configs.js +51 -7
- package/dist/providers/core/config/provider-oauth-configs.js.map +1 -1
- package/dist/providers/core/runtime/provider-error-classifier.js +32 -15
- package/dist/providers/core/runtime/provider-error-classifier.js.map +1 -1
- package/dist/providers/core/runtime/provider-family-profile-utils.js +1 -1
- package/dist/providers/core/runtime/provider-family-profile-utils.js.map +1 -1
- package/dist/providers/core/runtime/provider-response-postprocessor.js +61 -14
- package/dist/providers/core/runtime/provider-response-postprocessor.js.map +1 -1
- package/dist/providers/core/strategies/oauth-auth-code-flow.d.ts +1 -0
- package/dist/providers/core/strategies/oauth-auth-code-flow.js +124 -19
- package/dist/providers/core/strategies/oauth-auth-code-flow.js.map +1 -1
- package/dist/providers/core/strategies/oauth-device-flow.js +6 -3
- package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
- package/dist/providers/profile/families/iflow-profile.js +83 -10
- package/dist/providers/profile/families/iflow-profile.js.map +1 -1
- package/dist/scripts/camoufox/launch-auth.mjs +112 -5
- package/dist/server/handlers/config-admin-handler.js +9 -2
- package/dist/server/handlers/config-admin-handler.js.map +1 -1
- package/dist/server/handlers/handler-utils.js +3 -12
- package/dist/server/handlers/handler-utils.js.map +1 -1
- package/dist/server/handlers/logging.js +3 -4
- package/dist/server/handlers/logging.js.map +1 -1
- package/dist/server/runtime/http-server/clock-client-reaper.js +3 -26
- package/dist/server/runtime/http-server/clock-client-reaper.js.map +1 -1
- package/dist/server/runtime/http-server/clock-client-registry-utils.d.ts +4 -0
- package/dist/server/runtime/http-server/clock-client-registry-utils.js +74 -16
- package/dist/server/runtime/http-server/clock-client-registry-utils.js.map +1 -1
- package/dist/server/runtime/http-server/clock-client-registry.d.ts +15 -0
- package/dist/server/runtime/http-server/clock-client-registry.js +300 -6
- package/dist/server/runtime/http-server/clock-client-registry.js.map +1 -1
- package/dist/server/runtime/http-server/clock-client-routes.js +49 -19
- package/dist/server/runtime/http-server/clock-client-routes.js.map +1 -1
- package/dist/server/runtime/http-server/clock-daemon-log-throttle.d.ts +16 -0
- package/dist/server/runtime/http-server/clock-daemon-log-throttle.js +49 -0
- package/dist/server/runtime/http-server/clock-daemon-log-throttle.js.map +1 -1
- package/dist/server/runtime/http-server/clock-scope-resolution.d.ts +14 -0
- package/dist/server/runtime/http-server/clock-scope-resolution.js +212 -0
- package/dist/server/runtime/http-server/clock-scope-resolution.js.map +1 -0
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js +5 -3
- package/dist/server/runtime/http-server/daemon-admin/auth-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/control-handler.js +104 -15
- package/dist/server/runtime/http-server/daemon-admin/control-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js +2 -2
- package/dist/server/runtime/http-server/daemon-admin/credentials-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.d.ts +24 -0
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.js +316 -70
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js +190 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/routing-policy.js +18 -29
- package/dist/server/runtime/http-server/daemon-admin/routing-policy.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/stats-handler.js +2 -0
- package/dist/server/runtime/http-server/daemon-admin/stats-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin-routes.d.ts +8 -1
- package/dist/server/runtime/http-server/daemon-admin-routes.js +30 -0
- package/dist/server/runtime/http-server/daemon-admin-routes.js.map +1 -1
- package/dist/server/runtime/http-server/executor/client-injection-flow.d.ts +14 -0
- package/dist/server/runtime/http-server/executor/client-injection-flow.js +287 -0
- package/dist/server/runtime/http-server/executor/client-injection-flow.js.map +1 -0
- package/dist/server/runtime/http-server/executor/index.d.ts +1 -1
- package/dist/server/runtime/http-server/executor/index.js +1 -1
- package/dist/server/runtime/http-server/executor/index.js.map +1 -1
- package/dist/server/runtime/http-server/executor/provider-response-converter.js +236 -62
- package/dist/server/runtime/http-server/executor/provider-response-converter.js.map +1 -1
- package/dist/server/runtime/http-server/executor/request-executor-core-utils.d.ts +1 -0
- package/dist/server/runtime/http-server/executor/request-executor-core-utils.js +12 -0
- package/dist/server/runtime/http-server/executor/request-executor-core-utils.js.map +1 -1
- package/dist/server/runtime/http-server/executor/request-retry-helpers.js +16 -12
- package/dist/server/runtime/http-server/executor/request-retry-helpers.js.map +1 -1
- package/dist/server/runtime/http-server/executor/sse-error-handler.d.ts +1 -0
- package/dist/server/runtime/http-server/executor/sse-error-handler.js +13 -2
- package/dist/server/runtime/http-server/executor/sse-error-handler.js.map +1 -1
- package/dist/server/runtime/http-server/executor/usage-aggregator.d.ts +0 -12
- package/dist/server/runtime/http-server/executor/usage-aggregator.js +84 -88
- package/dist/server/runtime/http-server/executor/usage-aggregator.js.map +1 -1
- package/dist/server/runtime/http-server/executor-metadata.js +328 -7
- package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
- package/dist/server/runtime/http-server/executor-response.d.ts +1 -0
- package/dist/server/runtime/http-server/executor-response.js +52 -58
- package/dist/server/runtime/http-server/executor-response.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-bootstrap.js +50 -6
- package/dist/server/runtime/http-server/http-server-bootstrap.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-clock-daemon.d.ts +1 -0
- package/dist/server/runtime/http-server/http-server-clock-daemon.js +186 -44
- package/dist/server/runtime/http-server/http-server-clock-daemon.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-lifecycle.js +4 -4
- package/dist/server/runtime/http-server/http-server-lifecycle.js.map +1 -1
- package/dist/server/runtime/http-server/hub-shadow-compare.js +1 -1
- package/dist/server/runtime/http-server/hub-shadow-compare.js.map +1 -1
- package/dist/server/runtime/http-server/index.d.ts +1 -0
- package/dist/server/runtime/http-server/index.js +1 -0
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/middleware.js +82 -4
- package/dist/server/runtime/http-server/middleware.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +6 -5
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.d.ts +2 -1
- package/dist/server/runtime/http-server/routes.js +4 -2
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/session-dir.js +12 -1
- package/dist/server/runtime/http-server/session-dir.js.map +1 -1
- package/dist/server/runtime/http-server/stats-manager.d.ts +35 -0
- package/dist/server/runtime/http-server/stats-manager.js +269 -21
- package/dist/server/runtime/http-server/stats-manager.js.map +1 -1
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.d.ts +13 -0
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.js +168 -0
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.js.map +1 -0
- package/dist/server/runtime/http-server/tmux-session-probe.d.ts +10 -0
- package/dist/server/runtime/http-server/tmux-session-probe.js +97 -0
- package/dist/server/runtime/http-server/tmux-session-probe.js.map +1 -1
- package/dist/server-lifecycle/port-utils.d.ts +2 -1
- package/dist/server-lifecycle/port-utils.js +84 -4
- package/dist/server-lifecycle/port-utils.js.map +1 -1
- package/dist/token-daemon/index.d.ts +1 -0
- package/dist/token-daemon/index.js +17 -12
- package/dist/token-daemon/index.js.map +1 -1
- package/dist/utils/clock-client-token.d.ts +2 -1
- package/dist/utils/clock-client-token.js +52 -8
- package/dist/utils/clock-client-token.js.map +1 -1
- package/dist/utils/clock-scope-trace.d.ts +11 -0
- package/dist/utils/clock-scope-trace.js +41 -0
- package/dist/utils/clock-scope-trace.js.map +1 -0
- package/dist/utils/llms-engine-shadow.js +1 -1
- package/dist/utils/llms-engine-shadow.js.map +1 -1
- package/docs/DAEMON_CONTROL_PLANE.md +1 -0
- package/docs/ROUTING_POLICY_SCHEMA.md +4 -2
- package/docs/daemon-admin-ui.html +328 -57
- package/docs/design/servertool-stopmessage-lifecycle.md +109 -0
- package/docs/exec-command-guard-policy.example.v1.json +7 -1
- package/docs/providers/antigravity-gemini-provider-compat.md +2 -2
- package/package.json +21 -5
- package/scripts/build-core.mjs +12 -0
- package/scripts/camoufox/launch-auth.mjs +112 -5
- package/scripts/ci/repo-sanity.mjs +1 -0
- package/scripts/install-global.sh +6 -0
- package/scripts/install-verify.mjs +33 -16
- package/scripts/run-bg.sh +226 -43
- package/scripts/run-fg-gtimeout.sh +158 -14
- package/scripts/tests/blackbox-rcc-vs-routecodex-antigravity.mjs +3 -3
- package/scripts/tests/ci-jest.mjs +9 -1
- package/scripts/triage-errorsamples.mjs +216 -0
- package/scripts/verify-codex-error-samples.mjs +92 -15
- package/scripts/verify-install-e2e.mjs +57 -27
|
@@ -1489,6 +1489,14 @@
|
|
|
1489
1489
|
<select id="routingSourceSelect" style="width: 420px;"></select>
|
|
1490
1490
|
<button id="refreshRoutingSourcesBtn">Refresh sources</button>
|
|
1491
1491
|
</div>
|
|
1492
|
+
<div class="row" style="margin-bottom: 10px;">
|
|
1493
|
+
<label for="routingGroupSelect">group</label>
|
|
1494
|
+
<select id="routingGroupSelect" style="width: 240px;"></select>
|
|
1495
|
+
<input id="routingGroupNameInput" type="text" placeholder="new group id" style="width: 200px;" />
|
|
1496
|
+
<button id="createRoutingGroupBtn">Create/Copy group</button>
|
|
1497
|
+
<button id="deleteRoutingGroupBtn" class="danger">Delete group</button>
|
|
1498
|
+
<span id="routingActiveGroupHint" class="mono muted" style="margin-left:auto;"></span>
|
|
1499
|
+
</div>
|
|
1492
1500
|
<div class="row" style="margin-bottom: 10px;">
|
|
1493
1501
|
<label for="routingQuotaModeSelect">mode</label>
|
|
1494
1502
|
<select id="routingQuotaModeSelect" style="width: 160px;">
|
|
@@ -1509,9 +1517,9 @@
|
|
|
1509
1517
|
</div>
|
|
1510
1518
|
<div class="row" style="margin-bottom: 10px;">
|
|
1511
1519
|
<button id="loadRoutingBtn" class="primary">Load</button>
|
|
1512
|
-
<button id="saveRoutingBtn" class="primary">Save</button>
|
|
1513
|
-
<button id="saveRoutingRestartLocalBtn">
|
|
1514
|
-
<button id="saveRoutingRestartAllBtn">
|
|
1520
|
+
<button id="saveRoutingBtn" class="primary">Save group</button>
|
|
1521
|
+
<button id="saveRoutingRestartLocalBtn">Activate group</button>
|
|
1522
|
+
<button id="saveRoutingRestartAllBtn">Activate + Restart all</button>
|
|
1515
1523
|
<button id="refreshRoutingPoolBtn">Refresh pool status</button>
|
|
1516
1524
|
<button id="routingRegExpandBtn">Expand all</button>
|
|
1517
1525
|
<button id="routingRegCollapseBtn">Collapse all</button>
|
|
@@ -1551,6 +1559,9 @@
|
|
|
1551
1559
|
routingTargetsUpdatedAt: 0,
|
|
1552
1560
|
routingSources: [],
|
|
1553
1561
|
routingSourcesUpdatedAt: 0,
|
|
1562
|
+
routingGroups: {},
|
|
1563
|
+
routingActiveGroupId: "",
|
|
1564
|
+
routingSelectedGroupId: "",
|
|
1554
1565
|
routingLocation: "virtualrouter.routing",
|
|
1555
1566
|
routingHasLoadBalancing: false,
|
|
1556
1567
|
credentials: [],
|
|
@@ -4245,9 +4256,13 @@
|
|
|
4245
4256
|
}
|
|
4246
4257
|
|
|
4247
4258
|
function buildRoutingPolicyEditorValue(snapshot) {
|
|
4248
|
-
const
|
|
4249
|
-
const
|
|
4250
|
-
const loadBalancingObj = toPlainObjectOrNull(
|
|
4259
|
+
const source = toPlainObjectOrNull(snapshot) || {};
|
|
4260
|
+
const routingObj = toPlainObjectOrNull(source.routing) || {};
|
|
4261
|
+
const loadBalancingObj = toPlainObjectOrNull(source.loadBalancing) || {};
|
|
4262
|
+
const hasLoadBalancing =
|
|
4263
|
+
typeof source.hasLoadBalancing === "boolean"
|
|
4264
|
+
? Boolean(source.hasLoadBalancing)
|
|
4265
|
+
: Boolean(loadBalancingObj && Object.keys(loadBalancingObj).length > 0);
|
|
4251
4266
|
UI.routingHasLoadBalancing = hasLoadBalancing;
|
|
4252
4267
|
return {
|
|
4253
4268
|
routing: routingObj,
|
|
@@ -4276,30 +4291,114 @@
|
|
|
4276
4291
|
};
|
|
4277
4292
|
}
|
|
4278
4293
|
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4294
|
+
function normalizeRoutingGroupsMap(value) {
|
|
4295
|
+
const out = {};
|
|
4296
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return out;
|
|
4297
|
+
for (const [groupId, groupPolicy] of Object.entries(value)) {
|
|
4298
|
+
const policyObj = toPlainObjectOrNull(groupPolicy);
|
|
4299
|
+
if (!groupId || !policyObj) continue;
|
|
4300
|
+
out[groupId] = policyObj;
|
|
4301
|
+
}
|
|
4302
|
+
return out;
|
|
4303
|
+
}
|
|
4304
|
+
|
|
4305
|
+
function currentRoutingSourcePath() {
|
|
4306
|
+
return textOf($("routingSourceSelect").value || "").trim();
|
|
4307
|
+
}
|
|
4308
|
+
|
|
4309
|
+
function currentRoutingSourceQuery() {
|
|
4310
|
+
const selectedPath = currentRoutingSourcePath();
|
|
4311
|
+
return selectedPath ? `?path=${encodeURIComponent(selectedPath)}` : "";
|
|
4312
|
+
}
|
|
4313
|
+
|
|
4314
|
+
function updateRoutingGroupHint() {
|
|
4315
|
+
const hint = $("routingActiveGroupHint");
|
|
4316
|
+
if (!hint) return;
|
|
4317
|
+
const selected = textOf(UI.routingSelectedGroupId || "").trim();
|
|
4318
|
+
const active = textOf(UI.routingActiveGroupId || "").trim();
|
|
4319
|
+
if (!selected && !active) {
|
|
4320
|
+
hint.textContent = "group: —";
|
|
4321
|
+
return;
|
|
4322
|
+
}
|
|
4323
|
+
hint.textContent = `selected=${selected || "—"} · active=${active || "—"}`;
|
|
4324
|
+
}
|
|
4325
|
+
|
|
4326
|
+
function renderRoutingGroupSelect(preferredGroupId) {
|
|
4327
|
+
const select = $("routingGroupSelect");
|
|
4328
|
+
if (!select) return "";
|
|
4329
|
+
const groups = normalizeRoutingGroupsMap(UI.routingGroups);
|
|
4330
|
+
let ids = Object.keys(groups).sort((a, b) => a.localeCompare(b));
|
|
4331
|
+
if (!ids.length) {
|
|
4332
|
+
groups.default = { routing: {} };
|
|
4333
|
+
ids = ["default"];
|
|
4334
|
+
}
|
|
4335
|
+
UI.routingGroups = groups;
|
|
4336
|
+
|
|
4337
|
+
const prev = textOf(select.value || "").trim();
|
|
4338
|
+
select.replaceChildren();
|
|
4339
|
+
for (const id of ids) {
|
|
4340
|
+
const opt = document.createElement("option");
|
|
4341
|
+
opt.value = id;
|
|
4342
|
+
opt.textContent = id === UI.routingActiveGroupId ? `${id} (active)` : id;
|
|
4343
|
+
select.appendChild(opt);
|
|
4344
|
+
}
|
|
4345
|
+
const nextSelected =
|
|
4346
|
+
(preferredGroupId && groups[preferredGroupId] ? preferredGroupId : "")
|
|
4347
|
+
|| (prev && groups[prev] ? prev : "")
|
|
4348
|
+
|| (UI.routingSelectedGroupId && groups[UI.routingSelectedGroupId] ? UI.routingSelectedGroupId : "")
|
|
4349
|
+
|| (UI.routingActiveGroupId && groups[UI.routingActiveGroupId] ? UI.routingActiveGroupId : "")
|
|
4350
|
+
|| ids[0];
|
|
4351
|
+
select.value = nextSelected;
|
|
4352
|
+
UI.routingSelectedGroupId = nextSelected;
|
|
4353
|
+
updateRoutingGroupHint();
|
|
4354
|
+
return nextSelected;
|
|
4355
|
+
}
|
|
4356
|
+
|
|
4357
|
+
function getSelectedRoutingGroupId() {
|
|
4358
|
+
const select = $("routingGroupSelect");
|
|
4359
|
+
const selected = textOf((select && select.value) || UI.routingSelectedGroupId || "").trim();
|
|
4360
|
+
if (selected) UI.routingSelectedGroupId = selected;
|
|
4361
|
+
return selected;
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4364
|
+
function loadSelectedRoutingGroupIntoEditor() {
|
|
4365
|
+
const selectedGroupId = getSelectedRoutingGroupId();
|
|
4366
|
+
const groups = normalizeRoutingGroupsMap(UI.routingGroups);
|
|
4367
|
+
const selectedPolicy = toPlainObjectOrNull(groups[selectedGroupId]) || { routing: {} };
|
|
4368
|
+
routingEditorSetValue(buildRoutingPolicyEditorValue(selectedPolicy));
|
|
4369
|
+
updateRoutingGroupHint();
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4372
|
+
async function loadRouting(preferredGroupId) {
|
|
4373
|
+
setLog("routingOpLog", "");
|
|
4374
|
+
const auth = UI.adminAuth ? UI.adminAuth : await refreshAdminAuthStatus();
|
|
4375
|
+
if (!auth || !auth.authenticated) {
|
|
4376
|
+
notifyUnauthorizedOnce("routing");
|
|
4377
|
+
return;
|
|
4378
|
+
}
|
|
4379
|
+
try {
|
|
4380
|
+
const selectedPath = currentRoutingSourcePath();
|
|
4381
|
+
const query = currentRoutingSourceQuery();
|
|
4382
|
+
const out = await apiFetch(`/config/routing/groups${query}`);
|
|
4383
|
+
UI.routingLocation = out.location || "virtualrouter.routing";
|
|
4384
|
+
UI.routingGroups = normalizeRoutingGroupsMap(out.groups);
|
|
4385
|
+
UI.routingActiveGroupId = textOf(out.activeGroupId || "").trim();
|
|
4386
|
+
const selectedGroupId = renderRoutingGroupSelect(preferredGroupId);
|
|
4387
|
+
if (!UI.routingActiveGroupId && selectedGroupId) {
|
|
4388
|
+
UI.routingActiveGroupId = selectedGroupId;
|
|
4389
|
+
}
|
|
4390
|
+
loadSelectedRoutingGroupIntoEditor();
|
|
4391
|
+
setLog(
|
|
4392
|
+
"routingOpLog",
|
|
4393
|
+
`Loaded groups. Path: ${out.path || selectedPath || "—"}\nLocation: ${UI.routingLocation}\nselected: ${UI.routingSelectedGroupId || "—"}\nactive: ${UI.routingActiveGroupId || "—"}\nloadBalancing: ${UI.routingHasLoadBalancing ? "present" : "absent"}`
|
|
4394
|
+
);
|
|
4395
|
+
toast("Routing groups loaded.", "ok");
|
|
4396
|
+
} catch (e) {
|
|
4397
|
+
if (e && e.status === 401) notifyUnauthorizedOnce("routing");
|
|
4398
|
+
setLog("routingOpLog", `Load failed: ${e.message}`);
|
|
4399
|
+
toast(`Load failed: ${e.message}`);
|
|
4400
|
+
}
|
|
4401
|
+
}
|
|
4303
4402
|
|
|
4304
4403
|
async function saveRouting() {
|
|
4305
4404
|
setLog("routingOpLog", "");
|
|
@@ -4309,30 +4408,41 @@
|
|
|
4309
4408
|
return null;
|
|
4310
4409
|
}
|
|
4311
4410
|
try {
|
|
4312
|
-
const selectedPath =
|
|
4313
|
-
const query =
|
|
4411
|
+
const selectedPath = currentRoutingSourcePath();
|
|
4412
|
+
const query = currentRoutingSourceQuery();
|
|
4413
|
+
const selectedGroupId = getSelectedRoutingGroupId();
|
|
4414
|
+
if (!selectedGroupId) {
|
|
4415
|
+
throw new Error("No routing group selected");
|
|
4416
|
+
}
|
|
4314
4417
|
const policy = parseRoutingPolicyEditorValue(routingEditorGetValue() || {});
|
|
4315
|
-
const
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4418
|
+
const basePolicy = toPlainObjectOrNull((UI.routingGroups || {})[selectedGroupId]) || {};
|
|
4419
|
+
const nextPolicy = {
|
|
4420
|
+
...basePolicy,
|
|
4421
|
+
routing: policy.routing
|
|
4319
4422
|
};
|
|
4320
4423
|
if (policy.shouldWriteLoadBalancing) {
|
|
4321
|
-
|
|
4424
|
+
nextPolicy.loadBalancing = policy.loadBalancing || {};
|
|
4425
|
+
} else {
|
|
4426
|
+
delete nextPolicy.loadBalancing;
|
|
4322
4427
|
}
|
|
4323
|
-
const out = await apiFetch(`/config/routing${query}`, {
|
|
4428
|
+
const out = await apiFetch(`/config/routing/groups/${encodeURIComponent(selectedGroupId)}${query}`, {
|
|
4324
4429
|
method: "PUT",
|
|
4325
|
-
body: JSON.stringify(
|
|
4430
|
+
body: JSON.stringify({
|
|
4431
|
+
policy: nextPolicy,
|
|
4432
|
+
location: UI.routingLocation,
|
|
4433
|
+
path: selectedPath || undefined
|
|
4434
|
+
})
|
|
4326
4435
|
});
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4436
|
+
UI.routingLocation = out.location || UI.routingLocation;
|
|
4437
|
+
UI.routingGroups = normalizeRoutingGroupsMap(out.groups);
|
|
4438
|
+
UI.routingActiveGroupId = textOf(out.activeGroupId || UI.routingActiveGroupId || "").trim();
|
|
4439
|
+
renderRoutingGroupSelect(selectedGroupId);
|
|
4440
|
+
loadSelectedRoutingGroupIntoEditor();
|
|
4331
4441
|
setLog(
|
|
4332
4442
|
"routingOpLog",
|
|
4333
|
-
`Saved. Path: ${out.path || "—"}\nLocation: ${UI.routingLocation}\
|
|
4443
|
+
`Saved group. Path: ${out.path || selectedPath || "—"}\nLocation: ${UI.routingLocation}\nselected: ${UI.routingSelectedGroupId || "—"}\nactive: ${UI.routingActiveGroupId || "—"}`
|
|
4334
4444
|
);
|
|
4335
|
-
toast("Routing
|
|
4445
|
+
toast("Routing group saved.", "ok");
|
|
4336
4446
|
routingEditorSetDirty(false);
|
|
4337
4447
|
return out;
|
|
4338
4448
|
} catch (e) {
|
|
@@ -4344,17 +4454,39 @@
|
|
|
4344
4454
|
}
|
|
4345
4455
|
|
|
4346
4456
|
async function saveRoutingAndRestartLocal() {
|
|
4347
|
-
const
|
|
4348
|
-
if (!
|
|
4349
|
-
|
|
4457
|
+
const selectedGroupId = getSelectedRoutingGroupId();
|
|
4458
|
+
if (!selectedGroupId) {
|
|
4459
|
+
toast("No routing group selected.");
|
|
4460
|
+
return;
|
|
4461
|
+
}
|
|
4462
|
+
if (routingEditorState.dirty) {
|
|
4463
|
+
const shouldSave = confirm("Current group has unsaved changes. Save now before activation?");
|
|
4464
|
+
if (!shouldSave) return;
|
|
4465
|
+
const saved = await saveRouting();
|
|
4466
|
+
if (!saved) return;
|
|
4467
|
+
}
|
|
4468
|
+
if (!confirm(`Activate routing group \"${selectedGroupId}\" and reload local runtime now?`)) return;
|
|
4350
4469
|
try {
|
|
4351
|
-
const
|
|
4352
|
-
const
|
|
4470
|
+
const selectedPath = currentRoutingSourcePath();
|
|
4471
|
+
const query = currentRoutingSourceQuery();
|
|
4472
|
+
const out = await apiFetch(`/config/routing/groups/activate${query}`, {
|
|
4473
|
+
method: "POST",
|
|
4474
|
+
body: JSON.stringify({
|
|
4475
|
+
groupId: selectedGroupId,
|
|
4476
|
+
location: UI.routingLocation,
|
|
4477
|
+
path: selectedPath || undefined
|
|
4478
|
+
})
|
|
4479
|
+
});
|
|
4480
|
+
UI.routingLocation = out.location || UI.routingLocation;
|
|
4481
|
+
UI.routingGroups = normalizeRoutingGroupsMap(out.groups);
|
|
4482
|
+
UI.routingActiveGroupId = textOf(out.activeGroupId || selectedGroupId).trim();
|
|
4483
|
+
renderRoutingGroupSelect(selectedGroupId);
|
|
4484
|
+
loadSelectedRoutingGroupIntoEditor();
|
|
4353
4485
|
setLog(
|
|
4354
4486
|
"routingOpLog",
|
|
4355
|
-
`
|
|
4487
|
+
`Activated local.\nPath: ${out.path || selectedPath || "—"}\nselected: ${UI.routingSelectedGroupId || "—"}\nactive: ${UI.routingActiveGroupId || "—"}\nselfReload: ${JSON.stringify(out.selfReload ?? null, null, 2)}`
|
|
4356
4488
|
);
|
|
4357
|
-
toast("Routing
|
|
4489
|
+
toast("Routing group activated (local).", "ok");
|
|
4358
4490
|
await refreshStatus();
|
|
4359
4491
|
await refreshProviders();
|
|
4360
4492
|
await refreshCredentials();
|
|
@@ -4369,13 +4501,37 @@
|
|
|
4369
4501
|
}
|
|
4370
4502
|
|
|
4371
4503
|
async function saveRoutingAndRestartAll() {
|
|
4372
|
-
const
|
|
4373
|
-
if (!
|
|
4504
|
+
const selectedGroupId = getSelectedRoutingGroupId();
|
|
4505
|
+
if (!selectedGroupId) {
|
|
4506
|
+
toast("No routing group selected.");
|
|
4507
|
+
return;
|
|
4508
|
+
}
|
|
4509
|
+
if (routingEditorState.dirty) {
|
|
4510
|
+
const shouldSave = confirm("Current group has unsaved changes. Save now before activation?");
|
|
4511
|
+
if (!shouldSave) return;
|
|
4512
|
+
const saved = await saveRouting();
|
|
4513
|
+
if (!saved) return;
|
|
4514
|
+
}
|
|
4374
4515
|
if (!confirm("Broadcast restart all local RouteCodex servers now?")) return;
|
|
4375
4516
|
try {
|
|
4517
|
+
const selectedPath = currentRoutingSourcePath();
|
|
4518
|
+
const query = currentRoutingSourceQuery();
|
|
4519
|
+
const activated = await apiFetch(`/config/routing/groups/activate${query}`, {
|
|
4520
|
+
method: "POST",
|
|
4521
|
+
body: JSON.stringify({
|
|
4522
|
+
groupId: selectedGroupId,
|
|
4523
|
+
location: UI.routingLocation,
|
|
4524
|
+
path: selectedPath || undefined
|
|
4525
|
+
})
|
|
4526
|
+
});
|
|
4527
|
+
UI.routingLocation = activated.location || UI.routingLocation;
|
|
4528
|
+
UI.routingGroups = normalizeRoutingGroupsMap(activated.groups);
|
|
4529
|
+
UI.routingActiveGroupId = textOf(activated.activeGroupId || selectedGroupId).trim();
|
|
4530
|
+
renderRoutingGroupSelect(selectedGroupId);
|
|
4531
|
+
loadSelectedRoutingGroupIntoEditor();
|
|
4376
4532
|
const out = await controlMutate("servers.restart", {});
|
|
4377
|
-
setLog("routingOpLog", `
|
|
4378
|
-
toast("Routing
|
|
4533
|
+
setLog("routingOpLog", `Activated + restart-all requested.\n${JSON.stringify(out, null, 2)}`);
|
|
4534
|
+
toast("Routing group activated and restart-all requested.", "ok");
|
|
4379
4535
|
await refreshControl();
|
|
4380
4536
|
await refreshStatus();
|
|
4381
4537
|
} catch (e) {
|
|
@@ -4384,6 +4540,106 @@
|
|
|
4384
4540
|
}
|
|
4385
4541
|
}
|
|
4386
4542
|
|
|
4543
|
+
function buildRoutingTemplatePolicyForNewGroup() {
|
|
4544
|
+
const selectedGroupId = getSelectedRoutingGroupId();
|
|
4545
|
+
const groups = normalizeRoutingGroupsMap(UI.routingGroups);
|
|
4546
|
+
const base = toPlainObjectOrNull(groups[selectedGroupId]) || { routing: {} };
|
|
4547
|
+
if (!routingEditorState.dirty) {
|
|
4548
|
+
return { ...base };
|
|
4549
|
+
}
|
|
4550
|
+
const parsed = parseRoutingPolicyEditorValue(routingEditorGetValue() || {});
|
|
4551
|
+
const next = {
|
|
4552
|
+
...base,
|
|
4553
|
+
routing: parsed.routing
|
|
4554
|
+
};
|
|
4555
|
+
if (parsed.shouldWriteLoadBalancing) {
|
|
4556
|
+
next.loadBalancing = parsed.loadBalancing || {};
|
|
4557
|
+
} else {
|
|
4558
|
+
delete next.loadBalancing;
|
|
4559
|
+
}
|
|
4560
|
+
return next;
|
|
4561
|
+
}
|
|
4562
|
+
|
|
4563
|
+
async function createRoutingGroup() {
|
|
4564
|
+
setLog("routingOpLog", "");
|
|
4565
|
+
const auth = UI.adminAuth ? UI.adminAuth : await refreshAdminAuthStatus();
|
|
4566
|
+
if (!auth || !auth.authenticated) {
|
|
4567
|
+
notifyUnauthorizedOnce("routing groups");
|
|
4568
|
+
return;
|
|
4569
|
+
}
|
|
4570
|
+
const input = $("routingGroupNameInput");
|
|
4571
|
+
const groupId = textOf((input && input.value) || "").trim();
|
|
4572
|
+
if (!groupId) {
|
|
4573
|
+
toast("Group id is required.");
|
|
4574
|
+
return;
|
|
4575
|
+
}
|
|
4576
|
+
const selectedPath = currentRoutingSourcePath();
|
|
4577
|
+
const query = currentRoutingSourceQuery();
|
|
4578
|
+
try {
|
|
4579
|
+
const policy = buildRoutingTemplatePolicyForNewGroup();
|
|
4580
|
+
const out = await apiFetch(`/config/routing/groups/${encodeURIComponent(groupId)}${query}`, {
|
|
4581
|
+
method: "PUT",
|
|
4582
|
+
body: JSON.stringify({
|
|
4583
|
+
policy,
|
|
4584
|
+
location: UI.routingLocation,
|
|
4585
|
+
path: selectedPath || undefined
|
|
4586
|
+
})
|
|
4587
|
+
});
|
|
4588
|
+
UI.routingLocation = out.location || UI.routingLocation;
|
|
4589
|
+
UI.routingGroups = normalizeRoutingGroupsMap(out.groups);
|
|
4590
|
+
UI.routingActiveGroupId = textOf(out.activeGroupId || UI.routingActiveGroupId || "").trim();
|
|
4591
|
+
renderRoutingGroupSelect(groupId);
|
|
4592
|
+
loadSelectedRoutingGroupIntoEditor();
|
|
4593
|
+
if (input) input.value = "";
|
|
4594
|
+
setLog(
|
|
4595
|
+
"routingOpLog",
|
|
4596
|
+
`Created/updated group.\nPath: ${out.path || selectedPath || "—"}\nselected: ${UI.routingSelectedGroupId || "—"}\nactive: ${UI.routingActiveGroupId || "—"}`
|
|
4597
|
+
);
|
|
4598
|
+
toast("Routing group created/updated.", "ok");
|
|
4599
|
+
} catch (e) {
|
|
4600
|
+
if (e && e.status === 401) notifyUnauthorizedOnce("routing groups");
|
|
4601
|
+
setLog("routingOpLog", `Create group failed: ${e && e.message ? e.message : String(e)}`);
|
|
4602
|
+
toast(`Create group failed: ${e && e.message ? e.message : String(e)}`);
|
|
4603
|
+
}
|
|
4604
|
+
}
|
|
4605
|
+
|
|
4606
|
+
async function deleteRoutingGroup() {
|
|
4607
|
+
setLog("routingOpLog", "");
|
|
4608
|
+
const auth = UI.adminAuth ? UI.adminAuth : await refreshAdminAuthStatus();
|
|
4609
|
+
if (!auth || !auth.authenticated) {
|
|
4610
|
+
notifyUnauthorizedOnce("routing groups");
|
|
4611
|
+
return;
|
|
4612
|
+
}
|
|
4613
|
+
const groupId = getSelectedRoutingGroupId();
|
|
4614
|
+
if (!groupId) {
|
|
4615
|
+
toast("No routing group selected.");
|
|
4616
|
+
return;
|
|
4617
|
+
}
|
|
4618
|
+
if (!confirm(`Delete routing group \"${groupId}\"?`)) return;
|
|
4619
|
+
try {
|
|
4620
|
+
const queryBase = currentRoutingSourceQuery();
|
|
4621
|
+
const locationPart = UI.routingLocation ? `${queryBase ? "&" : "?"}location=${encodeURIComponent(UI.routingLocation)}` : "";
|
|
4622
|
+
const query = `${queryBase}${locationPart}`;
|
|
4623
|
+
const out = await apiFetch(`/config/routing/groups/${encodeURIComponent(groupId)}${query}`, {
|
|
4624
|
+
method: "DELETE"
|
|
4625
|
+
});
|
|
4626
|
+
UI.routingLocation = out.location || UI.routingLocation;
|
|
4627
|
+
UI.routingGroups = normalizeRoutingGroupsMap(out.groups);
|
|
4628
|
+
UI.routingActiveGroupId = textOf(out.activeGroupId || UI.routingActiveGroupId || "").trim();
|
|
4629
|
+
renderRoutingGroupSelect();
|
|
4630
|
+
loadSelectedRoutingGroupIntoEditor();
|
|
4631
|
+
setLog(
|
|
4632
|
+
"routingOpLog",
|
|
4633
|
+
`Deleted group \"${groupId}\".\nPath: ${out.path || currentRoutingSourcePath() || "—"}\nselected: ${UI.routingSelectedGroupId || "—"}\nactive: ${UI.routingActiveGroupId || "—"}`
|
|
4634
|
+
);
|
|
4635
|
+
toast("Routing group deleted.", "ok");
|
|
4636
|
+
} catch (e) {
|
|
4637
|
+
if (e && e.status === 401) notifyUnauthorizedOnce("routing groups");
|
|
4638
|
+
setLog("routingOpLog", `Delete group failed: ${e && e.message ? e.message : String(e)}`);
|
|
4639
|
+
toast(`Delete group failed: ${e && e.message ? e.message : String(e)}`);
|
|
4640
|
+
}
|
|
4641
|
+
}
|
|
4642
|
+
|
|
4387
4643
|
async function refreshRoutingSources() {
|
|
4388
4644
|
const select = $("routingSourceSelect");
|
|
4389
4645
|
if (!select) return;
|
|
@@ -5642,8 +5898,23 @@
|
|
|
5642
5898
|
$("saveRoutingBtn").addEventListener("click", saveRouting);
|
|
5643
5899
|
$("saveRoutingRestartLocalBtn").addEventListener("click", () => void saveRoutingAndRestartLocal());
|
|
5644
5900
|
$("saveRoutingRestartAllBtn").addEventListener("click", () => void saveRoutingAndRestartAll());
|
|
5901
|
+
$("createRoutingGroupBtn").addEventListener("click", () => void createRoutingGroup());
|
|
5902
|
+
$("deleteRoutingGroupBtn").addEventListener("click", () => void deleteRoutingGroup());
|
|
5645
5903
|
$("refreshRoutingSourcesBtn").addEventListener("click", refreshRoutingSources);
|
|
5646
|
-
$("routingSourceSelect").addEventListener("change",
|
|
5904
|
+
$("routingSourceSelect").addEventListener("change", async () => {
|
|
5905
|
+
if (routingEditorState.dirty && !confirm("Discard unsaved routing editor changes and switch source?")) {
|
|
5906
|
+
return;
|
|
5907
|
+
}
|
|
5908
|
+
await loadRouting();
|
|
5909
|
+
});
|
|
5910
|
+
$("routingGroupSelect").addEventListener("change", () => {
|
|
5911
|
+
if (routingEditorState.dirty && !confirm("Discard unsaved routing editor changes and switch group?")) {
|
|
5912
|
+
renderRoutingGroupSelect(UI.routingSelectedGroupId || UI.routingActiveGroupId || "");
|
|
5913
|
+
return;
|
|
5914
|
+
}
|
|
5915
|
+
UI.routingSelectedGroupId = textOf($("routingGroupSelect").value || "").trim();
|
|
5916
|
+
loadSelectedRoutingGroupIntoEditor();
|
|
5917
|
+
});
|
|
5647
5918
|
$("routingRegExpandBtn").addEventListener("click", () => setAllDetailsOpen($("routingKvEditor"), true));
|
|
5648
5919
|
$("routingRegCollapseBtn").addEventListener("click", () => setAllDetailsOpen($("routingKvEditor"), false));
|
|
5649
5920
|
$("refreshRoutingPoolBtn").addEventListener("click", async () => {
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# ServerTool / StopMessage Lifecycle (tmux-only)
|
|
2
|
+
|
|
3
|
+
## 1. Scope
|
|
4
|
+
|
|
5
|
+
This document defines the only valid lifecycle for:
|
|
6
|
+
|
|
7
|
+
- `stopMessage`
|
|
8
|
+
- `clock` client injection
|
|
9
|
+
- `continue_execution` client injection
|
|
10
|
+
|
|
11
|
+
Design goals:
|
|
12
|
+
|
|
13
|
+
1. Trigger logic stays in Chat Process response orchestration.
|
|
14
|
+
2. Execution path is tmux stdin injection only.
|
|
15
|
+
3. `stopMessage` does not use nested reenter model requests.
|
|
16
|
+
4. State is scoped by `tmux:<sessionId>` only.
|
|
17
|
+
|
|
18
|
+
## 2. Current Code Entry Points
|
|
19
|
+
|
|
20
|
+
- Request metadata resolution: `src/server/runtime/http-server/executor-metadata.ts`
|
|
21
|
+
- Scope resolution: `src/server/runtime/http-server/clock-scope-resolution.ts`
|
|
22
|
+
- Injection implementation: `src/server/runtime/http-server/executor/client-injection-flow.ts`
|
|
23
|
+
- ServerTool orchestration (response side): `sharedmodule/llmswitch-core/src/servertool/engine.ts`
|
|
24
|
+
- StopMessage handler: `sharedmodule/llmswitch-core/src/servertool/handlers/stop-message-auto.ts`
|
|
25
|
+
- Routing state store (tmux scope selection): `sharedmodule/llmswitch-core/src/router/virtual-router/engine/routing-state/store.ts`
|
|
26
|
+
|
|
27
|
+
## 3. Lifecycle (Approved Target)
|
|
28
|
+
|
|
29
|
+
1. Client starts via `routecodex codex` / `routecodex claude` inside tmux.
|
|
30
|
+
2. Client request carries tmux metadata (`tmuxSessionId` family fields / headers).
|
|
31
|
+
3. Server resolves tmux session and marks `clientInjectReady=true`.
|
|
32
|
+
4. User sends `<**stopMessage,...**>` instruction.
|
|
33
|
+
5. Chat-process parser saves instruction state under `tmux:<sessionId>`.
|
|
34
|
+
6. Model response reaches response orchestration.
|
|
35
|
+
7. StopMessage matcher runs in chat-process servertool stage.
|
|
36
|
+
8. If matched, build reviewer followup text.
|
|
37
|
+
9. Dispatch to client injection (tmux stdin) directly.
|
|
38
|
+
10. Injection success: increment `used`, keep/update state.
|
|
39
|
+
11. Injection failure: clear stopMessage state for that tmux scope, skip followup.
|
|
40
|
+
12. Main request must still complete (no request-level hard failure only because stopMessage inject failed).
|
|
41
|
+
|
|
42
|
+
## 4. Hard Rules
|
|
43
|
+
|
|
44
|
+
1. Split dispatch:
|
|
45
|
+
- Normal servertools (e.g. search/vision) may use `reenterPipeline`.
|
|
46
|
+
- `stopMessage/clock/continue_execution` must use client injection dispatcher only.
|
|
47
|
+
|
|
48
|
+
2. No fallback:
|
|
49
|
+
- No old session-based fallback compare.
|
|
50
|
+
- No daemon-only fallback for stopMessage matching.
|
|
51
|
+
|
|
52
|
+
3. Scope:
|
|
53
|
+
- All stopMessage state read/write keys are `tmux:<sessionId>`.
|
|
54
|
+
|
|
55
|
+
4. Set behavior:
|
|
56
|
+
- If tmux scope missing when setting stopMessage: drop set instruction, keep request normal.
|
|
57
|
+
|
|
58
|
+
5. Trigger behavior:
|
|
59
|
+
- If tmux not ready at trigger time: clear stale state and skip followup (no loop).
|
|
60
|
+
|
|
61
|
+
## 5. Client Restart Rebinding (New Requirement)
|
|
62
|
+
|
|
63
|
+
When tmux client restarts and re-registers:
|
|
64
|
+
|
|
65
|
+
1. Registration updates daemon->tmux mapping immediately.
|
|
66
|
+
2. If previous stopMessage state exists under old tmux scope and the same daemon/client identity is re-registered with a new tmux session, migrate stopMessage binding to the new `tmux:<newSessionId>` scope.
|
|
67
|
+
3. Migration is atomic:
|
|
68
|
+
- copy state to new tmux scope
|
|
69
|
+
- delete old tmux scope state
|
|
70
|
+
4. If old tmux session is already gone and no valid rebind target exists, clean old state.
|
|
71
|
+
|
|
72
|
+
This prevents:
|
|
73
|
+
|
|
74
|
+
- trigger using stale scope
|
|
75
|
+
- inject lookup miss loops after client restart
|
|
76
|
+
|
|
77
|
+
## 6. Observability Requirements
|
|
78
|
+
|
|
79
|
+
Required logs:
|
|
80
|
+
|
|
81
|
+
1. stopMessage set parse:
|
|
82
|
+
- parse success/fail
|
|
83
|
+
- resolved tmux scope
|
|
84
|
+
|
|
85
|
+
2. stopMessage match:
|
|
86
|
+
- matched/miss
|
|
87
|
+
- reason
|
|
88
|
+
- scope
|
|
89
|
+
|
|
90
|
+
3. client injection:
|
|
91
|
+
- selected tmux session
|
|
92
|
+
- submit key result
|
|
93
|
+
- success/failure reason
|
|
94
|
+
|
|
95
|
+
4. state mutation:
|
|
96
|
+
- set/override
|
|
97
|
+
- trigger used counter
|
|
98
|
+
- clear on failure
|
|
99
|
+
- rebind migration (old scope -> new scope)
|
|
100
|
+
|
|
101
|
+
## 7. Validation Checklist
|
|
102
|
+
|
|
103
|
+
1. Set stopMessage in tmux session A -> state key is `tmux:A`.
|
|
104
|
+
2. Trigger matched response -> tmux A receives injected text + enter.
|
|
105
|
+
3. Counter decrements and persists.
|
|
106
|
+
4. Restart client with new tmux session B (same client identity) -> state migrates to `tmux:B`.
|
|
107
|
+
5. Next trigger injects into B, not A.
|
|
108
|
+
6. Injection failure clears active state and does not create reenter loop.
|
|
109
|
+
7. Non-stop servertools still execute through normal reenter path.
|
|
@@ -36,7 +36,13 @@
|
|
|
36
36
|
"pattern": "\\b(xargs\\s+rm\\b|for\\s+[^;\\n]+;\\s*do\\s+rm\\b|while\\s+[^;\\n]+;\\s*do\\s+rm\\b)",
|
|
37
37
|
"flags": "i",
|
|
38
38
|
"reason": "Loop/batch deletion is not allowed"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"id": "deny-mass-kill-commands",
|
|
42
|
+
"type": "regex",
|
|
43
|
+
"pattern": "\\bpkill\\b|\\bkillall\\b|\\btaskkill\\b|\\bxargs\\b[^\\n]*\\bkill\\b|\\blsof\\b[^\\n]*\\|[^\\n]*\\bxargs\\b[^\\n]*\\bkill\\b",
|
|
44
|
+
"flags": "i",
|
|
45
|
+
"reason": "mass kill command is not allowed"
|
|
39
46
|
}
|
|
40
47
|
]
|
|
41
48
|
}
|
|
42
|
-
|
|
@@ -171,9 +171,9 @@ antigravity/<version> <os>/<arch>
|
|
|
171
171
|
版本解析顺序(从高到低):
|
|
172
172
|
1. 显式 UA:`ROUTECODEX_ANTIGRAVITY_USER_AGENT` / `RCC_ANTIGRAVITY_USER_AGENT`(完全覆盖)
|
|
173
173
|
2. 显式版本号:`ROUTECODEX_ANTIGRAVITY_UA_VERSION` / `RCC_ANTIGRAVITY_UA_VERSION`
|
|
174
|
-
3. 远程拉取:`VERSION_URL`(可用 `ROUTECODEX_ANTIGRAVITY_UA_DISABLE_REMOTE=1` 禁用)
|
|
174
|
+
3. 远程拉取:`VERSION_URL`,失败时回退 `CHANGELOG_URL`(可用 `ROUTECODEX_ANTIGRAVITY_UA_DISABLE_REMOTE=1` 禁用)
|
|
175
175
|
4. 本地磁盘 cache:`~/.routecodex/state/antigravity-ua-version.json`
|
|
176
|
-
5. 最后兜底:`
|
|
176
|
+
5. 最后兜底:`KNOWN_STABLE_VERSION`(当前 `4.1.24`,对齐 Antigravity-Manager)
|
|
177
177
|
|
|
178
178
|
### 4.3 `<os>/<arch>` suffix 如何从指纹推断(并且为何禁 linux)
|
|
179
179
|
|