opencode-swarm 7.16.0 → 7.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/agents/index.d.ts +3 -2
- package/dist/agents/project-context.d.ts +58 -0
- package/dist/agents/template.d.ts +85 -0
- package/dist/build/discovery.d.ts +2 -4
- package/dist/cli/index.js +1745 -343
- package/dist/index.js +2939 -1367
- package/dist/lang/backend.d.ts +199 -0
- package/dist/lang/backends/go.d.ts +21 -0
- package/dist/lang/backends/index.d.ts +27 -0
- package/dist/lang/backends/python.d.ts +25 -0
- package/dist/lang/backends/typescript.d.ts +56 -0
- package/dist/lang/default-backend.d.ts +105 -0
- package/dist/lang/dispatch.d.ts +52 -0
- package/dist/lang/profiles.d.ts +28 -0
- package/dist/lang/registry-backend.d.ts +35 -0
- package/dist/test-impact/analyzer.d.ts +7 -0
- package/dist/tools/test-runner.d.ts +22 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.
|
|
37
|
+
version: "7.17.0",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -40347,11 +40347,34 @@ class LanguageRegistry {
|
|
|
40347
40347
|
this.profiles = new Map;
|
|
40348
40348
|
this.extensionIndex = new Map;
|
|
40349
40349
|
}
|
|
40350
|
+
unregister(id) {
|
|
40351
|
+
const profile = this.profiles.get(id);
|
|
40352
|
+
if (!profile)
|
|
40353
|
+
return;
|
|
40354
|
+
this.profiles.delete(id);
|
|
40355
|
+
if (!profile.parserOnly) {
|
|
40356
|
+
for (const ext of profile.extensions) {
|
|
40357
|
+
if (this.extensionIndex.get(ext) === id) {
|
|
40358
|
+
this.extensionIndex.delete(ext);
|
|
40359
|
+
}
|
|
40360
|
+
}
|
|
40361
|
+
}
|
|
40362
|
+
}
|
|
40350
40363
|
register(profile) {
|
|
40351
|
-
this.profiles.
|
|
40352
|
-
|
|
40353
|
-
|
|
40364
|
+
const existing = this.profiles.get(profile.id);
|
|
40365
|
+
if (existing && existing !== profile) {
|
|
40366
|
+
throw new Error(`LanguageRegistry: profile id "${profile.id}" registered twice. ` + `Each LanguageProfile.id must be unique. ` + `Got: ${profile.displayName} vs existing ${existing.displayName}.`);
|
|
40354
40367
|
}
|
|
40368
|
+
if (!profile.parserOnly) {
|
|
40369
|
+
for (const ext of profile.extensions) {
|
|
40370
|
+
const claimedBy = this.extensionIndex.get(ext);
|
|
40371
|
+
if (claimedBy && claimedBy !== profile.id) {
|
|
40372
|
+
throw new Error(`LanguageRegistry: extension "${ext}" registered by both ` + `"${claimedBy}" and "${profile.id}". A non-parserOnly profile ` + `must not collide on extensions. If both languages legitimately ` + `share an extension, mark one parserOnly: true.`);
|
|
40373
|
+
}
|
|
40374
|
+
this.extensionIndex.set(ext, profile.id);
|
|
40375
|
+
}
|
|
40376
|
+
}
|
|
40377
|
+
this.profiles.set(profile.id, profile);
|
|
40355
40378
|
}
|
|
40356
40379
|
get(id) {
|
|
40357
40380
|
return this.profiles.get(id);
|
|
@@ -40383,7 +40406,8 @@ var init_profiles = __esm(() => {
|
|
|
40383
40406
|
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"],
|
|
40384
40407
|
treeSitter: {
|
|
40385
40408
|
grammarId: "typescript",
|
|
40386
|
-
wasmFile: "tree-sitter-typescript.wasm"
|
|
40409
|
+
wasmFile: "tree-sitter-typescript.wasm",
|
|
40410
|
+
commentNodes: ["comment", "line_comment", "block_comment"]
|
|
40387
40411
|
},
|
|
40388
40412
|
build: {
|
|
40389
40413
|
detectFiles: ["package.json"],
|
|
@@ -40409,7 +40433,13 @@ var init_profiles = __esm(() => {
|
|
|
40409
40433
|
]
|
|
40410
40434
|
},
|
|
40411
40435
|
test: {
|
|
40412
|
-
detectFiles: [
|
|
40436
|
+
detectFiles: [
|
|
40437
|
+
"package.json",
|
|
40438
|
+
"vitest.config.ts",
|
|
40439
|
+
"jest.config.js",
|
|
40440
|
+
".mocharc.js",
|
|
40441
|
+
".mocharc.json"
|
|
40442
|
+
],
|
|
40413
40443
|
frameworks: [
|
|
40414
40444
|
{
|
|
40415
40445
|
name: "vitest",
|
|
@@ -40420,9 +40450,15 @@ var init_profiles = __esm(() => {
|
|
|
40420
40450
|
{ name: "jest", detect: "jest.config.js", cmd: "npx jest", priority: 9 },
|
|
40421
40451
|
{
|
|
40422
40452
|
name: "bun:test",
|
|
40423
|
-
detect: "
|
|
40453
|
+
detect: "bun.lock",
|
|
40424
40454
|
cmd: "bun test",
|
|
40425
40455
|
priority: 8
|
|
40456
|
+
},
|
|
40457
|
+
{
|
|
40458
|
+
name: "mocha",
|
|
40459
|
+
detect: ".mocharc.json",
|
|
40460
|
+
cmd: "npx mocha",
|
|
40461
|
+
priority: 7
|
|
40426
40462
|
}
|
|
40427
40463
|
]
|
|
40428
40464
|
},
|
|
@@ -40476,7 +40512,11 @@ var init_profiles = __esm(() => {
|
|
|
40476
40512
|
displayName: "Python",
|
|
40477
40513
|
tier: 1,
|
|
40478
40514
|
extensions: [".py", ".pyw"],
|
|
40479
|
-
treeSitter: {
|
|
40515
|
+
treeSitter: {
|
|
40516
|
+
grammarId: "python",
|
|
40517
|
+
wasmFile: "tree-sitter-python.wasm",
|
|
40518
|
+
commentNodes: ["comment"]
|
|
40519
|
+
},
|
|
40480
40520
|
build: {
|
|
40481
40521
|
detectFiles: ["setup.py", "pyproject.toml", "setup.cfg"],
|
|
40482
40522
|
commands: [
|
|
@@ -40546,7 +40586,11 @@ var init_profiles = __esm(() => {
|
|
|
40546
40586
|
displayName: "Rust",
|
|
40547
40587
|
tier: 1,
|
|
40548
40588
|
extensions: [".rs"],
|
|
40549
|
-
treeSitter: {
|
|
40589
|
+
treeSitter: {
|
|
40590
|
+
grammarId: "rust",
|
|
40591
|
+
wasmFile: "tree-sitter-rust.wasm",
|
|
40592
|
+
commentNodes: ["line_comment", "block_comment"]
|
|
40593
|
+
},
|
|
40550
40594
|
build: {
|
|
40551
40595
|
detectFiles: ["Cargo.toml"],
|
|
40552
40596
|
commands: [
|
|
@@ -40615,7 +40659,11 @@ var init_profiles = __esm(() => {
|
|
|
40615
40659
|
displayName: "Go",
|
|
40616
40660
|
tier: 1,
|
|
40617
40661
|
extensions: [".go"],
|
|
40618
|
-
treeSitter: {
|
|
40662
|
+
treeSitter: {
|
|
40663
|
+
grammarId: "go",
|
|
40664
|
+
wasmFile: "tree-sitter-go.wasm",
|
|
40665
|
+
commentNodes: ["comment"]
|
|
40666
|
+
},
|
|
40619
40667
|
build: {
|
|
40620
40668
|
detectFiles: ["go.mod"],
|
|
40621
40669
|
commands: [
|
|
@@ -40679,7 +40727,11 @@ var init_profiles = __esm(() => {
|
|
|
40679
40727
|
displayName: "Java",
|
|
40680
40728
|
tier: 2,
|
|
40681
40729
|
extensions: [".java"],
|
|
40682
|
-
treeSitter: {
|
|
40730
|
+
treeSitter: {
|
|
40731
|
+
grammarId: "java",
|
|
40732
|
+
wasmFile: "tree-sitter-java.wasm",
|
|
40733
|
+
commentNodes: ["line_comment", "block_comment"]
|
|
40734
|
+
},
|
|
40683
40735
|
build: {
|
|
40684
40736
|
detectFiles: ["pom.xml", "build.gradle", "build.gradle.kts"],
|
|
40685
40737
|
commands: [
|
|
@@ -40759,7 +40811,11 @@ var init_profiles = __esm(() => {
|
|
|
40759
40811
|
displayName: "Kotlin",
|
|
40760
40812
|
tier: 2,
|
|
40761
40813
|
extensions: [".kt", ".kts"],
|
|
40762
|
-
treeSitter: {
|
|
40814
|
+
treeSitter: {
|
|
40815
|
+
grammarId: "kotlin",
|
|
40816
|
+
wasmFile: "tree-sitter-kotlin.wasm",
|
|
40817
|
+
commentNodes: ["line_comment", "multiline_comment"]
|
|
40818
|
+
},
|
|
40763
40819
|
build: {
|
|
40764
40820
|
detectFiles: ["build.gradle.kts", "build.gradle", "pom.xml"],
|
|
40765
40821
|
commands: [
|
|
@@ -40839,7 +40895,11 @@ var init_profiles = __esm(() => {
|
|
|
40839
40895
|
displayName: "C# / .NET",
|
|
40840
40896
|
tier: 2,
|
|
40841
40897
|
extensions: [".cs", ".csx"],
|
|
40842
|
-
treeSitter: {
|
|
40898
|
+
treeSitter: {
|
|
40899
|
+
grammarId: "csharp",
|
|
40900
|
+
wasmFile: "tree-sitter-c-sharp.wasm",
|
|
40901
|
+
commentNodes: ["comment"]
|
|
40902
|
+
},
|
|
40843
40903
|
build: {
|
|
40844
40904
|
detectFiles: ["*.csproj", "*.sln", "Directory.Build.props"],
|
|
40845
40905
|
commands: [
|
|
@@ -40907,7 +40967,11 @@ var init_profiles = __esm(() => {
|
|
|
40907
40967
|
displayName: "C / C++",
|
|
40908
40968
|
tier: 2,
|
|
40909
40969
|
extensions: [".c", ".h", ".cpp", ".hpp", ".cc", ".cxx"],
|
|
40910
|
-
treeSitter: {
|
|
40970
|
+
treeSitter: {
|
|
40971
|
+
grammarId: "cpp",
|
|
40972
|
+
wasmFile: "tree-sitter-cpp.wasm",
|
|
40973
|
+
commentNodes: ["comment"]
|
|
40974
|
+
},
|
|
40911
40975
|
build: {
|
|
40912
40976
|
detectFiles: ["CMakeLists.txt", "Makefile", "meson.build"],
|
|
40913
40977
|
commands: [
|
|
@@ -40982,7 +41046,11 @@ var init_profiles = __esm(() => {
|
|
|
40982
41046
|
displayName: "Swift",
|
|
40983
41047
|
tier: 2,
|
|
40984
41048
|
extensions: [".swift"],
|
|
40985
|
-
treeSitter: {
|
|
41049
|
+
treeSitter: {
|
|
41050
|
+
grammarId: "swift",
|
|
41051
|
+
wasmFile: "tree-sitter-swift.wasm",
|
|
41052
|
+
commentNodes: ["comment", "multiline_comment"]
|
|
41053
|
+
},
|
|
40986
41054
|
build: {
|
|
40987
41055
|
detectFiles: ["Package.swift", "*.xcodeproj", "*.xcworkspace"],
|
|
40988
41056
|
commands: [
|
|
@@ -41056,7 +41124,11 @@ var init_profiles = __esm(() => {
|
|
|
41056
41124
|
displayName: "Dart / Flutter",
|
|
41057
41125
|
tier: 3,
|
|
41058
41126
|
extensions: [".dart"],
|
|
41059
|
-
treeSitter: {
|
|
41127
|
+
treeSitter: {
|
|
41128
|
+
grammarId: "dart",
|
|
41129
|
+
wasmFile: "tree-sitter-dart.wasm",
|
|
41130
|
+
commentNodes: ["comment", "documentation_comment"]
|
|
41131
|
+
},
|
|
41060
41132
|
build: {
|
|
41061
41133
|
detectFiles: ["pubspec.yaml"],
|
|
41062
41134
|
commands: [
|
|
@@ -41130,7 +41202,11 @@ var init_profiles = __esm(() => {
|
|
|
41130
41202
|
displayName: "Ruby",
|
|
41131
41203
|
tier: 3,
|
|
41132
41204
|
extensions: [".rb", ".rake", ".gemspec"],
|
|
41133
|
-
treeSitter: {
|
|
41205
|
+
treeSitter: {
|
|
41206
|
+
grammarId: "ruby",
|
|
41207
|
+
wasmFile: "tree-sitter-ruby.wasm",
|
|
41208
|
+
commentNodes: ["comment"]
|
|
41209
|
+
},
|
|
41134
41210
|
build: {
|
|
41135
41211
|
detectFiles: ["Gemfile", "Rakefile"],
|
|
41136
41212
|
commands: [
|
|
@@ -41199,7 +41275,11 @@ var init_profiles = __esm(() => {
|
|
|
41199
41275
|
displayName: "PHP",
|
|
41200
41276
|
tier: 3,
|
|
41201
41277
|
extensions: [".php", ".phtml", ".blade.php"],
|
|
41202
|
-
treeSitter: {
|
|
41278
|
+
treeSitter: {
|
|
41279
|
+
grammarId: "php",
|
|
41280
|
+
wasmFile: "tree-sitter-php.wasm",
|
|
41281
|
+
commentNodes: ["comment"]
|
|
41282
|
+
},
|
|
41203
41283
|
build: {
|
|
41204
41284
|
detectFiles: ["composer.json"],
|
|
41205
41285
|
commands: [
|
|
@@ -41207,7 +41287,7 @@ var init_profiles = __esm(() => {
|
|
|
41207
41287
|
name: "Composer Install",
|
|
41208
41288
|
cmd: "composer install --no-interaction --prefer-dist",
|
|
41209
41289
|
detectFile: "composer.json",
|
|
41210
|
-
priority:
|
|
41290
|
+
priority: 10
|
|
41211
41291
|
}
|
|
41212
41292
|
]
|
|
41213
41293
|
},
|
|
@@ -41218,19 +41298,19 @@ var init_profiles = __esm(() => {
|
|
|
41218
41298
|
name: "Pest",
|
|
41219
41299
|
detect: "Pest.php",
|
|
41220
41300
|
cmd: "vendor/bin/pest",
|
|
41221
|
-
priority:
|
|
41301
|
+
priority: 10
|
|
41222
41302
|
},
|
|
41223
41303
|
{
|
|
41224
41304
|
name: "PHPUnit",
|
|
41225
41305
|
detect: "phpunit.xml",
|
|
41226
41306
|
cmd: "vendor/bin/phpunit",
|
|
41227
|
-
priority:
|
|
41307
|
+
priority: 8
|
|
41228
41308
|
},
|
|
41229
41309
|
{
|
|
41230
41310
|
name: "PHPUnit",
|
|
41231
41311
|
detect: "phpunit.xml.dist",
|
|
41232
41312
|
cmd: "vendor/bin/phpunit",
|
|
41233
|
-
priority:
|
|
41313
|
+
priority: 7
|
|
41234
41314
|
}
|
|
41235
41315
|
]
|
|
41236
41316
|
},
|
|
@@ -41247,25 +41327,25 @@ var init_profiles = __esm(() => {
|
|
|
41247
41327
|
name: "PHPStan",
|
|
41248
41328
|
detect: "phpstan.neon",
|
|
41249
41329
|
cmd: "vendor/bin/phpstan analyse",
|
|
41250
|
-
priority:
|
|
41330
|
+
priority: 10
|
|
41251
41331
|
},
|
|
41252
41332
|
{
|
|
41253
41333
|
name: "PHPStan",
|
|
41254
41334
|
detect: "phpstan.neon.dist",
|
|
41255
41335
|
cmd: "vendor/bin/phpstan analyse",
|
|
41256
|
-
priority:
|
|
41336
|
+
priority: 9
|
|
41257
41337
|
},
|
|
41258
41338
|
{
|
|
41259
41339
|
name: "Pint",
|
|
41260
41340
|
detect: "pint.json",
|
|
41261
41341
|
cmd: "vendor/bin/pint --test",
|
|
41262
|
-
priority:
|
|
41342
|
+
priority: 8
|
|
41263
41343
|
},
|
|
41264
41344
|
{
|
|
41265
41345
|
name: "PHP-CS-Fixer",
|
|
41266
41346
|
detect: ".php-cs-fixer.php",
|
|
41267
41347
|
cmd: "vendor/bin/php-cs-fixer fix --dry-run --diff",
|
|
41268
|
-
priority:
|
|
41348
|
+
priority: 7
|
|
41269
41349
|
}
|
|
41270
41350
|
]
|
|
41271
41351
|
},
|
|
@@ -41370,9 +41450,12 @@ function isCommandAvailable(command) {
|
|
|
41370
41450
|
const isWindows = process.platform === "win32";
|
|
41371
41451
|
const cmd = isWindows ? `${command}.exe` : command;
|
|
41372
41452
|
try {
|
|
41373
|
-
const result =
|
|
41374
|
-
|
|
41375
|
-
|
|
41453
|
+
const result = _internals11.spawnSyncImpl(isWindows ? ["where", cmd] : ["which", cmd], {
|
|
41454
|
+
cwd: process.cwd(),
|
|
41455
|
+
stdin: "ignore",
|
|
41456
|
+
stdout: "ignore",
|
|
41457
|
+
stderr: "ignore",
|
|
41458
|
+
timeout: IS_COMMAND_AVAILABLE_TIMEOUT_MS
|
|
41376
41459
|
});
|
|
41377
41460
|
const available = result.success;
|
|
41378
41461
|
toolchainCache.set(command, available);
|
|
@@ -41580,7 +41663,7 @@ function clearToolchainCache() {
|
|
|
41580
41663
|
function getEcosystems() {
|
|
41581
41664
|
return ECOSYSTEMS.map((e) => e.ecosystem);
|
|
41582
41665
|
}
|
|
41583
|
-
var ECOSYSTEMS, PROFILE_TO_ECOSYSTEM_NAMES, toolchainCache, _internals11, build_discovery;
|
|
41666
|
+
var ECOSYSTEMS, PROFILE_TO_ECOSYSTEM_NAMES, toolchainCache, IS_COMMAND_AVAILABLE_TIMEOUT_MS = 3000, _internals11, build_discovery;
|
|
41584
41667
|
var init_discovery = __esm(() => {
|
|
41585
41668
|
init_dist();
|
|
41586
41669
|
init_detector();
|
|
@@ -41703,7 +41786,8 @@ var init_discovery = __esm(() => {
|
|
|
41703
41786
|
discoverBuildCommandsFromProfiles,
|
|
41704
41787
|
discoverBuildCommands,
|
|
41705
41788
|
clearToolchainCache,
|
|
41706
|
-
getEcosystems
|
|
41789
|
+
getEcosystems,
|
|
41790
|
+
spawnSyncImpl: bunSpawnSync
|
|
41707
41791
|
};
|
|
41708
41792
|
build_discovery = tool({
|
|
41709
41793
|
description: "Discover build commands for various ecosystems in a project directory",
|
|
@@ -45582,16 +45666,710 @@ var init_secretscan = __esm(() => {
|
|
|
45582
45666
|
};
|
|
45583
45667
|
});
|
|
45584
45668
|
|
|
45669
|
+
// src/lang/default-backend.ts
|
|
45670
|
+
import * as fs14 from "fs";
|
|
45671
|
+
import * as path31 from "path";
|
|
45672
|
+
function detectFileExists(dir, pattern) {
|
|
45673
|
+
if (pattern.includes("*") || pattern.includes("?")) {
|
|
45674
|
+
try {
|
|
45675
|
+
const files = fs14.readdirSync(dir);
|
|
45676
|
+
const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
|
|
45677
|
+
return files.some((f) => regex.test(f));
|
|
45678
|
+
} catch {
|
|
45679
|
+
return false;
|
|
45680
|
+
}
|
|
45681
|
+
}
|
|
45682
|
+
try {
|
|
45683
|
+
fs14.accessSync(path31.join(dir, pattern));
|
|
45684
|
+
return true;
|
|
45685
|
+
} catch {
|
|
45686
|
+
return false;
|
|
45687
|
+
}
|
|
45688
|
+
}
|
|
45689
|
+
function tokenizeCommand(cmd) {
|
|
45690
|
+
const out = [];
|
|
45691
|
+
let buf = "";
|
|
45692
|
+
let quote = null;
|
|
45693
|
+
for (const ch of cmd) {
|
|
45694
|
+
if (quote) {
|
|
45695
|
+
if (ch === quote) {
|
|
45696
|
+
quote = null;
|
|
45697
|
+
} else {
|
|
45698
|
+
buf += ch;
|
|
45699
|
+
}
|
|
45700
|
+
continue;
|
|
45701
|
+
}
|
|
45702
|
+
if (ch === '"' || ch === "'") {
|
|
45703
|
+
quote = ch;
|
|
45704
|
+
continue;
|
|
45705
|
+
}
|
|
45706
|
+
if (ch === " " || ch === "\t") {
|
|
45707
|
+
if (buf.length > 0) {
|
|
45708
|
+
out.push(buf);
|
|
45709
|
+
buf = "";
|
|
45710
|
+
}
|
|
45711
|
+
continue;
|
|
45712
|
+
}
|
|
45713
|
+
buf += ch;
|
|
45714
|
+
}
|
|
45715
|
+
if (buf.length > 0)
|
|
45716
|
+
out.push(buf);
|
|
45717
|
+
return out;
|
|
45718
|
+
}
|
|
45719
|
+
async function defaultSelectTestFramework(profile, dir) {
|
|
45720
|
+
const sorted = [...profile.test.frameworks].sort((a, b) => b.priority - a.priority);
|
|
45721
|
+
for (const fw of sorted) {
|
|
45722
|
+
if (!detectFileExists(dir, fw.detect))
|
|
45723
|
+
continue;
|
|
45724
|
+
const argv = tokenizeCommand(fw.cmd);
|
|
45725
|
+
if (argv.length === 0)
|
|
45726
|
+
continue;
|
|
45727
|
+
if (!isCommandAvailable(argv[0]))
|
|
45728
|
+
continue;
|
|
45729
|
+
return {
|
|
45730
|
+
name: fw.name,
|
|
45731
|
+
cmd: argv,
|
|
45732
|
+
cwd: dir,
|
|
45733
|
+
detectedVia: fw.detect,
|
|
45734
|
+
filesIgnored: false
|
|
45735
|
+
};
|
|
45736
|
+
}
|
|
45737
|
+
return null;
|
|
45738
|
+
}
|
|
45739
|
+
function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}) {
|
|
45740
|
+
const scope = opts.scope ?? "all";
|
|
45741
|
+
const coverage = opts.coverage ?? false;
|
|
45742
|
+
switch (framework) {
|
|
45743
|
+
case "bun": {
|
|
45744
|
+
const args = ["bun", "test"];
|
|
45745
|
+
if (coverage)
|
|
45746
|
+
args.push("--coverage");
|
|
45747
|
+
if (scope !== "all" && files.length > 0)
|
|
45748
|
+
args.push(...files);
|
|
45749
|
+
return args;
|
|
45750
|
+
}
|
|
45751
|
+
case "vitest": {
|
|
45752
|
+
const args = ["npx", "vitest", "run"];
|
|
45753
|
+
if (coverage)
|
|
45754
|
+
args.push("--coverage");
|
|
45755
|
+
if (scope !== "all" && files.length > 0)
|
|
45756
|
+
args.push(...files);
|
|
45757
|
+
return args;
|
|
45758
|
+
}
|
|
45759
|
+
case "jest": {
|
|
45760
|
+
const args = ["npx", "jest"];
|
|
45761
|
+
if (coverage)
|
|
45762
|
+
args.push("--coverage");
|
|
45763
|
+
if (scope !== "all" && files.length > 0)
|
|
45764
|
+
args.push(...files);
|
|
45765
|
+
return args;
|
|
45766
|
+
}
|
|
45767
|
+
case "mocha": {
|
|
45768
|
+
const args = ["npx", "mocha"];
|
|
45769
|
+
if (scope !== "all" && files.length > 0)
|
|
45770
|
+
args.push(...files);
|
|
45771
|
+
return args;
|
|
45772
|
+
}
|
|
45773
|
+
case "pytest": {
|
|
45774
|
+
const isWindows = process.platform === "win32";
|
|
45775
|
+
const args = isWindows ? ["python", "-m", "pytest"] : ["python3", "-m", "pytest"];
|
|
45776
|
+
if (coverage)
|
|
45777
|
+
args.push("--cov=.", "--cov-report=term-missing");
|
|
45778
|
+
if (scope !== "all" && files.length > 0)
|
|
45779
|
+
args.push(...files);
|
|
45780
|
+
return args;
|
|
45781
|
+
}
|
|
45782
|
+
case "cargo": {
|
|
45783
|
+
const args = ["cargo", "test"];
|
|
45784
|
+
if (scope !== "all" && files.length > 0)
|
|
45785
|
+
args.push(...files);
|
|
45786
|
+
return args;
|
|
45787
|
+
}
|
|
45788
|
+
case "pester": {
|
|
45789
|
+
if (scope !== "all" && files.length > 0) {
|
|
45790
|
+
const escapedFiles = files.map((f) => f.replace(/'/g, "''").replace(/`/g, "``").replace(/\$/g, "`$"));
|
|
45791
|
+
const psCommand = `Invoke-Pester -Path @('${escapedFiles.join("','")}')`;
|
|
45792
|
+
const utf16Bytes = Buffer.from(psCommand, "utf16le");
|
|
45793
|
+
const base64Command = utf16Bytes.toString("base64");
|
|
45794
|
+
return ["pwsh", "-EncodedCommand", base64Command];
|
|
45795
|
+
}
|
|
45796
|
+
return ["pwsh", "-Command", "Invoke-Pester"];
|
|
45797
|
+
}
|
|
45798
|
+
case "go-test":
|
|
45799
|
+
return ["go", "test", "./..."];
|
|
45800
|
+
case "maven":
|
|
45801
|
+
return ["mvn", "test"];
|
|
45802
|
+
case "gradle": {
|
|
45803
|
+
const isWindows = process.platform === "win32";
|
|
45804
|
+
const hasGradlewBat = fs14.existsSync(path31.join(dir, "gradlew.bat"));
|
|
45805
|
+
const hasGradlew = fs14.existsSync(path31.join(dir, "gradlew"));
|
|
45806
|
+
if (hasGradlewBat && isWindows)
|
|
45807
|
+
return ["gradlew.bat", "test"];
|
|
45808
|
+
if (hasGradlew)
|
|
45809
|
+
return ["./gradlew", "test"];
|
|
45810
|
+
return ["gradle", "test"];
|
|
45811
|
+
}
|
|
45812
|
+
case "dotnet-test":
|
|
45813
|
+
return ["dotnet", "test"];
|
|
45814
|
+
case "ctest": {
|
|
45815
|
+
const buildDirCandidates = [
|
|
45816
|
+
"build",
|
|
45817
|
+
"_build",
|
|
45818
|
+
"cmake-build-debug",
|
|
45819
|
+
"cmake-build-release",
|
|
45820
|
+
"out"
|
|
45821
|
+
];
|
|
45822
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs14.existsSync(path31.join(dir, d, "CMakeCache.txt"))) ?? "build";
|
|
45823
|
+
return ["ctest", "--test-dir", actualBuildDir];
|
|
45824
|
+
}
|
|
45825
|
+
case "swift-test":
|
|
45826
|
+
return ["swift", "test"];
|
|
45827
|
+
case "dart-test":
|
|
45828
|
+
return isCommandAvailable("flutter") ? ["flutter", "test", ...files] : ["dart", "test", ...files];
|
|
45829
|
+
case "rspec": {
|
|
45830
|
+
const args = isCommandAvailable("bundle") ? ["bundle", "exec", "rspec"] : ["rspec"];
|
|
45831
|
+
if (scope !== "all" && files.length > 0)
|
|
45832
|
+
args.push(...files);
|
|
45833
|
+
return args;
|
|
45834
|
+
}
|
|
45835
|
+
case "minitest":
|
|
45836
|
+
if (scope !== "all" && files.length > 0) {
|
|
45837
|
+
const requires = files.map((f) => `require_relative '${f.replace(/\\/g, "/").replace(/'/g, "\\'")}'`).join("; ");
|
|
45838
|
+
return ["ruby", "-Itest", "-e", requires];
|
|
45839
|
+
}
|
|
45840
|
+
return [
|
|
45841
|
+
"ruby",
|
|
45842
|
+
"-Itest",
|
|
45843
|
+
"-e",
|
|
45844
|
+
'Dir.glob("test/**/*_test.rb").sort.each { |f| require_relative f }'
|
|
45845
|
+
];
|
|
45846
|
+
default: {
|
|
45847
|
+
const fw = profile.test.frameworks.find((f) => f.name === framework);
|
|
45848
|
+
if (!fw)
|
|
45849
|
+
return null;
|
|
45850
|
+
const argv = tokenizeCommand(fw.cmd);
|
|
45851
|
+
if (argv.length === 0)
|
|
45852
|
+
return null;
|
|
45853
|
+
if (files.length === 0)
|
|
45854
|
+
return argv;
|
|
45855
|
+
return [...argv, ...files];
|
|
45856
|
+
}
|
|
45857
|
+
}
|
|
45858
|
+
}
|
|
45859
|
+
function defaultParseTestOutput(framework, stdout, stderr, exitCode) {
|
|
45860
|
+
const output = stdout && stderr ? `${stdout}
|
|
45861
|
+
${stderr}` : stdout || stderr || "";
|
|
45862
|
+
let passed = 0;
|
|
45863
|
+
let failed = 0;
|
|
45864
|
+
let skipped = 0;
|
|
45865
|
+
let total;
|
|
45866
|
+
let coveragePercent;
|
|
45867
|
+
switch (framework) {
|
|
45868
|
+
case "vitest":
|
|
45869
|
+
case "jest":
|
|
45870
|
+
case "bun": {
|
|
45871
|
+
const jsonMatch = output.match(/\{[\s\S]*"testResults"[\s\S]*\}/);
|
|
45872
|
+
if (jsonMatch) {
|
|
45873
|
+
try {
|
|
45874
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
45875
|
+
if (parsed.numTotalTests !== undefined) {
|
|
45876
|
+
passed = parsed.numPassedTests || 0;
|
|
45877
|
+
failed = parsed.numFailedTests || 0;
|
|
45878
|
+
skipped = parsed.numPendingTests || 0;
|
|
45879
|
+
total = parsed.numTotalTests || 0;
|
|
45880
|
+
}
|
|
45881
|
+
if (parsed.coverage !== undefined) {
|
|
45882
|
+
coveragePercent = parsed.coverage;
|
|
45883
|
+
}
|
|
45884
|
+
} catch {}
|
|
45885
|
+
}
|
|
45886
|
+
if (total === undefined || total === 0) {
|
|
45887
|
+
const passMatch = output.match(/(\d+)\s+pass(ing|ed)?/);
|
|
45888
|
+
const failMatch = output.match(/(\d+)\s+fail(ing|ed)?/);
|
|
45889
|
+
const skipMatch = output.match(/(\d+)\s+skip(ping|ped)?/);
|
|
45890
|
+
if (passMatch)
|
|
45891
|
+
passed = parseInt(passMatch[1], 10);
|
|
45892
|
+
if (failMatch)
|
|
45893
|
+
failed = parseInt(failMatch[1], 10);
|
|
45894
|
+
if (skipMatch)
|
|
45895
|
+
skipped = parseInt(skipMatch[1], 10);
|
|
45896
|
+
total = passed + failed + skipped;
|
|
45897
|
+
}
|
|
45898
|
+
const coverageMatch = output.match(/All files[^\d]*(\d+\.?\d*)\s*%/);
|
|
45899
|
+
if (coveragePercent === undefined && coverageMatch) {
|
|
45900
|
+
coveragePercent = parseFloat(coverageMatch[1]);
|
|
45901
|
+
}
|
|
45902
|
+
break;
|
|
45903
|
+
}
|
|
45904
|
+
case "mocha": {
|
|
45905
|
+
const passMatch = output.match(/(\d+)\s+passing/);
|
|
45906
|
+
const failMatch = output.match(/(\d+)\s+failing/);
|
|
45907
|
+
const pendingMatch = output.match(/(\d+)\s+pending/);
|
|
45908
|
+
if (passMatch)
|
|
45909
|
+
passed = parseInt(passMatch[1], 10);
|
|
45910
|
+
if (failMatch)
|
|
45911
|
+
failed = parseInt(failMatch[1], 10);
|
|
45912
|
+
if (pendingMatch)
|
|
45913
|
+
skipped = parseInt(pendingMatch[1], 10);
|
|
45914
|
+
total = passed + failed + skipped;
|
|
45915
|
+
break;
|
|
45916
|
+
}
|
|
45917
|
+
case "pytest": {
|
|
45918
|
+
const passMatch = output.match(/(\d+)\s+passed/);
|
|
45919
|
+
const failMatch = output.match(/(\d+)\s+failed/);
|
|
45920
|
+
const skipMatch = output.match(/(\d+)\s+skipped/);
|
|
45921
|
+
if (passMatch)
|
|
45922
|
+
passed = parseInt(passMatch[1], 10);
|
|
45923
|
+
if (failMatch)
|
|
45924
|
+
failed = parseInt(failMatch[1], 10);
|
|
45925
|
+
if (skipMatch)
|
|
45926
|
+
skipped = parseInt(skipMatch[1], 10);
|
|
45927
|
+
total = passed + failed + skipped;
|
|
45928
|
+
const coverageMatch = output.match(/TOTAL\s+(\d+\.?\d*)\s*%/);
|
|
45929
|
+
if (coverageMatch)
|
|
45930
|
+
coveragePercent = parseFloat(coverageMatch[1]);
|
|
45931
|
+
break;
|
|
45932
|
+
}
|
|
45933
|
+
case "cargo": {
|
|
45934
|
+
const passMatch = output.match(/test result: ok\. (\d+) passed/);
|
|
45935
|
+
const failMatch = output.match(/test result: FAILED\. (\d+) passed; (\d+) failed/);
|
|
45936
|
+
if (failMatch) {
|
|
45937
|
+
passed = parseInt(failMatch[1], 10);
|
|
45938
|
+
failed = parseInt(failMatch[2], 10);
|
|
45939
|
+
} else if (passMatch) {
|
|
45940
|
+
passed = parseInt(passMatch[1], 10);
|
|
45941
|
+
}
|
|
45942
|
+
total = passed + failed;
|
|
45943
|
+
break;
|
|
45944
|
+
}
|
|
45945
|
+
case "pester": {
|
|
45946
|
+
const passMatch = output.match(/Passed:\s*(\d+)/);
|
|
45947
|
+
const failMatch = output.match(/Failed:\s*(\d+)/);
|
|
45948
|
+
const skipMatch = output.match(/Skipped:\s*(\d+)/);
|
|
45949
|
+
if (passMatch)
|
|
45950
|
+
passed = parseInt(passMatch[1], 10);
|
|
45951
|
+
if (failMatch)
|
|
45952
|
+
failed = parseInt(failMatch[1], 10);
|
|
45953
|
+
if (skipMatch)
|
|
45954
|
+
skipped = parseInt(skipMatch[1], 10);
|
|
45955
|
+
total = passed + failed + skipped;
|
|
45956
|
+
break;
|
|
45957
|
+
}
|
|
45958
|
+
case "go-test": {
|
|
45959
|
+
const passMatches = [...output.matchAll(/--- PASS:/g)];
|
|
45960
|
+
const failMatches = [...output.matchAll(/--- FAIL:/g)];
|
|
45961
|
+
const skipMatches = [...output.matchAll(/--- SKIP:/g)];
|
|
45962
|
+
passed = passMatches.length;
|
|
45963
|
+
failed = failMatches.length;
|
|
45964
|
+
skipped = skipMatches.length;
|
|
45965
|
+
total = passed + failed + skipped;
|
|
45966
|
+
const covMatch = output.match(/coverage:\s*(\d+\.?\d*)\s*%/);
|
|
45967
|
+
if (covMatch)
|
|
45968
|
+
coveragePercent = parseFloat(covMatch[1]);
|
|
45969
|
+
break;
|
|
45970
|
+
}
|
|
45971
|
+
case "maven": {
|
|
45972
|
+
const mavenMatch = output.match(/Tests run:\s*(\d+),\s*Failures:\s*(\d+),\s*Errors:\s*(\d+),\s*Skipped:\s*(\d+)/);
|
|
45973
|
+
if (mavenMatch) {
|
|
45974
|
+
const tot = parseInt(mavenMatch[1], 10);
|
|
45975
|
+
const failures = parseInt(mavenMatch[2], 10);
|
|
45976
|
+
const errors5 = parseInt(mavenMatch[3], 10);
|
|
45977
|
+
const sk = parseInt(mavenMatch[4], 10);
|
|
45978
|
+
failed = failures + errors5;
|
|
45979
|
+
skipped = sk;
|
|
45980
|
+
passed = tot - failed - sk;
|
|
45981
|
+
total = tot;
|
|
45982
|
+
}
|
|
45983
|
+
break;
|
|
45984
|
+
}
|
|
45985
|
+
case "gradle": {
|
|
45986
|
+
const gradleMatch = output.match(/(\d+) tests? completed(?:,\s*(\d+) failed)?(?:,\s*(\d+) skipped)?/);
|
|
45987
|
+
if (gradleMatch) {
|
|
45988
|
+
total = parseInt(gradleMatch[1], 10);
|
|
45989
|
+
failed = gradleMatch[2] ? parseInt(gradleMatch[2], 10) : 0;
|
|
45990
|
+
skipped = gradleMatch[3] ? parseInt(gradleMatch[3], 10) : 0;
|
|
45991
|
+
passed = total - failed - skipped;
|
|
45992
|
+
}
|
|
45993
|
+
break;
|
|
45994
|
+
}
|
|
45995
|
+
case "dotnet-test": {
|
|
45996
|
+
const passMatch = output.match(/Passed[!:]?\s*(\d+)/i);
|
|
45997
|
+
const failMatch = output.match(/Failed[!:]?\s*(\d+)/i);
|
|
45998
|
+
const skipMatch = output.match(/Skipped[!:]?\s*(\d+)/i);
|
|
45999
|
+
if (passMatch)
|
|
46000
|
+
passed = parseInt(passMatch[1], 10);
|
|
46001
|
+
if (failMatch)
|
|
46002
|
+
failed = parseInt(failMatch[1], 10);
|
|
46003
|
+
if (skipMatch)
|
|
46004
|
+
skipped = parseInt(skipMatch[1], 10);
|
|
46005
|
+
total = passed + failed + skipped;
|
|
46006
|
+
break;
|
|
46007
|
+
}
|
|
46008
|
+
case "ctest": {
|
|
46009
|
+
const ctestMatch = output.match(/(\d+) tests? failed out of (\d+)/);
|
|
46010
|
+
if (ctestMatch) {
|
|
46011
|
+
failed = parseInt(ctestMatch[1], 10);
|
|
46012
|
+
total = parseInt(ctestMatch[2], 10);
|
|
46013
|
+
passed = total - failed;
|
|
46014
|
+
} else {
|
|
46015
|
+
const allPassMatch = output.match(/100% tests passed.*?(\d+) tests?/);
|
|
46016
|
+
if (allPassMatch) {
|
|
46017
|
+
total = parseInt(allPassMatch[1], 10);
|
|
46018
|
+
passed = total;
|
|
46019
|
+
}
|
|
46020
|
+
}
|
|
46021
|
+
break;
|
|
46022
|
+
}
|
|
46023
|
+
case "swift-test": {
|
|
46024
|
+
const swiftMatch = output.match(/Executed (\d+) tests?,\s*with (\d+) failures?/);
|
|
46025
|
+
if (swiftMatch) {
|
|
46026
|
+
total = parseInt(swiftMatch[1], 10);
|
|
46027
|
+
failed = parseInt(swiftMatch[2], 10);
|
|
46028
|
+
passed = total - failed;
|
|
46029
|
+
}
|
|
46030
|
+
break;
|
|
46031
|
+
}
|
|
46032
|
+
case "dart-test": {
|
|
46033
|
+
const dartPassMatch = output.match(/\+(\d+):\s*All tests passed/);
|
|
46034
|
+
const dartMixMatch = output.match(/\+(\d+)\s+-(\d+):/);
|
|
46035
|
+
if (dartPassMatch) {
|
|
46036
|
+
passed = parseInt(dartPassMatch[1], 10);
|
|
46037
|
+
total = passed;
|
|
46038
|
+
} else if (dartMixMatch) {
|
|
46039
|
+
passed = parseInt(dartMixMatch[1], 10);
|
|
46040
|
+
failed = parseInt(dartMixMatch[2], 10);
|
|
46041
|
+
total = passed + failed;
|
|
46042
|
+
}
|
|
46043
|
+
break;
|
|
46044
|
+
}
|
|
46045
|
+
case "rspec": {
|
|
46046
|
+
const rspecMatch = output.match(/(\d+) examples?,\s*(\d+) failures?(?:,\s*(\d+) pending)?/);
|
|
46047
|
+
if (rspecMatch) {
|
|
46048
|
+
total = parseInt(rspecMatch[1], 10);
|
|
46049
|
+
failed = parseInt(rspecMatch[2], 10);
|
|
46050
|
+
skipped = rspecMatch[3] ? parseInt(rspecMatch[3], 10) : 0;
|
|
46051
|
+
passed = total - failed - skipped;
|
|
46052
|
+
}
|
|
46053
|
+
break;
|
|
46054
|
+
}
|
|
46055
|
+
case "minitest": {
|
|
46056
|
+
const minitestMatch = output.match(/(\d+) runs?,\s*\d+ assertions?,\s*(\d+) failures?,\s*(\d+) errors?,\s*(\d+) skips?/);
|
|
46057
|
+
if (minitestMatch) {
|
|
46058
|
+
total = parseInt(minitestMatch[1], 10);
|
|
46059
|
+
const failures = parseInt(minitestMatch[2], 10);
|
|
46060
|
+
const errors5 = parseInt(minitestMatch[3], 10);
|
|
46061
|
+
skipped = parseInt(minitestMatch[4], 10);
|
|
46062
|
+
failed = failures + errors5;
|
|
46063
|
+
passed = total - failed - skipped;
|
|
46064
|
+
}
|
|
46065
|
+
break;
|
|
46066
|
+
}
|
|
46067
|
+
default:
|
|
46068
|
+
break;
|
|
46069
|
+
}
|
|
46070
|
+
if (total === undefined)
|
|
46071
|
+
total = passed + failed + skipped;
|
|
46072
|
+
return {
|
|
46073
|
+
ok: exitCode === 0,
|
|
46074
|
+
raw: { stdout, stderr, exitCode },
|
|
46075
|
+
passed,
|
|
46076
|
+
failed,
|
|
46077
|
+
skipped,
|
|
46078
|
+
total,
|
|
46079
|
+
...coveragePercent !== undefined ? { coveragePercent } : {}
|
|
46080
|
+
};
|
|
46081
|
+
}
|
|
46082
|
+
async function defaultDetectProject(profile, dir) {
|
|
46083
|
+
for (const f of profile.build.detectFiles) {
|
|
46084
|
+
if (detectFileExists(dir, f))
|
|
46085
|
+
return true;
|
|
46086
|
+
}
|
|
46087
|
+
return false;
|
|
46088
|
+
}
|
|
46089
|
+
async function defaultSelectBuildCommand(profile, dir) {
|
|
46090
|
+
const sorted = [...profile.build.commands].sort((a, b) => b.priority - a.priority);
|
|
46091
|
+
for (const cmd of sorted) {
|
|
46092
|
+
if (cmd.detectFile && !detectFileExists(dir, cmd.detectFile))
|
|
46093
|
+
continue;
|
|
46094
|
+
const argv = tokenizeCommand(cmd.cmd);
|
|
46095
|
+
if (argv.length === 0)
|
|
46096
|
+
continue;
|
|
46097
|
+
if (!isCommandAvailable(argv[0]))
|
|
46098
|
+
continue;
|
|
46099
|
+
return {
|
|
46100
|
+
name: cmd.name,
|
|
46101
|
+
cmd: argv,
|
|
46102
|
+
cwd: dir,
|
|
46103
|
+
detectedVia: cmd.detectFile ?? `${profile.id} default`
|
|
46104
|
+
};
|
|
46105
|
+
}
|
|
46106
|
+
return null;
|
|
46107
|
+
}
|
|
46108
|
+
async function defaultTestFilesFor(profile, sourceFile, dir) {
|
|
46109
|
+
const ext = path31.extname(sourceFile);
|
|
46110
|
+
if (!profile.extensions.includes(ext))
|
|
46111
|
+
return [];
|
|
46112
|
+
const base = path31.basename(sourceFile, ext);
|
|
46113
|
+
const rel = path31.relative(dir, sourceFile);
|
|
46114
|
+
const relDir = path31.dirname(rel);
|
|
46115
|
+
const stripSrc = relDir.replace(/^src(\/|\\)/, "");
|
|
46116
|
+
const candidates = new Set;
|
|
46117
|
+
for (const tDir of ["tests", "test", "__tests__", "spec"]) {
|
|
46118
|
+
for (const suffix of ["", "_test", ".test", "_spec", ".spec"]) {
|
|
46119
|
+
candidates.add(path31.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
|
|
46120
|
+
}
|
|
46121
|
+
}
|
|
46122
|
+
const existing = [];
|
|
46123
|
+
for (const c of candidates) {
|
|
46124
|
+
try {
|
|
46125
|
+
fs14.accessSync(c);
|
|
46126
|
+
existing.push(c);
|
|
46127
|
+
} catch {}
|
|
46128
|
+
}
|
|
46129
|
+
return existing;
|
|
46130
|
+
}
|
|
46131
|
+
function defaultExtractImports() {
|
|
46132
|
+
return [];
|
|
46133
|
+
}
|
|
46134
|
+
async function defaultSelectFramework() {
|
|
46135
|
+
return null;
|
|
46136
|
+
}
|
|
46137
|
+
async function defaultSelectEntryPoints() {
|
|
46138
|
+
return [];
|
|
46139
|
+
}
|
|
46140
|
+
function defaultBackendFor(profile) {
|
|
46141
|
+
return {
|
|
46142
|
+
...profile,
|
|
46143
|
+
detectProject: (dir) => defaultDetectProject(profile, dir),
|
|
46144
|
+
selectTestFramework: (dir) => defaultSelectTestFramework(profile, dir),
|
|
46145
|
+
buildTestCommand: (framework, files, dir, opts) => defaultBuildTestCommand(profile, framework, files, dir, opts),
|
|
46146
|
+
parseTestOutput: (framework, stdout, stderr, exitCode) => defaultParseTestOutput(framework, stdout, stderr, exitCode),
|
|
46147
|
+
testFilesFor: (sourceFile, dir) => defaultTestFilesFor(profile, sourceFile, dir),
|
|
46148
|
+
extractImports: () => defaultExtractImports(),
|
|
46149
|
+
selectBuildCommand: (dir) => defaultSelectBuildCommand(profile, dir),
|
|
46150
|
+
selectFramework: () => defaultSelectFramework(),
|
|
46151
|
+
selectEntryPoints: () => defaultSelectEntryPoints()
|
|
46152
|
+
};
|
|
46153
|
+
}
|
|
46154
|
+
var init_default_backend = __esm(() => {
|
|
46155
|
+
init_discovery();
|
|
46156
|
+
});
|
|
46157
|
+
|
|
46158
|
+
// src/lang/backends/go.ts
|
|
46159
|
+
import * as fs15 from "fs";
|
|
46160
|
+
import * as path32 from "path";
|
|
46161
|
+
function extractImports(_sourceFile, source) {
|
|
46162
|
+
const out = new Set;
|
|
46163
|
+
IMPORT_REGEX_SINGLE.lastIndex = 0;
|
|
46164
|
+
let m = IMPORT_REGEX_SINGLE.exec(source);
|
|
46165
|
+
while (m !== null) {
|
|
46166
|
+
out.add(m[1]);
|
|
46167
|
+
m = IMPORT_REGEX_SINGLE.exec(source);
|
|
46168
|
+
}
|
|
46169
|
+
IMPORT_REGEX_GROUP.lastIndex = 0;
|
|
46170
|
+
m = IMPORT_REGEX_GROUP.exec(source);
|
|
46171
|
+
while (m !== null) {
|
|
46172
|
+
const block = m[1];
|
|
46173
|
+
IMPORT_REGEX_GROUP_LINE.lastIndex = 0;
|
|
46174
|
+
let inner = IMPORT_REGEX_GROUP_LINE.exec(block);
|
|
46175
|
+
while (inner !== null) {
|
|
46176
|
+
out.add(inner[1]);
|
|
46177
|
+
inner = IMPORT_REGEX_GROUP_LINE.exec(block);
|
|
46178
|
+
}
|
|
46179
|
+
m = IMPORT_REGEX_GROUP.exec(source);
|
|
46180
|
+
}
|
|
46181
|
+
return [...out];
|
|
46182
|
+
}
|
|
46183
|
+
async function selectFramework(dir) {
|
|
46184
|
+
let content;
|
|
46185
|
+
try {
|
|
46186
|
+
content = fs15.readFileSync(path32.join(dir, "go.mod"), "utf-8");
|
|
46187
|
+
} catch {
|
|
46188
|
+
return null;
|
|
46189
|
+
}
|
|
46190
|
+
const candidates = [
|
|
46191
|
+
["github.com/gin-gonic/gin", "gin"],
|
|
46192
|
+
["github.com/labstack/echo", "echo"],
|
|
46193
|
+
["github.com/gofiber/fiber", "fiber"],
|
|
46194
|
+
["github.com/gorilla/mux", "gorilla"],
|
|
46195
|
+
["github.com/go-chi/chi", "chi"]
|
|
46196
|
+
];
|
|
46197
|
+
for (const [pkg, name] of candidates) {
|
|
46198
|
+
if (content.includes(pkg)) {
|
|
46199
|
+
return { name, detectedVia: `go.mod require ${pkg}` };
|
|
46200
|
+
}
|
|
46201
|
+
}
|
|
46202
|
+
return null;
|
|
46203
|
+
}
|
|
46204
|
+
async function selectEntryPoints(dir) {
|
|
46205
|
+
const points = [];
|
|
46206
|
+
try {
|
|
46207
|
+
fs15.accessSync(path32.join(dir, "main.go"));
|
|
46208
|
+
points.push("main.go");
|
|
46209
|
+
} catch {}
|
|
46210
|
+
try {
|
|
46211
|
+
const cmdDir = path32.join(dir, "cmd");
|
|
46212
|
+
const subdirs = fs15.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
46213
|
+
for (const sub of subdirs) {
|
|
46214
|
+
const main = path32.join("cmd", sub.name, "main.go");
|
|
46215
|
+
try {
|
|
46216
|
+
fs15.accessSync(path32.join(dir, main));
|
|
46217
|
+
points.push(main);
|
|
46218
|
+
} catch {}
|
|
46219
|
+
}
|
|
46220
|
+
} catch {}
|
|
46221
|
+
return points;
|
|
46222
|
+
}
|
|
46223
|
+
function buildGoBackend() {
|
|
46224
|
+
const profile = LANGUAGE_REGISTRY.get(PROFILE_ID);
|
|
46225
|
+
if (!profile) {
|
|
46226
|
+
throw new Error("buildGoBackend: go profile not in LANGUAGE_REGISTRY. " + "profiles.ts must be imported before this backend.");
|
|
46227
|
+
}
|
|
46228
|
+
return {
|
|
46229
|
+
...defaultBackendFor(profile),
|
|
46230
|
+
extractImports,
|
|
46231
|
+
selectFramework,
|
|
46232
|
+
selectEntryPoints
|
|
46233
|
+
};
|
|
46234
|
+
}
|
|
46235
|
+
var PROFILE_ID = "go", IMPORT_REGEX_SINGLE, IMPORT_REGEX_GROUP, IMPORT_REGEX_GROUP_LINE, _internals18;
|
|
46236
|
+
var init_go = __esm(() => {
|
|
46237
|
+
init_default_backend();
|
|
46238
|
+
init_profiles();
|
|
46239
|
+
IMPORT_REGEX_SINGLE = /^\s*import\s+(?:[a-zA-Z_.][a-zA-Z0-9_]*\s+)?"([^"]+)"/gm;
|
|
46240
|
+
IMPORT_REGEX_GROUP = /^\s*import\s*\(([\s\S]*?)\)/gm;
|
|
46241
|
+
IMPORT_REGEX_GROUP_LINE = /(?:[a-zA-Z_.][a-zA-Z0-9_]*\s+)?"([^"]+)"/g;
|
|
46242
|
+
_internals18 = { extractImports };
|
|
46243
|
+
});
|
|
46244
|
+
|
|
46245
|
+
// src/lang/backends/python.ts
|
|
46246
|
+
import * as fs16 from "fs";
|
|
46247
|
+
import * as path33 from "path";
|
|
46248
|
+
function parseImportTargets(rawTargets) {
|
|
46249
|
+
const cleaned = rawTargets.replace(/[()]/g, "").split(`
|
|
46250
|
+
`).map((line) => line.replace(/#.*$/, "").replace(/\\\s*$/, "")).join(" ");
|
|
46251
|
+
const out = [];
|
|
46252
|
+
for (const seg of cleaned.split(",")) {
|
|
46253
|
+
const trimmed = seg.trim();
|
|
46254
|
+
if (trimmed.length === 0)
|
|
46255
|
+
continue;
|
|
46256
|
+
const name = trimmed.split(/\s+as\s+/)[0].trim();
|
|
46257
|
+
if (/^[\w]+$/.test(name))
|
|
46258
|
+
out.push(name);
|
|
46259
|
+
}
|
|
46260
|
+
return out;
|
|
46261
|
+
}
|
|
46262
|
+
function extractImports2(_sourceFile, source) {
|
|
46263
|
+
const out = new Set;
|
|
46264
|
+
source = source.replace(/\\\r?\n[ \t]*/g, " ");
|
|
46265
|
+
IMPORT_REGEX_FROM_WITH_TARGETS.lastIndex = 0;
|
|
46266
|
+
let m = IMPORT_REGEX_FROM_WITH_TARGETS.exec(source);
|
|
46267
|
+
while (m !== null) {
|
|
46268
|
+
const fromClause = m[1];
|
|
46269
|
+
const targets = parseImportTargets(m[2]);
|
|
46270
|
+
const isPurelyRelative = fromClause.length > 0 && /^\.+$/.test(fromClause);
|
|
46271
|
+
if (isPurelyRelative && targets.length > 0) {
|
|
46272
|
+
for (const t of targets)
|
|
46273
|
+
out.add(`${fromClause}${t}`);
|
|
46274
|
+
} else if (fromClause.length > 0) {
|
|
46275
|
+
out.add(fromClause);
|
|
46276
|
+
}
|
|
46277
|
+
m = IMPORT_REGEX_FROM_WITH_TARGETS.exec(source);
|
|
46278
|
+
}
|
|
46279
|
+
IMPORT_REGEX_IMPORT.lastIndex = 0;
|
|
46280
|
+
m = IMPORT_REGEX_IMPORT.exec(source);
|
|
46281
|
+
while (m !== null) {
|
|
46282
|
+
const segments = m[1].split(",");
|
|
46283
|
+
for (const seg of segments) {
|
|
46284
|
+
const trimmed = seg.trim();
|
|
46285
|
+
if (trimmed.length === 0)
|
|
46286
|
+
continue;
|
|
46287
|
+
const mod = trimmed.split(/\s+as\s+/)[0].trim();
|
|
46288
|
+
if (/^[\w.]+$/.test(mod))
|
|
46289
|
+
out.add(mod);
|
|
46290
|
+
}
|
|
46291
|
+
m = IMPORT_REGEX_IMPORT.exec(source);
|
|
46292
|
+
}
|
|
46293
|
+
return [...out];
|
|
46294
|
+
}
|
|
46295
|
+
async function selectFramework2(dir) {
|
|
46296
|
+
const candidates = [
|
|
46297
|
+
["django", "django"],
|
|
46298
|
+
["flask", "flask"],
|
|
46299
|
+
["fastapi", "fastapi"],
|
|
46300
|
+
["starlette", "starlette"],
|
|
46301
|
+
["tornado", "tornado"],
|
|
46302
|
+
["aiohttp", "aiohttp"],
|
|
46303
|
+
["bottle", "bottle"]
|
|
46304
|
+
];
|
|
46305
|
+
for (const candidate of ["pyproject.toml", "requirements.txt", "setup.py"]) {
|
|
46306
|
+
try {
|
|
46307
|
+
const content = fs16.readFileSync(path33.join(dir, candidate), "utf-8");
|
|
46308
|
+
const lower = content.toLowerCase();
|
|
46309
|
+
for (const [pkg, name] of candidates) {
|
|
46310
|
+
if (lower.includes(pkg)) {
|
|
46311
|
+
return { name, detectedVia: candidate };
|
|
46312
|
+
}
|
|
46313
|
+
}
|
|
46314
|
+
} catch {}
|
|
46315
|
+
}
|
|
46316
|
+
return null;
|
|
46317
|
+
}
|
|
46318
|
+
async function selectEntryPoints2(dir) {
|
|
46319
|
+
const points = new Set;
|
|
46320
|
+
try {
|
|
46321
|
+
const content = fs16.readFileSync(path33.join(dir, "pyproject.toml"), "utf-8");
|
|
46322
|
+
const scriptsBlock = content.match(/\[project\.scripts\][\s\S]*?(?=\n\[|$)/);
|
|
46323
|
+
if (scriptsBlock) {
|
|
46324
|
+
for (const line of scriptsBlock[0].split(`
|
|
46325
|
+
`)) {
|
|
46326
|
+
const m = line.match(/=\s*['"]([^'":]+)/);
|
|
46327
|
+
if (m) {
|
|
46328
|
+
const modPath = m[1].replace(/\./g, "/") + ".py";
|
|
46329
|
+
points.add(modPath);
|
|
46330
|
+
}
|
|
46331
|
+
}
|
|
46332
|
+
}
|
|
46333
|
+
} catch {}
|
|
46334
|
+
for (const name of ["manage.py", "main.py", "app.py", "__main__.py"]) {
|
|
46335
|
+
try {
|
|
46336
|
+
fs16.accessSync(path33.join(dir, name));
|
|
46337
|
+
points.add(name);
|
|
46338
|
+
} catch {}
|
|
46339
|
+
}
|
|
46340
|
+
return [...points];
|
|
46341
|
+
}
|
|
46342
|
+
function buildPythonBackend() {
|
|
46343
|
+
const profile = LANGUAGE_REGISTRY.get(PROFILE_ID2);
|
|
46344
|
+
if (!profile) {
|
|
46345
|
+
throw new Error("buildPythonBackend: python profile not in LANGUAGE_REGISTRY. " + "profiles.ts must be imported before this backend.");
|
|
46346
|
+
}
|
|
46347
|
+
return {
|
|
46348
|
+
...defaultBackendFor(profile),
|
|
46349
|
+
extractImports: extractImports2,
|
|
46350
|
+
selectFramework: selectFramework2,
|
|
46351
|
+
selectEntryPoints: selectEntryPoints2
|
|
46352
|
+
};
|
|
46353
|
+
}
|
|
46354
|
+
var PROFILE_ID2 = "python", IMPORT_REGEX_FROM_WITH_TARGETS, IMPORT_REGEX_IMPORT, _internals19;
|
|
46355
|
+
var init_python = __esm(() => {
|
|
46356
|
+
init_default_backend();
|
|
46357
|
+
init_profiles();
|
|
46358
|
+
IMPORT_REGEX_FROM_WITH_TARGETS = /^\s*from\s+(\.*[\w.]*)\s+import\s+(\([^)]*\)|[^\n#]+)/gm;
|
|
46359
|
+
IMPORT_REGEX_IMPORT = /^\s*import\s+([^\n#]+)/gm;
|
|
46360
|
+
_internals19 = { extractImports: extractImports2 };
|
|
46361
|
+
});
|
|
46362
|
+
|
|
45585
46363
|
// src/test-impact/analyzer.ts
|
|
45586
|
-
import
|
|
45587
|
-
import
|
|
46364
|
+
import fs17 from "fs";
|
|
46365
|
+
import path34 from "path";
|
|
45588
46366
|
function normalizePath(p) {
|
|
45589
46367
|
return p.replace(/\\/g, "/");
|
|
45590
46368
|
}
|
|
45591
46369
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
45592
46370
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
45593
46371
|
try {
|
|
45594
|
-
const stat3 =
|
|
46372
|
+
const stat3 = fs17.statSync(sourcePath);
|
|
45595
46373
|
if (stat3.mtimeMs > generatedAtMs) {
|
|
45596
46374
|
return true;
|
|
45597
46375
|
}
|
|
@@ -45605,21 +46383,108 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
45605
46383
|
if (!importPath.startsWith(".")) {
|
|
45606
46384
|
return null;
|
|
45607
46385
|
}
|
|
45608
|
-
const resolved =
|
|
45609
|
-
if (
|
|
45610
|
-
if (
|
|
46386
|
+
const resolved = path34.resolve(fromDir, importPath);
|
|
46387
|
+
if (path34.extname(resolved)) {
|
|
46388
|
+
if (fs17.existsSync(resolved) && fs17.statSync(resolved).isFile()) {
|
|
45611
46389
|
return normalizePath(resolved);
|
|
45612
46390
|
}
|
|
45613
46391
|
} else {
|
|
45614
46392
|
for (const ext of EXTENSIONS_TO_TRY) {
|
|
45615
46393
|
const withExt = resolved + ext;
|
|
45616
|
-
if (
|
|
46394
|
+
if (fs17.existsSync(withExt) && fs17.statSync(withExt).isFile()) {
|
|
45617
46395
|
return normalizePath(withExt);
|
|
45618
46396
|
}
|
|
45619
46397
|
}
|
|
45620
46398
|
}
|
|
45621
46399
|
return null;
|
|
45622
46400
|
}
|
|
46401
|
+
function resolvePythonImport(fromDir, module) {
|
|
46402
|
+
if (!module.startsWith("."))
|
|
46403
|
+
return null;
|
|
46404
|
+
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
46405
|
+
let baseDir = fromDir;
|
|
46406
|
+
for (let i = 1;i < leadingDots; i++) {
|
|
46407
|
+
baseDir = path34.dirname(baseDir);
|
|
46408
|
+
}
|
|
46409
|
+
const rest = module.slice(leadingDots);
|
|
46410
|
+
if (rest.length === 0) {
|
|
46411
|
+
const initPath = path34.join(baseDir, "__init__.py");
|
|
46412
|
+
if (fs17.existsSync(initPath) && fs17.statSync(initPath).isFile()) {
|
|
46413
|
+
return normalizePath(initPath);
|
|
46414
|
+
}
|
|
46415
|
+
return null;
|
|
46416
|
+
}
|
|
46417
|
+
const subpath = rest.replace(/\./g, path34.sep);
|
|
46418
|
+
const candidates = [
|
|
46419
|
+
`${path34.join(baseDir, subpath)}.py`,
|
|
46420
|
+
path34.join(baseDir, subpath, "__init__.py")
|
|
46421
|
+
];
|
|
46422
|
+
for (const c of candidates) {
|
|
46423
|
+
if (fs17.existsSync(c) && fs17.statSync(c).isFile())
|
|
46424
|
+
return normalizePath(c);
|
|
46425
|
+
}
|
|
46426
|
+
return null;
|
|
46427
|
+
}
|
|
46428
|
+
function findGoModule(fromDir) {
|
|
46429
|
+
const resolved = path34.resolve(fromDir);
|
|
46430
|
+
let cur = resolved;
|
|
46431
|
+
const walked = [];
|
|
46432
|
+
for (let i = 0;i < 16; i++) {
|
|
46433
|
+
const cached3 = goModuleCache.get(cur);
|
|
46434
|
+
if (cached3 !== undefined) {
|
|
46435
|
+
for (const d of walked)
|
|
46436
|
+
goModuleCache.set(d, cached3);
|
|
46437
|
+
return cached3;
|
|
46438
|
+
}
|
|
46439
|
+
walked.push(cur);
|
|
46440
|
+
try {
|
|
46441
|
+
const goMod = path34.join(cur, "go.mod");
|
|
46442
|
+
const content = fs17.readFileSync(goMod, "utf-8");
|
|
46443
|
+
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
46444
|
+
if (moduleMatch) {
|
|
46445
|
+
const result = { moduleRoot: cur, modulePath: moduleMatch[1] };
|
|
46446
|
+
for (const d of walked)
|
|
46447
|
+
goModuleCache.set(d, result);
|
|
46448
|
+
return result;
|
|
46449
|
+
}
|
|
46450
|
+
} catch {}
|
|
46451
|
+
try {
|
|
46452
|
+
fs17.accessSync(path34.join(cur, ".git"));
|
|
46453
|
+
break;
|
|
46454
|
+
} catch {}
|
|
46455
|
+
const parent = path34.dirname(cur);
|
|
46456
|
+
if (parent === cur)
|
|
46457
|
+
break;
|
|
46458
|
+
cur = parent;
|
|
46459
|
+
}
|
|
46460
|
+
for (const d of walked)
|
|
46461
|
+
goModuleCache.set(d, null);
|
|
46462
|
+
return null;
|
|
46463
|
+
}
|
|
46464
|
+
function resolveGoImport(fromDir, importPath) {
|
|
46465
|
+
let dir = null;
|
|
46466
|
+
if (importPath.startsWith(".")) {
|
|
46467
|
+
dir = path34.resolve(fromDir, importPath);
|
|
46468
|
+
} else {
|
|
46469
|
+
const mod = findGoModule(fromDir);
|
|
46470
|
+
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
46471
|
+
const subpath = importPath.slice(mod.modulePath.length);
|
|
46472
|
+
dir = path34.join(mod.moduleRoot, subpath);
|
|
46473
|
+
}
|
|
46474
|
+
}
|
|
46475
|
+
if (dir === null)
|
|
46476
|
+
return [];
|
|
46477
|
+
if (!fs17.existsSync(dir) || !fs17.statSync(dir).isDirectory())
|
|
46478
|
+
return [];
|
|
46479
|
+
try {
|
|
46480
|
+
return fs17.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(path34.join(dir, f)));
|
|
46481
|
+
} catch {
|
|
46482
|
+
return [];
|
|
46483
|
+
}
|
|
46484
|
+
}
|
|
46485
|
+
function _clearGoModuleCache() {
|
|
46486
|
+
goModuleCache.clear();
|
|
46487
|
+
}
|
|
45623
46488
|
function findTestFilesSync(cwd) {
|
|
45624
46489
|
const testFiles = [];
|
|
45625
46490
|
const skipDirs = new Set([
|
|
@@ -45632,13 +46497,13 @@ function findTestFilesSync(cwd) {
|
|
|
45632
46497
|
function walk(dir, visitedInodes) {
|
|
45633
46498
|
let entries;
|
|
45634
46499
|
try {
|
|
45635
|
-
entries =
|
|
46500
|
+
entries = fs17.readdirSync(dir, { withFileTypes: true });
|
|
45636
46501
|
} catch {
|
|
45637
46502
|
return;
|
|
45638
46503
|
}
|
|
45639
46504
|
let dirInode;
|
|
45640
46505
|
try {
|
|
45641
|
-
dirInode =
|
|
46506
|
+
dirInode = fs17.statSync(dir).ino;
|
|
45642
46507
|
} catch {
|
|
45643
46508
|
return;
|
|
45644
46509
|
}
|
|
@@ -45651,12 +46516,15 @@ function findTestFilesSync(cwd) {
|
|
|
45651
46516
|
for (const entry of entries) {
|
|
45652
46517
|
if (entry.isDirectory()) {
|
|
45653
46518
|
if (!skipDirs.has(entry.name)) {
|
|
45654
|
-
walk(
|
|
46519
|
+
walk(path34.join(dir, entry.name), visitedInodes);
|
|
45655
46520
|
}
|
|
45656
46521
|
} else if (entry.isFile()) {
|
|
45657
46522
|
const name = entry.name;
|
|
45658
|
-
|
|
45659
|
-
|
|
46523
|
+
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
46524
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path34.sep}tests${path34.sep}`) && name.endsWith(".py");
|
|
46525
|
+
const isGoTest = /.+_test\.go$/.test(name);
|
|
46526
|
+
if (isTsTest || isPyTest || isGoTest) {
|
|
46527
|
+
testFiles.push(normalizePath(path34.join(dir, entry.name)));
|
|
45660
46528
|
}
|
|
45661
46529
|
}
|
|
45662
46530
|
}
|
|
@@ -45664,7 +46532,7 @@ function findTestFilesSync(cwd) {
|
|
|
45664
46532
|
walk(cwd, new Set);
|
|
45665
46533
|
return [...new Set(testFiles)];
|
|
45666
46534
|
}
|
|
45667
|
-
function
|
|
46535
|
+
function extractImports3(content) {
|
|
45668
46536
|
function execRegex(regex, content2) {
|
|
45669
46537
|
const results = [];
|
|
45670
46538
|
regex.lastIndex = 0;
|
|
@@ -45680,68 +46548,93 @@ function extractImports(content) {
|
|
|
45680
46548
|
...execRegex(IMPORT_REGEX_REEXPORT, content)
|
|
45681
46549
|
];
|
|
45682
46550
|
}
|
|
46551
|
+
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
46552
|
+
const ext = path34.extname(testFile).toLowerCase();
|
|
46553
|
+
const testDir = path34.dirname(testFile);
|
|
46554
|
+
function addEdge(source) {
|
|
46555
|
+
if (!impactMap[source])
|
|
46556
|
+
impactMap[source] = [];
|
|
46557
|
+
if (!impactMap[source].includes(testFile)) {
|
|
46558
|
+
impactMap[source].push(testFile);
|
|
46559
|
+
}
|
|
46560
|
+
}
|
|
46561
|
+
if (TS_EXTENSIONS.has(ext)) {
|
|
46562
|
+
const imports = extractImports3(content);
|
|
46563
|
+
for (const importPath of imports) {
|
|
46564
|
+
const resolved = resolveRelativeImport(testDir, importPath);
|
|
46565
|
+
if (resolved !== null)
|
|
46566
|
+
addEdge(resolved);
|
|
46567
|
+
}
|
|
46568
|
+
return;
|
|
46569
|
+
}
|
|
46570
|
+
if (PYTHON_EXTENSIONS.has(ext)) {
|
|
46571
|
+
const modules = _internals19.extractImports(testFile, content);
|
|
46572
|
+
for (const mod of modules) {
|
|
46573
|
+
const resolved = resolvePythonImport(testDir, mod);
|
|
46574
|
+
if (resolved !== null)
|
|
46575
|
+
addEdge(resolved);
|
|
46576
|
+
}
|
|
46577
|
+
return;
|
|
46578
|
+
}
|
|
46579
|
+
if (GO_EXTENSIONS.has(ext)) {
|
|
46580
|
+
const imports = _internals18.extractImports(testFile, content);
|
|
46581
|
+
for (const importPath of imports) {
|
|
46582
|
+
const sourceFiles = resolveGoImport(testDir, importPath);
|
|
46583
|
+
for (const source of sourceFiles)
|
|
46584
|
+
addEdge(source);
|
|
46585
|
+
}
|
|
46586
|
+
return;
|
|
46587
|
+
}
|
|
46588
|
+
}
|
|
45683
46589
|
async function buildImpactMapInternal(cwd) {
|
|
45684
46590
|
const testFiles = findTestFilesSync(cwd);
|
|
45685
46591
|
const impactMap = {};
|
|
45686
46592
|
for (const testFile of testFiles) {
|
|
45687
46593
|
let content;
|
|
45688
46594
|
try {
|
|
45689
|
-
content =
|
|
46595
|
+
content = fs17.readFileSync(testFile, "utf-8");
|
|
45690
46596
|
} catch {
|
|
45691
46597
|
continue;
|
|
45692
46598
|
}
|
|
45693
46599
|
if (content.substring(0, 8192).includes("\x00")) {
|
|
45694
46600
|
continue;
|
|
45695
46601
|
}
|
|
45696
|
-
|
|
45697
|
-
const testDir = path31.dirname(testFile);
|
|
45698
|
-
for (const importPath of imports) {
|
|
45699
|
-
const resolvedSource = resolveRelativeImport(testDir, importPath);
|
|
45700
|
-
if (resolvedSource === null) {
|
|
45701
|
-
continue;
|
|
45702
|
-
}
|
|
45703
|
-
if (!impactMap[resolvedSource]) {
|
|
45704
|
-
impactMap[resolvedSource] = [];
|
|
45705
|
-
}
|
|
45706
|
-
if (!impactMap[resolvedSource].includes(testFile)) {
|
|
45707
|
-
impactMap[resolvedSource].push(testFile);
|
|
45708
|
-
}
|
|
45709
|
-
}
|
|
46602
|
+
addImpactEdgesForTestFile(testFile, content, impactMap);
|
|
45710
46603
|
}
|
|
45711
46604
|
return impactMap;
|
|
45712
46605
|
}
|
|
45713
46606
|
async function buildImpactMap(cwd) {
|
|
45714
|
-
const impactMap = await
|
|
45715
|
-
await
|
|
46607
|
+
const impactMap = await _internals20.buildImpactMapInternal(cwd);
|
|
46608
|
+
await _internals20.saveImpactMap(cwd, impactMap);
|
|
45716
46609
|
return impactMap;
|
|
45717
46610
|
}
|
|
45718
46611
|
async function loadImpactMap(cwd) {
|
|
45719
|
-
const cachePath =
|
|
45720
|
-
if (
|
|
46612
|
+
const cachePath = path34.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
46613
|
+
if (fs17.existsSync(cachePath)) {
|
|
45721
46614
|
try {
|
|
45722
|
-
const content =
|
|
46615
|
+
const content = fs17.readFileSync(cachePath, "utf-8");
|
|
45723
46616
|
const data = JSON.parse(content);
|
|
45724
46617
|
const map3 = data.map;
|
|
45725
46618
|
const generatedAt = new Date(data.generatedAt).getTime();
|
|
45726
|
-
if (!
|
|
46619
|
+
if (!_internals20.isCacheStale(map3, generatedAt)) {
|
|
45727
46620
|
return map3;
|
|
45728
46621
|
}
|
|
45729
46622
|
} catch {}
|
|
45730
46623
|
}
|
|
45731
|
-
return
|
|
46624
|
+
return _internals20.buildImpactMap(cwd);
|
|
45732
46625
|
}
|
|
45733
46626
|
async function saveImpactMap(cwd, impactMap) {
|
|
45734
|
-
const cacheDir2 =
|
|
45735
|
-
const cachePath =
|
|
45736
|
-
if (!
|
|
45737
|
-
|
|
46627
|
+
const cacheDir2 = path34.join(cwd, ".swarm", "cache");
|
|
46628
|
+
const cachePath = path34.join(cacheDir2, "impact-map.json");
|
|
46629
|
+
if (!fs17.existsSync(cacheDir2)) {
|
|
46630
|
+
fs17.mkdirSync(cacheDir2, { recursive: true });
|
|
45738
46631
|
}
|
|
45739
46632
|
const data = {
|
|
45740
46633
|
generatedAt: new Date().toISOString(),
|
|
45741
46634
|
fileCount: Object.keys(impactMap).length,
|
|
45742
46635
|
map: impactMap
|
|
45743
46636
|
};
|
|
45744
|
-
|
|
46637
|
+
fs17.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
45745
46638
|
}
|
|
45746
46639
|
async function analyzeImpact(changedFiles, cwd) {
|
|
45747
46640
|
if (!Array.isArray(changedFiles)) {
|
|
@@ -45754,11 +46647,11 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
45754
46647
|
};
|
|
45755
46648
|
}
|
|
45756
46649
|
const validFiles = changedFiles.filter((f) => typeof f === "string" && f.length > 0 && !f.includes("\x00"));
|
|
45757
|
-
const impactMap = await
|
|
46650
|
+
const impactMap = await _internals20.loadImpactMap(cwd);
|
|
45758
46651
|
const impactedTestsSet = new Set;
|
|
45759
46652
|
const untestedFiles = [];
|
|
45760
46653
|
for (const changedFile of validFiles) {
|
|
45761
|
-
const normalizedChanged = normalizePath(
|
|
46654
|
+
const normalizedChanged = normalizePath(path34.resolve(changedFile));
|
|
45762
46655
|
const tests = impactMap[normalizedChanged];
|
|
45763
46656
|
if (tests && tests.length > 0) {
|
|
45764
46657
|
for (const test of tests) {
|
|
@@ -45795,23 +46688,30 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
45795
46688
|
impactMap
|
|
45796
46689
|
};
|
|
45797
46690
|
}
|
|
45798
|
-
var IMPORT_REGEX_ES, IMPORT_REGEX_REQUIRE, IMPORT_REGEX_REEXPORT, EXTENSIONS_TO_TRY,
|
|
46691
|
+
var IMPORT_REGEX_ES, IMPORT_REGEX_REQUIRE, IMPORT_REGEX_REEXPORT, TS_EXTENSIONS, PYTHON_EXTENSIONS, GO_EXTENSIONS, EXTENSIONS_TO_TRY, goModuleCache, _internals20;
|
|
45799
46692
|
var init_analyzer = __esm(() => {
|
|
45800
|
-
|
|
46693
|
+
init_go();
|
|
46694
|
+
init_python();
|
|
46695
|
+
IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
45801
46696
|
IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
45802
46697
|
IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
46698
|
+
TS_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
46699
|
+
PYTHON_EXTENSIONS = new Set([".py"]);
|
|
46700
|
+
GO_EXTENSIONS = new Set([".go"]);
|
|
45803
46701
|
EXTENSIONS_TO_TRY = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
45804
|
-
|
|
46702
|
+
goModuleCache = new Map;
|
|
46703
|
+
_internals20 = {
|
|
45805
46704
|
normalizePath,
|
|
45806
46705
|
isCacheStale,
|
|
45807
46706
|
resolveRelativeImport,
|
|
45808
46707
|
findTestFilesSync,
|
|
45809
|
-
extractImports,
|
|
46708
|
+
extractImports: extractImports3,
|
|
45810
46709
|
buildImpactMapInternal,
|
|
45811
46710
|
buildImpactMap,
|
|
45812
46711
|
loadImpactMap,
|
|
45813
46712
|
saveImpactMap,
|
|
45814
|
-
analyzeImpact
|
|
46713
|
+
analyzeImpact,
|
|
46714
|
+
_clearGoModuleCache
|
|
45815
46715
|
};
|
|
45816
46716
|
});
|
|
45817
46717
|
|
|
@@ -46021,10 +46921,10 @@ function detectFlakyTests(allHistory) {
|
|
|
46021
46921
|
var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
|
|
46022
46922
|
|
|
46023
46923
|
// src/test-impact/history-store.ts
|
|
46024
|
-
import
|
|
46025
|
-
import
|
|
46924
|
+
import fs18 from "fs";
|
|
46925
|
+
import path35 from "path";
|
|
46026
46926
|
function getHistoryPath(workingDir) {
|
|
46027
|
-
return
|
|
46927
|
+
return path35.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
|
|
46028
46928
|
}
|
|
46029
46929
|
function sanitizeErrorMessage(errorMessage) {
|
|
46030
46930
|
if (errorMessage === undefined) {
|
|
@@ -46079,9 +46979,9 @@ function appendTestRun(record3, workingDir) {
|
|
|
46079
46979
|
changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
|
|
46080
46980
|
};
|
|
46081
46981
|
const historyPath = getHistoryPath(workingDir);
|
|
46082
|
-
const historyDir =
|
|
46083
|
-
if (!
|
|
46084
|
-
|
|
46982
|
+
const historyDir = path35.dirname(historyPath);
|
|
46983
|
+
if (!fs18.existsSync(historyDir)) {
|
|
46984
|
+
fs18.mkdirSync(historyDir, { recursive: true });
|
|
46085
46985
|
}
|
|
46086
46986
|
const existingRecords = readAllRecords(historyPath);
|
|
46087
46987
|
existingRecords.push(sanitizedRecord);
|
|
@@ -46106,24 +47006,24 @@ function appendTestRun(record3, workingDir) {
|
|
|
46106
47006
|
`)}
|
|
46107
47007
|
`;
|
|
46108
47008
|
const tempPath = `${historyPath}.tmp`;
|
|
46109
|
-
|
|
46110
|
-
|
|
47009
|
+
fs18.writeFileSync(tempPath, content, "utf-8");
|
|
47010
|
+
fs18.renameSync(tempPath, historyPath);
|
|
46111
47011
|
} catch (err) {
|
|
46112
47012
|
try {
|
|
46113
47013
|
const tempPath = `${historyPath}.tmp`;
|
|
46114
|
-
if (
|
|
46115
|
-
|
|
47014
|
+
if (fs18.existsSync(tempPath)) {
|
|
47015
|
+
fs18.unlinkSync(tempPath);
|
|
46116
47016
|
}
|
|
46117
47017
|
} catch {}
|
|
46118
47018
|
throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
|
|
46119
47019
|
}
|
|
46120
47020
|
}
|
|
46121
47021
|
function readAllRecords(historyPath) {
|
|
46122
|
-
if (!
|
|
47022
|
+
if (!fs18.existsSync(historyPath)) {
|
|
46123
47023
|
return [];
|
|
46124
47024
|
}
|
|
46125
47025
|
try {
|
|
46126
|
-
const content =
|
|
47026
|
+
const content = fs18.readFileSync(historyPath, "utf-8");
|
|
46127
47027
|
const lines = content.split(`
|
|
46128
47028
|
`);
|
|
46129
47029
|
const records = [];
|
|
@@ -46160,8 +47060,8 @@ var init_history_store = __esm(() => {
|
|
|
46160
47060
|
});
|
|
46161
47061
|
|
|
46162
47062
|
// src/tools/resolve-working-directory.ts
|
|
46163
|
-
import * as
|
|
46164
|
-
import * as
|
|
47063
|
+
import * as fs19 from "fs";
|
|
47064
|
+
import * as path36 from "path";
|
|
46165
47065
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
46166
47066
|
if (workingDirectory == null || workingDirectory === "") {
|
|
46167
47067
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -46181,18 +47081,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
46181
47081
|
};
|
|
46182
47082
|
}
|
|
46183
47083
|
}
|
|
46184
|
-
const normalizedDir =
|
|
46185
|
-
const pathParts = normalizedDir.split(
|
|
47084
|
+
const normalizedDir = path36.normalize(workingDirectory);
|
|
47085
|
+
const pathParts = normalizedDir.split(path36.sep);
|
|
46186
47086
|
if (pathParts.includes("..")) {
|
|
46187
47087
|
return {
|
|
46188
47088
|
success: false,
|
|
46189
47089
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
46190
47090
|
};
|
|
46191
47091
|
}
|
|
46192
|
-
const resolvedDir =
|
|
47092
|
+
const resolvedDir = path36.resolve(normalizedDir);
|
|
46193
47093
|
let statResult;
|
|
46194
47094
|
try {
|
|
46195
|
-
statResult =
|
|
47095
|
+
statResult = fs19.statSync(resolvedDir);
|
|
46196
47096
|
} catch {
|
|
46197
47097
|
return {
|
|
46198
47098
|
success: false,
|
|
@@ -46205,17 +47105,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
46205
47105
|
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
46206
47106
|
};
|
|
46207
47107
|
}
|
|
46208
|
-
const resolvedFallback =
|
|
47108
|
+
const resolvedFallback = path36.resolve(fallbackDirectory);
|
|
46209
47109
|
let fallbackExists = false;
|
|
46210
47110
|
try {
|
|
46211
|
-
|
|
47111
|
+
fs19.statSync(resolvedFallback);
|
|
46212
47112
|
fallbackExists = true;
|
|
46213
47113
|
} catch {
|
|
46214
47114
|
fallbackExists = false;
|
|
46215
47115
|
}
|
|
46216
47116
|
if (workingDirectory != null && workingDirectory !== "") {
|
|
46217
47117
|
if (fallbackExists) {
|
|
46218
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
47118
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path36.sep);
|
|
46219
47119
|
if (isSubdirectory) {
|
|
46220
47120
|
return {
|
|
46221
47121
|
success: false,
|
|
@@ -46235,9 +47135,418 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
46235
47135
|
}
|
|
46236
47136
|
var init_resolve_working_directory = () => {};
|
|
46237
47137
|
|
|
47138
|
+
// src/lang/registry-backend.ts
|
|
47139
|
+
class LanguageBackendRegistry {
|
|
47140
|
+
backends = new Map;
|
|
47141
|
+
register(backend) {
|
|
47142
|
+
const existing = this.backends.get(backend.id);
|
|
47143
|
+
if (existing && existing !== backend) {
|
|
47144
|
+
throw new Error(`LanguageBackendRegistry: backend id "${backend.id}" registered twice. ` + `Each LanguageBackend.id must be unique.`);
|
|
47145
|
+
}
|
|
47146
|
+
this.backends.set(backend.id, backend);
|
|
47147
|
+
}
|
|
47148
|
+
get(id) {
|
|
47149
|
+
return this.backends.get(id);
|
|
47150
|
+
}
|
|
47151
|
+
getOrDefault(id) {
|
|
47152
|
+
const registered = this.backends.get(id);
|
|
47153
|
+
if (registered)
|
|
47154
|
+
return registered;
|
|
47155
|
+
const profile = LANGUAGE_REGISTRY.get(id);
|
|
47156
|
+
if (!profile)
|
|
47157
|
+
return;
|
|
47158
|
+
return defaultBackendFor(profile);
|
|
47159
|
+
}
|
|
47160
|
+
unregister(id) {
|
|
47161
|
+
this.backends.delete(id);
|
|
47162
|
+
}
|
|
47163
|
+
}
|
|
47164
|
+
var LANGUAGE_BACKEND_REGISTRY;
|
|
47165
|
+
var init_registry_backend = __esm(() => {
|
|
47166
|
+
init_default_backend();
|
|
47167
|
+
init_profiles();
|
|
47168
|
+
LANGUAGE_BACKEND_REGISTRY = new LanguageBackendRegistry;
|
|
47169
|
+
});
|
|
47170
|
+
|
|
47171
|
+
// src/lang/backends/typescript.ts
|
|
47172
|
+
import * as fs20 from "fs";
|
|
47173
|
+
import * as path37 from "path";
|
|
47174
|
+
function readPackageJsonRaw(dir) {
|
|
47175
|
+
try {
|
|
47176
|
+
const content = fs20.readFileSync(path37.join(dir, "package.json"), "utf-8");
|
|
47177
|
+
return JSON.parse(content);
|
|
47178
|
+
} catch {
|
|
47179
|
+
return null;
|
|
47180
|
+
}
|
|
47181
|
+
}
|
|
47182
|
+
function readPackageJson(dir) {
|
|
47183
|
+
return _internals21.readPackageJsonRaw(dir);
|
|
47184
|
+
}
|
|
47185
|
+
function readPackageJsonTestScript(dir) {
|
|
47186
|
+
return readPackageJson(dir)?.scripts?.test ?? null;
|
|
47187
|
+
}
|
|
47188
|
+
function frameworkFromScriptsTest(script) {
|
|
47189
|
+
if (script.includes("vitest"))
|
|
47190
|
+
return "vitest";
|
|
47191
|
+
if (script.includes("jest"))
|
|
47192
|
+
return "jest";
|
|
47193
|
+
if (script.includes("mocha"))
|
|
47194
|
+
return "mocha";
|
|
47195
|
+
if (script.includes("bun test"))
|
|
47196
|
+
return "bun:test";
|
|
47197
|
+
return null;
|
|
47198
|
+
}
|
|
47199
|
+
function frameworkFromDevDeps(devDeps) {
|
|
47200
|
+
if (!devDeps)
|
|
47201
|
+
return null;
|
|
47202
|
+
if (devDeps.vitest || devDeps["@vitest/ui"])
|
|
47203
|
+
return "vitest";
|
|
47204
|
+
if (devDeps.jest || devDeps["@types/jest"])
|
|
47205
|
+
return "jest";
|
|
47206
|
+
if (devDeps.mocha || devDeps["@types/mocha"])
|
|
47207
|
+
return "mocha";
|
|
47208
|
+
return null;
|
|
47209
|
+
}
|
|
47210
|
+
function selectionFromFramework(profile, fwName, dir, detectedVia) {
|
|
47211
|
+
const fw = profile.test.frameworks.find((f) => f.name === fwName);
|
|
47212
|
+
if (!fw)
|
|
47213
|
+
return null;
|
|
47214
|
+
const argv = tokenizeCommand(fw.cmd);
|
|
47215
|
+
if (argv.length === 0)
|
|
47216
|
+
return null;
|
|
47217
|
+
return {
|
|
47218
|
+
name: fw.name,
|
|
47219
|
+
cmd: argv,
|
|
47220
|
+
cwd: dir,
|
|
47221
|
+
detectedVia,
|
|
47222
|
+
filesIgnored: false
|
|
47223
|
+
};
|
|
47224
|
+
}
|
|
47225
|
+
async function selectTestFramework(dir) {
|
|
47226
|
+
const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
|
|
47227
|
+
if (!profile)
|
|
47228
|
+
return null;
|
|
47229
|
+
const pkg = readPackageJson(dir);
|
|
47230
|
+
const script = pkg?.scripts?.test;
|
|
47231
|
+
if (script) {
|
|
47232
|
+
const fwName = frameworkFromScriptsTest(script);
|
|
47233
|
+
if (fwName) {
|
|
47234
|
+
const sel = selectionFromFramework(profile, fwName, dir, "package.json#scripts.test");
|
|
47235
|
+
if (sel)
|
|
47236
|
+
return sel;
|
|
47237
|
+
}
|
|
47238
|
+
}
|
|
47239
|
+
const devDepsFw = frameworkFromDevDeps(pkg?.devDependencies);
|
|
47240
|
+
if (devDepsFw) {
|
|
47241
|
+
const sel = selectionFromFramework(profile, devDepsFw, dir, "package.json#devDependencies");
|
|
47242
|
+
if (sel)
|
|
47243
|
+
return sel;
|
|
47244
|
+
}
|
|
47245
|
+
return defaultSelectTestFramework(profile, dir);
|
|
47246
|
+
}
|
|
47247
|
+
function buildTestCommand(framework, files, dir, opts) {
|
|
47248
|
+
const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
|
|
47249
|
+
if (!profile)
|
|
47250
|
+
return null;
|
|
47251
|
+
return defaultBuildTestCommand(profile, framework, files, dir, opts);
|
|
47252
|
+
}
|
|
47253
|
+
function parseTestOutput(framework, stdout, stderr, exitCode) {
|
|
47254
|
+
return defaultParseTestOutput(framework, stdout, stderr, exitCode);
|
|
47255
|
+
}
|
|
47256
|
+
async function selectFramework3(dir) {
|
|
47257
|
+
const pkg = readPackageJson(dir);
|
|
47258
|
+
if (!pkg)
|
|
47259
|
+
return null;
|
|
47260
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
47261
|
+
const order = [
|
|
47262
|
+
["next", "next"],
|
|
47263
|
+
["nuxt", "nuxt"],
|
|
47264
|
+
["@angular/core", "angular"],
|
|
47265
|
+
["svelte", "svelte"],
|
|
47266
|
+
["react", "react"],
|
|
47267
|
+
["vue", "vue"],
|
|
47268
|
+
["express", "express"],
|
|
47269
|
+
["fastify", "fastify"],
|
|
47270
|
+
["@nestjs/core", "nestjs"]
|
|
47271
|
+
];
|
|
47272
|
+
for (const [pkgName, displayName] of order) {
|
|
47273
|
+
if (deps[pkgName]) {
|
|
47274
|
+
return {
|
|
47275
|
+
name: displayName,
|
|
47276
|
+
detectedVia: `package.json#dependencies.${pkgName}`
|
|
47277
|
+
};
|
|
47278
|
+
}
|
|
47279
|
+
}
|
|
47280
|
+
return null;
|
|
47281
|
+
}
|
|
47282
|
+
async function selectEntryPoints3(dir) {
|
|
47283
|
+
const pkg = readPackageJson(dir);
|
|
47284
|
+
if (!pkg)
|
|
47285
|
+
return [];
|
|
47286
|
+
const points = [];
|
|
47287
|
+
const obj = pkg;
|
|
47288
|
+
if (obj.bin) {
|
|
47289
|
+
if (typeof obj.bin === "string")
|
|
47290
|
+
points.push(obj.bin);
|
|
47291
|
+
else
|
|
47292
|
+
for (const v of Object.values(obj.bin))
|
|
47293
|
+
points.push(v);
|
|
47294
|
+
}
|
|
47295
|
+
if (obj.main)
|
|
47296
|
+
points.push(obj.main);
|
|
47297
|
+
if (obj.module && obj.module !== obj.main)
|
|
47298
|
+
points.push(obj.module);
|
|
47299
|
+
if (obj.exports && typeof obj.exports === "object") {
|
|
47300
|
+
const root = obj.exports["."];
|
|
47301
|
+
if (typeof root === "string" && !points.includes(root))
|
|
47302
|
+
points.push(root);
|
|
47303
|
+
}
|
|
47304
|
+
return [...new Set(points.filter((p) => p.length > 0))];
|
|
47305
|
+
}
|
|
47306
|
+
function extractImports4(_sourceFile, source) {
|
|
47307
|
+
const out = new Set;
|
|
47308
|
+
for (const re of [
|
|
47309
|
+
IMPORT_REGEX_ES2,
|
|
47310
|
+
IMPORT_REGEX_BARE,
|
|
47311
|
+
IMPORT_REGEX_REQUIRE2,
|
|
47312
|
+
IMPORT_REGEX_DYNAMIC,
|
|
47313
|
+
IMPORT_REGEX_REEXPORT2
|
|
47314
|
+
]) {
|
|
47315
|
+
re.lastIndex = 0;
|
|
47316
|
+
let m = re.exec(source);
|
|
47317
|
+
while (m !== null) {
|
|
47318
|
+
out.add(m[1]);
|
|
47319
|
+
m = re.exec(source);
|
|
47320
|
+
}
|
|
47321
|
+
}
|
|
47322
|
+
return [...out];
|
|
47323
|
+
}
|
|
47324
|
+
async function selectBuildCommand(dir) {
|
|
47325
|
+
const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
|
|
47326
|
+
if (!profile)
|
|
47327
|
+
return null;
|
|
47328
|
+
return defaultSelectBuildCommand(profile, dir);
|
|
47329
|
+
}
|
|
47330
|
+
async function testFilesFor(sourceFile, dir) {
|
|
47331
|
+
const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
|
|
47332
|
+
if (!profile)
|
|
47333
|
+
return [];
|
|
47334
|
+
return defaultTestFilesFor(profile, sourceFile, dir);
|
|
47335
|
+
}
|
|
47336
|
+
function buildTypescriptBackend() {
|
|
47337
|
+
const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
|
|
47338
|
+
if (!profile) {
|
|
47339
|
+
throw new Error("buildTypescriptBackend: typescript profile not in LANGUAGE_REGISTRY. " + "profiles.ts must be imported before this backend.");
|
|
47340
|
+
}
|
|
47341
|
+
return {
|
|
47342
|
+
...profile,
|
|
47343
|
+
selectTestFramework,
|
|
47344
|
+
buildTestCommand,
|
|
47345
|
+
parseTestOutput,
|
|
47346
|
+
extractImports: extractImports4,
|
|
47347
|
+
selectBuildCommand,
|
|
47348
|
+
testFilesFor,
|
|
47349
|
+
selectFramework: selectFramework3,
|
|
47350
|
+
selectEntryPoints: selectEntryPoints3
|
|
47351
|
+
};
|
|
47352
|
+
}
|
|
47353
|
+
var PROFILE_ID3 = "typescript", IMPORT_REGEX_ES2, IMPORT_REGEX_BARE, IMPORT_REGEX_REQUIRE2, IMPORT_REGEX_DYNAMIC, IMPORT_REGEX_REEXPORT2, _internals21;
|
|
47354
|
+
var init_typescript = __esm(() => {
|
|
47355
|
+
init_default_backend();
|
|
47356
|
+
init_profiles();
|
|
47357
|
+
IMPORT_REGEX_ES2 = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
47358
|
+
IMPORT_REGEX_BARE = /import\s+['"]([^'"]+)['"]/g;
|
|
47359
|
+
IMPORT_REGEX_REQUIRE2 = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
47360
|
+
IMPORT_REGEX_DYNAMIC = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
47361
|
+
IMPORT_REGEX_REEXPORT2 = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
47362
|
+
_internals21 = {
|
|
47363
|
+
readPackageJsonRaw,
|
|
47364
|
+
readPackageJsonTestScript,
|
|
47365
|
+
frameworkFromScriptsTest
|
|
47366
|
+
};
|
|
47367
|
+
});
|
|
47368
|
+
|
|
47369
|
+
// src/lang/backends/index.ts
|
|
47370
|
+
function registerAllBackends() {
|
|
47371
|
+
if (registered)
|
|
47372
|
+
return;
|
|
47373
|
+
LANGUAGE_BACKEND_REGISTRY.register(buildTypescriptBackend());
|
|
47374
|
+
LANGUAGE_BACKEND_REGISTRY.register(buildPythonBackend());
|
|
47375
|
+
LANGUAGE_BACKEND_REGISTRY.register(buildGoBackend());
|
|
47376
|
+
registered = true;
|
|
47377
|
+
}
|
|
47378
|
+
var registered = false;
|
|
47379
|
+
var init_backends = __esm(() => {
|
|
47380
|
+
init_registry_backend();
|
|
47381
|
+
init_go();
|
|
47382
|
+
init_python();
|
|
47383
|
+
init_typescript();
|
|
47384
|
+
registerAllBackends();
|
|
47385
|
+
});
|
|
47386
|
+
|
|
47387
|
+
// src/lang/dispatch.ts
|
|
47388
|
+
var exports_dispatch = {};
|
|
47389
|
+
__export(exports_dispatch, {
|
|
47390
|
+
pickedProfiles: () => pickedProfiles,
|
|
47391
|
+
pickBackend: () => pickBackend,
|
|
47392
|
+
clearDispatchCache: () => clearDispatchCache,
|
|
47393
|
+
_internals: () => _internals22
|
|
47394
|
+
});
|
|
47395
|
+
import * as fs21 from "fs";
|
|
47396
|
+
import * as path38 from "path";
|
|
47397
|
+
function safeReaddirSet(dir) {
|
|
47398
|
+
try {
|
|
47399
|
+
return new Set(fs21.readdirSync(dir));
|
|
47400
|
+
} catch {
|
|
47401
|
+
return new Set;
|
|
47402
|
+
}
|
|
47403
|
+
}
|
|
47404
|
+
function manifestHash(dir) {
|
|
47405
|
+
const entries = safeReaddirSet(dir);
|
|
47406
|
+
if (entries.size === 0)
|
|
47407
|
+
return "";
|
|
47408
|
+
const parts = [];
|
|
47409
|
+
for (const name of MANIFEST_FILES) {
|
|
47410
|
+
if (!entries.has(name))
|
|
47411
|
+
continue;
|
|
47412
|
+
try {
|
|
47413
|
+
const stat3 = fs21.statSync(path38.join(dir, name));
|
|
47414
|
+
parts.push(`${name}:${stat3.size}:${stat3.mtimeMs}:${stat3.ino}`);
|
|
47415
|
+
} catch {}
|
|
47416
|
+
}
|
|
47417
|
+
return parts.join("|");
|
|
47418
|
+
}
|
|
47419
|
+
function findManifestRoot(start) {
|
|
47420
|
+
const resolved = path38.resolve(start);
|
|
47421
|
+
const cached3 = manifestRootCache.get(resolved);
|
|
47422
|
+
if (cached3 !== undefined)
|
|
47423
|
+
return cached3;
|
|
47424
|
+
let cur = resolved;
|
|
47425
|
+
for (let i = 0;i < 32; i++) {
|
|
47426
|
+
const entries = safeReaddirSet(cur);
|
|
47427
|
+
if (entries.size > 0) {
|
|
47428
|
+
for (const name of MANIFEST_FILES) {
|
|
47429
|
+
if (entries.has(name)) {
|
|
47430
|
+
manifestRootCache.set(resolved, cur);
|
|
47431
|
+
return cur;
|
|
47432
|
+
}
|
|
47433
|
+
}
|
|
47434
|
+
if (entries.has(".git")) {
|
|
47435
|
+
manifestRootCache.set(resolved, cur);
|
|
47436
|
+
return cur;
|
|
47437
|
+
}
|
|
47438
|
+
}
|
|
47439
|
+
const parent = path38.dirname(cur);
|
|
47440
|
+
if (parent === cur)
|
|
47441
|
+
break;
|
|
47442
|
+
cur = parent;
|
|
47443
|
+
}
|
|
47444
|
+
manifestRootCache.set(resolved, start);
|
|
47445
|
+
return start;
|
|
47446
|
+
}
|
|
47447
|
+
function evictIfNeeded() {
|
|
47448
|
+
if (cache.size <= _internals22.cacheCapacity)
|
|
47449
|
+
return;
|
|
47450
|
+
let oldestKey;
|
|
47451
|
+
let oldestOrder = Infinity;
|
|
47452
|
+
for (const [k, v] of cache.entries()) {
|
|
47453
|
+
if (v.insertOrder < oldestOrder) {
|
|
47454
|
+
oldestOrder = v.insertOrder;
|
|
47455
|
+
oldestKey = k;
|
|
47456
|
+
}
|
|
47457
|
+
}
|
|
47458
|
+
if (oldestKey !== undefined)
|
|
47459
|
+
cache.delete(oldestKey);
|
|
47460
|
+
}
|
|
47461
|
+
async function pickBackend(dir) {
|
|
47462
|
+
const root = findManifestRoot(dir);
|
|
47463
|
+
const hash3 = manifestHash(root);
|
|
47464
|
+
const cacheKey = root;
|
|
47465
|
+
const cached3 = cache.get(cacheKey);
|
|
47466
|
+
if (cached3 && cached3.hash === hash3) {
|
|
47467
|
+
return cached3.backend;
|
|
47468
|
+
}
|
|
47469
|
+
if (hash3 === "") {
|
|
47470
|
+
cache.set(cacheKey, {
|
|
47471
|
+
hash: hash3,
|
|
47472
|
+
backend: null,
|
|
47473
|
+
profiles: [],
|
|
47474
|
+
insertOrder: insertCounter++
|
|
47475
|
+
});
|
|
47476
|
+
evictIfNeeded();
|
|
47477
|
+
return null;
|
|
47478
|
+
}
|
|
47479
|
+
const profiles = await _internals22.detectProjectLanguages(root);
|
|
47480
|
+
if (profiles.length === 0) {
|
|
47481
|
+
cache.set(cacheKey, {
|
|
47482
|
+
hash: hash3,
|
|
47483
|
+
backend: null,
|
|
47484
|
+
profiles: [],
|
|
47485
|
+
insertOrder: insertCounter++
|
|
47486
|
+
});
|
|
47487
|
+
evictIfNeeded();
|
|
47488
|
+
return null;
|
|
47489
|
+
}
|
|
47490
|
+
const winner = profiles[0];
|
|
47491
|
+
const backend = LANGUAGE_BACKEND_REGISTRY.getOrDefault(winner.id) ?? null;
|
|
47492
|
+
cache.set(cacheKey, {
|
|
47493
|
+
hash: hash3,
|
|
47494
|
+
backend,
|
|
47495
|
+
profiles: profiles.map((p) => ({ id: p.id })),
|
|
47496
|
+
insertOrder: insertCounter++
|
|
47497
|
+
});
|
|
47498
|
+
evictIfNeeded();
|
|
47499
|
+
return backend;
|
|
47500
|
+
}
|
|
47501
|
+
function pickedProfiles(dir) {
|
|
47502
|
+
const root = findManifestRoot(dir);
|
|
47503
|
+
const cached3 = cache.get(root);
|
|
47504
|
+
return cached3?.profiles ?? [];
|
|
47505
|
+
}
|
|
47506
|
+
function clearDispatchCache() {
|
|
47507
|
+
cache.clear();
|
|
47508
|
+
manifestRootCache.clear();
|
|
47509
|
+
insertCounter = 0;
|
|
47510
|
+
}
|
|
47511
|
+
var _internals22, cache, insertCounter = 0, MANIFEST_FILES, MANIFEST_SET, manifestRootCache;
|
|
47512
|
+
var init_dispatch = __esm(() => {
|
|
47513
|
+
init_backends();
|
|
47514
|
+
init_detector();
|
|
47515
|
+
init_registry_backend();
|
|
47516
|
+
_internals22 = {
|
|
47517
|
+
detectProjectLanguages,
|
|
47518
|
+
cacheCapacity: 64
|
|
47519
|
+
};
|
|
47520
|
+
cache = new Map;
|
|
47521
|
+
MANIFEST_FILES = [
|
|
47522
|
+
"package.json",
|
|
47523
|
+
"tsconfig.json",
|
|
47524
|
+
"pyproject.toml",
|
|
47525
|
+
"setup.py",
|
|
47526
|
+
"setup.cfg",
|
|
47527
|
+
"requirements.txt",
|
|
47528
|
+
"Pipfile",
|
|
47529
|
+
"Cargo.toml",
|
|
47530
|
+
"go.mod",
|
|
47531
|
+
"pom.xml",
|
|
47532
|
+
"build.gradle",
|
|
47533
|
+
"build.gradle.kts",
|
|
47534
|
+
"build.zig",
|
|
47535
|
+
"CMakeLists.txt",
|
|
47536
|
+
"Makefile",
|
|
47537
|
+
"meson.build",
|
|
47538
|
+
"Package.swift",
|
|
47539
|
+
"pubspec.yaml",
|
|
47540
|
+
"Gemfile",
|
|
47541
|
+
"composer.json"
|
|
47542
|
+
];
|
|
47543
|
+
MANIFEST_SET = new Set(MANIFEST_FILES);
|
|
47544
|
+
manifestRootCache = new Map;
|
|
47545
|
+
});
|
|
47546
|
+
|
|
46238
47547
|
// src/tools/test-runner.ts
|
|
46239
|
-
import * as
|
|
46240
|
-
import * as
|
|
47548
|
+
import * as fs22 from "fs";
|
|
47549
|
+
import * as path39 from "path";
|
|
46241
47550
|
function isAbsolutePath(str) {
|
|
46242
47551
|
if (str.startsWith("/"))
|
|
46243
47552
|
return true;
|
|
@@ -46302,19 +47611,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
46302
47611
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
46303
47612
|
}
|
|
46304
47613
|
function detectGoTest(cwd) {
|
|
46305
|
-
return
|
|
47614
|
+
return fs22.existsSync(path39.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
46306
47615
|
}
|
|
46307
47616
|
function detectJavaMaven(cwd) {
|
|
46308
|
-
return
|
|
47617
|
+
return fs22.existsSync(path39.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
46309
47618
|
}
|
|
46310
47619
|
function detectGradle(cwd) {
|
|
46311
|
-
const hasBuildFile =
|
|
46312
|
-
const hasGradlew =
|
|
47620
|
+
const hasBuildFile = fs22.existsSync(path39.join(cwd, "build.gradle")) || fs22.existsSync(path39.join(cwd, "build.gradle.kts"));
|
|
47621
|
+
const hasGradlew = fs22.existsSync(path39.join(cwd, "gradlew")) || fs22.existsSync(path39.join(cwd, "gradlew.bat"));
|
|
46313
47622
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
46314
47623
|
}
|
|
46315
47624
|
function detectDotnetTest(cwd) {
|
|
46316
47625
|
try {
|
|
46317
|
-
const files =
|
|
47626
|
+
const files = fs22.readdirSync(cwd);
|
|
46318
47627
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
46319
47628
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
46320
47629
|
} catch {
|
|
@@ -46322,32 +47631,89 @@ function detectDotnetTest(cwd) {
|
|
|
46322
47631
|
}
|
|
46323
47632
|
}
|
|
46324
47633
|
function detectCTest(cwd) {
|
|
46325
|
-
const hasSource =
|
|
46326
|
-
const hasBuildCache =
|
|
47634
|
+
const hasSource = fs22.existsSync(path39.join(cwd, "CMakeLists.txt"));
|
|
47635
|
+
const hasBuildCache = fs22.existsSync(path39.join(cwd, "CMakeCache.txt")) || fs22.existsSync(path39.join(cwd, "build", "CMakeCache.txt"));
|
|
46327
47636
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
46328
47637
|
}
|
|
46329
47638
|
function detectSwiftTest(cwd) {
|
|
46330
|
-
return
|
|
47639
|
+
return fs22.existsSync(path39.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
46331
47640
|
}
|
|
46332
47641
|
function detectDartTest(cwd) {
|
|
46333
|
-
return
|
|
47642
|
+
return fs22.existsSync(path39.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
46334
47643
|
}
|
|
46335
47644
|
function detectRSpec(cwd) {
|
|
46336
|
-
const hasRSpecFile =
|
|
46337
|
-
const hasGemfile =
|
|
46338
|
-
const hasSpecDir =
|
|
47645
|
+
const hasRSpecFile = fs22.existsSync(path39.join(cwd, ".rspec"));
|
|
47646
|
+
const hasGemfile = fs22.existsSync(path39.join(cwd, "Gemfile"));
|
|
47647
|
+
const hasSpecDir = fs22.existsSync(path39.join(cwd, "spec"));
|
|
46339
47648
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
46340
47649
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
46341
47650
|
}
|
|
46342
47651
|
function detectMinitest(cwd) {
|
|
46343
|
-
return
|
|
47652
|
+
return fs22.existsSync(path39.join(cwd, "test")) && (fs22.existsSync(path39.join(cwd, "Gemfile")) || fs22.existsSync(path39.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
47653
|
+
}
|
|
47654
|
+
async function detectTestFrameworkViaDispatch(cwd) {
|
|
47655
|
+
try {
|
|
47656
|
+
const { pickBackend: pickBackend2 } = await Promise.resolve().then(() => (init_dispatch(), exports_dispatch));
|
|
47657
|
+
const backend = await pickBackend2(cwd);
|
|
47658
|
+
if (!backend?.selectTestFramework)
|
|
47659
|
+
return "none";
|
|
47660
|
+
const sel = await backend.selectTestFramework(cwd);
|
|
47661
|
+
if (!sel)
|
|
47662
|
+
return "none";
|
|
47663
|
+
return DISPATCH_FRAMEWORK_MAP[sel.name] ?? "none";
|
|
47664
|
+
} catch {
|
|
47665
|
+
return "none";
|
|
47666
|
+
}
|
|
47667
|
+
}
|
|
47668
|
+
async function buildTestCommandViaDispatch(framework, scope, files, coverage, baseDir) {
|
|
47669
|
+
if (framework === "none")
|
|
47670
|
+
return null;
|
|
47671
|
+
try {
|
|
47672
|
+
const { pickBackend: pickBackend2 } = await Promise.resolve().then(() => (init_dispatch(), exports_dispatch));
|
|
47673
|
+
const backend = await pickBackend2(baseDir);
|
|
47674
|
+
if (backend?.buildTestCommand) {
|
|
47675
|
+
const cmd = backend.buildTestCommand(framework, files, baseDir, {
|
|
47676
|
+
scope,
|
|
47677
|
+
coverage
|
|
47678
|
+
});
|
|
47679
|
+
if (cmd)
|
|
47680
|
+
return cmd;
|
|
47681
|
+
}
|
|
47682
|
+
return null;
|
|
47683
|
+
} catch {
|
|
47684
|
+
return null;
|
|
47685
|
+
}
|
|
47686
|
+
}
|
|
47687
|
+
async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
47688
|
+
if (framework === "none")
|
|
47689
|
+
return null;
|
|
47690
|
+
try {
|
|
47691
|
+
const { pickBackend: pickBackend2 } = await Promise.resolve().then(() => (init_dispatch(), exports_dispatch));
|
|
47692
|
+
const backend = await pickBackend2(baseDir);
|
|
47693
|
+
if (!backend?.parseTestOutput)
|
|
47694
|
+
return null;
|
|
47695
|
+
const summary = backend.parseTestOutput(framework, output, "", 0);
|
|
47696
|
+
const passed = summary.passed ?? 0;
|
|
47697
|
+
const failed = summary.failed ?? 0;
|
|
47698
|
+
const skipped = summary.skipped ?? 0;
|
|
47699
|
+
const total = summary.total ?? passed + failed + skipped;
|
|
47700
|
+
const result = {
|
|
47701
|
+
totals: { passed, failed, skipped, total }
|
|
47702
|
+
};
|
|
47703
|
+
if (summary.coveragePercent !== undefined) {
|
|
47704
|
+
result.coveragePercent = summary.coveragePercent;
|
|
47705
|
+
}
|
|
47706
|
+
return result;
|
|
47707
|
+
} catch {
|
|
47708
|
+
return null;
|
|
47709
|
+
}
|
|
46344
47710
|
}
|
|
46345
47711
|
async function detectTestFramework(cwd) {
|
|
46346
47712
|
const baseDir = cwd;
|
|
46347
47713
|
try {
|
|
46348
|
-
const packageJsonPath =
|
|
46349
|
-
if (
|
|
46350
|
-
const content =
|
|
47714
|
+
const packageJsonPath = path39.join(baseDir, "package.json");
|
|
47715
|
+
if (fs22.existsSync(packageJsonPath)) {
|
|
47716
|
+
const content = fs22.readFileSync(packageJsonPath, "utf-8");
|
|
46351
47717
|
const pkg = JSON.parse(content);
|
|
46352
47718
|
const _deps = pkg.dependencies || {};
|
|
46353
47719
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -46366,38 +47732,38 @@ async function detectTestFramework(cwd) {
|
|
|
46366
47732
|
return "jest";
|
|
46367
47733
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
46368
47734
|
return "mocha";
|
|
46369
|
-
if (
|
|
47735
|
+
if (fs22.existsSync(path39.join(baseDir, "bun.lockb")) || fs22.existsSync(path39.join(baseDir, "bun.lock"))) {
|
|
46370
47736
|
if (scripts.test?.includes("bun"))
|
|
46371
47737
|
return "bun";
|
|
46372
47738
|
}
|
|
46373
47739
|
}
|
|
46374
47740
|
} catch {}
|
|
46375
47741
|
try {
|
|
46376
|
-
const pyprojectTomlPath =
|
|
46377
|
-
const setupCfgPath =
|
|
46378
|
-
const requirementsTxtPath =
|
|
46379
|
-
if (
|
|
46380
|
-
const content =
|
|
47742
|
+
const pyprojectTomlPath = path39.join(baseDir, "pyproject.toml");
|
|
47743
|
+
const setupCfgPath = path39.join(baseDir, "setup.cfg");
|
|
47744
|
+
const requirementsTxtPath = path39.join(baseDir, "requirements.txt");
|
|
47745
|
+
if (fs22.existsSync(pyprojectTomlPath)) {
|
|
47746
|
+
const content = fs22.readFileSync(pyprojectTomlPath, "utf-8");
|
|
46381
47747
|
if (content.includes("[tool.pytest"))
|
|
46382
47748
|
return "pytest";
|
|
46383
47749
|
if (content.includes("pytest"))
|
|
46384
47750
|
return "pytest";
|
|
46385
47751
|
}
|
|
46386
|
-
if (
|
|
46387
|
-
const content =
|
|
47752
|
+
if (fs22.existsSync(setupCfgPath)) {
|
|
47753
|
+
const content = fs22.readFileSync(setupCfgPath, "utf-8");
|
|
46388
47754
|
if (content.includes("[pytest]"))
|
|
46389
47755
|
return "pytest";
|
|
46390
47756
|
}
|
|
46391
|
-
if (
|
|
46392
|
-
const content =
|
|
47757
|
+
if (fs22.existsSync(requirementsTxtPath)) {
|
|
47758
|
+
const content = fs22.readFileSync(requirementsTxtPath, "utf-8");
|
|
46393
47759
|
if (content.includes("pytest"))
|
|
46394
47760
|
return "pytest";
|
|
46395
47761
|
}
|
|
46396
47762
|
} catch {}
|
|
46397
47763
|
try {
|
|
46398
|
-
const cargoTomlPath =
|
|
46399
|
-
if (
|
|
46400
|
-
const content =
|
|
47764
|
+
const cargoTomlPath = path39.join(baseDir, "Cargo.toml");
|
|
47765
|
+
if (fs22.existsSync(cargoTomlPath)) {
|
|
47766
|
+
const content = fs22.readFileSync(cargoTomlPath, "utf-8");
|
|
46401
47767
|
if (content.includes("[dev-dependencies]")) {
|
|
46402
47768
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
46403
47769
|
return "cargo";
|
|
@@ -46406,10 +47772,10 @@ async function detectTestFramework(cwd) {
|
|
|
46406
47772
|
}
|
|
46407
47773
|
} catch {}
|
|
46408
47774
|
try {
|
|
46409
|
-
const pesterConfigPath =
|
|
46410
|
-
const pesterConfigJsonPath =
|
|
46411
|
-
const pesterPs1Path =
|
|
46412
|
-
if (
|
|
47775
|
+
const pesterConfigPath = path39.join(baseDir, "pester.config.ps1");
|
|
47776
|
+
const pesterConfigJsonPath = path39.join(baseDir, "pester.config.ps1.json");
|
|
47777
|
+
const pesterPs1Path = path39.join(baseDir, "tests.ps1");
|
|
47778
|
+
if (fs22.existsSync(pesterConfigPath) || fs22.existsSync(pesterConfigJsonPath) || fs22.existsSync(pesterPs1Path)) {
|
|
46413
47779
|
return "pester";
|
|
46414
47780
|
}
|
|
46415
47781
|
} catch {}
|
|
@@ -46437,12 +47803,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
46437
47803
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
46438
47804
|
}
|
|
46439
47805
|
function resolveWorkspacePath(file3, workingDir) {
|
|
46440
|
-
return
|
|
47806
|
+
return path39.isAbsolute(file3) ? path39.resolve(file3) : path39.resolve(workingDir, file3);
|
|
46441
47807
|
}
|
|
46442
47808
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
46443
47809
|
if (!preferRelative)
|
|
46444
47810
|
return absolutePath;
|
|
46445
|
-
return
|
|
47811
|
+
return path39.relative(workingDir, absolutePath);
|
|
46446
47812
|
}
|
|
46447
47813
|
function dedupePush(target, value) {
|
|
46448
47814
|
if (!target.includes(value)) {
|
|
@@ -46479,18 +47845,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
46479
47845
|
}
|
|
46480
47846
|
}
|
|
46481
47847
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
46482
|
-
const relativeDir =
|
|
47848
|
+
const relativeDir = path39.dirname(relativePath);
|
|
46483
47849
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
46484
47850
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
46485
|
-
const rootDir =
|
|
46486
|
-
return nestedRelativeDir ? [rootDir,
|
|
47851
|
+
const rootDir = path39.join(workingDir, dirName);
|
|
47852
|
+
return nestedRelativeDir ? [rootDir, path39.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
46487
47853
|
});
|
|
46488
47854
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
46489
47855
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
46490
|
-
directories.push(
|
|
47856
|
+
directories.push(path39.join(workingDir, "src/test/java", path39.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
46491
47857
|
}
|
|
46492
47858
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
46493
|
-
directories.push(
|
|
47859
|
+
directories.push(path39.join(workingDir, "src/test/kotlin", path39.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
46494
47860
|
}
|
|
46495
47861
|
return [...new Set(directories)];
|
|
46496
47862
|
}
|
|
@@ -46498,19 +47864,19 @@ function hasCompoundTestExtension(filename) {
|
|
|
46498
47864
|
const lower = filename.toLowerCase();
|
|
46499
47865
|
return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
46500
47866
|
}
|
|
46501
|
-
function isLanguageSpecificTestFile(
|
|
46502
|
-
const lower =
|
|
47867
|
+
function isLanguageSpecificTestFile(basename6) {
|
|
47868
|
+
const lower = basename6.toLowerCase();
|
|
46503
47869
|
if (lower.endsWith("_test.go"))
|
|
46504
47870
|
return true;
|
|
46505
47871
|
if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
|
|
46506
47872
|
return true;
|
|
46507
47873
|
if (lower.endsWith("_spec.rb"))
|
|
46508
47874
|
return true;
|
|
46509
|
-
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(
|
|
47875
|
+
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename6) || basename6.endsWith("Test.java") || basename6.endsWith("Tests.java") || lower.endsWith("it.java")))
|
|
46510
47876
|
return true;
|
|
46511
47877
|
if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
|
|
46512
47878
|
return true;
|
|
46513
|
-
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(
|
|
47879
|
+
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename6) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
|
|
46514
47880
|
return true;
|
|
46515
47881
|
if (lower.endsWith(".tests.ps1"))
|
|
46516
47882
|
return true;
|
|
@@ -46518,23 +47884,23 @@ function isLanguageSpecificTestFile(basename5) {
|
|
|
46518
47884
|
}
|
|
46519
47885
|
function isConventionTestFilePath(filePath) {
|
|
46520
47886
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
46521
|
-
const
|
|
46522
|
-
return hasCompoundTestExtension(
|
|
47887
|
+
const basename6 = path39.basename(filePath);
|
|
47888
|
+
return hasCompoundTestExtension(basename6) || basename6.includes(".spec.") || basename6.includes(".test.") || isLanguageSpecificTestFile(basename6) || isTestDirectoryPath(normalizedPath);
|
|
46523
47889
|
}
|
|
46524
47890
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
46525
47891
|
const testFiles = [];
|
|
46526
47892
|
for (const file3 of sourceFiles) {
|
|
46527
47893
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
46528
|
-
const relativeFile =
|
|
46529
|
-
const
|
|
46530
|
-
const
|
|
46531
|
-
const preferRelativeOutput = !
|
|
47894
|
+
const relativeFile = path39.relative(workingDir, absoluteFile);
|
|
47895
|
+
const basename6 = path39.basename(absoluteFile);
|
|
47896
|
+
const dirname18 = path39.dirname(absoluteFile);
|
|
47897
|
+
const preferRelativeOutput = !path39.isAbsolute(file3);
|
|
46532
47898
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
46533
47899
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
46534
47900
|
continue;
|
|
46535
47901
|
}
|
|
46536
|
-
const nameWithoutExt =
|
|
46537
|
-
const ext =
|
|
47902
|
+
const nameWithoutExt = basename6.replace(/\.[^.]+$/, "");
|
|
47903
|
+
const ext = path39.extname(basename6);
|
|
46538
47904
|
const genericTestNames = [
|
|
46539
47905
|
`${nameWithoutExt}.spec${ext}`,
|
|
46540
47906
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -46543,20 +47909,20 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
46543
47909
|
const colocatedCandidates = [
|
|
46544
47910
|
...genericTestNames,
|
|
46545
47911
|
...languageSpecificTestNames
|
|
46546
|
-
].map((candidateName) =>
|
|
47912
|
+
].map((candidateName) => path39.join(dirname18, candidateName));
|
|
46547
47913
|
const testDirectoryNames = [
|
|
46548
|
-
|
|
47914
|
+
basename6,
|
|
46549
47915
|
...genericTestNames,
|
|
46550
47916
|
...languageSpecificTestNames
|
|
46551
47917
|
];
|
|
46552
47918
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
46553
47919
|
const possibleTestFiles = [
|
|
46554
47920
|
...colocatedCandidates,
|
|
46555
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
46556
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
47921
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path39.join(dirname18, dirName, candidateName))),
|
|
47922
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path39.join(candidateDir, candidateName)))
|
|
46557
47923
|
];
|
|
46558
47924
|
for (const testFile of possibleTestFiles) {
|
|
46559
|
-
if (
|
|
47925
|
+
if (fs22.existsSync(testFile)) {
|
|
46560
47926
|
dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
|
|
46561
47927
|
}
|
|
46562
47928
|
}
|
|
@@ -46573,8 +47939,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
46573
47939
|
for (const testFile of candidateTestFiles) {
|
|
46574
47940
|
try {
|
|
46575
47941
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
46576
|
-
const content =
|
|
46577
|
-
const testDir =
|
|
47942
|
+
const content = fs22.readFileSync(absoluteTestFile, "utf-8");
|
|
47943
|
+
const testDir = path39.dirname(absoluteTestFile);
|
|
46578
47944
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
46579
47945
|
let match;
|
|
46580
47946
|
match = importRegex.exec(content);
|
|
@@ -46582,8 +47948,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
46582
47948
|
const importPath = match[1];
|
|
46583
47949
|
let resolvedImport;
|
|
46584
47950
|
if (importPath.startsWith(".")) {
|
|
46585
|
-
resolvedImport =
|
|
46586
|
-
const existingExt =
|
|
47951
|
+
resolvedImport = path39.resolve(testDir, importPath);
|
|
47952
|
+
const existingExt = path39.extname(resolvedImport);
|
|
46587
47953
|
if (!existingExt) {
|
|
46588
47954
|
for (const extToTry of [
|
|
46589
47955
|
".ts",
|
|
@@ -46594,7 +47960,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
46594
47960
|
".cjs"
|
|
46595
47961
|
]) {
|
|
46596
47962
|
const withExt = resolvedImport + extToTry;
|
|
46597
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
47963
|
+
if (absoluteSourceFiles.includes(withExt) || fs22.existsSync(withExt)) {
|
|
46598
47964
|
resolvedImport = withExt;
|
|
46599
47965
|
break;
|
|
46600
47966
|
}
|
|
@@ -46603,12 +47969,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
46603
47969
|
} else {
|
|
46604
47970
|
continue;
|
|
46605
47971
|
}
|
|
46606
|
-
const importBasename =
|
|
46607
|
-
const importDir =
|
|
47972
|
+
const importBasename = path39.basename(resolvedImport, path39.extname(resolvedImport));
|
|
47973
|
+
const importDir = path39.dirname(resolvedImport);
|
|
46608
47974
|
for (const sourceFile of absoluteSourceFiles) {
|
|
46609
|
-
const sourceDir =
|
|
46610
|
-
const sourceBasename =
|
|
46611
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
47975
|
+
const sourceDir = path39.dirname(sourceFile);
|
|
47976
|
+
const sourceBasename = path39.basename(sourceFile, path39.extname(sourceFile));
|
|
47977
|
+
const isRelatedDir = importDir === sourceDir || importDir === path39.join(sourceDir, "__tests__") || importDir === path39.join(sourceDir, "tests") || importDir === path39.join(sourceDir, "test") || importDir === path39.join(sourceDir, "spec");
|
|
46612
47978
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
46613
47979
|
dedupePush(testFiles, testFile);
|
|
46614
47980
|
break;
|
|
@@ -46621,8 +47987,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
46621
47987
|
while (match !== null) {
|
|
46622
47988
|
const importPath = match[1];
|
|
46623
47989
|
if (importPath.startsWith(".")) {
|
|
46624
|
-
let resolvedImport =
|
|
46625
|
-
const existingExt =
|
|
47990
|
+
let resolvedImport = path39.resolve(testDir, importPath);
|
|
47991
|
+
const existingExt = path39.extname(resolvedImport);
|
|
46626
47992
|
if (!existingExt) {
|
|
46627
47993
|
for (const extToTry of [
|
|
46628
47994
|
".ts",
|
|
@@ -46633,18 +47999,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
46633
47999
|
".cjs"
|
|
46634
48000
|
]) {
|
|
46635
48001
|
const withExt = resolvedImport + extToTry;
|
|
46636
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
48002
|
+
if (absoluteSourceFiles.includes(withExt) || fs22.existsSync(withExt)) {
|
|
46637
48003
|
resolvedImport = withExt;
|
|
46638
48004
|
break;
|
|
46639
48005
|
}
|
|
46640
48006
|
}
|
|
46641
48007
|
}
|
|
46642
|
-
const importDir =
|
|
46643
|
-
const importBasename =
|
|
48008
|
+
const importDir = path39.dirname(resolvedImport);
|
|
48009
|
+
const importBasename = path39.basename(resolvedImport, path39.extname(resolvedImport));
|
|
46644
48010
|
for (const sourceFile of absoluteSourceFiles) {
|
|
46645
|
-
const sourceDir =
|
|
46646
|
-
const sourceBasename =
|
|
46647
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
48011
|
+
const sourceDir = path39.dirname(sourceFile);
|
|
48012
|
+
const sourceBasename = path39.basename(sourceFile, path39.extname(sourceFile));
|
|
48013
|
+
const isRelatedDir = importDir === sourceDir || importDir === path39.join(sourceDir, "__tests__") || importDir === path39.join(sourceDir, "tests") || importDir === path39.join(sourceDir, "test") || importDir === path39.join(sourceDir, "spec");
|
|
46648
48014
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
46649
48015
|
dedupePush(testFiles, testFile);
|
|
46650
48016
|
break;
|
|
@@ -46677,7 +48043,7 @@ function getTargetedExecutionUnsupportedReason(framework) {
|
|
|
46677
48043
|
return null;
|
|
46678
48044
|
}
|
|
46679
48045
|
}
|
|
46680
|
-
function
|
|
48046
|
+
function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
46681
48047
|
switch (framework) {
|
|
46682
48048
|
case "bun": {
|
|
46683
48049
|
const args = ["bun", "test"];
|
|
@@ -46747,8 +48113,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
46747
48113
|
return ["mvn", "test"];
|
|
46748
48114
|
case "gradle": {
|
|
46749
48115
|
const isWindows = process.platform === "win32";
|
|
46750
|
-
const hasGradlewBat =
|
|
46751
|
-
const hasGradlew =
|
|
48116
|
+
const hasGradlewBat = fs22.existsSync(path39.join(baseDir, "gradlew.bat"));
|
|
48117
|
+
const hasGradlew = fs22.existsSync(path39.join(baseDir, "gradlew"));
|
|
46752
48118
|
if (hasGradlewBat && isWindows)
|
|
46753
48119
|
return ["gradlew.bat", "test"];
|
|
46754
48120
|
if (hasGradlew)
|
|
@@ -46765,7 +48131,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
46765
48131
|
"cmake-build-release",
|
|
46766
48132
|
"out"
|
|
46767
48133
|
];
|
|
46768
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
48134
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs22.existsSync(path39.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
46769
48135
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
46770
48136
|
}
|
|
46771
48137
|
case "swift-test":
|
|
@@ -46794,7 +48160,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
46794
48160
|
return null;
|
|
46795
48161
|
}
|
|
46796
48162
|
}
|
|
46797
|
-
function
|
|
48163
|
+
function parseTestOutput2(framework, output) {
|
|
46798
48164
|
const totals = {
|
|
46799
48165
|
passed: 0,
|
|
46800
48166
|
failed: 0,
|
|
@@ -47057,7 +48423,8 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
47057
48423
|
};
|
|
47058
48424
|
}
|
|
47059
48425
|
}
|
|
47060
|
-
const
|
|
48426
|
+
const useDispatchBuild = process.env.SWARM_LANG_BACKEND !== "legacy";
|
|
48427
|
+
const command = useDispatchBuild ? await buildTestCommandViaDispatch(framework, scope, files, coverage, cwd) ?? buildTestCommand2(framework, scope, files, coverage, cwd) : buildTestCommand2(framework, scope, files, coverage, cwd);
|
|
47061
48428
|
if (!command) {
|
|
47062
48429
|
return {
|
|
47063
48430
|
success: false,
|
|
@@ -47086,9 +48453,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
47086
48453
|
stderr: "pipe",
|
|
47087
48454
|
cwd
|
|
47088
48455
|
});
|
|
47089
|
-
const timeoutPromise = new Promise((
|
|
48456
|
+
const timeoutPromise = new Promise((resolve14) => setTimeout(() => {
|
|
47090
48457
|
proc.kill();
|
|
47091
|
-
|
|
48458
|
+
resolve14(-1);
|
|
47092
48459
|
}, timeout_ms));
|
|
47093
48460
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
47094
48461
|
Promise.race([proc.exited, timeoutPromise]),
|
|
@@ -47105,7 +48472,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
47105
48472
|
output += `
|
|
47106
48473
|
... (output truncated at stream read limit)`;
|
|
47107
48474
|
}
|
|
47108
|
-
const
|
|
48475
|
+
const useDispatchParse = process.env.SWARM_LANG_BACKEND !== "legacy";
|
|
48476
|
+
const parsed = useDispatchParse ? await parseTestOutputViaDispatch(framework, output, cwd) ?? parseTestOutput2(framework, output) : parseTestOutput2(framework, output);
|
|
48477
|
+
const { totals, coveragePercent } = parsed;
|
|
47109
48478
|
const isTimeout = exitCode === -1;
|
|
47110
48479
|
const testPassed = exitCode === 0 && totals.failed === 0;
|
|
47111
48480
|
if (testPassed) {
|
|
@@ -47208,7 +48577,7 @@ function analyzeFailures(workingDir) {
|
|
|
47208
48577
|
} catch {}
|
|
47209
48578
|
return report;
|
|
47210
48579
|
}
|
|
47211
|
-
var MAX_OUTPUT_BYTES3 = 512000, MAX_COMMAND_LENGTH2 = 500, DEFAULT_TIMEOUT_MS = 60000, MAX_TIMEOUT_MS = 300000, MAX_SAFE_TEST_FILES = 50, POWERSHELL_METACHARACTERS, COMPOUND_TEST_EXTENSIONS, TEST_DIRECTORY_NAMES, SOURCE_EXTENSIONS, SKIP_DIRECTORIES, test_runner;
|
|
48580
|
+
var MAX_OUTPUT_BYTES3 = 512000, MAX_COMMAND_LENGTH2 = 500, DEFAULT_TIMEOUT_MS = 60000, MAX_TIMEOUT_MS = 300000, MAX_SAFE_TEST_FILES = 50, POWERSHELL_METACHARACTERS, DISPATCH_FRAMEWORK_MAP, COMPOUND_TEST_EXTENSIONS, TEST_DIRECTORY_NAMES, SOURCE_EXTENSIONS, SKIP_DIRECTORIES, test_runner;
|
|
47212
48581
|
var init_test_runner = __esm(() => {
|
|
47213
48582
|
init_zod();
|
|
47214
48583
|
init_discovery();
|
|
@@ -47219,6 +48588,30 @@ var init_test_runner = __esm(() => {
|
|
|
47219
48588
|
init_create_tool();
|
|
47220
48589
|
init_resolve_working_directory();
|
|
47221
48590
|
POWERSHELL_METACHARACTERS = /[|;&`$(){}[\]<>"'#*?\x00-\x1f]/;
|
|
48591
|
+
DISPATCH_FRAMEWORK_MAP = {
|
|
48592
|
+
"bun:test": "bun",
|
|
48593
|
+
bun: "bun",
|
|
48594
|
+
vitest: "vitest",
|
|
48595
|
+
jest: "jest",
|
|
48596
|
+
mocha: "mocha",
|
|
48597
|
+
pytest: "pytest",
|
|
48598
|
+
"cargo test": "cargo",
|
|
48599
|
+
cargo: "cargo",
|
|
48600
|
+
pester: "pester",
|
|
48601
|
+
"go test": "go-test",
|
|
48602
|
+
"maven-test": "maven",
|
|
48603
|
+
"gradle-test": "gradle",
|
|
48604
|
+
"gradle-test-groovy": "gradle",
|
|
48605
|
+
"gradle-kts": "gradle",
|
|
48606
|
+
"dotnet test": "dotnet-test",
|
|
48607
|
+
ctest: "ctest",
|
|
48608
|
+
"swift test": "swift-test",
|
|
48609
|
+
"xcodebuild-test": "swift-test",
|
|
48610
|
+
"flutter test": "dart-test",
|
|
48611
|
+
"dart test": "dart-test",
|
|
48612
|
+
rspec: "rspec",
|
|
48613
|
+
minitest: "minitest"
|
|
48614
|
+
};
|
|
47222
48615
|
COMPOUND_TEST_EXTENSIONS = [
|
|
47223
48616
|
".test.ts",
|
|
47224
48617
|
".test.tsx",
|
|
@@ -47392,7 +48785,16 @@ var init_test_runner = __esm(() => {
|
|
|
47392
48785
|
const _files = args.files || [];
|
|
47393
48786
|
const coverage = args.coverage || false;
|
|
47394
48787
|
const timeout_ms = Math.min(args.timeout_ms || DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS);
|
|
47395
|
-
const
|
|
48788
|
+
const useDispatch = process.env.SWARM_LANG_BACKEND !== "legacy";
|
|
48789
|
+
let framework;
|
|
48790
|
+
if (useDispatch) {
|
|
48791
|
+
framework = await detectTestFrameworkViaDispatch(workingDir);
|
|
48792
|
+
if (framework === "none") {
|
|
48793
|
+
framework = await detectTestFramework(workingDir);
|
|
48794
|
+
}
|
|
48795
|
+
} else {
|
|
48796
|
+
framework = await detectTestFramework(workingDir);
|
|
48797
|
+
}
|
|
47396
48798
|
if (framework === "none") {
|
|
47397
48799
|
const result2 = {
|
|
47398
48800
|
success: false,
|
|
@@ -47418,7 +48820,7 @@ var init_test_runner = __esm(() => {
|
|
|
47418
48820
|
const sourceFiles = args.files.filter((file3) => {
|
|
47419
48821
|
if (directTestFiles.includes(file3))
|
|
47420
48822
|
return false;
|
|
47421
|
-
const ext =
|
|
48823
|
+
const ext = path39.extname(file3).toLowerCase();
|
|
47422
48824
|
return SOURCE_EXTENSIONS.has(ext);
|
|
47423
48825
|
});
|
|
47424
48826
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -47453,7 +48855,7 @@ var init_test_runner = __esm(() => {
|
|
|
47453
48855
|
if (isConventionTestFilePath(f)) {
|
|
47454
48856
|
return false;
|
|
47455
48857
|
}
|
|
47456
|
-
const ext =
|
|
48858
|
+
const ext = path39.extname(f).toLowerCase();
|
|
47457
48859
|
return SOURCE_EXTENSIONS.has(ext);
|
|
47458
48860
|
});
|
|
47459
48861
|
if (sourceFiles.length === 0) {
|
|
@@ -47480,7 +48882,7 @@ var init_test_runner = __esm(() => {
|
|
|
47480
48882
|
if (isConventionTestFilePath(f)) {
|
|
47481
48883
|
return false;
|
|
47482
48884
|
}
|
|
47483
|
-
const ext =
|
|
48885
|
+
const ext = path39.extname(f).toLowerCase();
|
|
47484
48886
|
return SOURCE_EXTENSIONS.has(ext);
|
|
47485
48887
|
});
|
|
47486
48888
|
if (sourceFiles.length === 0) {
|
|
@@ -47498,8 +48900,8 @@ var init_test_runner = __esm(() => {
|
|
|
47498
48900
|
const impactResult = await analyzeImpact(sourceFiles, workingDir);
|
|
47499
48901
|
if (impactResult.impactedTests.length > 0) {
|
|
47500
48902
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
47501
|
-
const relativePath =
|
|
47502
|
-
return
|
|
48903
|
+
const relativePath = path39.relative(workingDir, absPath);
|
|
48904
|
+
return path39.isAbsolute(relativePath) ? absPath : relativePath;
|
|
47503
48905
|
});
|
|
47504
48906
|
} else {
|
|
47505
48907
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -47574,8 +48976,8 @@ var init_test_runner = __esm(() => {
|
|
|
47574
48976
|
});
|
|
47575
48977
|
|
|
47576
48978
|
// src/services/preflight-service.ts
|
|
47577
|
-
import * as
|
|
47578
|
-
import * as
|
|
48979
|
+
import * as fs23 from "fs";
|
|
48980
|
+
import * as path40 from "path";
|
|
47579
48981
|
function validateDirectoryPath(dir) {
|
|
47580
48982
|
if (!dir || typeof dir !== "string") {
|
|
47581
48983
|
throw new Error("Directory path is required");
|
|
@@ -47583,8 +48985,8 @@ function validateDirectoryPath(dir) {
|
|
|
47583
48985
|
if (dir.includes("..")) {
|
|
47584
48986
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
47585
48987
|
}
|
|
47586
|
-
const normalized =
|
|
47587
|
-
const absolutePath =
|
|
48988
|
+
const normalized = path40.normalize(dir);
|
|
48989
|
+
const absolutePath = path40.isAbsolute(normalized) ? normalized : path40.resolve(normalized);
|
|
47588
48990
|
return absolutePath;
|
|
47589
48991
|
}
|
|
47590
48992
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -47607,9 +49009,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
47607
49009
|
}
|
|
47608
49010
|
function getPackageVersion(dir) {
|
|
47609
49011
|
try {
|
|
47610
|
-
const packagePath =
|
|
47611
|
-
if (
|
|
47612
|
-
const content =
|
|
49012
|
+
const packagePath = path40.join(dir, "package.json");
|
|
49013
|
+
if (fs23.existsSync(packagePath)) {
|
|
49014
|
+
const content = fs23.readFileSync(packagePath, "utf-8");
|
|
47613
49015
|
const pkg = JSON.parse(content);
|
|
47614
49016
|
return pkg.version ?? null;
|
|
47615
49017
|
}
|
|
@@ -47618,9 +49020,9 @@ function getPackageVersion(dir) {
|
|
|
47618
49020
|
}
|
|
47619
49021
|
function getChangelogVersion(dir) {
|
|
47620
49022
|
try {
|
|
47621
|
-
const changelogPath =
|
|
47622
|
-
if (
|
|
47623
|
-
const content =
|
|
49023
|
+
const changelogPath = path40.join(dir, "CHANGELOG.md");
|
|
49024
|
+
if (fs23.existsSync(changelogPath)) {
|
|
49025
|
+
const content = fs23.readFileSync(changelogPath, "utf-8");
|
|
47624
49026
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
47625
49027
|
if (match) {
|
|
47626
49028
|
return match[1];
|
|
@@ -47632,10 +49034,10 @@ function getChangelogVersion(dir) {
|
|
|
47632
49034
|
function getVersionFileVersion(dir) {
|
|
47633
49035
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
47634
49036
|
for (const file3 of possibleFiles) {
|
|
47635
|
-
const filePath =
|
|
47636
|
-
if (
|
|
49037
|
+
const filePath = path40.join(dir, file3);
|
|
49038
|
+
if (fs23.existsSync(filePath)) {
|
|
47637
49039
|
try {
|
|
47638
|
-
const content =
|
|
49040
|
+
const content = fs23.readFileSync(filePath, "utf-8").trim();
|
|
47639
49041
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
47640
49042
|
if (match) {
|
|
47641
49043
|
return match[1];
|
|
@@ -47648,9 +49050,9 @@ function getVersionFileVersion(dir) {
|
|
|
47648
49050
|
async function runVersionCheck(dir, _timeoutMs) {
|
|
47649
49051
|
const startTime = Date.now();
|
|
47650
49052
|
try {
|
|
47651
|
-
const packageVersion =
|
|
47652
|
-
const changelogVersion =
|
|
47653
|
-
const versionFileVersion =
|
|
49053
|
+
const packageVersion = _internals23.getPackageVersion(dir);
|
|
49054
|
+
const changelogVersion = _internals23.getChangelogVersion(dir);
|
|
49055
|
+
const versionFileVersion = _internals23.getVersionFileVersion(dir);
|
|
47654
49056
|
const versions3 = [];
|
|
47655
49057
|
if (packageVersion)
|
|
47656
49058
|
versions3.push(`package.json: ${packageVersion}`);
|
|
@@ -47959,8 +49361,8 @@ async function runEvidenceCheck(dir) {
|
|
|
47959
49361
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
47960
49362
|
const startTime = Date.now();
|
|
47961
49363
|
try {
|
|
47962
|
-
const specPath =
|
|
47963
|
-
if (!
|
|
49364
|
+
const specPath = path40.join(dir, ".swarm", "spec.md");
|
|
49365
|
+
if (!fs23.existsSync(specPath)) {
|
|
47964
49366
|
return {
|
|
47965
49367
|
type: "req_coverage",
|
|
47966
49368
|
status: "skip",
|
|
@@ -48000,7 +49402,7 @@ async function runPreflight(dir, phase, config3) {
|
|
|
48000
49402
|
const reportId = `preflight-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
48001
49403
|
let validatedDir;
|
|
48002
49404
|
try {
|
|
48003
|
-
validatedDir =
|
|
49405
|
+
validatedDir = _internals23.validateDirectoryPath(dir);
|
|
48004
49406
|
} catch (error93) {
|
|
48005
49407
|
return {
|
|
48006
49408
|
id: reportId,
|
|
@@ -48020,7 +49422,7 @@ async function runPreflight(dir, phase, config3) {
|
|
|
48020
49422
|
}
|
|
48021
49423
|
let validatedTimeout;
|
|
48022
49424
|
try {
|
|
48023
|
-
validatedTimeout =
|
|
49425
|
+
validatedTimeout = _internals23.validateTimeout(config3?.checkTimeoutMs, DEFAULT_CONFIG.checkTimeoutMs);
|
|
48024
49426
|
} catch (error93) {
|
|
48025
49427
|
return {
|
|
48026
49428
|
id: reportId,
|
|
@@ -48061,12 +49463,12 @@ async function runPreflight(dir, phase, config3) {
|
|
|
48061
49463
|
});
|
|
48062
49464
|
const checks5 = [];
|
|
48063
49465
|
log("[Preflight] Running lint check...");
|
|
48064
|
-
const lintResult = await
|
|
49466
|
+
const lintResult = await _internals23.runLintCheck(validatedDir, cfg.linter, cfg.checkTimeoutMs);
|
|
48065
49467
|
checks5.push(lintResult);
|
|
48066
49468
|
log(`[Preflight] Lint check: ${lintResult.status} ${lintResult.message}`);
|
|
48067
49469
|
if (!cfg.skipTests) {
|
|
48068
49470
|
log("[Preflight] Running tests check...");
|
|
48069
|
-
const testsResult = await
|
|
49471
|
+
const testsResult = await _internals23.runTestsCheck(validatedDir, cfg.testScope, cfg.checkTimeoutMs);
|
|
48070
49472
|
checks5.push(testsResult);
|
|
48071
49473
|
log(`[Preflight] Tests check: ${testsResult.status} ${testsResult.message}`);
|
|
48072
49474
|
} else {
|
|
@@ -48078,7 +49480,7 @@ async function runPreflight(dir, phase, config3) {
|
|
|
48078
49480
|
}
|
|
48079
49481
|
if (!cfg.skipSecrets) {
|
|
48080
49482
|
log("[Preflight] Running secrets check...");
|
|
48081
|
-
const secretsResult = await
|
|
49483
|
+
const secretsResult = await _internals23.runSecretsCheck(validatedDir, cfg.checkTimeoutMs);
|
|
48082
49484
|
checks5.push(secretsResult);
|
|
48083
49485
|
log(`[Preflight] Secrets check: ${secretsResult.status} ${secretsResult.message}`);
|
|
48084
49486
|
} else {
|
|
@@ -48090,7 +49492,7 @@ async function runPreflight(dir, phase, config3) {
|
|
|
48090
49492
|
}
|
|
48091
49493
|
if (!cfg.skipEvidence) {
|
|
48092
49494
|
log("[Preflight] Running evidence check...");
|
|
48093
|
-
const evidenceResult = await
|
|
49495
|
+
const evidenceResult = await _internals23.runEvidenceCheck(validatedDir);
|
|
48094
49496
|
checks5.push(evidenceResult);
|
|
48095
49497
|
log(`[Preflight] Evidence check: ${evidenceResult.status} ${evidenceResult.message}`);
|
|
48096
49498
|
} else {
|
|
@@ -48101,12 +49503,12 @@ async function runPreflight(dir, phase, config3) {
|
|
|
48101
49503
|
});
|
|
48102
49504
|
}
|
|
48103
49505
|
log("[Preflight] Running requirement coverage check...");
|
|
48104
|
-
const reqCoverageResult = await
|
|
49506
|
+
const reqCoverageResult = await _internals23.runRequirementCoverageCheck(validatedDir, phase);
|
|
48105
49507
|
checks5.push(reqCoverageResult);
|
|
48106
49508
|
log(`[Preflight] Requirement coverage check: ${reqCoverageResult.status} ${reqCoverageResult.message}`);
|
|
48107
49509
|
if (!cfg.skipVersion) {
|
|
48108
49510
|
log("[Preflight] Running version check...");
|
|
48109
|
-
const versionResult = await
|
|
49511
|
+
const versionResult = await _internals23.runVersionCheck(validatedDir, cfg.checkTimeoutMs);
|
|
48110
49512
|
checks5.push(versionResult);
|
|
48111
49513
|
log(`[Preflight] Version check: ${versionResult.status} ${versionResult.message}`);
|
|
48112
49514
|
} else {
|
|
@@ -48169,10 +49571,10 @@ function formatPreflightMarkdown(report) {
|
|
|
48169
49571
|
async function handlePreflightCommand(directory, _args) {
|
|
48170
49572
|
const plan = await loadPlan(directory);
|
|
48171
49573
|
const phase = plan?.current_phase ?? 1;
|
|
48172
|
-
const report = await
|
|
48173
|
-
return
|
|
49574
|
+
const report = await _internals23.runPreflight(directory, phase);
|
|
49575
|
+
return _internals23.formatPreflightMarkdown(report);
|
|
48174
49576
|
}
|
|
48175
|
-
var MIN_CHECK_TIMEOUT_MS = 5000, MAX_CHECK_TIMEOUT_MS = 300000, DEFAULT_CONFIG,
|
|
49577
|
+
var MIN_CHECK_TIMEOUT_MS = 5000, MAX_CHECK_TIMEOUT_MS = 300000, DEFAULT_CONFIG, _internals23;
|
|
48176
49578
|
var init_preflight_service = __esm(() => {
|
|
48177
49579
|
init_manager2();
|
|
48178
49580
|
init_manager();
|
|
@@ -48189,7 +49591,7 @@ var init_preflight_service = __esm(() => {
|
|
|
48189
49591
|
testScope: "convention",
|
|
48190
49592
|
linter: "biome"
|
|
48191
49593
|
};
|
|
48192
|
-
|
|
49594
|
+
_internals23 = {
|
|
48193
49595
|
runPreflight,
|
|
48194
49596
|
formatPreflightMarkdown,
|
|
48195
49597
|
handlePreflightCommand,
|
|
@@ -48437,13 +49839,13 @@ class CircuitBreaker {
|
|
|
48437
49839
|
if (this.config.callTimeoutMs <= 0) {
|
|
48438
49840
|
return fn();
|
|
48439
49841
|
}
|
|
48440
|
-
return new Promise((
|
|
49842
|
+
return new Promise((resolve15, reject) => {
|
|
48441
49843
|
const timeout = setTimeout(() => {
|
|
48442
49844
|
reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
|
|
48443
49845
|
}, this.config.callTimeoutMs);
|
|
48444
49846
|
fn().then((result) => {
|
|
48445
49847
|
clearTimeout(timeout);
|
|
48446
|
-
|
|
49848
|
+
resolve15(result);
|
|
48447
49849
|
}).catch((error93) => {
|
|
48448
49850
|
clearTimeout(timeout);
|
|
48449
49851
|
reject(error93);
|
|
@@ -48730,7 +50132,7 @@ var init_queue = __esm(() => {
|
|
|
48730
50132
|
|
|
48731
50133
|
// src/background/worker.ts
|
|
48732
50134
|
function sleep(ms) {
|
|
48733
|
-
return new Promise((
|
|
50135
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
48734
50136
|
}
|
|
48735
50137
|
|
|
48736
50138
|
class WorkerManager {
|
|
@@ -49075,8 +50477,8 @@ var init_manager3 = __esm(() => {
|
|
|
49075
50477
|
});
|
|
49076
50478
|
|
|
49077
50479
|
// src/commands/reset.ts
|
|
49078
|
-
import * as
|
|
49079
|
-
import * as
|
|
50480
|
+
import * as fs24 from "fs";
|
|
50481
|
+
import * as path41 from "path";
|
|
49080
50482
|
async function handleResetCommand(directory, args) {
|
|
49081
50483
|
const hasConfirm = args.includes("--confirm");
|
|
49082
50484
|
if (!hasConfirm) {
|
|
@@ -49104,8 +50506,8 @@ async function handleResetCommand(directory, args) {
|
|
|
49104
50506
|
for (const filename of filesToReset) {
|
|
49105
50507
|
try {
|
|
49106
50508
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
49107
|
-
if (
|
|
49108
|
-
|
|
50509
|
+
if (fs24.existsSync(resolvedPath)) {
|
|
50510
|
+
fs24.unlinkSync(resolvedPath);
|
|
49109
50511
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
49110
50512
|
} else {
|
|
49111
50513
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -49116,9 +50518,9 @@ async function handleResetCommand(directory, args) {
|
|
|
49116
50518
|
}
|
|
49117
50519
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
49118
50520
|
try {
|
|
49119
|
-
const rootPath =
|
|
49120
|
-
if (
|
|
49121
|
-
|
|
50521
|
+
const rootPath = path41.join(directory, filename);
|
|
50522
|
+
if (fs24.existsSync(rootPath)) {
|
|
50523
|
+
fs24.unlinkSync(rootPath);
|
|
49122
50524
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
49123
50525
|
}
|
|
49124
50526
|
} catch {}
|
|
@@ -49131,8 +50533,8 @@ async function handleResetCommand(directory, args) {
|
|
|
49131
50533
|
}
|
|
49132
50534
|
try {
|
|
49133
50535
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
49134
|
-
if (
|
|
49135
|
-
|
|
50536
|
+
if (fs24.existsSync(summariesPath)) {
|
|
50537
|
+
fs24.rmSync(summariesPath, { recursive: true, force: true });
|
|
49136
50538
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
49137
50539
|
} else {
|
|
49138
50540
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -49155,14 +50557,14 @@ var init_reset = __esm(() => {
|
|
|
49155
50557
|
});
|
|
49156
50558
|
|
|
49157
50559
|
// src/commands/reset-session.ts
|
|
49158
|
-
import * as
|
|
49159
|
-
import * as
|
|
50560
|
+
import * as fs25 from "fs";
|
|
50561
|
+
import * as path42 from "path";
|
|
49160
50562
|
async function handleResetSessionCommand(directory, _args) {
|
|
49161
50563
|
const results = [];
|
|
49162
50564
|
try {
|
|
49163
50565
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
49164
|
-
if (
|
|
49165
|
-
|
|
50566
|
+
if (fs25.existsSync(statePath)) {
|
|
50567
|
+
fs25.unlinkSync(statePath);
|
|
49166
50568
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
49167
50569
|
} else {
|
|
49168
50570
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -49171,15 +50573,15 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
49171
50573
|
results.push("\u274C Failed to delete state.json");
|
|
49172
50574
|
}
|
|
49173
50575
|
try {
|
|
49174
|
-
const sessionDir =
|
|
49175
|
-
if (
|
|
49176
|
-
const files =
|
|
50576
|
+
const sessionDir = path42.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
50577
|
+
if (fs25.existsSync(sessionDir)) {
|
|
50578
|
+
const files = fs25.readdirSync(sessionDir);
|
|
49177
50579
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
49178
50580
|
let deletedCount = 0;
|
|
49179
50581
|
for (const file3 of otherFiles) {
|
|
49180
|
-
const filePath =
|
|
49181
|
-
if (
|
|
49182
|
-
|
|
50582
|
+
const filePath = path42.join(sessionDir, file3);
|
|
50583
|
+
if (fs25.lstatSync(filePath).isFile()) {
|
|
50584
|
+
fs25.unlinkSync(filePath);
|
|
49183
50585
|
deletedCount++;
|
|
49184
50586
|
}
|
|
49185
50587
|
}
|
|
@@ -49209,7 +50611,7 @@ var init_reset_session = __esm(() => {
|
|
|
49209
50611
|
});
|
|
49210
50612
|
|
|
49211
50613
|
// src/summaries/manager.ts
|
|
49212
|
-
import * as
|
|
50614
|
+
import * as path43 from "path";
|
|
49213
50615
|
function sanitizeSummaryId(id) {
|
|
49214
50616
|
if (!id || id.length === 0) {
|
|
49215
50617
|
throw new Error("Invalid summary ID: empty string");
|
|
@@ -49232,7 +50634,7 @@ function sanitizeSummaryId(id) {
|
|
|
49232
50634
|
}
|
|
49233
50635
|
async function loadFullOutput(directory, id) {
|
|
49234
50636
|
const sanitizedId = sanitizeSummaryId(id);
|
|
49235
|
-
const relativePath =
|
|
50637
|
+
const relativePath = path43.join("summaries", `${sanitizedId}.json`);
|
|
49236
50638
|
validateSwarmPath(directory, relativePath);
|
|
49237
50639
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
49238
50640
|
if (content === null) {
|
|
@@ -49294,18 +50696,18 @@ var init_retrieve = __esm(() => {
|
|
|
49294
50696
|
});
|
|
49295
50697
|
|
|
49296
50698
|
// src/commands/rollback.ts
|
|
49297
|
-
import * as
|
|
49298
|
-
import * as
|
|
50699
|
+
import * as fs26 from "fs";
|
|
50700
|
+
import * as path44 from "path";
|
|
49299
50701
|
async function handleRollbackCommand(directory, args) {
|
|
49300
50702
|
const phaseArg = args[0];
|
|
49301
50703
|
if (!phaseArg) {
|
|
49302
50704
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
49303
|
-
if (!
|
|
50705
|
+
if (!fs26.existsSync(manifestPath2)) {
|
|
49304
50706
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
49305
50707
|
}
|
|
49306
50708
|
let manifest2;
|
|
49307
50709
|
try {
|
|
49308
|
-
manifest2 = JSON.parse(
|
|
50710
|
+
manifest2 = JSON.parse(fs26.readFileSync(manifestPath2, "utf-8"));
|
|
49309
50711
|
} catch {
|
|
49310
50712
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
49311
50713
|
}
|
|
@@ -49327,12 +50729,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
49327
50729
|
return "Error: Phase number must be a positive integer.";
|
|
49328
50730
|
}
|
|
49329
50731
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
49330
|
-
if (!
|
|
50732
|
+
if (!fs26.existsSync(manifestPath)) {
|
|
49331
50733
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
49332
50734
|
}
|
|
49333
50735
|
let manifest;
|
|
49334
50736
|
try {
|
|
49335
|
-
manifest = JSON.parse(
|
|
50737
|
+
manifest = JSON.parse(fs26.readFileSync(manifestPath, "utf-8"));
|
|
49336
50738
|
} catch {
|
|
49337
50739
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
49338
50740
|
}
|
|
@@ -49342,10 +50744,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
49342
50744
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
49343
50745
|
}
|
|
49344
50746
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
49345
|
-
if (!
|
|
50747
|
+
if (!fs26.existsSync(checkpointDir)) {
|
|
49346
50748
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
49347
50749
|
}
|
|
49348
|
-
const checkpointFiles =
|
|
50750
|
+
const checkpointFiles = fs26.readdirSync(checkpointDir);
|
|
49349
50751
|
if (checkpointFiles.length === 0) {
|
|
49350
50752
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
49351
50753
|
}
|
|
@@ -49360,10 +50762,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
49360
50762
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
49361
50763
|
continue;
|
|
49362
50764
|
}
|
|
49363
|
-
const src =
|
|
49364
|
-
const dest =
|
|
50765
|
+
const src = path44.join(checkpointDir, file3);
|
|
50766
|
+
const dest = path44.join(swarmDir, file3);
|
|
49365
50767
|
try {
|
|
49366
|
-
|
|
50768
|
+
fs26.cpSync(src, dest, { recursive: true, force: true });
|
|
49367
50769
|
successes.push(file3);
|
|
49368
50770
|
} catch (error93) {
|
|
49369
50771
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -49380,14 +50782,14 @@ async function handleRollbackCommand(directory, args) {
|
|
|
49380
50782
|
].join(`
|
|
49381
50783
|
`);
|
|
49382
50784
|
}
|
|
49383
|
-
const existingLedgerPath =
|
|
49384
|
-
if (
|
|
49385
|
-
|
|
50785
|
+
const existingLedgerPath = path44.join(swarmDir, "plan-ledger.jsonl");
|
|
50786
|
+
if (fs26.existsSync(existingLedgerPath)) {
|
|
50787
|
+
fs26.unlinkSync(existingLedgerPath);
|
|
49386
50788
|
}
|
|
49387
50789
|
try {
|
|
49388
|
-
const planJsonPath =
|
|
49389
|
-
if (
|
|
49390
|
-
const planRaw =
|
|
50790
|
+
const planJsonPath = path44.join(swarmDir, "plan.json");
|
|
50791
|
+
if (fs26.existsSync(planJsonPath)) {
|
|
50792
|
+
const planRaw = fs26.readFileSync(planJsonPath, "utf-8");
|
|
49391
50793
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
49392
50794
|
const planId = derivePlanId(plan);
|
|
49393
50795
|
const planHash = computePlanHash(plan);
|
|
@@ -49414,7 +50816,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
49414
50816
|
timestamp: new Date().toISOString()
|
|
49415
50817
|
};
|
|
49416
50818
|
try {
|
|
49417
|
-
|
|
50819
|
+
fs26.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
49418
50820
|
`);
|
|
49419
50821
|
} catch (error93) {
|
|
49420
50822
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -49475,11 +50877,11 @@ Ensure this is a git repository with commit history.`;
|
|
|
49475
50877
|
const report = reportLines.filter(Boolean).join(`
|
|
49476
50878
|
`);
|
|
49477
50879
|
try {
|
|
49478
|
-
const
|
|
49479
|
-
const
|
|
49480
|
-
const reportPath =
|
|
49481
|
-
await
|
|
49482
|
-
await
|
|
50880
|
+
const fs27 = await import("fs/promises");
|
|
50881
|
+
const path45 = await import("path");
|
|
50882
|
+
const reportPath = path45.join(directory, ".swarm", "simulate-report.md");
|
|
50883
|
+
await fs27.mkdir(path45.dirname(reportPath), { recursive: true });
|
|
50884
|
+
await fs27.writeFile(reportPath, report, "utf-8");
|
|
49483
50885
|
} catch (err) {
|
|
49484
50886
|
const writeErr = err instanceof Error ? err.message : String(err);
|
|
49485
50887
|
warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
|
|
@@ -49501,15 +50903,15 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
49501
50903
|
}
|
|
49502
50904
|
|
|
49503
50905
|
// src/turbo/lean/state.ts
|
|
49504
|
-
import * as
|
|
49505
|
-
import * as
|
|
50906
|
+
import * as fs27 from "fs";
|
|
50907
|
+
import * as path45 from "path";
|
|
49506
50908
|
function nowISO2() {
|
|
49507
50909
|
return new Date().toISOString();
|
|
49508
50910
|
}
|
|
49509
50911
|
function ensureSwarmDir2(directory) {
|
|
49510
|
-
const swarmDir =
|
|
49511
|
-
if (!
|
|
49512
|
-
|
|
50912
|
+
const swarmDir = path45.resolve(directory, ".swarm");
|
|
50913
|
+
if (!fs27.existsSync(swarmDir)) {
|
|
50914
|
+
fs27.mkdirSync(swarmDir, { recursive: true });
|
|
49513
50915
|
}
|
|
49514
50916
|
return swarmDir;
|
|
49515
50917
|
}
|
|
@@ -49551,17 +50953,17 @@ function markStateUnreadable2(directory, reason) {
|
|
|
49551
50953
|
}
|
|
49552
50954
|
function readPersisted2(directory) {
|
|
49553
50955
|
try {
|
|
49554
|
-
const filePath =
|
|
49555
|
-
if (!
|
|
50956
|
+
const filePath = path45.join(directory, ".swarm", STATE_FILE2);
|
|
50957
|
+
if (!fs27.existsSync(filePath)) {
|
|
49556
50958
|
const seed = emptyPersisted2();
|
|
49557
50959
|
try {
|
|
49558
50960
|
ensureSwarmDir2(directory);
|
|
49559
|
-
|
|
50961
|
+
fs27.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
|
|
49560
50962
|
`, "utf-8");
|
|
49561
50963
|
} catch {}
|
|
49562
50964
|
return seed;
|
|
49563
50965
|
}
|
|
49564
|
-
const raw =
|
|
50966
|
+
const raw = fs27.readFileSync(filePath, "utf-8");
|
|
49565
50967
|
const parsed = JSON.parse(raw);
|
|
49566
50968
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
|
|
49567
50969
|
markStateUnreadable2(directory, `malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
|
|
@@ -49587,7 +50989,7 @@ function writePersisted2(directory, persisted) {
|
|
|
49587
50989
|
let payload;
|
|
49588
50990
|
try {
|
|
49589
50991
|
ensureSwarmDir2(directory);
|
|
49590
|
-
filePath =
|
|
50992
|
+
filePath = path45.join(directory, ".swarm", STATE_FILE2);
|
|
49591
50993
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
49592
50994
|
persisted.updatedAt = nowISO2();
|
|
49593
50995
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -49598,14 +51000,14 @@ function writePersisted2(directory, persisted) {
|
|
|
49598
51000
|
throw new Error(`Lean Turbo state persistence prepare failed: ${msg}`);
|
|
49599
51001
|
}
|
|
49600
51002
|
try {
|
|
49601
|
-
|
|
49602
|
-
|
|
51003
|
+
fs27.writeFileSync(tmpPath, payload, "utf-8");
|
|
51004
|
+
fs27.renameSync(tmpPath, filePath);
|
|
49603
51005
|
} catch (error93) {
|
|
49604
51006
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
49605
51007
|
error(`[turbo/lean/state] Failed to persist ${STATE_FILE2} atomically: ${msg}`);
|
|
49606
51008
|
try {
|
|
49607
|
-
if (
|
|
49608
|
-
|
|
51009
|
+
if (fs27.existsSync(tmpPath)) {
|
|
51010
|
+
fs27.unlinkSync(tmpPath);
|
|
49609
51011
|
}
|
|
49610
51012
|
} catch {}
|
|
49611
51013
|
throw new Error(`Lean Turbo state persistence failed: ${msg}`);
|
|
@@ -49782,7 +51184,7 @@ async function getStatusData(directory, agents) {
|
|
|
49782
51184
|
}
|
|
49783
51185
|
function enrichWithLeanTurbo(status, directory) {
|
|
49784
51186
|
const turboMode = hasActiveTurboMode();
|
|
49785
|
-
const leanActive =
|
|
51187
|
+
const leanActive = _internals24.hasActiveLeanTurbo();
|
|
49786
51188
|
let turboStrategy = "off";
|
|
49787
51189
|
if (leanActive) {
|
|
49788
51190
|
turboStrategy = "lean";
|
|
@@ -49801,7 +51203,7 @@ function enrichWithLeanTurbo(status, directory) {
|
|
|
49801
51203
|
}
|
|
49802
51204
|
}
|
|
49803
51205
|
if (leanSessionID) {
|
|
49804
|
-
const runState =
|
|
51206
|
+
const runState = _internals24.loadLeanTurboRunState(directory, leanSessionID);
|
|
49805
51207
|
if (runState) {
|
|
49806
51208
|
status.leanTurboPhase = runState.phase;
|
|
49807
51209
|
status.leanMaxParallelCoders = runState.maxParallelCoders;
|
|
@@ -49833,7 +51235,7 @@ function enrichWithLeanTurbo(status, directory) {
|
|
|
49833
51235
|
}
|
|
49834
51236
|
}
|
|
49835
51237
|
}
|
|
49836
|
-
status.fullAutoActive =
|
|
51238
|
+
status.fullAutoActive = _internals24.hasActiveFullAuto();
|
|
49837
51239
|
return status;
|
|
49838
51240
|
}
|
|
49839
51241
|
function formatStatusMarkdown(status) {
|
|
@@ -49897,7 +51299,7 @@ async function handleStatusCommand(directory, agents) {
|
|
|
49897
51299
|
}
|
|
49898
51300
|
return formatStatusMarkdown(statusData);
|
|
49899
51301
|
}
|
|
49900
|
-
var
|
|
51302
|
+
var _internals24;
|
|
49901
51303
|
var init_status_service = __esm(() => {
|
|
49902
51304
|
init_extractors();
|
|
49903
51305
|
init_utils2();
|
|
@@ -49906,7 +51308,7 @@ var init_status_service = __esm(() => {
|
|
|
49906
51308
|
init_state3();
|
|
49907
51309
|
init_compaction_service();
|
|
49908
51310
|
init_context_budget_service();
|
|
49909
|
-
|
|
51311
|
+
_internals24 = {
|
|
49910
51312
|
loadLeanTurboRunState,
|
|
49911
51313
|
hasActiveLeanTurbo,
|
|
49912
51314
|
hasActiveFullAuto
|
|
@@ -50250,8 +51652,8 @@ __export(exports_commands, {
|
|
|
50250
51652
|
COMMAND_NAME_SET: () => COMMAND_NAME_SET,
|
|
50251
51653
|
COMMAND_NAMES: () => COMMAND_NAMES
|
|
50252
51654
|
});
|
|
50253
|
-
import
|
|
50254
|
-
import
|
|
51655
|
+
import fs28 from "fs";
|
|
51656
|
+
import path46 from "path";
|
|
50255
51657
|
function buildHelpText() {
|
|
50256
51658
|
const lines = ["## Swarm Commands", ""];
|
|
50257
51659
|
const CATEGORIES = [
|
|
@@ -50354,11 +51756,11 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
50354
51756
|
return;
|
|
50355
51757
|
}
|
|
50356
51758
|
let isFirstRun = false;
|
|
50357
|
-
const sentinelPath =
|
|
51759
|
+
const sentinelPath = path46.join(directory, ".swarm", ".first-run-complete");
|
|
50358
51760
|
try {
|
|
50359
|
-
const swarmDir =
|
|
50360
|
-
|
|
50361
|
-
|
|
51761
|
+
const swarmDir = path46.join(directory, ".swarm");
|
|
51762
|
+
fs28.mkdirSync(swarmDir, { recursive: true });
|
|
51763
|
+
fs28.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
|
|
50362
51764
|
`, { flag: "wx" });
|
|
50363
51765
|
isFirstRun = true;
|
|
50364
51766
|
} catch (_err) {}
|
|
@@ -50379,7 +51781,7 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
50379
51781
|
const attemptedCommand = tokens[0] || "";
|
|
50380
51782
|
const MAX_DISPLAY = 100;
|
|
50381
51783
|
const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
|
|
50382
|
-
const similar =
|
|
51784
|
+
const similar = _internals25.findSimilarCommands(attemptedCommand);
|
|
50383
51785
|
const header = `Command \`/swarm ${displayCommand}\` not found.`;
|
|
50384
51786
|
const suggestions = similar.length > 0 ? `Did you mean:
|
|
50385
51787
|
${similar.map((cmd) => ` \u2022 /swarm ${cmd}`).join(`
|
|
@@ -50486,7 +51888,7 @@ function findSimilarCommands(query) {
|
|
|
50486
51888
|
}
|
|
50487
51889
|
const scored = VALID_COMMANDS.map((cmd) => {
|
|
50488
51890
|
const cmdLower = cmd.toLowerCase();
|
|
50489
|
-
const fullScore =
|
|
51891
|
+
const fullScore = _internals25.levenshteinDistance(q, cmdLower);
|
|
50490
51892
|
let tokenScore = Infinity;
|
|
50491
51893
|
if (cmd.includes(" ") || cmd.includes("-")) {
|
|
50492
51894
|
const qTokens = q.split(/[\s-]+/);
|
|
@@ -50499,7 +51901,7 @@ function findSimilarCommands(query) {
|
|
|
50499
51901
|
for (const ct of cmdTokens) {
|
|
50500
51902
|
if (ct.length === 0)
|
|
50501
51903
|
continue;
|
|
50502
|
-
const dist =
|
|
51904
|
+
const dist = _internals25.levenshteinDistance(qt, ct);
|
|
50503
51905
|
if (dist < minDist)
|
|
50504
51906
|
minDist = dist;
|
|
50505
51907
|
}
|
|
@@ -50509,7 +51911,7 @@ function findSimilarCommands(query) {
|
|
|
50509
51911
|
}
|
|
50510
51912
|
const dashStrippedQ = q.replace(/-/g, "");
|
|
50511
51913
|
const dashStrippedCmd = cmdLower.replace(/-/g, "");
|
|
50512
|
-
const dashScore =
|
|
51914
|
+
const dashScore = _internals25.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
|
|
50513
51915
|
const score = Math.min(fullScore, tokenScore, dashScore);
|
|
50514
51916
|
return { cmd, score };
|
|
50515
51917
|
});
|
|
@@ -50541,11 +51943,11 @@ async function handleHelpCommand(ctx) {
|
|
|
50541
51943
|
return buildHelpText2();
|
|
50542
51944
|
}
|
|
50543
51945
|
const tokens = targetCommand.split(/\s+/);
|
|
50544
|
-
const resolved =
|
|
51946
|
+
const resolved = _internals25.resolveCommand(tokens);
|
|
50545
51947
|
if (resolved) {
|
|
50546
|
-
return
|
|
51948
|
+
return _internals25.buildDetailedHelp(resolved.key, resolved.entry);
|
|
50547
51949
|
}
|
|
50548
|
-
const similar =
|
|
51950
|
+
const similar = _internals25.findSimilarCommands(targetCommand);
|
|
50549
51951
|
const { buildHelpText: fullHelp } = await Promise.resolve().then(() => (init_commands(), exports_commands));
|
|
50550
51952
|
if (similar.length > 0) {
|
|
50551
51953
|
return `Command '/swarm ${targetCommand}' not found.
|
|
@@ -50581,24 +51983,24 @@ function validateAliases() {
|
|
|
50581
51983
|
}
|
|
50582
51984
|
aliasTargets.get(target).push(name);
|
|
50583
51985
|
const visited = new Set;
|
|
50584
|
-
const
|
|
51986
|
+
const path47 = [];
|
|
50585
51987
|
let current = target;
|
|
50586
51988
|
while (current) {
|
|
50587
51989
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
50588
51990
|
if (!currentEntry)
|
|
50589
51991
|
break;
|
|
50590
51992
|
if (visited.has(current)) {
|
|
50591
|
-
const cycleStart =
|
|
51993
|
+
const cycleStart = path47.indexOf(current);
|
|
50592
51994
|
const fullChain = [
|
|
50593
51995
|
name,
|
|
50594
|
-
...
|
|
51996
|
+
...path47.slice(0, cycleStart > 0 ? cycleStart : path47.length),
|
|
50595
51997
|
current
|
|
50596
51998
|
].join(" \u2192 ");
|
|
50597
51999
|
errors5.push(`Circular alias detected: ${fullChain}`);
|
|
50598
52000
|
break;
|
|
50599
52001
|
}
|
|
50600
52002
|
visited.add(current);
|
|
50601
|
-
|
|
52003
|
+
path47.push(current);
|
|
50602
52004
|
current = currentEntry.aliasOf || "";
|
|
50603
52005
|
}
|
|
50604
52006
|
}
|
|
@@ -50639,7 +52041,7 @@ function resolveCommand(tokens) {
|
|
|
50639
52041
|
}
|
|
50640
52042
|
return null;
|
|
50641
52043
|
}
|
|
50642
|
-
var COMMAND_REGISTRY, VALID_COMMANDS,
|
|
52044
|
+
var COMMAND_REGISTRY, VALID_COMMANDS, _internals25, validation;
|
|
50643
52045
|
var init_registry = __esm(() => {
|
|
50644
52046
|
init_acknowledge_spec_drift();
|
|
50645
52047
|
init_agents();
|
|
@@ -50709,7 +52111,7 @@ var init_registry = __esm(() => {
|
|
|
50709
52111
|
clashesWithNativeCcCommand: "/agents"
|
|
50710
52112
|
},
|
|
50711
52113
|
help: {
|
|
50712
|
-
handler: (ctx) =>
|
|
52114
|
+
handler: (ctx) => _internals25.handleHelpCommand(ctx),
|
|
50713
52115
|
description: "Show help for swarm commands",
|
|
50714
52116
|
category: "core",
|
|
50715
52117
|
args: "[command]",
|
|
@@ -51066,7 +52468,7 @@ var init_registry = __esm(() => {
|
|
|
51066
52468
|
}
|
|
51067
52469
|
};
|
|
51068
52470
|
VALID_COMMANDS = Object.keys(COMMAND_REGISTRY);
|
|
51069
|
-
|
|
52471
|
+
_internals25 = {
|
|
51070
52472
|
handleHelpCommand,
|
|
51071
52473
|
validateAliases,
|
|
51072
52474
|
resolveCommand,
|
|
@@ -51074,7 +52476,7 @@ var init_registry = __esm(() => {
|
|
|
51074
52476
|
findSimilarCommands,
|
|
51075
52477
|
buildDetailedHelp
|
|
51076
52478
|
};
|
|
51077
|
-
validation =
|
|
52479
|
+
validation = _internals25.validateAliases();
|
|
51078
52480
|
if (!validation.valid) {
|
|
51079
52481
|
throw new Error(`COMMAND_REGISTRY alias validation failed:
|
|
51080
52482
|
${validation.errors.join(`
|
|
@@ -51092,68 +52494,68 @@ init_package();
|
|
|
51092
52494
|
init_registry();
|
|
51093
52495
|
init_cache_paths();
|
|
51094
52496
|
init_constants();
|
|
51095
|
-
import * as
|
|
52497
|
+
import * as fs29 from "fs";
|
|
51096
52498
|
import * as os7 from "os";
|
|
51097
|
-
import * as
|
|
52499
|
+
import * as path47 from "path";
|
|
51098
52500
|
var { version: version4 } = package_default;
|
|
51099
52501
|
var CONFIG_DIR = getPluginConfigDir();
|
|
51100
|
-
var OPENCODE_CONFIG_PATH =
|
|
51101
|
-
var PLUGIN_CONFIG_PATH =
|
|
51102
|
-
var PROMPTS_DIR =
|
|
52502
|
+
var OPENCODE_CONFIG_PATH = path47.join(CONFIG_DIR, "opencode.json");
|
|
52503
|
+
var PLUGIN_CONFIG_PATH = path47.join(CONFIG_DIR, "opencode-swarm.json");
|
|
52504
|
+
var PROMPTS_DIR = path47.join(CONFIG_DIR, "opencode-swarm");
|
|
51103
52505
|
var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
51104
52506
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
51105
52507
|
function isSafeCachePath(p) {
|
|
51106
|
-
const resolved =
|
|
51107
|
-
const home =
|
|
52508
|
+
const resolved = path47.resolve(p);
|
|
52509
|
+
const home = path47.resolve(os7.homedir());
|
|
51108
52510
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
51109
52511
|
return false;
|
|
51110
52512
|
}
|
|
51111
|
-
const segments = resolved.split(
|
|
52513
|
+
const segments = resolved.split(path47.sep).filter((s) => s.length > 0);
|
|
51112
52514
|
if (segments.length < 4) {
|
|
51113
52515
|
return false;
|
|
51114
52516
|
}
|
|
51115
|
-
const leaf =
|
|
52517
|
+
const leaf = path47.basename(resolved);
|
|
51116
52518
|
if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
|
|
51117
52519
|
return false;
|
|
51118
52520
|
}
|
|
51119
|
-
const parent =
|
|
52521
|
+
const parent = path47.basename(path47.dirname(resolved));
|
|
51120
52522
|
if (parent !== "packages" && parent !== "node_modules") {
|
|
51121
52523
|
return false;
|
|
51122
52524
|
}
|
|
51123
|
-
const grandparent =
|
|
52525
|
+
const grandparent = path47.basename(path47.dirname(path47.dirname(resolved)));
|
|
51124
52526
|
if (grandparent !== "opencode") {
|
|
51125
52527
|
return false;
|
|
51126
52528
|
}
|
|
51127
52529
|
return true;
|
|
51128
52530
|
}
|
|
51129
52531
|
function isSafeLockFilePath(p) {
|
|
51130
|
-
const resolved =
|
|
51131
|
-
const home =
|
|
52532
|
+
const resolved = path47.resolve(p);
|
|
52533
|
+
const home = path47.resolve(os7.homedir());
|
|
51132
52534
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
51133
52535
|
return false;
|
|
51134
52536
|
}
|
|
51135
|
-
const segments = resolved.split(
|
|
52537
|
+
const segments = resolved.split(path47.sep).filter((s) => s.length > 0);
|
|
51136
52538
|
if (segments.length < 4) {
|
|
51137
52539
|
return false;
|
|
51138
52540
|
}
|
|
51139
|
-
const leaf =
|
|
52541
|
+
const leaf = path47.basename(resolved);
|
|
51140
52542
|
if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
|
|
51141
52543
|
return false;
|
|
51142
52544
|
}
|
|
51143
|
-
const parent =
|
|
52545
|
+
const parent = path47.basename(path47.dirname(resolved));
|
|
51144
52546
|
if (parent !== "opencode") {
|
|
51145
52547
|
return false;
|
|
51146
52548
|
}
|
|
51147
52549
|
return true;
|
|
51148
52550
|
}
|
|
51149
52551
|
function ensureDir(dir) {
|
|
51150
|
-
if (!
|
|
51151
|
-
|
|
52552
|
+
if (!fs29.existsSync(dir)) {
|
|
52553
|
+
fs29.mkdirSync(dir, { recursive: true });
|
|
51152
52554
|
}
|
|
51153
52555
|
}
|
|
51154
52556
|
function loadJson(filepath) {
|
|
51155
52557
|
try {
|
|
51156
|
-
const content =
|
|
52558
|
+
const content = fs29.readFileSync(filepath, "utf-8");
|
|
51157
52559
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
51158
52560
|
return JSON.parse(stripped);
|
|
51159
52561
|
} catch {
|
|
@@ -51161,14 +52563,14 @@ function loadJson(filepath) {
|
|
|
51161
52563
|
}
|
|
51162
52564
|
}
|
|
51163
52565
|
function saveJson(filepath, data) {
|
|
51164
|
-
|
|
52566
|
+
fs29.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
51165
52567
|
`, "utf-8");
|
|
51166
52568
|
}
|
|
51167
52569
|
function writeProjectConfigIfMissing(cwd) {
|
|
51168
52570
|
try {
|
|
51169
|
-
const opencodeDir =
|
|
51170
|
-
const projectConfigPath =
|
|
51171
|
-
if (
|
|
52571
|
+
const opencodeDir = path47.join(cwd, ".opencode");
|
|
52572
|
+
const projectConfigPath = path47.join(opencodeDir, "opencode-swarm.json");
|
|
52573
|
+
if (fs29.existsSync(projectConfigPath)) {
|
|
51172
52574
|
return;
|
|
51173
52575
|
}
|
|
51174
52576
|
ensureDir(opencodeDir);
|
|
@@ -51184,7 +52586,7 @@ async function install() {
|
|
|
51184
52586
|
`);
|
|
51185
52587
|
ensureDir(CONFIG_DIR);
|
|
51186
52588
|
ensureDir(PROMPTS_DIR);
|
|
51187
|
-
const LEGACY_CONFIG_PATH =
|
|
52589
|
+
const LEGACY_CONFIG_PATH = path47.join(CONFIG_DIR, "config.json");
|
|
51188
52590
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
51189
52591
|
if (!opencodeConfig) {
|
|
51190
52592
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|
|
@@ -51231,7 +52633,7 @@ async function install() {
|
|
|
51231
52633
|
console.warn(`\u26A0 Could not clear opencode lock file \u2014 you may need to delete it manually:
|
|
51232
52634
|
${failed}`);
|
|
51233
52635
|
}
|
|
51234
|
-
if (!
|
|
52636
|
+
if (!fs29.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
51235
52637
|
const defaultConfig = {
|
|
51236
52638
|
agents: { ...DEFAULT_AGENT_CONFIGS },
|
|
51237
52639
|
max_iterations: 5
|
|
@@ -51310,14 +52712,14 @@ function evictPluginCaches() {
|
|
|
51310
52712
|
const cleared = [];
|
|
51311
52713
|
const failed = [];
|
|
51312
52714
|
for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
|
|
51313
|
-
if (!
|
|
52715
|
+
if (!fs29.existsSync(cachePath))
|
|
51314
52716
|
continue;
|
|
51315
52717
|
if (!isSafeCachePath(cachePath)) {
|
|
51316
52718
|
failed.push(`${cachePath} (refused: failed safety check)`);
|
|
51317
52719
|
continue;
|
|
51318
52720
|
}
|
|
51319
52721
|
try {
|
|
51320
|
-
|
|
52722
|
+
fs29.rmSync(cachePath, { recursive: true, force: true });
|
|
51321
52723
|
cleared.push(cachePath);
|
|
51322
52724
|
} catch (err) {
|
|
51323
52725
|
failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
|
|
@@ -51329,14 +52731,14 @@ function evictLockFiles() {
|
|
|
51329
52731
|
const cleared = [];
|
|
51330
52732
|
const failed = [];
|
|
51331
52733
|
for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
|
|
51332
|
-
if (!
|
|
52734
|
+
if (!fs29.existsSync(lockPath))
|
|
51333
52735
|
continue;
|
|
51334
52736
|
if (!isSafeLockFilePath(lockPath)) {
|
|
51335
52737
|
failed.push(`${lockPath} (refused: failed safety check)`);
|
|
51336
52738
|
continue;
|
|
51337
52739
|
}
|
|
51338
52740
|
try {
|
|
51339
|
-
|
|
52741
|
+
fs29.unlinkSync(lockPath);
|
|
51340
52742
|
cleared.push(lockPath);
|
|
51341
52743
|
} catch (err) {
|
|
51342
52744
|
const code = err?.code;
|
|
@@ -51355,7 +52757,7 @@ async function uninstall() {
|
|
|
51355
52757
|
`);
|
|
51356
52758
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
51357
52759
|
if (!opencodeConfig) {
|
|
51358
|
-
if (
|
|
52760
|
+
if (fs29.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
51359
52761
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
51360
52762
|
return 1;
|
|
51361
52763
|
} else {
|
|
@@ -51387,13 +52789,13 @@ async function uninstall() {
|
|
|
51387
52789
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
51388
52790
|
if (process.argv.includes("--clean")) {
|
|
51389
52791
|
let cleaned = false;
|
|
51390
|
-
if (
|
|
51391
|
-
|
|
52792
|
+
if (fs29.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
52793
|
+
fs29.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
51392
52794
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
51393
52795
|
cleaned = true;
|
|
51394
52796
|
}
|
|
51395
|
-
if (
|
|
51396
|
-
|
|
52797
|
+
if (fs29.existsSync(PROMPTS_DIR)) {
|
|
52798
|
+
fs29.rmSync(PROMPTS_DIR, { recursive: true });
|
|
51397
52799
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
51398
52800
|
cleaned = true;
|
|
51399
52801
|
}
|