@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
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
|
|
7
|
+
const ROOT =
|
|
8
|
+
process.env.ROUTECODEX_ERROR_SAMPLES_DIR &&
|
|
9
|
+
process.env.ROUTECODEX_ERROR_SAMPLES_DIR.trim().length
|
|
10
|
+
? path.resolve(process.env.ROUTECODEX_ERROR_SAMPLES_DIR)
|
|
11
|
+
: path.join(os.homedir(), '.routecodex', 'errorsamples');
|
|
12
|
+
|
|
13
|
+
const SKIP_SUBDIR = (() => {
|
|
14
|
+
const raw = String(process.env.ROUTECODEX_ERROR_SAMPLES_SKIP_SUBDIR || '').trim();
|
|
15
|
+
return raw || 'skip';
|
|
16
|
+
})();
|
|
17
|
+
const GOLD_SUBDIR = (() => {
|
|
18
|
+
const raw = String(process.env.ROUTECODEX_ERROR_SAMPLES_GOLD_SUBDIR || '').trim();
|
|
19
|
+
return raw || 'gold';
|
|
20
|
+
})();
|
|
21
|
+
|
|
22
|
+
const SHAPE_ERROR_PATTERNS = [
|
|
23
|
+
'failed to parse function arguments: missing field `cmd`',
|
|
24
|
+
'failed to parse function arguments: missing field `input`',
|
|
25
|
+
'failed to parse function arguments: missing field `command`',
|
|
26
|
+
'invalid type: map, expected a string'
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
const APPLY_PATCH_SHAPE_PATTERNS = [
|
|
30
|
+
'invalid patch',
|
|
31
|
+
'failed to parse',
|
|
32
|
+
'missing field `input`',
|
|
33
|
+
'missing field `cmd`',
|
|
34
|
+
'missing field `command`',
|
|
35
|
+
'invalid type: map, expected a string'
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const APPLY_PATCH_NON_SHAPE_PATTERNS = [
|
|
39
|
+
'failed to find context',
|
|
40
|
+
'failed to find expected lines',
|
|
41
|
+
'failed to read file',
|
|
42
|
+
'no such file',
|
|
43
|
+
'file not found'
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
function isJsonFile(name) {
|
|
47
|
+
return name.toLowerCase().endsWith('.json');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function exists(p) {
|
|
51
|
+
try {
|
|
52
|
+
await fs.access(p);
|
|
53
|
+
return true;
|
|
54
|
+
} catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function collectSampleFiles(rootDir) {
|
|
60
|
+
const files = [];
|
|
61
|
+
const queue = [rootDir];
|
|
62
|
+
|
|
63
|
+
while (queue.length > 0) {
|
|
64
|
+
const currentDir = queue.shift();
|
|
65
|
+
if (!currentDir) continue;
|
|
66
|
+
|
|
67
|
+
let entries = [];
|
|
68
|
+
try {
|
|
69
|
+
entries = await fs.readdir(currentDir, { withFileTypes: true });
|
|
70
|
+
} catch {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (const entry of entries) {
|
|
75
|
+
const fullPath = path.join(currentDir, entry.name);
|
|
76
|
+
if (entry.isDirectory()) {
|
|
77
|
+
queue.push(fullPath);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (!entry.isFile()) continue;
|
|
81
|
+
if (!isJsonFile(entry.name)) continue;
|
|
82
|
+
files.push(fullPath);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return files.sort();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function classifySample(raw) {
|
|
90
|
+
const lower = raw.toLowerCase();
|
|
91
|
+
|
|
92
|
+
const shapeHits = SHAPE_ERROR_PATTERNS.filter((pattern) => raw.includes(pattern));
|
|
93
|
+
if (shapeHits.length > 0) {
|
|
94
|
+
return { kind: 'shape', hits: shapeHits };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (lower.includes('apply_patch verification failed')) {
|
|
98
|
+
const shapeMatched = APPLY_PATCH_SHAPE_PATTERNS.filter((needle) => lower.includes(needle));
|
|
99
|
+
if (shapeMatched.length > 0) {
|
|
100
|
+
return { kind: 'shape', hits: ['apply_patch verification failed (shape)'] };
|
|
101
|
+
}
|
|
102
|
+
const nonShapeMatched = APPLY_PATCH_NON_SHAPE_PATTERNS.filter((needle) => lower.includes(needle));
|
|
103
|
+
if (nonShapeMatched.length > 0) {
|
|
104
|
+
return { kind: 'non_shape', hits: ['apply_patch verification failed (context/non-shape)'] };
|
|
105
|
+
}
|
|
106
|
+
return { kind: 'non_shape', hits: ['apply_patch verification failed (unknown subtype)'] };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return { kind: 'none', hits: [] };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function inIgnoredSubdir(filePath) {
|
|
113
|
+
const rel = path.relative(ROOT, filePath);
|
|
114
|
+
if (rel.startsWith('..') || path.isAbsolute(rel)) {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
const parts = rel.split(path.sep).filter(Boolean);
|
|
118
|
+
return parts.includes(SKIP_SUBDIR) || parts.includes(GOLD_SUBDIR);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function moveIntoSkip(filePath) {
|
|
122
|
+
const rel = path.relative(ROOT, filePath);
|
|
123
|
+
const target = path.join(ROOT, SKIP_SUBDIR, rel);
|
|
124
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
125
|
+
await fs.rename(filePath, target);
|
|
126
|
+
return target;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function moveIntoGold(filePath) {
|
|
130
|
+
const rel = path.relative(ROOT, filePath);
|
|
131
|
+
const target = path.join(ROOT, GOLD_SUBDIR, rel);
|
|
132
|
+
await fs.mkdir(path.dirname(target), { recursive: true });
|
|
133
|
+
await fs.rename(filePath, target);
|
|
134
|
+
return target;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function main() {
|
|
138
|
+
const apply = process.argv.includes('--apply');
|
|
139
|
+
|
|
140
|
+
if (!(await exists(ROOT))) {
|
|
141
|
+
console.log(`[triage:errorsamples] skip (directory not found: ${ROOT})`);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const files = await collectSampleFiles(ROOT);
|
|
146
|
+
if (!files.length) {
|
|
147
|
+
console.log(`[triage:errorsamples] skip (no *.json samples under ${ROOT})`);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const shape = [];
|
|
152
|
+
const nonShape = [];
|
|
153
|
+
for (const file of files) {
|
|
154
|
+
if (inIgnoredSubdir(file)) {
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
let raw = '';
|
|
158
|
+
try {
|
|
159
|
+
raw = await fs.readFile(file, 'utf-8');
|
|
160
|
+
} catch {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const classified = classifySample(raw);
|
|
164
|
+
if (classified.kind === 'shape') {
|
|
165
|
+
shape.push({ file, hits: classified.hits });
|
|
166
|
+
} else if (classified.kind === 'non_shape') {
|
|
167
|
+
nonShape.push({ file, hits: classified.hits });
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
console.log(`[triage:errorsamples] scanned: ${files.length}`);
|
|
172
|
+
console.log(`[triage:errorsamples] shape/actionable: ${shape.length}`);
|
|
173
|
+
console.log(`[triage:errorsamples] non-shape/skip-candidate: ${nonShape.length}`);
|
|
174
|
+
|
|
175
|
+
if (shape.length > 0) {
|
|
176
|
+
console.log('[triage:errorsamples] actionable shape samples (move to gold regression set):');
|
|
177
|
+
for (const item of shape.slice(0, 20)) {
|
|
178
|
+
console.log(` - ${path.basename(item.file)} → ${item.hits.join(', ')}`);
|
|
179
|
+
}
|
|
180
|
+
if (shape.length > 20) {
|
|
181
|
+
console.log(` - ... and ${shape.length - 20} more`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!apply) {
|
|
186
|
+
console.log(`[triage:errorsamples] dry-run complete (pass --apply to move shape -> ${GOLD_SUBDIR}/ and non-shape -> ${SKIP_SUBDIR}/)`);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
let movedGold = 0;
|
|
191
|
+
for (const item of shape) {
|
|
192
|
+
try {
|
|
193
|
+
await moveIntoGold(item.file);
|
|
194
|
+
movedGold += 1;
|
|
195
|
+
} catch {
|
|
196
|
+
// best-effort
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let movedSkip = 0;
|
|
201
|
+
for (const item of nonShape) {
|
|
202
|
+
try {
|
|
203
|
+
await moveIntoSkip(item.file);
|
|
204
|
+
movedSkip += 1;
|
|
205
|
+
} catch {
|
|
206
|
+
// best-effort
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
console.log(`[triage:errorsamples] moved to ${GOLD_SUBDIR}/: ${movedGold}/${shape.length}`);
|
|
210
|
+
console.log(`[triage:errorsamples] moved to ${SKIP_SUBDIR}/: ${movedSkip}/${nonShape.length}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
main().catch((error) => {
|
|
214
|
+
console.error('[triage:errorsamples] failed:', error);
|
|
215
|
+
process.exit(99);
|
|
216
|
+
});
|
|
@@ -22,13 +22,40 @@ const ROOT =
|
|
|
22
22
|
process.env.ROUTECODEX_ERROR_SAMPLES_DIR.trim().length
|
|
23
23
|
? path.resolve(process.env.ROUTECODEX_ERROR_SAMPLES_DIR)
|
|
24
24
|
: path.join(os.homedir(), '.routecodex', 'errorsamples');
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
25
|
+
const SKIP_SUBDIR = (() => {
|
|
26
|
+
const raw = String(process.env.ROUTECODEX_ERROR_SAMPLES_SKIP_SUBDIR || '').trim();
|
|
27
|
+
return raw || 'skip';
|
|
28
|
+
})();
|
|
29
|
+
const GOLD_SUBDIR = (() => {
|
|
30
|
+
const raw = String(process.env.ROUTECODEX_ERROR_SAMPLES_GOLD_SUBDIR || '').trim();
|
|
31
|
+
return raw || 'gold';
|
|
32
|
+
})();
|
|
33
|
+
|
|
34
|
+
const SHAPE_ERROR_PATTERNS = [
|
|
35
|
+
// exec_command / shell_command / apply_patch 参数形状错误
|
|
28
36
|
'failed to parse function arguments: missing field `cmd`',
|
|
29
37
|
'failed to parse function arguments: missing field `input`',
|
|
30
|
-
|
|
31
|
-
'
|
|
38
|
+
'failed to parse function arguments: missing field `command`',
|
|
39
|
+
'invalid type: map, expected a string'
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
const APPLY_PATCH_SHAPE_PATTERNS = [
|
|
43
|
+
// apply_patch 仍属于“可修复形状问题”的子类
|
|
44
|
+
'invalid patch',
|
|
45
|
+
'failed to parse',
|
|
46
|
+
'missing field `input`',
|
|
47
|
+
'missing field `cmd`',
|
|
48
|
+
'missing field `command`',
|
|
49
|
+
'invalid type: map, expected a string'
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const APPLY_PATCH_NON_SHAPE_PATTERNS = [
|
|
53
|
+
// 这些是上下文/执行问题,不应作为“形状回归”阻塞构建
|
|
54
|
+
'failed to find context',
|
|
55
|
+
'failed to find expected lines',
|
|
56
|
+
'failed to read file',
|
|
57
|
+
'no such file',
|
|
58
|
+
'file not found'
|
|
32
59
|
];
|
|
33
60
|
|
|
34
61
|
async function fileExists(p) {
|
|
@@ -43,6 +70,8 @@ async function fileExists(p) {
|
|
|
43
70
|
async function collectSampleFiles(rootDir) {
|
|
44
71
|
const files = [];
|
|
45
72
|
const queue = [rootDir];
|
|
73
|
+
const skippedDirs = [];
|
|
74
|
+
const goldDirs = [];
|
|
46
75
|
|
|
47
76
|
while (queue.length > 0) {
|
|
48
77
|
const currentDir = queue.shift();
|
|
@@ -60,6 +89,14 @@ async function collectSampleFiles(rootDir) {
|
|
|
60
89
|
for (const entry of entries) {
|
|
61
90
|
const fullPath = path.join(currentDir, entry.name);
|
|
62
91
|
if (entry.isDirectory()) {
|
|
92
|
+
if (entry.name === SKIP_SUBDIR) {
|
|
93
|
+
skippedDirs.push(fullPath);
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (entry.name === GOLD_SUBDIR) {
|
|
97
|
+
goldDirs.push(fullPath);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
63
100
|
queue.push(fullPath);
|
|
64
101
|
continue;
|
|
65
102
|
}
|
|
@@ -69,18 +106,38 @@ async function collectSampleFiles(rootDir) {
|
|
|
69
106
|
}
|
|
70
107
|
}
|
|
71
108
|
|
|
72
|
-
return
|
|
109
|
+
return {
|
|
110
|
+
files: files.sort(),
|
|
111
|
+
skippedDirs,
|
|
112
|
+
goldDirs
|
|
113
|
+
};
|
|
73
114
|
}
|
|
74
115
|
|
|
75
116
|
async function checkFile(filePath) {
|
|
76
117
|
const raw = await fs.readFile(filePath, 'utf-8');
|
|
77
|
-
const
|
|
78
|
-
|
|
118
|
+
const lower = raw.toLowerCase();
|
|
119
|
+
const failHits = [];
|
|
120
|
+
const warnHits = [];
|
|
121
|
+
|
|
122
|
+
for (const pattern of SHAPE_ERROR_PATTERNS) {
|
|
79
123
|
if (raw.includes(pattern)) {
|
|
80
|
-
|
|
124
|
+
failHits.push(pattern);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (lower.includes('apply_patch verification failed')) {
|
|
129
|
+
const shapeMatched = APPLY_PATCH_SHAPE_PATTERNS.some((needle) => lower.includes(needle));
|
|
130
|
+
const nonShapeMatched = APPLY_PATCH_NON_SHAPE_PATTERNS.some((needle) => lower.includes(needle));
|
|
131
|
+
if (shapeMatched) {
|
|
132
|
+
failHits.push('apply_patch verification failed (shape)');
|
|
133
|
+
} else if (nonShapeMatched) {
|
|
134
|
+
warnHits.push('apply_patch verification failed (context/non-shape)');
|
|
135
|
+
} else {
|
|
136
|
+
warnHits.push('apply_patch verification failed (unknown subtype)');
|
|
81
137
|
}
|
|
82
138
|
}
|
|
83
|
-
|
|
139
|
+
|
|
140
|
+
return { failHits, warnHits };
|
|
84
141
|
}
|
|
85
142
|
|
|
86
143
|
async function main() {
|
|
@@ -89,24 +146,44 @@ async function main() {
|
|
|
89
146
|
return;
|
|
90
147
|
}
|
|
91
148
|
|
|
92
|
-
const files = await collectSampleFiles(ROOT);
|
|
149
|
+
const { files, skippedDirs, goldDirs } = await collectSampleFiles(ROOT);
|
|
93
150
|
if (!files.length) {
|
|
94
151
|
console.log(`[verify:errorsamples] skip (no *.json samples under ${ROOT})`);
|
|
95
152
|
return;
|
|
96
153
|
}
|
|
97
154
|
|
|
98
155
|
console.log(`[verify:errorsamples] scanning ${files.length} sample(s) under ${ROOT}`);
|
|
156
|
+
if (skippedDirs.length > 0) {
|
|
157
|
+
console.log(`[verify:errorsamples] skip subdir "${SKIP_SUBDIR}" (${skippedDirs.length} dir(s))`);
|
|
158
|
+
}
|
|
159
|
+
if (goldDirs.length > 0) {
|
|
160
|
+
console.log(`[verify:errorsamples] gold subdir "${GOLD_SUBDIR}" (${goldDirs.length} dir(s))`);
|
|
161
|
+
}
|
|
99
162
|
|
|
100
163
|
const failures = [];
|
|
164
|
+
const warnings = [];
|
|
101
165
|
for (const file of files) {
|
|
102
|
-
const
|
|
103
|
-
if (
|
|
104
|
-
failures.push({ file, hits });
|
|
166
|
+
const { failHits, warnHits } = await checkFile(file);
|
|
167
|
+
if (failHits.length) {
|
|
168
|
+
failures.push({ file, hits: failHits });
|
|
169
|
+
}
|
|
170
|
+
if (warnHits.length) {
|
|
171
|
+
warnings.push({ file, hits: warnHits });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (warnings.length > 0) {
|
|
176
|
+
console.log(`[verify:errorsamples] warning-only samples: ${warnings.length}`);
|
|
177
|
+
for (const item of warnings.slice(0, 8)) {
|
|
178
|
+
console.log(` - ${path.basename(item.file)} → ${item.hits.join(', ')}`);
|
|
179
|
+
}
|
|
180
|
+
if (warnings.length > 8) {
|
|
181
|
+
console.log(` - ... and ${warnings.length - 8} more warning sample(s)`);
|
|
105
182
|
}
|
|
106
183
|
}
|
|
107
184
|
|
|
108
185
|
if (!failures.length) {
|
|
109
|
-
console.log('[verify:errorsamples] ✅ no
|
|
186
|
+
console.log('[verify:errorsamples] ✅ no shape-error regressions found');
|
|
110
187
|
return;
|
|
111
188
|
}
|
|
112
189
|
|
|
@@ -7,19 +7,20 @@ import fs from 'node:fs';
|
|
|
7
7
|
import os from 'node:os';
|
|
8
8
|
import path from 'node:path';
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const REQUESTED_PORT = Number(process.env.ROUTECODEX_INSTALL_VERIFY_PORT || process.env.RCC_INSTALL_VERIFY_PORT || 5560);
|
|
11
11
|
const HOST = process.env.ROUTECODEX_INSTALL_VERIFY_HOST || '127.0.0.1';
|
|
12
|
-
const
|
|
12
|
+
const PORT_SEARCH_LIMIT = 50;
|
|
13
13
|
|
|
14
|
-
function
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
function resolveServerEntryArgs() {
|
|
15
|
+
const serverEntry = path.join(process.cwd(), 'dist', 'index.js');
|
|
16
|
+
const modulesConfigPath = path.join(process.cwd(), 'dist', 'config', 'modules.json');
|
|
17
|
+
if (!fs.existsSync(serverEntry)) {
|
|
18
|
+
throw new Error(`verify-install-e2e missing server entry: ${serverEntry}`);
|
|
19
|
+
}
|
|
20
|
+
if (!fs.existsSync(modulesConfigPath)) {
|
|
21
|
+
throw new Error(`verify-install-e2e missing modules config: ${modulesConfigPath}`);
|
|
21
22
|
}
|
|
22
|
-
return
|
|
23
|
+
return [serverEntry, modulesConfigPath];
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
function cleanupStaleServerPidFiles() {
|
|
@@ -32,11 +33,11 @@ function cleanupStaleServerPidFiles() {
|
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
async function waitForHealth(timeoutMs = 60000) {
|
|
36
|
+
async function waitForHealth(baseUrl, timeoutMs = 60000) {
|
|
36
37
|
const start = Date.now();
|
|
37
38
|
while (Date.now() - start < timeoutMs) {
|
|
38
39
|
try {
|
|
39
|
-
const res = await fetch(`${
|
|
40
|
+
const res = await fetch(`${baseUrl}/health`);
|
|
40
41
|
if (res.ok) {
|
|
41
42
|
return;
|
|
42
43
|
}
|
|
@@ -48,7 +49,7 @@ async function waitForHealth(timeoutMs = 60000) {
|
|
|
48
49
|
throw new Error('Timed out waiting for /health');
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
async function runChatTest() {
|
|
52
|
+
async function runChatTest(baseUrl) {
|
|
52
53
|
const payload = {
|
|
53
54
|
model: process.env.ROUTECODEX_VERIFY_CHAT_MODEL || 'glm-4.6',
|
|
54
55
|
messages: [
|
|
@@ -57,7 +58,7 @@ async function runChatTest() {
|
|
|
57
58
|
],
|
|
58
59
|
stream: false
|
|
59
60
|
};
|
|
60
|
-
const res = await fetch(`${
|
|
61
|
+
const res = await fetch(`${baseUrl}/v1/chat/completions`, {
|
|
61
62
|
method: 'POST',
|
|
62
63
|
headers: { 'Content-Type': 'application/json' },
|
|
63
64
|
body: JSON.stringify(payload)
|
|
@@ -76,7 +77,7 @@ async function runChatTest() {
|
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
79
|
|
|
79
|
-
async function runAnthropicSseTest() {
|
|
80
|
+
async function runAnthropicSseTest(baseUrl) {
|
|
80
81
|
const payload = {
|
|
81
82
|
model: process.env.ROUTECODEX_VERIFY_ANTHROPIC_MODEL || 'glm-4.6',
|
|
82
83
|
messages: [
|
|
@@ -84,7 +85,7 @@ async function runAnthropicSseTest() {
|
|
|
84
85
|
],
|
|
85
86
|
stream: true
|
|
86
87
|
};
|
|
87
|
-
const res = await fetch(`${
|
|
88
|
+
const res = await fetch(`${baseUrl}/v1/messages`, {
|
|
88
89
|
method: 'POST',
|
|
89
90
|
headers: {
|
|
90
91
|
'Content-Type': 'application/json',
|
|
@@ -125,14 +126,16 @@ async function runAnthropicSseTest() {
|
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
async function main() {
|
|
128
|
-
const
|
|
129
|
+
const port = await resolveVerifyPort(REQUESTED_PORT, HOST);
|
|
130
|
+
const baseUrl = `http://${HOST}:${port}`;
|
|
131
|
+
const serverArgs = resolveServerEntryArgs();
|
|
129
132
|
const customConfigPath = process.env.ROUTECODEX_INSTALL_CONFIG;
|
|
130
133
|
const mockServer = customConfigPath ? null : await startMockProviderServer();
|
|
131
|
-
const verifyConfigPath = customConfigPath || await writeVerifyConfig(mockServer.baseUrl);
|
|
134
|
+
const verifyConfigPath = customConfigPath || await writeVerifyConfig(mockServer.baseUrl, HOST, port);
|
|
132
135
|
const env = {
|
|
133
136
|
...process.env,
|
|
134
|
-
ROUTECODEX_PORT: String(
|
|
135
|
-
RCC_PORT: String(
|
|
137
|
+
ROUTECODEX_PORT: String(port),
|
|
138
|
+
RCC_PORT: String(port),
|
|
136
139
|
ROUTECODEX_HOST: HOST,
|
|
137
140
|
RCC_HOST: HOST,
|
|
138
141
|
ROUTECODEX_CONFIG: verifyConfigPath,
|
|
@@ -142,7 +145,7 @@ async function main() {
|
|
|
142
145
|
// does not depend on external network availability.
|
|
143
146
|
ROUTECODEX_USE_MOCK: '1'
|
|
144
147
|
};
|
|
145
|
-
const server = spawn(
|
|
148
|
+
const server = spawn(process.execPath, serverArgs, {
|
|
146
149
|
env,
|
|
147
150
|
stdio: ['ignore', 'pipe', 'pipe']
|
|
148
151
|
});
|
|
@@ -164,9 +167,9 @@ async function main() {
|
|
|
164
167
|
});
|
|
165
168
|
|
|
166
169
|
try {
|
|
167
|
-
await waitForHealth();
|
|
168
|
-
await runChatTest();
|
|
169
|
-
await runAnthropicSseTest();
|
|
170
|
+
await waitForHealth(baseUrl);
|
|
171
|
+
await runChatTest(baseUrl);
|
|
172
|
+
await runAnthropicSseTest(baseUrl);
|
|
170
173
|
} finally {
|
|
171
174
|
if (!serverExited) {
|
|
172
175
|
server.kill('SIGTERM');
|
|
@@ -295,14 +298,14 @@ function extractUserPrompt(payload) {
|
|
|
295
298
|
: 'verification prompt';
|
|
296
299
|
}
|
|
297
300
|
|
|
298
|
-
async function writeVerifyConfig(baseUrl) {
|
|
301
|
+
async function writeVerifyConfig(baseUrl, host, port) {
|
|
299
302
|
const dir = await fs.promises.mkdtemp(path.join(os.tmpdir(), 'routecodex-verify-'));
|
|
300
303
|
const filePath = path.join(dir, 'config.json');
|
|
301
304
|
const config = {
|
|
302
305
|
version: '1.0.0',
|
|
303
306
|
httpserver: {
|
|
304
|
-
host
|
|
305
|
-
port
|
|
307
|
+
host,
|
|
308
|
+
port
|
|
306
309
|
},
|
|
307
310
|
virtualrouter: {
|
|
308
311
|
inputProtocol: 'openai',
|
|
@@ -335,3 +338,30 @@ async function writeVerifyConfig(baseUrl) {
|
|
|
335
338
|
await fs.promises.writeFile(filePath, JSON.stringify(config, null, 2), 'utf8');
|
|
336
339
|
return filePath;
|
|
337
340
|
}
|
|
341
|
+
|
|
342
|
+
async function resolveVerifyPort(preferredPort, host) {
|
|
343
|
+
const basePort = Number.isFinite(preferredPort) && preferredPort > 0 ? preferredPort : 5560;
|
|
344
|
+
for (let offset = 0; offset < PORT_SEARCH_LIMIT; offset += 1) {
|
|
345
|
+
const port = basePort + offset;
|
|
346
|
+
// eslint-disable-next-line no-await-in-loop
|
|
347
|
+
if (await canListenOnPort(port, host)) {
|
|
348
|
+
return port;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
throw new Error(`No available verification port in range ${basePort}-${basePort + PORT_SEARCH_LIMIT - 1}`);
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async function canListenOnPort(port, host) {
|
|
355
|
+
const probe = http.createServer();
|
|
356
|
+
try {
|
|
357
|
+
await new Promise((resolve, reject) => {
|
|
358
|
+
probe.once('error', reject);
|
|
359
|
+
probe.listen(port, host, resolve);
|
|
360
|
+
});
|
|
361
|
+
return true;
|
|
362
|
+
} catch {
|
|
363
|
+
return false;
|
|
364
|
+
} finally {
|
|
365
|
+
await new Promise((resolve) => probe.close(() => resolve(undefined))).catch(() => {});
|
|
366
|
+
}
|
|
367
|
+
}
|