@kaitranntt/ccs 7.73.1-dev.2 → 7.73.1-dev.3
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 +3 -0
- package/package.json +5 -3
- package/scripts/ci-parity-gate.sh +8 -2
- package/scripts/run-test-bucket.js +181 -0
package/README.md
CHANGED
|
@@ -177,6 +177,9 @@ ccs ollama "summarize these logs"
|
|
|
177
177
|
## Contribute And Report Safely
|
|
178
178
|
|
|
179
179
|
- Contributing guide: [CONTRIBUTING.md](./CONTRIBUTING.md)
|
|
180
|
+
- Daily local gate: `bun run format && bun run lint:fix && bun run validate` (`validate` is the fast path only)
|
|
181
|
+
- Before review or merge confidence: `bun run validate:ci-parity`
|
|
182
|
+
- If PR checks stay queued for more than 10 minutes, assume the self-hosted runner is offline and notify a maintainer instead of retrying blindly
|
|
180
183
|
- Starter work:
|
|
181
184
|
[good first issue](https://github.com/kaitranntt/ccs/labels/good%20first%20issue),
|
|
182
185
|
[help wanted](https://github.com/kaitranntt/ccs/labels/help%20wanted)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaitranntt/ccs",
|
|
3
|
-
"version": "7.73.1-dev.
|
|
3
|
+
"version": "7.73.1-dev.3",
|
|
4
4
|
"description": "Claude Code Switch - Instant profile switching between Claude, GLM, Kimi, and more",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -70,12 +70,14 @@
|
|
|
70
70
|
"lint:fix": "eslint src/ --fix",
|
|
71
71
|
"format": "prettier --write src/",
|
|
72
72
|
"format:check": "prettier --check src/",
|
|
73
|
-
"validate": "bun run typecheck && bun run lint
|
|
73
|
+
"validate": "bun run typecheck && bun run lint && bun run format:check && bun run test:fast",
|
|
74
74
|
"validate:ci-parity": "bash scripts/ci-parity-gate.sh",
|
|
75
75
|
"verify:bundle": "node scripts/verify-bundle.js",
|
|
76
76
|
"test": "bun run build && bun run test:all",
|
|
77
77
|
"test:ci": "bun run test:all",
|
|
78
|
-
"test:
|
|
78
|
+
"test:fast": "node scripts/run-test-bucket.js fast",
|
|
79
|
+
"test:slow": "node scripts/run-test-bucket.js slow",
|
|
80
|
+
"test:all": "node scripts/run-test-bucket.js all",
|
|
79
81
|
"test:unit": "bun test tests/unit",
|
|
80
82
|
"test:npm": "bun test tests/npm/",
|
|
81
83
|
"test:native": "bash tests/native/unix/edge-cases.sh",
|
|
@@ -55,8 +55,14 @@ if git show-ref --verify --quiet "refs/remotes/origin/$BASE_BRANCH"; then
|
|
|
55
55
|
fi
|
|
56
56
|
fi
|
|
57
57
|
|
|
58
|
-
echo "[i] Running CI-
|
|
58
|
+
echo "[i] Running CI-parity local checks..."
|
|
59
|
+
# `set -euo pipefail` above makes every step fail fast. Keep these commands
|
|
60
|
+
# explicit so parity drift is visible when CI changes.
|
|
61
|
+
bun run typecheck
|
|
62
|
+
bun run lint
|
|
63
|
+
bun run format:check
|
|
59
64
|
bun run build:all
|
|
60
|
-
bun run
|
|
65
|
+
bun run test:all
|
|
66
|
+
CCS_E2E_SKIP_BUILD=1 bun run test:e2e
|
|
61
67
|
|
|
62
68
|
echo "[OK] CI parity gate passed."
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const { spawnSync } = require('node:child_process');
|
|
6
|
+
|
|
7
|
+
const rootDir = path.resolve(__dirname, '..');
|
|
8
|
+
const candidateRoots = ['tests/unit', 'tests/integration', 'tests/npm'];
|
|
9
|
+
// Add a `.ts` test to `slowTests` when ANY of these apply:
|
|
10
|
+
// 1. It spawns a child process (CLI, bun test, node, gh, etc.).
|
|
11
|
+
// 2. It binds a port, starts a server, or talks to localhost.
|
|
12
|
+
// 3. It reads a real file from `dist/` or the repo root at runtime.
|
|
13
|
+
// 4. It waits on a timer > 500ms or a filesystem watcher.
|
|
14
|
+
// 5. A single run consistently takes > 1500ms on reference hardware.
|
|
15
|
+
// Tests that literally reference `dist/` in source are auto-forced slow by
|
|
16
|
+
// `readsBuiltDist`. This list is the manual catch-all for `.ts` tests that
|
|
17
|
+
// meet the criteria above without the literal `dist/` string.
|
|
18
|
+
// `tests/unit/scripts/run-test-bucket.test.js` verifies every path here exists
|
|
19
|
+
// (catches deletion drift) but CANNOT detect new undeclared slow tests.
|
|
20
|
+
// Automated perf-budget enforcement tracked in issue #1071.
|
|
21
|
+
const slowTests = [
|
|
22
|
+
'tests/integration/cursor-daemon-lifecycle.test.ts',
|
|
23
|
+
'tests/integration/proxy/daemon-lifecycle.test.ts',
|
|
24
|
+
'tests/unit/commands/persist-command-handler.test.ts',
|
|
25
|
+
'tests/unit/hooks/ccs-browser-mcp-server.test.ts',
|
|
26
|
+
'tests/unit/targets/codex-runtime-integration.test.ts',
|
|
27
|
+
'tests/unit/targets/codex-settings-bridge-launch.test.ts',
|
|
28
|
+
'tests/unit/targets/droid-command-routing-integration.test.ts',
|
|
29
|
+
'tests/unit/targets/droid-config-manager.test.ts',
|
|
30
|
+
'tests/unit/targets/settings-profile-browser-launch.test.ts',
|
|
31
|
+
'tests/unit/targets/settings-profile-image-analysis-launch.test.ts',
|
|
32
|
+
'tests/unit/targets/settings-profile-websearch-launch.test.ts',
|
|
33
|
+
'tests/unit/web-server/cursor-routes.test.ts',
|
|
34
|
+
'tests/unit/web-server/websearch-routes.test.ts',
|
|
35
|
+
];
|
|
36
|
+
// CommonJS-heavy JS suites stay slow by default because many of them mutate
|
|
37
|
+
// module cache or process state. Opt them into `test:fast` only after they are
|
|
38
|
+
// proven stable in the mixed fast bucket.
|
|
39
|
+
const fastJsTests = new Set([
|
|
40
|
+
'tests/unit/flag-parsing-simple.test.js',
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const filePattern = /(\.test\.(c|m)?[jt]s|\.spec\.(c|m)?[jt]s|-test\.(c|m)?[jt]s)$/;
|
|
44
|
+
|
|
45
|
+
function collectFiles(dir, files = []) {
|
|
46
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
47
|
+
const fullPath = path.join(dir, entry.name);
|
|
48
|
+
if (entry.isDirectory()) {
|
|
49
|
+
collectFiles(fullPath, files);
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (filePattern.test(entry.name)) {
|
|
54
|
+
files.push(path.relative(rootDir, fullPath).split(path.sep).join('/'));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return files;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function readsBuiltDist(relativePath) {
|
|
62
|
+
const source = fs.readFileSync(path.join(rootDir, relativePath), 'utf8');
|
|
63
|
+
return source.includes('dist/');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getDiscoveredTests() {
|
|
67
|
+
return candidateRoots
|
|
68
|
+
.flatMap((relativeDir) => collectFiles(path.join(rootDir, relativeDir)))
|
|
69
|
+
.sort();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function shouldForceSlow(file) {
|
|
73
|
+
if (file.startsWith('tests/npm/')) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (/\.(c|m)?js$/.test(file) && !fastJsTests.has(file)) {
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return readsBuiltDist(file);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function getSlowSet() {
|
|
85
|
+
const discovered = getDiscoveredTests();
|
|
86
|
+
const forceSlow = discovered.filter((file) => shouldForceSlow(file));
|
|
87
|
+
return new Set([...slowTests, ...forceSlow]);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function selectBucket(name) {
|
|
91
|
+
const discovered = getDiscoveredTests();
|
|
92
|
+
const slowSet = getSlowSet();
|
|
93
|
+
|
|
94
|
+
return name === 'slow'
|
|
95
|
+
? [...slowSet].sort()
|
|
96
|
+
: discovered.filter((file) => !slowSet.has(file));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function ensureBuildForSlowBucket() {
|
|
100
|
+
if (fs.existsSync(path.join(rootDir, 'dist', 'ccs.js'))) {
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const build = spawnSync('bun', ['run', 'build'], {
|
|
105
|
+
cwd: rootDir,
|
|
106
|
+
stdio: 'inherit',
|
|
107
|
+
shell: process.platform === 'win32',
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
return build.status ?? 1;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function runBucket(name) {
|
|
114
|
+
const selected = selectBucket(name);
|
|
115
|
+
|
|
116
|
+
if (selected.length === 0) {
|
|
117
|
+
console.error(`[X] No tests matched the '${name}' bucket.`);
|
|
118
|
+
return 1;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (name === 'slow') {
|
|
122
|
+
const buildStatus = ensureBuildForSlowBucket();
|
|
123
|
+
if (buildStatus !== 0) {
|
|
124
|
+
return buildStatus;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Slow bucket forces sequential execution because it spawns subprocesses,
|
|
129
|
+
// binds ports, and touches shared state — parallelism causes flakes.
|
|
130
|
+
// Fast bucket keeps bun's default parallelism for speed.
|
|
131
|
+
const bunArgs = name === 'slow'
|
|
132
|
+
? ['test', '--max-concurrency=1', ...selected]
|
|
133
|
+
: ['test', ...selected];
|
|
134
|
+
|
|
135
|
+
const result = spawnSync('bun', bunArgs, {
|
|
136
|
+
cwd: rootDir,
|
|
137
|
+
stdio: 'inherit',
|
|
138
|
+
shell: process.platform === 'win32',
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
return result.status ?? 1;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function main(args = process.argv.slice(2)) {
|
|
145
|
+
const bucket = args[0];
|
|
146
|
+
|
|
147
|
+
if (!['fast', 'slow', 'all'].includes(bucket)) {
|
|
148
|
+
console.error('[X] Usage: node scripts/run-test-bucket.js <fast|slow|all>');
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (bucket === 'all') {
|
|
153
|
+
let exitCode = 0;
|
|
154
|
+
|
|
155
|
+
for (const name of ['fast', 'slow']) {
|
|
156
|
+
const status = runBucket(name);
|
|
157
|
+
if (status !== 0) {
|
|
158
|
+
exitCode = status;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return exitCode;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return runBucket(bucket);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (require.main === module) {
|
|
169
|
+
process.exit(main());
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
module.exports = {
|
|
173
|
+
slowTests,
|
|
174
|
+
fastJsTests,
|
|
175
|
+
readsBuiltDist,
|
|
176
|
+
shouldForceSlow,
|
|
177
|
+
getDiscoveredTests,
|
|
178
|
+
getSlowSet,
|
|
179
|
+
selectBucket,
|
|
180
|
+
main,
|
|
181
|
+
};
|