@jsonstudio/rcc 0.89.1136 → 0.89.1189
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/build-info.js +2 -2
- package/dist/cli/commands/clean.d.ts +16 -0
- package/dist/cli/commands/clean.js +58 -0
- package/dist/cli/commands/clean.js.map +1 -0
- package/dist/cli/commands/code.d.ts +55 -0
- package/dist/cli/commands/code.js +376 -0
- package/dist/cli/commands/code.js.map +1 -0
- package/dist/cli/commands/config.d.ts +31 -0
- package/dist/cli/commands/config.js +168 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/env.d.ts +20 -0
- package/dist/cli/commands/env.js +73 -0
- package/dist/cli/commands/env.js.map +1 -0
- package/dist/cli/commands/examples.d.ts +5 -0
- package/dist/cli/commands/examples.js +66 -0
- package/dist/cli/commands/examples.js.map +1 -0
- package/dist/cli/commands/port.d.ts +24 -0
- package/dist/cli/commands/port.js +85 -0
- package/dist/cli/commands/port.js.map +1 -0
- package/dist/cli/commands/restart.d.ts +50 -0
- package/dist/cli/commands/restart.js +176 -0
- package/dist/cli/commands/restart.js.map +1 -0
- package/dist/cli/commands/start.d.ts +68 -0
- package/dist/cli/commands/start.js +295 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +16 -0
- package/dist/cli/commands/status.js +104 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +35 -0
- package/dist/cli/commands/stop.js +95 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/logger.d.ts +8 -0
- package/dist/cli/logger.js +9 -0
- package/dist/cli/logger.js.map +1 -0
- package/dist/cli/main.d.ts +6 -0
- package/dist/cli/main.js +16 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/program.d.ts +8 -0
- package/dist/cli/program.js +16 -0
- package/dist/cli/program.js.map +1 -0
- package/dist/cli/register/basic-commands.d.ts +30 -0
- package/dist/cli/register/basic-commands.js +11 -0
- package/dist/cli/register/basic-commands.js.map +1 -0
- package/dist/cli/register/code-command.d.ts +3 -0
- package/dist/cli/register/code-command.js +5 -0
- package/dist/cli/register/code-command.js.map +1 -0
- package/dist/cli/register/restart-command.d.ts +3 -0
- package/dist/cli/register/restart-command.js +5 -0
- package/dist/cli/register/restart-command.js.map +1 -0
- package/dist/cli/register/start-command.d.ts +3 -0
- package/dist/cli/register/start-command.js +5 -0
- package/dist/cli/register/start-command.js.map +1 -0
- package/dist/cli/register/status-config-commands.d.ts +16 -0
- package/dist/cli/register/status-config-commands.js +7 -0
- package/dist/cli/register/status-config-commands.js.map +1 -0
- package/dist/cli/register/stop-command.d.ts +3 -0
- package/dist/cli/register/stop-command.js +5 -0
- package/dist/cli/register/stop-command.js.map +1 -0
- package/dist/cli/runtime.d.ts +5 -0
- package/dist/cli/runtime.js +11 -0
- package/dist/cli/runtime.js.map +1 -0
- package/dist/cli/server/port-utils.d.ts +52 -0
- package/dist/cli/server/port-utils.js +193 -0
- package/dist/cli/server/port-utils.js.map +1 -0
- package/dist/cli/spinner.d.ts +10 -0
- package/dist/cli/spinner.js +59 -0
- package/dist/cli/spinner.js.map +1 -0
- package/dist/cli/utils/normalize.d.ts +2 -0
- package/dist/cli/utils/normalize.js +22 -0
- package/dist/cli/utils/normalize.js.map +1 -0
- package/dist/cli/utils/safe-read-json.d.ts +1 -0
- package/dist/cli/utils/safe-read-json.js +11 -0
- package/dist/cli/utils/safe-read-json.js.map +1 -0
- package/dist/cli.js +148 -1775
- package/dist/cli.js.map +1 -1
- package/dist/client/anthropic/anthropic-protocol-client.js +4 -3
- package/dist/client/anthropic/anthropic-protocol-client.js.map +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.d.ts +1 -1
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js +10 -3
- package/dist/client/gemini-cli/gemini-cli-protocol-client.js.map +1 -1
- package/dist/commands/quota-daemon.js +2 -2
- package/dist/commands/quota-daemon.js.map +1 -1
- package/dist/config/provider-v2-loader.js +4 -2
- package/dist/config/provider-v2-loader.js.map +1 -1
- package/dist/manager/modules/quota/index.js +21 -4
- package/dist/manager/modules/quota/index.js.map +1 -1
- package/dist/manager/modules/routing/index.js.map +1 -1
- package/dist/manager/storage/file-store.js +1 -1
- package/dist/manager/storage/file-store.js.map +1 -1
- package/dist/providers/auth/oauth-lifecycle.js +2 -2
- package/dist/providers/auth/oauth-lifecycle.js.map +1 -1
- package/dist/providers/core/api/provider-config.d.ts +2 -0
- package/dist/providers/core/api/provider-types.d.ts +2 -0
- package/dist/providers/core/runtime/base-provider.js +21 -27
- package/dist/providers/core/runtime/base-provider.js.map +1 -1
- package/dist/providers/core/runtime/gemini-cli-http-provider.d.ts +1 -0
- package/dist/providers/core/runtime/gemini-cli-http-provider.js +37 -5
- package/dist/providers/core/runtime/gemini-cli-http-provider.js.map +1 -1
- package/dist/providers/core/runtime/http-request-executor.js +23 -29
- package/dist/providers/core/runtime/http-request-executor.js.map +1 -1
- package/dist/providers/core/runtime/http-transport-provider.js +20 -0
- package/dist/providers/core/runtime/http-transport-provider.js.map +1 -1
- package/dist/providers/core/utils/http-client.d.ts +9 -0
- package/dist/providers/core/utils/http-client.js +9 -11
- package/dist/providers/core/utils/http-client.js.map +1 -1
- package/dist/providers/core/utils/provider-error-reporter.js +2 -6
- package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
- package/dist/providers/mock/mock-provider-runtime.js +19 -5
- package/dist/providers/mock/mock-provider-runtime.js.map +1 -1
- package/dist/server/runtime/http-server/index.d.ts +1 -0
- package/dist/server/runtime/http-server/index.js +70 -11
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +9 -1
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.js +8 -4
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/stats-manager.js +9 -3
- package/dist/server/runtime/http-server/stats-manager.js.map +1 -1
- package/package.json +10 -4
- package/scripts/anthropic-compare-modes.mjs +40 -3
- package/scripts/antigravity-smoke.mjs +180 -0
- package/scripts/backfill-apply-patch-exec-errorsamples.mjs +225 -0
- package/scripts/compare-codex-rccx.mjs +59 -1
- package/scripts/compare-responses-request.mjs +50 -4
- package/scripts/lib/errorsamples.mjs +23 -0
- package/scripts/mock-provider/run-regressions.mjs +12 -2
- package/scripts/policy-violations-report.mjs +257 -0
- package/scripts/publish-rcc.mjs +16 -2
- package/scripts/tests/unified-hub-responses-enforce-safe.mjs +37 -0
- package/scripts/tests/unified-hub-shadow-regression.mjs +55 -0
- package/scripts/unified-hub-shadow-compare.mjs +359 -0
- package/scripts/verify-e2e-gemini-followup-sample.mjs +269 -0
- package/scripts/virtual-router-shadow-v2-real.mjs +71 -1
- package/scripts/virtual-router-shadow-v2.mjs +41 -0
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Report Unified Hub policy violations/enforcement rewrites captured under:
|
|
4
|
+
* ~/.routecodex/codex-samples/__policy_violations__/
|
|
5
|
+
*
|
|
6
|
+
* This is intended for day-to-day monitoring when policy is enabled by default.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from 'node:fs/promises';
|
|
10
|
+
import os from 'node:os';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
|
|
13
|
+
function usage() {
|
|
14
|
+
console.log(`Usage:
|
|
15
|
+
node scripts/policy-violations-report.mjs [options]
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--root <dir> default: ~/.routecodex/codex-samples/__policy_violations__
|
|
19
|
+
--since-hours <n> only include files modified in last N hours
|
|
20
|
+
--limit <n> limit printed rows per section (default: 30)
|
|
21
|
+
--fail exit 1 if any records found
|
|
22
|
+
--help show help
|
|
23
|
+
`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseArgs(argv) {
|
|
27
|
+
const out = {
|
|
28
|
+
root: path.join(os.homedir(), '.routecodex', 'errorsamples', 'policy'),
|
|
29
|
+
sinceHours: undefined,
|
|
30
|
+
limit: 30,
|
|
31
|
+
fail: false
|
|
32
|
+
};
|
|
33
|
+
for (let i = 2; i < argv.length; i += 1) {
|
|
34
|
+
const a = argv[i];
|
|
35
|
+
if (a === '--root' && i + 1 < argv.length) out.root = argv[++i];
|
|
36
|
+
else if (a === '--since-hours' && i + 1 < argv.length) out.sinceHours = Number(argv[++i]);
|
|
37
|
+
else if (a === '--limit' && i + 1 < argv.length) out.limit = Number(argv[++i]);
|
|
38
|
+
else if (a === '--fail') out.fail = true;
|
|
39
|
+
else if (a === '--help' || a === '-h') out.help = true;
|
|
40
|
+
else {
|
|
41
|
+
console.error(`Unknown arg: ${a}`);
|
|
42
|
+
out.help = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async function fileExists(p) {
|
|
49
|
+
try {
|
|
50
|
+
await fs.access(p);
|
|
51
|
+
return true;
|
|
52
|
+
} catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function walk(dir) {
|
|
58
|
+
const out = [];
|
|
59
|
+
const stack = [dir];
|
|
60
|
+
while (stack.length) {
|
|
61
|
+
const current = stack.pop();
|
|
62
|
+
let entries = [];
|
|
63
|
+
try {
|
|
64
|
+
entries = await fs.readdir(current, { withFileTypes: true });
|
|
65
|
+
} catch {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
for (const ent of entries) {
|
|
69
|
+
const p = path.join(current, ent.name);
|
|
70
|
+
if (ent.isDirectory()) stack.push(p);
|
|
71
|
+
else if (ent.isFile() && ent.name.endsWith('.json')) out.push(p);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function inc(map, key, by = 1) {
|
|
78
|
+
map.set(key, (map.get(key) || 0) + by);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function topN(map, n) {
|
|
82
|
+
return [...map.entries()].sort((a, b) => b[1] - a[1]).slice(0, n);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function readJson(p) {
|
|
86
|
+
try {
|
|
87
|
+
const raw = await fs.readFile(p, 'utf8');
|
|
88
|
+
return JSON.parse(raw);
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function classifyRecord(obj) {
|
|
95
|
+
if (!obj || typeof obj !== 'object') return { kind: 'unknown' };
|
|
96
|
+
const o = obj;
|
|
97
|
+
if (Array.isArray(o.violations) || (o.summary && typeof o.summary === 'object')) return { kind: 'observe' };
|
|
98
|
+
if (Array.isArray(o.removedTopLevelKeys) || Array.isArray(o.flattenedWrappers)) return { kind: 'enforce' };
|
|
99
|
+
return { kind: 'unknown' };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function safeString(value) {
|
|
103
|
+
return typeof value === 'string' && value.trim() ? value.trim() : '';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function inferStageFromFilename(filePath) {
|
|
107
|
+
const base = path.basename(filePath, '.json');
|
|
108
|
+
return base.replace(/_[0-9]+$/, '');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function fmtRow(cols, widths) {
|
|
112
|
+
return cols
|
|
113
|
+
.map((c, i) => {
|
|
114
|
+
const w = widths[i] || 20;
|
|
115
|
+
const s = String(c ?? '');
|
|
116
|
+
return s.length > w ? `${s.slice(0, Math.max(0, w - 1))}…` : s.padEnd(w, ' ');
|
|
117
|
+
})
|
|
118
|
+
.join(' ');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function main() {
|
|
122
|
+
const args = parseArgs(process.argv);
|
|
123
|
+
if (args.help) {
|
|
124
|
+
usage();
|
|
125
|
+
process.exit(0);
|
|
126
|
+
}
|
|
127
|
+
let root = path.resolve(args.root);
|
|
128
|
+
if (!(await fileExists(root))) {
|
|
129
|
+
const fallback = path.join(os.homedir(), '.routecodex', 'codex-samples', '__policy_violations__');
|
|
130
|
+
if (await fileExists(fallback)) {
|
|
131
|
+
root = fallback;
|
|
132
|
+
} else {
|
|
133
|
+
console.log(`[policy-report] no folder: ${root}`);
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const sinceMs =
|
|
139
|
+
typeof args.sinceHours === 'number' && Number.isFinite(args.sinceHours) && args.sinceHours > 0
|
|
140
|
+
? Date.now() - args.sinceHours * 60 * 60 * 1000
|
|
141
|
+
: null;
|
|
142
|
+
|
|
143
|
+
const files = await walk(root);
|
|
144
|
+
const rows = [];
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
let st;
|
|
147
|
+
try {
|
|
148
|
+
st = await fs.stat(file);
|
|
149
|
+
} catch {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (sinceMs !== null && st.mtimeMs < sinceMs) continue;
|
|
153
|
+
const obj = await readJson(file);
|
|
154
|
+
if (!obj) continue;
|
|
155
|
+
const rel = path.relative(root, file);
|
|
156
|
+
const parts = rel.split(path.sep);
|
|
157
|
+
const endpointFolder = parts[0] || '';
|
|
158
|
+
const providerKey = parts[1] || '';
|
|
159
|
+
const requestId = parts[2] || '';
|
|
160
|
+
rows.push({
|
|
161
|
+
file,
|
|
162
|
+
rel,
|
|
163
|
+
endpointFolder,
|
|
164
|
+
providerKey,
|
|
165
|
+
requestId,
|
|
166
|
+
stage: safeString(obj?.stage) || safeString(obj?.meta?.stage) || inferStageFromFilename(file),
|
|
167
|
+
protocol: safeString(obj?.providerProtocol) || safeString(obj?.protocol),
|
|
168
|
+
kind: classifyRecord(obj).kind,
|
|
169
|
+
obj
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
console.log(`[policy-report] root=${root}`);
|
|
174
|
+
if (sinceMs !== null) {
|
|
175
|
+
console.log(`[policy-report] sinceHours=${args.sinceHours}`);
|
|
176
|
+
}
|
|
177
|
+
console.log(`[policy-report] records=${rows.length}`);
|
|
178
|
+
if (!rows.length) {
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const byStage = new Map();
|
|
183
|
+
const byProtocol = new Map();
|
|
184
|
+
const violationPathCounts = new Map();
|
|
185
|
+
const wrapperCounts = new Map();
|
|
186
|
+
const removedKeyCounts = new Map();
|
|
187
|
+
|
|
188
|
+
for (const r of rows) {
|
|
189
|
+
inc(byStage, r.stage);
|
|
190
|
+
if (r.protocol) inc(byProtocol, r.protocol);
|
|
191
|
+
|
|
192
|
+
if (r.kind === 'observe' && Array.isArray(r.obj?.violations)) {
|
|
193
|
+
for (const v of r.obj.violations) {
|
|
194
|
+
const p = safeString(v?.path) || '(unknown)';
|
|
195
|
+
inc(violationPathCounts, p);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (r.kind === 'enforce') {
|
|
199
|
+
const flattened = Array.isArray(r.obj?.flattenedWrappers) ? r.obj.flattenedWrappers : [];
|
|
200
|
+
for (const w of flattened) inc(wrapperCounts, String(w));
|
|
201
|
+
const removed = Array.isArray(r.obj?.removedTopLevelKeys) ? r.obj.removedTopLevelKeys : [];
|
|
202
|
+
for (const k of removed) inc(removedKeyCounts, String(k));
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const limit = Number.isFinite(args.limit) && args.limit > 0 ? args.limit : 30;
|
|
207
|
+
|
|
208
|
+
console.log('\n[policy-report] top stages:');
|
|
209
|
+
for (const [k, v] of topN(byStage, limit)) {
|
|
210
|
+
console.log(`- ${k}: ${v}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
console.log('\n[policy-report] top protocols:');
|
|
214
|
+
for (const [k, v] of topN(byProtocol, limit)) {
|
|
215
|
+
console.log(`- ${k}: ${v}`);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (violationPathCounts.size) {
|
|
219
|
+
console.log('\n[policy-report] top violation paths:');
|
|
220
|
+
for (const [k, v] of topN(violationPathCounts, limit)) {
|
|
221
|
+
console.log(`- ${k}: ${v}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (wrapperCounts.size) {
|
|
226
|
+
console.log('\n[policy-report] top flattened wrappers (enforce):');
|
|
227
|
+
for (const [k, v] of topN(wrapperCounts, limit)) {
|
|
228
|
+
console.log(`- ${k}: ${v}`);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (removedKeyCounts.size) {
|
|
233
|
+
console.log('\n[policy-report] top removed keys (enforce):');
|
|
234
|
+
for (const [k, v] of topN(removedKeyCounts, limit)) {
|
|
235
|
+
console.log(`- ${k}: ${v}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log('\n[policy-report] newest records:');
|
|
240
|
+
const newest = rows
|
|
241
|
+
.slice()
|
|
242
|
+
.sort((a, b) => (a.file < b.file ? 1 : -1))
|
|
243
|
+
.slice(0, Math.min(limit, rows.length));
|
|
244
|
+
console.log(fmtRow(['endpoint', 'providerKey', 'stage', 'protocol', 'requestId'], [16, 28, 40, 18, 24]));
|
|
245
|
+
for (const r of newest) {
|
|
246
|
+
console.log(fmtRow([r.endpointFolder, r.providerKey, r.stage, r.protocol || '-', r.requestId], [16, 28, 40, 18, 24]));
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (args.fail) {
|
|
250
|
+
process.exit(1);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
main().catch((err) => {
|
|
255
|
+
console.error('[policy-report] failed:', err);
|
|
256
|
+
process.exit(2);
|
|
257
|
+
});
|
package/scripts/publish-rcc.mjs
CHANGED
|
@@ -8,6 +8,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
8
8
|
const PROJECT_ROOT = path.resolve(__dirname, '..');
|
|
9
9
|
const PACK_SCRIPT = path.join(PROJECT_ROOT, 'scripts', 'pack-mode.mjs');
|
|
10
10
|
const pkgPath = path.join(PROJECT_ROOT, 'package.json');
|
|
11
|
+
const llmsPath = path.join(PROJECT_ROOT, 'node_modules', '@jsonstudio', 'llms');
|
|
11
12
|
|
|
12
13
|
function run(command, args, options = {}) {
|
|
13
14
|
const res = spawnSync(command, args, { stdio: 'inherit', ...options });
|
|
@@ -17,6 +18,14 @@ function run(command, args, options = {}) {
|
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
try {
|
|
21
|
+
const hadDevLink = (() => {
|
|
22
|
+
try {
|
|
23
|
+
return fs.lstatSync(llmsPath).isSymbolicLink();
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
})();
|
|
28
|
+
|
|
20
29
|
// 1) 使用 release 模式构建 dist(依赖 npm 上的 @jsonstudio/llms)
|
|
21
30
|
run('npm', ['run', 'build:min'], {
|
|
22
31
|
cwd: PROJECT_ROOT,
|
|
@@ -39,8 +48,13 @@ try {
|
|
|
39
48
|
// 3) 发布 npm 包
|
|
40
49
|
run('npm', ['publish', tarballName], { cwd: PROJECT_ROOT });
|
|
41
50
|
|
|
42
|
-
// 4)
|
|
43
|
-
|
|
51
|
+
// 4) 发布结束后恢复 dev 模式(routecodex 约定始终为 dev CLI;rcc 发布时才切 release)。
|
|
52
|
+
if (hadDevLink) {
|
|
53
|
+
run('npm', ['run', 'llmswitch:ensure'], {
|
|
54
|
+
cwd: PROJECT_ROOT,
|
|
55
|
+
env: { ...process.env, BUILD_MODE: 'dev' }
|
|
56
|
+
});
|
|
57
|
+
}
|
|
44
58
|
} catch (err) {
|
|
45
59
|
console.error('[publish-rcc] failed:', err.message);
|
|
46
60
|
process.exit(1);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
|
|
5
|
+
function runCase(args) {
|
|
6
|
+
const nodeArgs = ['scripts/unified-hub-shadow-compare.mjs', ...args];
|
|
7
|
+
const result = spawnSync(process.execPath, nodeArgs, {
|
|
8
|
+
cwd: path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..'),
|
|
9
|
+
stdio: 'inherit'
|
|
10
|
+
});
|
|
11
|
+
if (result.status !== 0) {
|
|
12
|
+
throw new Error(`shadow compare failed: ${nodeArgs.join(' ')}`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function main() {
|
|
17
|
+
const repoRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..');
|
|
18
|
+
const fixturesDir = path.join(repoRoot, 'tests', 'fixtures', 'unified-hub');
|
|
19
|
+
|
|
20
|
+
runCase([
|
|
21
|
+
'--request',
|
|
22
|
+
path.join(fixturesDir, 'responses.clean.json'),
|
|
23
|
+
'--entry-endpoint',
|
|
24
|
+
'/v1/responses',
|
|
25
|
+
'--route-hint',
|
|
26
|
+
'responses',
|
|
27
|
+
'--baseline-mode',
|
|
28
|
+
'off',
|
|
29
|
+
'--candidate-mode',
|
|
30
|
+
'enforce'
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
console.log('[unified-hub-responses-enforce-safe] OK');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
main();
|
|
37
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
|
|
6
|
+
function runCase(args) {
|
|
7
|
+
const nodeArgs = ['scripts/unified-hub-shadow-compare.mjs', ...args];
|
|
8
|
+
const result = spawnSync(process.execPath, nodeArgs, {
|
|
9
|
+
cwd: path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..'),
|
|
10
|
+
stdio: 'inherit'
|
|
11
|
+
});
|
|
12
|
+
if (result.status !== 0) {
|
|
13
|
+
throw new Error(`shadow compare failed: ${nodeArgs.join(' ')}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function main() {
|
|
18
|
+
const repoRoot = path.resolve(path.dirname(new URL(import.meta.url).pathname), '..', '..');
|
|
19
|
+
const fixturesDir = path.join(repoRoot, 'tests', 'fixtures', 'unified-hub');
|
|
20
|
+
if (!fs.existsSync(fixturesDir)) {
|
|
21
|
+
throw new Error(`fixtures dir missing: ${fixturesDir}`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
runCase([
|
|
25
|
+
'--request',
|
|
26
|
+
path.join(fixturesDir, 'chat.json'),
|
|
27
|
+
'--entry-endpoint',
|
|
28
|
+
'/v1/chat/completions',
|
|
29
|
+
'--route-hint',
|
|
30
|
+
'openai'
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
runCase([
|
|
34
|
+
'--request',
|
|
35
|
+
path.join(fixturesDir, 'responses.json'),
|
|
36
|
+
'--entry-endpoint',
|
|
37
|
+
'/v1/responses',
|
|
38
|
+
'--route-hint',
|
|
39
|
+
'responses'
|
|
40
|
+
]);
|
|
41
|
+
|
|
42
|
+
runCase([
|
|
43
|
+
'--request',
|
|
44
|
+
path.join(fixturesDir, 'anthropic.json'),
|
|
45
|
+
'--entry-endpoint',
|
|
46
|
+
'/v1/messages',
|
|
47
|
+
'--route-hint',
|
|
48
|
+
'anthropic'
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
console.log('[unified-hub-shadow-regression] OK');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
main();
|
|
55
|
+
|