opencode-swarm 6.44.0 → 6.44.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/critic.d.ts +1 -1
- package/dist/cli/index.js +390 -305
- package/dist/index.js +765 -610
- package/dist/knowledge/hive-promoter.d.ts +23 -0
- package/dist/parallel/file-locks.d.ts +12 -5
- package/dist/tools/lint.d.ts +8 -0
- package/package.json +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -5,43 +5,25 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
-
function __accessProp(key) {
|
|
9
|
-
return this[key];
|
|
10
|
-
}
|
|
11
|
-
var __toESMCache_node;
|
|
12
|
-
var __toESMCache_esm;
|
|
13
8
|
var __toESM = (mod, isNodeMode, target) => {
|
|
14
|
-
var canCache = mod != null && typeof mod === "object";
|
|
15
|
-
if (canCache) {
|
|
16
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
17
|
-
var cached = cache.get(mod);
|
|
18
|
-
if (cached)
|
|
19
|
-
return cached;
|
|
20
|
-
}
|
|
21
9
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
22
10
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
23
11
|
for (let key of __getOwnPropNames(mod))
|
|
24
12
|
if (!__hasOwnProp.call(to, key))
|
|
25
13
|
__defProp(to, key, {
|
|
26
|
-
get:
|
|
14
|
+
get: () => mod[key],
|
|
27
15
|
enumerable: true
|
|
28
16
|
});
|
|
29
|
-
if (canCache)
|
|
30
|
-
cache.set(mod, to);
|
|
31
17
|
return to;
|
|
32
18
|
};
|
|
33
19
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
34
|
-
var __returnValue = (v) => v;
|
|
35
|
-
function __exportSetter(name, newValue) {
|
|
36
|
-
this[name] = __returnValue.bind(null, newValue);
|
|
37
|
-
}
|
|
38
20
|
var __export = (target, all) => {
|
|
39
21
|
for (var name in all)
|
|
40
22
|
__defProp(target, name, {
|
|
41
23
|
get: all[name],
|
|
42
24
|
enumerable: true,
|
|
43
25
|
configurable: true,
|
|
44
|
-
set:
|
|
26
|
+
set: (newValue) => all[name] = () => newValue
|
|
45
27
|
});
|
|
46
28
|
};
|
|
47
29
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -17005,13 +16987,13 @@ __export(exports_config_doctor, {
|
|
|
17005
16987
|
import * as crypto3 from "crypto";
|
|
17006
16988
|
import * as fs7 from "fs";
|
|
17007
16989
|
import * as os4 from "os";
|
|
17008
|
-
import * as
|
|
16990
|
+
import * as path15 from "path";
|
|
17009
16991
|
function getUserConfigDir3() {
|
|
17010
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
16992
|
+
return process.env.XDG_CONFIG_HOME || path15.join(os4.homedir(), ".config");
|
|
17011
16993
|
}
|
|
17012
16994
|
function getConfigPaths(directory) {
|
|
17013
|
-
const userConfigPath =
|
|
17014
|
-
const projectConfigPath =
|
|
16995
|
+
const userConfigPath = path15.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
|
|
16996
|
+
const projectConfigPath = path15.join(directory, ".opencode", "opencode-swarm.json");
|
|
17015
16997
|
return { userConfigPath, projectConfigPath };
|
|
17016
16998
|
}
|
|
17017
16999
|
function computeHash(content) {
|
|
@@ -17036,9 +17018,9 @@ function isValidConfigPath(configPath, directory) {
|
|
|
17036
17018
|
const normalizedUser = userConfigPath.replace(/\\/g, "/");
|
|
17037
17019
|
const normalizedProject = projectConfigPath.replace(/\\/g, "/");
|
|
17038
17020
|
try {
|
|
17039
|
-
const resolvedConfig =
|
|
17040
|
-
const resolvedUser =
|
|
17041
|
-
const resolvedProject =
|
|
17021
|
+
const resolvedConfig = path15.resolve(configPath);
|
|
17022
|
+
const resolvedUser = path15.resolve(normalizedUser);
|
|
17023
|
+
const resolvedProject = path15.resolve(normalizedProject);
|
|
17042
17024
|
return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
|
|
17043
17025
|
} catch {
|
|
17044
17026
|
return false;
|
|
@@ -17078,12 +17060,12 @@ function createConfigBackup(directory) {
|
|
|
17078
17060
|
};
|
|
17079
17061
|
}
|
|
17080
17062
|
function writeBackupArtifact(directory, backup) {
|
|
17081
|
-
const swarmDir =
|
|
17063
|
+
const swarmDir = path15.join(directory, ".swarm");
|
|
17082
17064
|
if (!fs7.existsSync(swarmDir)) {
|
|
17083
17065
|
fs7.mkdirSync(swarmDir, { recursive: true });
|
|
17084
17066
|
}
|
|
17085
17067
|
const backupFilename = `config-backup-${backup.createdAt}.json`;
|
|
17086
|
-
const backupPath =
|
|
17068
|
+
const backupPath = path15.join(swarmDir, backupFilename);
|
|
17087
17069
|
const artifact = {
|
|
17088
17070
|
createdAt: backup.createdAt,
|
|
17089
17071
|
configPath: backup.configPath,
|
|
@@ -17113,7 +17095,7 @@ function restoreFromBackup(backupPath, directory) {
|
|
|
17113
17095
|
return null;
|
|
17114
17096
|
}
|
|
17115
17097
|
const targetPath = artifact.configPath;
|
|
17116
|
-
const targetDir =
|
|
17098
|
+
const targetDir = path15.dirname(targetPath);
|
|
17117
17099
|
if (!fs7.existsSync(targetDir)) {
|
|
17118
17100
|
fs7.mkdirSync(targetDir, { recursive: true });
|
|
17119
17101
|
}
|
|
@@ -17144,9 +17126,9 @@ function readConfigFromFile(directory) {
|
|
|
17144
17126
|
return null;
|
|
17145
17127
|
}
|
|
17146
17128
|
}
|
|
17147
|
-
function validateConfigKey(
|
|
17129
|
+
function validateConfigKey(path16, value, _config) {
|
|
17148
17130
|
const findings = [];
|
|
17149
|
-
switch (
|
|
17131
|
+
switch (path16) {
|
|
17150
17132
|
case "agents": {
|
|
17151
17133
|
if (value !== undefined) {
|
|
17152
17134
|
findings.push({
|
|
@@ -17393,27 +17375,27 @@ function validateConfigKey(path17, value, _config) {
|
|
|
17393
17375
|
}
|
|
17394
17376
|
return findings;
|
|
17395
17377
|
}
|
|
17396
|
-
function walkConfigAndValidate(obj,
|
|
17378
|
+
function walkConfigAndValidate(obj, path16, config3, findings) {
|
|
17397
17379
|
if (obj === null || obj === undefined) {
|
|
17398
17380
|
return;
|
|
17399
17381
|
}
|
|
17400
|
-
if (
|
|
17401
|
-
const keyFindings = validateConfigKey(
|
|
17382
|
+
if (path16 && typeof obj === "object" && !Array.isArray(obj)) {
|
|
17383
|
+
const keyFindings = validateConfigKey(path16, obj, config3);
|
|
17402
17384
|
findings.push(...keyFindings);
|
|
17403
17385
|
}
|
|
17404
17386
|
if (typeof obj !== "object") {
|
|
17405
|
-
const keyFindings = validateConfigKey(
|
|
17387
|
+
const keyFindings = validateConfigKey(path16, obj, config3);
|
|
17406
17388
|
findings.push(...keyFindings);
|
|
17407
17389
|
return;
|
|
17408
17390
|
}
|
|
17409
17391
|
if (Array.isArray(obj)) {
|
|
17410
17392
|
obj.forEach((item, index) => {
|
|
17411
|
-
walkConfigAndValidate(item, `${
|
|
17393
|
+
walkConfigAndValidate(item, `${path16}[${index}]`, config3, findings);
|
|
17412
17394
|
});
|
|
17413
17395
|
return;
|
|
17414
17396
|
}
|
|
17415
17397
|
for (const [key, value] of Object.entries(obj)) {
|
|
17416
|
-
const newPath =
|
|
17398
|
+
const newPath = path16 ? `${path16}.${key}` : key;
|
|
17417
17399
|
walkConfigAndValidate(value, newPath, config3, findings);
|
|
17418
17400
|
}
|
|
17419
17401
|
}
|
|
@@ -17533,7 +17515,7 @@ function applySafeAutoFixes(directory, result) {
|
|
|
17533
17515
|
}
|
|
17534
17516
|
}
|
|
17535
17517
|
if (appliedFixes.length > 0) {
|
|
17536
|
-
const configDir =
|
|
17518
|
+
const configDir = path15.dirname(configPath);
|
|
17537
17519
|
if (!fs7.existsSync(configDir)) {
|
|
17538
17520
|
fs7.mkdirSync(configDir, { recursive: true });
|
|
17539
17521
|
}
|
|
@@ -17543,12 +17525,12 @@ function applySafeAutoFixes(directory, result) {
|
|
|
17543
17525
|
return { appliedFixes, updatedConfigPath };
|
|
17544
17526
|
}
|
|
17545
17527
|
function writeDoctorArtifact(directory, result) {
|
|
17546
|
-
const swarmDir =
|
|
17528
|
+
const swarmDir = path15.join(directory, ".swarm");
|
|
17547
17529
|
if (!fs7.existsSync(swarmDir)) {
|
|
17548
17530
|
fs7.mkdirSync(swarmDir, { recursive: true });
|
|
17549
17531
|
}
|
|
17550
17532
|
const artifactFilename = "config-doctor.json";
|
|
17551
|
-
const artifactPath =
|
|
17533
|
+
const artifactPath = path15.join(swarmDir, artifactFilename);
|
|
17552
17534
|
const guiOutput = {
|
|
17553
17535
|
timestamp: result.timestamp,
|
|
17554
17536
|
summary: result.summary,
|
|
@@ -17909,8 +17891,8 @@ var init_evidence_summary_service = __esm(() => {
|
|
|
17909
17891
|
});
|
|
17910
17892
|
|
|
17911
17893
|
// src/cli/index.ts
|
|
17912
|
-
import * as
|
|
17913
|
-
import * as
|
|
17894
|
+
import * as fs18 from "fs";
|
|
17895
|
+
import * as os6 from "os";
|
|
17914
17896
|
import * as path27 from "path";
|
|
17915
17897
|
|
|
17916
17898
|
// src/commands/agents.ts
|
|
@@ -19241,7 +19223,7 @@ async function handleBenchmarkCommand(directory, args) {
|
|
|
19241
19223
|
init_zod();
|
|
19242
19224
|
|
|
19243
19225
|
// src/tools/checkpoint.ts
|
|
19244
|
-
import
|
|
19226
|
+
import * as child_process from "child_process";
|
|
19245
19227
|
import * as fs3 from "fs";
|
|
19246
19228
|
import * as path4 from "path";
|
|
19247
19229
|
|
|
@@ -31668,7 +31650,7 @@ function writeCheckpointLog(log2, directory) {
|
|
|
31668
31650
|
fs3.renameSync(tempPath, logPath);
|
|
31669
31651
|
}
|
|
31670
31652
|
function gitExec(args) {
|
|
31671
|
-
const result = spawnSync("git", args, {
|
|
31653
|
+
const result = child_process.spawnSync("git", args, {
|
|
31672
31654
|
encoding: "utf-8",
|
|
31673
31655
|
timeout: GIT_TIMEOUT_MS,
|
|
31674
31656
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -32765,6 +32747,12 @@ async function flushPendingSnapshot(directory) {
|
|
|
32765
32747
|
init_evidence_schema();
|
|
32766
32748
|
init_manager();
|
|
32767
32749
|
async function executeWriteRetro(args, directory) {
|
|
32750
|
+
if (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])(:|$)/i.test(directory)) {
|
|
32751
|
+
return JSON.stringify({
|
|
32752
|
+
success: false,
|
|
32753
|
+
message: "Invalid directory: reserved device name"
|
|
32754
|
+
}, null, 2);
|
|
32755
|
+
}
|
|
32768
32756
|
const phase = args.phase;
|
|
32769
32757
|
if (!Number.isInteger(phase) || phase < 1) {
|
|
32770
32758
|
return JSON.stringify({
|
|
@@ -33249,9 +33237,6 @@ async function handleConfigCommand(directory, _args) {
|
|
|
33249
33237
|
`);
|
|
33250
33238
|
}
|
|
33251
33239
|
|
|
33252
|
-
// src/hooks/hive-promoter.ts
|
|
33253
|
-
import path12 from "path";
|
|
33254
|
-
|
|
33255
33240
|
// src/background/event-bus.ts
|
|
33256
33241
|
init_utils();
|
|
33257
33242
|
|
|
@@ -33473,86 +33458,6 @@ async function checkHivePromotions(swarmEntries, config3) {
|
|
|
33473
33458
|
total_hive_entries: hiveEntries.length
|
|
33474
33459
|
};
|
|
33475
33460
|
}
|
|
33476
|
-
async function promoteToHive(directory, lesson, category) {
|
|
33477
|
-
const trimmedLesson = lesson.trim();
|
|
33478
|
-
const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
|
|
33479
|
-
const validationResult = validateLesson(trimmedLesson, hiveEntries.map((e) => e.lesson), {
|
|
33480
|
-
category: category || "process",
|
|
33481
|
-
scope: "global",
|
|
33482
|
-
confidence: 1
|
|
33483
|
-
});
|
|
33484
|
-
if (validationResult.severity === "error") {
|
|
33485
|
-
throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
|
|
33486
|
-
}
|
|
33487
|
-
if (findNearDuplicate(trimmedLesson, hiveEntries, 0.6)) {
|
|
33488
|
-
return `Lesson already exists in hive (near-duplicate).`;
|
|
33489
|
-
}
|
|
33490
|
-
const newHiveEntry = {
|
|
33491
|
-
id: crypto.randomUUID(),
|
|
33492
|
-
tier: "hive",
|
|
33493
|
-
lesson: trimmedLesson,
|
|
33494
|
-
category: category || "process",
|
|
33495
|
-
tags: [],
|
|
33496
|
-
scope: "global",
|
|
33497
|
-
confidence: 1,
|
|
33498
|
-
status: "promoted",
|
|
33499
|
-
confirmed_by: [],
|
|
33500
|
-
retrieval_outcomes: {
|
|
33501
|
-
applied_count: 0,
|
|
33502
|
-
succeeded_after_count: 0,
|
|
33503
|
-
failed_after_count: 0
|
|
33504
|
-
},
|
|
33505
|
-
schema_version: 1,
|
|
33506
|
-
created_at: new Date().toISOString(),
|
|
33507
|
-
updated_at: new Date().toISOString(),
|
|
33508
|
-
source_project: path12.basename(directory) || "unknown",
|
|
33509
|
-
encounter_score: 1
|
|
33510
|
-
};
|
|
33511
|
-
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
33512
|
-
return `Promoted to hive: "${trimmedLesson.slice(0, 50)}${trimmedLesson.length > 50 ? "..." : ""}" (confidence: 1.0, source: manual)`;
|
|
33513
|
-
}
|
|
33514
|
-
async function promoteFromSwarm(directory, lessonId) {
|
|
33515
|
-
const swarmEntries = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
33516
|
-
const swarmEntry = swarmEntries.find((e) => e.id === lessonId);
|
|
33517
|
-
if (!swarmEntry) {
|
|
33518
|
-
throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
|
|
33519
|
-
}
|
|
33520
|
-
const hiveEntries = await readKnowledge(resolveHiveKnowledgePath());
|
|
33521
|
-
const validationResult = validateLesson(swarmEntry.lesson, hiveEntries.map((e) => e.lesson), {
|
|
33522
|
-
category: swarmEntry.category,
|
|
33523
|
-
scope: swarmEntry.scope,
|
|
33524
|
-
confidence: swarmEntry.confidence
|
|
33525
|
-
});
|
|
33526
|
-
if (validationResult.severity === "error") {
|
|
33527
|
-
throw new Error(`Lesson rejected by validator: ${validationResult.reason}`);
|
|
33528
|
-
}
|
|
33529
|
-
if (findNearDuplicate(swarmEntry.lesson, hiveEntries, 0.6)) {
|
|
33530
|
-
return `Lesson already exists in hive (near-duplicate).`;
|
|
33531
|
-
}
|
|
33532
|
-
const newHiveEntry = {
|
|
33533
|
-
id: crypto.randomUUID(),
|
|
33534
|
-
tier: "hive",
|
|
33535
|
-
lesson: swarmEntry.lesson,
|
|
33536
|
-
category: swarmEntry.category,
|
|
33537
|
-
tags: swarmEntry.tags,
|
|
33538
|
-
scope: swarmEntry.scope,
|
|
33539
|
-
confidence: 1,
|
|
33540
|
-
status: "promoted",
|
|
33541
|
-
confirmed_by: [],
|
|
33542
|
-
retrieval_outcomes: {
|
|
33543
|
-
applied_count: 0,
|
|
33544
|
-
succeeded_after_count: 0,
|
|
33545
|
-
failed_after_count: 0
|
|
33546
|
-
},
|
|
33547
|
-
schema_version: 1,
|
|
33548
|
-
created_at: new Date().toISOString(),
|
|
33549
|
-
updated_at: new Date().toISOString(),
|
|
33550
|
-
source_project: swarmEntry.project_name,
|
|
33551
|
-
encounter_score: 1
|
|
33552
|
-
};
|
|
33553
|
-
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
33554
|
-
return `Promoted lesson ${lessonId} from swarm to hive: "${swarmEntry.lesson.slice(0, 50)}${swarmEntry.lesson.length > 50 ? "..." : ""}"`;
|
|
33555
|
-
}
|
|
33556
33461
|
|
|
33557
33462
|
// src/commands/curate.ts
|
|
33558
33463
|
async function handleCurateCommand(directory, _args) {
|
|
@@ -33583,16 +33488,16 @@ function formatCurationSummary(summary) {
|
|
|
33583
33488
|
}
|
|
33584
33489
|
|
|
33585
33490
|
// src/commands/dark-matter.ts
|
|
33586
|
-
import
|
|
33491
|
+
import path13 from "path";
|
|
33587
33492
|
|
|
33588
33493
|
// src/tools/co-change-analyzer.ts
|
|
33589
|
-
import * as
|
|
33494
|
+
import * as child_process2 from "child_process";
|
|
33590
33495
|
import { randomUUID } from "crypto";
|
|
33591
33496
|
import { readdir, readFile as readFile2, stat } from "fs/promises";
|
|
33592
|
-
import * as
|
|
33497
|
+
import * as path12 from "path";
|
|
33593
33498
|
import { promisify } from "util";
|
|
33594
33499
|
function getExecFileAsync() {
|
|
33595
|
-
return promisify(
|
|
33500
|
+
return promisify(child_process2.execFile);
|
|
33596
33501
|
}
|
|
33597
33502
|
async function parseGitLog(directory, maxCommits) {
|
|
33598
33503
|
const commitMap = new Map;
|
|
@@ -33691,7 +33596,7 @@ async function scanSourceFiles(dir) {
|
|
|
33691
33596
|
try {
|
|
33692
33597
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
33693
33598
|
for (const entry of entries) {
|
|
33694
|
-
const fullPath =
|
|
33599
|
+
const fullPath = path12.join(dir, entry.name);
|
|
33695
33600
|
if (entry.isDirectory()) {
|
|
33696
33601
|
if (skipDirs.has(entry.name)) {
|
|
33697
33602
|
continue;
|
|
@@ -33699,7 +33604,7 @@ async function scanSourceFiles(dir) {
|
|
|
33699
33604
|
const subFiles = await scanSourceFiles(fullPath);
|
|
33700
33605
|
results.push(...subFiles);
|
|
33701
33606
|
} else if (entry.isFile()) {
|
|
33702
|
-
const ext =
|
|
33607
|
+
const ext = path12.extname(entry.name);
|
|
33703
33608
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
33704
33609
|
results.push(fullPath);
|
|
33705
33610
|
}
|
|
@@ -33721,8 +33626,8 @@ async function getStaticEdges(directory) {
|
|
|
33721
33626
|
continue;
|
|
33722
33627
|
}
|
|
33723
33628
|
try {
|
|
33724
|
-
const sourceDir =
|
|
33725
|
-
const resolvedPath =
|
|
33629
|
+
const sourceDir = path12.dirname(sourceFile);
|
|
33630
|
+
const resolvedPath = path12.resolve(sourceDir, importPath);
|
|
33726
33631
|
const extensions = [
|
|
33727
33632
|
"",
|
|
33728
33633
|
".ts",
|
|
@@ -33747,8 +33652,8 @@ async function getStaticEdges(directory) {
|
|
|
33747
33652
|
if (!targetFile) {
|
|
33748
33653
|
continue;
|
|
33749
33654
|
}
|
|
33750
|
-
const relSource =
|
|
33751
|
-
const relTarget =
|
|
33655
|
+
const relSource = path12.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
33656
|
+
const relTarget = path12.relative(directory, targetFile).replace(/\\/g, "/");
|
|
33752
33657
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
33753
33658
|
edges.add(key);
|
|
33754
33659
|
} catch {}
|
|
@@ -33760,7 +33665,7 @@ async function getStaticEdges(directory) {
|
|
|
33760
33665
|
function isTestImplementationPair(fileA, fileB) {
|
|
33761
33666
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
33762
33667
|
const getBaseName = (filePath) => {
|
|
33763
|
-
const base =
|
|
33668
|
+
const base = path12.basename(filePath);
|
|
33764
33669
|
for (const pattern of testPatterns) {
|
|
33765
33670
|
if (base.endsWith(pattern)) {
|
|
33766
33671
|
return base.slice(0, -pattern.length);
|
|
@@ -33770,16 +33675,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
33770
33675
|
};
|
|
33771
33676
|
const baseA = getBaseName(fileA);
|
|
33772
33677
|
const baseB = getBaseName(fileB);
|
|
33773
|
-
return baseA === baseB && baseA !==
|
|
33678
|
+
return baseA === baseB && baseA !== path12.basename(fileA) && baseA !== path12.basename(fileB);
|
|
33774
33679
|
}
|
|
33775
33680
|
function hasSharedPrefix(fileA, fileB) {
|
|
33776
|
-
const dirA =
|
|
33777
|
-
const dirB =
|
|
33681
|
+
const dirA = path12.dirname(fileA);
|
|
33682
|
+
const dirB = path12.dirname(fileB);
|
|
33778
33683
|
if (dirA !== dirB) {
|
|
33779
33684
|
return false;
|
|
33780
33685
|
}
|
|
33781
|
-
const baseA =
|
|
33782
|
-
const baseB =
|
|
33686
|
+
const baseA = path12.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
33687
|
+
const baseB = path12.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
33783
33688
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
33784
33689
|
return true;
|
|
33785
33690
|
}
|
|
@@ -33833,8 +33738,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
33833
33738
|
const entries = [];
|
|
33834
33739
|
const now = new Date().toISOString();
|
|
33835
33740
|
for (const pair of pairs.slice(0, 10)) {
|
|
33836
|
-
const baseA =
|
|
33837
|
-
const baseB =
|
|
33741
|
+
const baseA = path12.basename(pair.fileA);
|
|
33742
|
+
const baseB = path12.basename(pair.fileB);
|
|
33838
33743
|
let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
33839
33744
|
if (lesson.length > 280) {
|
|
33840
33745
|
lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
@@ -33944,7 +33849,7 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
33944
33849
|
const output = formatDarkMatterOutput(pairs);
|
|
33945
33850
|
if (pairs.length > 0) {
|
|
33946
33851
|
try {
|
|
33947
|
-
const projectName =
|
|
33852
|
+
const projectName = path13.basename(path13.resolve(directory));
|
|
33948
33853
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
33949
33854
|
if (entries.length > 0) {
|
|
33950
33855
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -33964,9 +33869,9 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
33964
33869
|
}
|
|
33965
33870
|
|
|
33966
33871
|
// src/services/diagnose-service.ts
|
|
33967
|
-
import
|
|
33872
|
+
import * as child_process3 from "child_process";
|
|
33968
33873
|
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
33969
|
-
import
|
|
33874
|
+
import path14 from "path";
|
|
33970
33875
|
import { fileURLToPath } from "url";
|
|
33971
33876
|
init_manager();
|
|
33972
33877
|
init_utils2();
|
|
@@ -34209,7 +34114,10 @@ async function checkGitRepository(directory) {
|
|
|
34209
34114
|
detail: "Invalid directory \u2014 cannot check git status"
|
|
34210
34115
|
};
|
|
34211
34116
|
}
|
|
34212
|
-
execSync("git rev-parse --git-dir", {
|
|
34117
|
+
child_process3.execSync("git rev-parse --git-dir", {
|
|
34118
|
+
cwd: directory,
|
|
34119
|
+
stdio: "pipe"
|
|
34120
|
+
});
|
|
34213
34121
|
return {
|
|
34214
34122
|
name: "Git Repository",
|
|
34215
34123
|
status: "\u2705",
|
|
@@ -34263,7 +34171,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
34263
34171
|
};
|
|
34264
34172
|
}
|
|
34265
34173
|
async function checkConfigParseability(directory) {
|
|
34266
|
-
const configPath =
|
|
34174
|
+
const configPath = path14.join(directory, ".opencode/opencode-swarm.json");
|
|
34267
34175
|
if (!existsSync5(configPath)) {
|
|
34268
34176
|
return {
|
|
34269
34177
|
name: "Config Parseability",
|
|
@@ -34310,15 +34218,15 @@ async function checkGrammarWasmFiles() {
|
|
|
34310
34218
|
"tree-sitter-ini.wasm",
|
|
34311
34219
|
"tree-sitter-regex.wasm"
|
|
34312
34220
|
];
|
|
34313
|
-
const thisDir =
|
|
34221
|
+
const thisDir = path14.dirname(fileURLToPath(import.meta.url));
|
|
34314
34222
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/services");
|
|
34315
|
-
const grammarDir = isSource ?
|
|
34223
|
+
const grammarDir = isSource ? path14.join(thisDir, "..", "lang", "grammars") : path14.join(thisDir, "lang", "grammars");
|
|
34316
34224
|
const missing = [];
|
|
34317
|
-
if (!existsSync5(
|
|
34225
|
+
if (!existsSync5(path14.join(grammarDir, "tree-sitter.wasm"))) {
|
|
34318
34226
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
34319
34227
|
}
|
|
34320
34228
|
for (const file3 of grammarFiles) {
|
|
34321
|
-
if (!existsSync5(
|
|
34229
|
+
if (!existsSync5(path14.join(grammarDir, file3))) {
|
|
34322
34230
|
missing.push(file3);
|
|
34323
34231
|
}
|
|
34324
34232
|
}
|
|
@@ -34336,7 +34244,7 @@ async function checkGrammarWasmFiles() {
|
|
|
34336
34244
|
};
|
|
34337
34245
|
}
|
|
34338
34246
|
async function checkCheckpointManifest(directory) {
|
|
34339
|
-
const manifestPath =
|
|
34247
|
+
const manifestPath = path14.join(directory, ".swarm/checkpoints.json");
|
|
34340
34248
|
if (!existsSync5(manifestPath)) {
|
|
34341
34249
|
return {
|
|
34342
34250
|
name: "Checkpoint Manifest",
|
|
@@ -34388,7 +34296,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
34388
34296
|
}
|
|
34389
34297
|
}
|
|
34390
34298
|
async function checkEventStreamIntegrity(directory) {
|
|
34391
|
-
const eventsPath =
|
|
34299
|
+
const eventsPath = path14.join(directory, ".swarm/events.jsonl");
|
|
34392
34300
|
if (!existsSync5(eventsPath)) {
|
|
34393
34301
|
return {
|
|
34394
34302
|
name: "Event Stream",
|
|
@@ -34429,7 +34337,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
34429
34337
|
}
|
|
34430
34338
|
}
|
|
34431
34339
|
async function checkSteeringDirectives(directory) {
|
|
34432
|
-
const eventsPath =
|
|
34340
|
+
const eventsPath = path14.join(directory, ".swarm/events.jsonl");
|
|
34433
34341
|
if (!existsSync5(eventsPath)) {
|
|
34434
34342
|
return {
|
|
34435
34343
|
name: "Steering Directives",
|
|
@@ -34485,7 +34393,7 @@ async function checkCurator(directory) {
|
|
|
34485
34393
|
detail: "Disabled (enable via curator.enabled)"
|
|
34486
34394
|
};
|
|
34487
34395
|
}
|
|
34488
|
-
const summaryPath =
|
|
34396
|
+
const summaryPath = path14.join(directory, ".swarm/curator-summary.json");
|
|
34489
34397
|
if (!existsSync5(summaryPath)) {
|
|
34490
34398
|
return {
|
|
34491
34399
|
name: "Curator",
|
|
@@ -35382,10 +35290,10 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
35382
35290
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
35383
35291
|
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
35384
35292
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
35385
|
-
import * as
|
|
35293
|
+
import * as path16 from "path";
|
|
35386
35294
|
async function migrateContextToKnowledge(directory, config3) {
|
|
35387
|
-
const sentinelPath =
|
|
35388
|
-
const contextPath =
|
|
35295
|
+
const sentinelPath = path16.join(directory, ".swarm", ".knowledge-migrated");
|
|
35296
|
+
const contextPath = path16.join(directory, ".swarm", "context.md");
|
|
35389
35297
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
35390
35298
|
if (existsSync7(sentinelPath)) {
|
|
35391
35299
|
return {
|
|
@@ -35581,7 +35489,7 @@ function truncateLesson(text) {
|
|
|
35581
35489
|
return `${text.slice(0, 277)}...`;
|
|
35582
35490
|
}
|
|
35583
35491
|
function inferProjectName(directory) {
|
|
35584
|
-
const packageJsonPath =
|
|
35492
|
+
const packageJsonPath = path16.join(directory, "package.json");
|
|
35585
35493
|
if (existsSync7(packageJsonPath)) {
|
|
35586
35494
|
try {
|
|
35587
35495
|
const pkg = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
|
|
@@ -35590,7 +35498,7 @@ function inferProjectName(directory) {
|
|
|
35590
35498
|
}
|
|
35591
35499
|
} catch {}
|
|
35592
35500
|
}
|
|
35593
|
-
return
|
|
35501
|
+
return path16.basename(directory);
|
|
35594
35502
|
}
|
|
35595
35503
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
35596
35504
|
const sentinel = {
|
|
@@ -35602,7 +35510,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
35602
35510
|
schema_version: 1,
|
|
35603
35511
|
migration_tool: "knowledge-migrator.ts"
|
|
35604
35512
|
};
|
|
35605
|
-
await mkdir3(
|
|
35513
|
+
await mkdir3(path16.dirname(sentinelPath), { recursive: true });
|
|
35606
35514
|
await writeFile3(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
35607
35515
|
}
|
|
35608
35516
|
|
|
@@ -35839,15 +35747,15 @@ async function handlePlanCommand(directory, args) {
|
|
|
35839
35747
|
init_manager();
|
|
35840
35748
|
init_manager2();
|
|
35841
35749
|
import * as fs13 from "fs";
|
|
35842
|
-
import * as
|
|
35750
|
+
import * as path22 from "path";
|
|
35843
35751
|
|
|
35844
35752
|
// src/tools/lint.ts
|
|
35845
35753
|
import * as fs9 from "fs";
|
|
35846
|
-
import * as
|
|
35754
|
+
import * as path18 from "path";
|
|
35847
35755
|
|
|
35848
35756
|
// src/build/discovery.ts
|
|
35849
35757
|
import * as fs8 from "fs";
|
|
35850
|
-
import * as
|
|
35758
|
+
import * as path17 from "path";
|
|
35851
35759
|
|
|
35852
35760
|
// src/lang/detector.ts
|
|
35853
35761
|
import { access, readdir as readdir2 } from "fs/promises";
|
|
@@ -36944,11 +36852,11 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
36944
36852
|
const regex = simpleGlobToRegex(pattern);
|
|
36945
36853
|
const matches = files.filter((f) => regex.test(f));
|
|
36946
36854
|
if (matches.length > 0) {
|
|
36947
|
-
return
|
|
36855
|
+
return path17.join(dir, matches[0]);
|
|
36948
36856
|
}
|
|
36949
36857
|
} catch {}
|
|
36950
36858
|
} else {
|
|
36951
|
-
const filePath =
|
|
36859
|
+
const filePath = path17.join(workingDir, pattern);
|
|
36952
36860
|
if (fs8.existsSync(filePath)) {
|
|
36953
36861
|
return filePath;
|
|
36954
36862
|
}
|
|
@@ -36957,7 +36865,7 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
36957
36865
|
return null;
|
|
36958
36866
|
}
|
|
36959
36867
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
36960
|
-
const packageJsonPath =
|
|
36868
|
+
const packageJsonPath = path17.join(workingDir, "package.json");
|
|
36961
36869
|
if (!fs8.existsSync(packageJsonPath)) {
|
|
36962
36870
|
return [];
|
|
36963
36871
|
}
|
|
@@ -36998,7 +36906,7 @@ function findAllBuildFiles(workingDir) {
|
|
|
36998
36906
|
const regex = simpleGlobToRegex(pattern);
|
|
36999
36907
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
37000
36908
|
} else {
|
|
37001
|
-
const filePath =
|
|
36909
|
+
const filePath = path17.join(workingDir, pattern);
|
|
37002
36910
|
if (fs8.existsSync(filePath)) {
|
|
37003
36911
|
allBuildFiles.add(filePath);
|
|
37004
36912
|
}
|
|
@@ -37011,7 +36919,7 @@ function findFilesRecursive(dir, regex, results) {
|
|
|
37011
36919
|
try {
|
|
37012
36920
|
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
37013
36921
|
for (const entry of entries) {
|
|
37014
|
-
const fullPath =
|
|
36922
|
+
const fullPath = path17.join(dir, entry.name);
|
|
37015
36923
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
37016
36924
|
findFilesRecursive(fullPath, regex, results);
|
|
37017
36925
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -37034,7 +36942,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
|
|
|
37034
36942
|
let foundCommand = false;
|
|
37035
36943
|
for (const cmd of sortedCommands) {
|
|
37036
36944
|
if (cmd.detectFile) {
|
|
37037
|
-
const detectFilePath =
|
|
36945
|
+
const detectFilePath = path17.join(workingDir, cmd.detectFile);
|
|
37038
36946
|
if (!fs8.existsSync(detectFilePath)) {
|
|
37039
36947
|
continue;
|
|
37040
36948
|
}
|
|
@@ -37182,9 +37090,9 @@ function validateArgs(args) {
|
|
|
37182
37090
|
}
|
|
37183
37091
|
function getLinterCommand(linter, mode, projectDir) {
|
|
37184
37092
|
const isWindows = process.platform === "win32";
|
|
37185
|
-
const binDir =
|
|
37186
|
-
const biomeBin = isWindows ?
|
|
37187
|
-
const eslintBin = isWindows ?
|
|
37093
|
+
const binDir = path18.join(projectDir, "node_modules", ".bin");
|
|
37094
|
+
const biomeBin = isWindows ? path18.join(binDir, "biome.EXE") : path18.join(binDir, "biome");
|
|
37095
|
+
const eslintBin = isWindows ? path18.join(binDir, "eslint.cmd") : path18.join(binDir, "eslint");
|
|
37188
37096
|
switch (linter) {
|
|
37189
37097
|
case "biome":
|
|
37190
37098
|
if (mode === "fix") {
|
|
@@ -37200,7 +37108,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
37200
37108
|
}
|
|
37201
37109
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
37202
37110
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
37203
|
-
const gradlew = fs9.existsSync(
|
|
37111
|
+
const gradlew = fs9.existsSync(path18.join(cwd, gradlewName)) ? path18.join(cwd, gradlewName) : null;
|
|
37204
37112
|
switch (linter) {
|
|
37205
37113
|
case "ruff":
|
|
37206
37114
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -37234,10 +37142,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
37234
37142
|
}
|
|
37235
37143
|
}
|
|
37236
37144
|
function detectRuff(cwd) {
|
|
37237
|
-
if (fs9.existsSync(
|
|
37145
|
+
if (fs9.existsSync(path18.join(cwd, "ruff.toml")))
|
|
37238
37146
|
return isCommandAvailable("ruff");
|
|
37239
37147
|
try {
|
|
37240
|
-
const pyproject =
|
|
37148
|
+
const pyproject = path18.join(cwd, "pyproject.toml");
|
|
37241
37149
|
if (fs9.existsSync(pyproject)) {
|
|
37242
37150
|
const content = fs9.readFileSync(pyproject, "utf-8");
|
|
37243
37151
|
if (content.includes("[tool.ruff]"))
|
|
@@ -37247,19 +37155,19 @@ function detectRuff(cwd) {
|
|
|
37247
37155
|
return false;
|
|
37248
37156
|
}
|
|
37249
37157
|
function detectClippy(cwd) {
|
|
37250
|
-
return fs9.existsSync(
|
|
37158
|
+
return fs9.existsSync(path18.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
37251
37159
|
}
|
|
37252
37160
|
function detectGolangciLint(cwd) {
|
|
37253
|
-
return fs9.existsSync(
|
|
37161
|
+
return fs9.existsSync(path18.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
37254
37162
|
}
|
|
37255
37163
|
function detectCheckstyle(cwd) {
|
|
37256
|
-
const hasMaven = fs9.existsSync(
|
|
37257
|
-
const hasGradle = fs9.existsSync(
|
|
37258
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs9.existsSync(
|
|
37164
|
+
const hasMaven = fs9.existsSync(path18.join(cwd, "pom.xml"));
|
|
37165
|
+
const hasGradle = fs9.existsSync(path18.join(cwd, "build.gradle")) || fs9.existsSync(path18.join(cwd, "build.gradle.kts"));
|
|
37166
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs9.existsSync(path18.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
37259
37167
|
return (hasMaven || hasGradle) && hasBinary;
|
|
37260
37168
|
}
|
|
37261
37169
|
function detectKtlint(cwd) {
|
|
37262
|
-
const hasKotlin = fs9.existsSync(
|
|
37170
|
+
const hasKotlin = fs9.existsSync(path18.join(cwd, "build.gradle.kts")) || fs9.existsSync(path18.join(cwd, "build.gradle")) || (() => {
|
|
37263
37171
|
try {
|
|
37264
37172
|
return fs9.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
37265
37173
|
} catch {
|
|
@@ -37278,11 +37186,11 @@ function detectDotnetFormat(cwd) {
|
|
|
37278
37186
|
}
|
|
37279
37187
|
}
|
|
37280
37188
|
function detectCppcheck(cwd) {
|
|
37281
|
-
if (fs9.existsSync(
|
|
37189
|
+
if (fs9.existsSync(path18.join(cwd, "CMakeLists.txt"))) {
|
|
37282
37190
|
return isCommandAvailable("cppcheck");
|
|
37283
37191
|
}
|
|
37284
37192
|
try {
|
|
37285
|
-
const dirsToCheck = [cwd,
|
|
37193
|
+
const dirsToCheck = [cwd, path18.join(cwd, "src")];
|
|
37286
37194
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
37287
37195
|
try {
|
|
37288
37196
|
return fs9.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -37296,13 +37204,13 @@ function detectCppcheck(cwd) {
|
|
|
37296
37204
|
}
|
|
37297
37205
|
}
|
|
37298
37206
|
function detectSwiftlint(cwd) {
|
|
37299
|
-
return fs9.existsSync(
|
|
37207
|
+
return fs9.existsSync(path18.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
37300
37208
|
}
|
|
37301
37209
|
function detectDartAnalyze(cwd) {
|
|
37302
|
-
return fs9.existsSync(
|
|
37210
|
+
return fs9.existsSync(path18.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
37303
37211
|
}
|
|
37304
37212
|
function detectRubocop(cwd) {
|
|
37305
|
-
return (fs9.existsSync(
|
|
37213
|
+
return (fs9.existsSync(path18.join(cwd, "Gemfile")) || fs9.existsSync(path18.join(cwd, "gems.rb")) || fs9.existsSync(path18.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
37306
37214
|
}
|
|
37307
37215
|
function detectAdditionalLinter(cwd) {
|
|
37308
37216
|
if (detectRuff(cwd))
|
|
@@ -37327,17 +37235,53 @@ function detectAdditionalLinter(cwd) {
|
|
|
37327
37235
|
return "rubocop";
|
|
37328
37236
|
return null;
|
|
37329
37237
|
}
|
|
37238
|
+
function findBinInAncestors(startDir, binName) {
|
|
37239
|
+
let dir = startDir;
|
|
37240
|
+
while (true) {
|
|
37241
|
+
const candidate = path18.join(dir, "node_modules", ".bin", binName);
|
|
37242
|
+
if (fs9.existsSync(candidate))
|
|
37243
|
+
return candidate;
|
|
37244
|
+
const parent = path18.dirname(dir);
|
|
37245
|
+
if (parent === dir)
|
|
37246
|
+
break;
|
|
37247
|
+
dir = parent;
|
|
37248
|
+
}
|
|
37249
|
+
return null;
|
|
37250
|
+
}
|
|
37251
|
+
function findBinInEnvPath(binName) {
|
|
37252
|
+
const searchPath = process.env.PATH ?? "";
|
|
37253
|
+
for (const dir of searchPath.split(path18.delimiter)) {
|
|
37254
|
+
if (!dir)
|
|
37255
|
+
continue;
|
|
37256
|
+
const candidate = path18.join(dir, binName);
|
|
37257
|
+
if (fs9.existsSync(candidate))
|
|
37258
|
+
return candidate;
|
|
37259
|
+
}
|
|
37260
|
+
return null;
|
|
37261
|
+
}
|
|
37330
37262
|
async function detectAvailableLinter(directory) {
|
|
37331
|
-
const _DETECT_TIMEOUT = 2000;
|
|
37332
37263
|
if (!directory)
|
|
37333
37264
|
return null;
|
|
37334
37265
|
if (!fs9.existsSync(directory))
|
|
37335
37266
|
return null;
|
|
37336
37267
|
const projectDir = directory;
|
|
37337
37268
|
const isWindows = process.platform === "win32";
|
|
37338
|
-
const biomeBin = isWindows ?
|
|
37339
|
-
const eslintBin = isWindows ?
|
|
37340
|
-
|
|
37269
|
+
const biomeBin = isWindows ? path18.join(projectDir, "node_modules", ".bin", "biome.EXE") : path18.join(projectDir, "node_modules", ".bin", "biome");
|
|
37270
|
+
const eslintBin = isWindows ? path18.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path18.join(projectDir, "node_modules", ".bin", "eslint");
|
|
37271
|
+
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
37272
|
+
if (localResult)
|
|
37273
|
+
return localResult;
|
|
37274
|
+
const biomeAncestor = findBinInAncestors(path18.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
37275
|
+
const eslintAncestor = findBinInAncestors(path18.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
37276
|
+
if (biomeAncestor || eslintAncestor) {
|
|
37277
|
+
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
37278
|
+
}
|
|
37279
|
+
const pathBiome = findBinInEnvPath(isWindows ? "biome.EXE" : "biome");
|
|
37280
|
+
const pathEslint = findBinInEnvPath(isWindows ? "eslint.cmd" : "eslint");
|
|
37281
|
+
if (pathBiome || pathEslint) {
|
|
37282
|
+
return _detectAvailableLinter(projectDir, pathBiome ?? biomeBin, pathEslint ?? eslintBin);
|
|
37283
|
+
}
|
|
37284
|
+
return null;
|
|
37341
37285
|
}
|
|
37342
37286
|
async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
37343
37287
|
const DETECT_TIMEOUT = 2000;
|
|
@@ -37536,7 +37480,7 @@ For Rust: rustup component add clippy`
|
|
|
37536
37480
|
|
|
37537
37481
|
// src/tools/secretscan.ts
|
|
37538
37482
|
import * as fs10 from "fs";
|
|
37539
|
-
import * as
|
|
37483
|
+
import * as path19 from "path";
|
|
37540
37484
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
37541
37485
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
37542
37486
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -37763,7 +37707,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
37763
37707
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
37764
37708
|
}
|
|
37765
37709
|
function loadSecretScanIgnore(scanDir) {
|
|
37766
|
-
const ignorePath =
|
|
37710
|
+
const ignorePath = path19.join(scanDir, ".secretscanignore");
|
|
37767
37711
|
try {
|
|
37768
37712
|
if (!fs10.existsSync(ignorePath))
|
|
37769
37713
|
return [];
|
|
@@ -37786,7 +37730,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
37786
37730
|
if (exactNames.has(entry))
|
|
37787
37731
|
return true;
|
|
37788
37732
|
for (const pattern of globPatterns) {
|
|
37789
|
-
if (
|
|
37733
|
+
if (path19.matchesGlob(relPath, pattern))
|
|
37790
37734
|
return true;
|
|
37791
37735
|
}
|
|
37792
37736
|
return false;
|
|
@@ -37807,7 +37751,7 @@ function validateDirectoryInput(dir) {
|
|
|
37807
37751
|
return null;
|
|
37808
37752
|
}
|
|
37809
37753
|
function isBinaryFile(filePath, buffer) {
|
|
37810
|
-
const ext =
|
|
37754
|
+
const ext = path19.extname(filePath).toLowerCase();
|
|
37811
37755
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
37812
37756
|
return true;
|
|
37813
37757
|
}
|
|
@@ -37944,9 +37888,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
37944
37888
|
return false;
|
|
37945
37889
|
}
|
|
37946
37890
|
function isPathWithinScope(realPath, scanDir) {
|
|
37947
|
-
const resolvedScanDir =
|
|
37948
|
-
const resolvedRealPath =
|
|
37949
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
37891
|
+
const resolvedScanDir = path19.resolve(scanDir);
|
|
37892
|
+
const resolvedRealPath = path19.resolve(realPath);
|
|
37893
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path19.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
37950
37894
|
}
|
|
37951
37895
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
37952
37896
|
skippedDirs: 0,
|
|
@@ -37972,8 +37916,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
37972
37916
|
return a.localeCompare(b);
|
|
37973
37917
|
});
|
|
37974
37918
|
for (const entry of entries) {
|
|
37975
|
-
const fullPath =
|
|
37976
|
-
const relPath =
|
|
37919
|
+
const fullPath = path19.join(dir, entry);
|
|
37920
|
+
const relPath = path19.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
37977
37921
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
37978
37922
|
stats.skippedDirs++;
|
|
37979
37923
|
continue;
|
|
@@ -38008,7 +37952,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
38008
37952
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
38009
37953
|
files.push(...subFiles);
|
|
38010
37954
|
} else if (lstat.isFile()) {
|
|
38011
|
-
const ext =
|
|
37955
|
+
const ext = path19.extname(fullPath).toLowerCase();
|
|
38012
37956
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
38013
37957
|
files.push(fullPath);
|
|
38014
37958
|
} else {
|
|
@@ -38074,7 +38018,14 @@ var secretscan = createSwarmTool({
|
|
|
38074
38018
|
}
|
|
38075
38019
|
}
|
|
38076
38020
|
try {
|
|
38077
|
-
const
|
|
38021
|
+
const _scanDirRaw = path19.resolve(directory);
|
|
38022
|
+
const scanDir = (() => {
|
|
38023
|
+
try {
|
|
38024
|
+
return fs10.realpathSync(_scanDirRaw);
|
|
38025
|
+
} catch {
|
|
38026
|
+
return _scanDirRaw;
|
|
38027
|
+
}
|
|
38028
|
+
})();
|
|
38078
38029
|
if (!fs10.existsSync(scanDir)) {
|
|
38079
38030
|
const errorResult = {
|
|
38080
38031
|
error: "directory not found",
|
|
@@ -38225,11 +38176,11 @@ async function runSecretscan(directory) {
|
|
|
38225
38176
|
|
|
38226
38177
|
// src/tools/test-runner.ts
|
|
38227
38178
|
import * as fs12 from "fs";
|
|
38228
|
-
import * as
|
|
38179
|
+
import * as path21 from "path";
|
|
38229
38180
|
|
|
38230
38181
|
// src/tools/resolve-working-directory.ts
|
|
38231
38182
|
import * as fs11 from "fs";
|
|
38232
|
-
import * as
|
|
38183
|
+
import * as path20 from "path";
|
|
38233
38184
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
38234
38185
|
if (workingDirectory == null || workingDirectory === "") {
|
|
38235
38186
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -38249,15 +38200,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
38249
38200
|
};
|
|
38250
38201
|
}
|
|
38251
38202
|
}
|
|
38252
|
-
const normalizedDir =
|
|
38253
|
-
const pathParts = normalizedDir.split(
|
|
38203
|
+
const normalizedDir = path20.normalize(workingDirectory);
|
|
38204
|
+
const pathParts = normalizedDir.split(path20.sep);
|
|
38254
38205
|
if (pathParts.includes("..")) {
|
|
38255
38206
|
return {
|
|
38256
38207
|
success: false,
|
|
38257
38208
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
38258
38209
|
};
|
|
38259
38210
|
}
|
|
38260
|
-
const resolvedDir =
|
|
38211
|
+
const resolvedDir = path20.resolve(normalizedDir);
|
|
38261
38212
|
try {
|
|
38262
38213
|
const realPath = fs11.realpathSync(resolvedDir);
|
|
38263
38214
|
return { success: true, directory: realPath };
|
|
@@ -38340,14 +38291,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
38340
38291
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
38341
38292
|
}
|
|
38342
38293
|
function detectGoTest(cwd) {
|
|
38343
|
-
return fs12.existsSync(
|
|
38294
|
+
return fs12.existsSync(path21.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
38344
38295
|
}
|
|
38345
38296
|
function detectJavaMaven(cwd) {
|
|
38346
|
-
return fs12.existsSync(
|
|
38297
|
+
return fs12.existsSync(path21.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
38347
38298
|
}
|
|
38348
38299
|
function detectGradle(cwd) {
|
|
38349
|
-
const hasBuildFile = fs12.existsSync(
|
|
38350
|
-
const hasGradlew = fs12.existsSync(
|
|
38300
|
+
const hasBuildFile = fs12.existsSync(path21.join(cwd, "build.gradle")) || fs12.existsSync(path21.join(cwd, "build.gradle.kts"));
|
|
38301
|
+
const hasGradlew = fs12.existsSync(path21.join(cwd, "gradlew")) || fs12.existsSync(path21.join(cwd, "gradlew.bat"));
|
|
38351
38302
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
38352
38303
|
}
|
|
38353
38304
|
function detectDotnetTest(cwd) {
|
|
@@ -38360,30 +38311,30 @@ function detectDotnetTest(cwd) {
|
|
|
38360
38311
|
}
|
|
38361
38312
|
}
|
|
38362
38313
|
function detectCTest(cwd) {
|
|
38363
|
-
const hasSource = fs12.existsSync(
|
|
38364
|
-
const hasBuildCache = fs12.existsSync(
|
|
38314
|
+
const hasSource = fs12.existsSync(path21.join(cwd, "CMakeLists.txt"));
|
|
38315
|
+
const hasBuildCache = fs12.existsSync(path21.join(cwd, "CMakeCache.txt")) || fs12.existsSync(path21.join(cwd, "build", "CMakeCache.txt"));
|
|
38365
38316
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
38366
38317
|
}
|
|
38367
38318
|
function detectSwiftTest(cwd) {
|
|
38368
|
-
return fs12.existsSync(
|
|
38319
|
+
return fs12.existsSync(path21.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
38369
38320
|
}
|
|
38370
38321
|
function detectDartTest(cwd) {
|
|
38371
|
-
return fs12.existsSync(
|
|
38322
|
+
return fs12.existsSync(path21.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
38372
38323
|
}
|
|
38373
38324
|
function detectRSpec(cwd) {
|
|
38374
|
-
const hasRSpecFile = fs12.existsSync(
|
|
38375
|
-
const hasGemfile = fs12.existsSync(
|
|
38376
|
-
const hasSpecDir = fs12.existsSync(
|
|
38325
|
+
const hasRSpecFile = fs12.existsSync(path21.join(cwd, ".rspec"));
|
|
38326
|
+
const hasGemfile = fs12.existsSync(path21.join(cwd, "Gemfile"));
|
|
38327
|
+
const hasSpecDir = fs12.existsSync(path21.join(cwd, "spec"));
|
|
38377
38328
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
38378
38329
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
38379
38330
|
}
|
|
38380
38331
|
function detectMinitest(cwd) {
|
|
38381
|
-
return fs12.existsSync(
|
|
38332
|
+
return fs12.existsSync(path21.join(cwd, "test")) && (fs12.existsSync(path21.join(cwd, "Gemfile")) || fs12.existsSync(path21.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
38382
38333
|
}
|
|
38383
38334
|
async function detectTestFramework(cwd) {
|
|
38384
38335
|
const baseDir = cwd;
|
|
38385
38336
|
try {
|
|
38386
|
-
const packageJsonPath =
|
|
38337
|
+
const packageJsonPath = path21.join(baseDir, "package.json");
|
|
38387
38338
|
if (fs12.existsSync(packageJsonPath)) {
|
|
38388
38339
|
const content = fs12.readFileSync(packageJsonPath, "utf-8");
|
|
38389
38340
|
const pkg = JSON.parse(content);
|
|
@@ -38404,16 +38355,16 @@ async function detectTestFramework(cwd) {
|
|
|
38404
38355
|
return "jest";
|
|
38405
38356
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
38406
38357
|
return "mocha";
|
|
38407
|
-
if (fs12.existsSync(
|
|
38358
|
+
if (fs12.existsSync(path21.join(baseDir, "bun.lockb")) || fs12.existsSync(path21.join(baseDir, "bun.lock"))) {
|
|
38408
38359
|
if (scripts.test?.includes("bun"))
|
|
38409
38360
|
return "bun";
|
|
38410
38361
|
}
|
|
38411
38362
|
}
|
|
38412
38363
|
} catch {}
|
|
38413
38364
|
try {
|
|
38414
|
-
const pyprojectTomlPath =
|
|
38415
|
-
const setupCfgPath =
|
|
38416
|
-
const requirementsTxtPath =
|
|
38365
|
+
const pyprojectTomlPath = path21.join(baseDir, "pyproject.toml");
|
|
38366
|
+
const setupCfgPath = path21.join(baseDir, "setup.cfg");
|
|
38367
|
+
const requirementsTxtPath = path21.join(baseDir, "requirements.txt");
|
|
38417
38368
|
if (fs12.existsSync(pyprojectTomlPath)) {
|
|
38418
38369
|
const content = fs12.readFileSync(pyprojectTomlPath, "utf-8");
|
|
38419
38370
|
if (content.includes("[tool.pytest"))
|
|
@@ -38433,7 +38384,7 @@ async function detectTestFramework(cwd) {
|
|
|
38433
38384
|
}
|
|
38434
38385
|
} catch {}
|
|
38435
38386
|
try {
|
|
38436
|
-
const cargoTomlPath =
|
|
38387
|
+
const cargoTomlPath = path21.join(baseDir, "Cargo.toml");
|
|
38437
38388
|
if (fs12.existsSync(cargoTomlPath)) {
|
|
38438
38389
|
const content = fs12.readFileSync(cargoTomlPath, "utf-8");
|
|
38439
38390
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -38444,9 +38395,9 @@ async function detectTestFramework(cwd) {
|
|
|
38444
38395
|
}
|
|
38445
38396
|
} catch {}
|
|
38446
38397
|
try {
|
|
38447
|
-
const pesterConfigPath =
|
|
38448
|
-
const pesterConfigJsonPath =
|
|
38449
|
-
const pesterPs1Path =
|
|
38398
|
+
const pesterConfigPath = path21.join(baseDir, "pester.config.ps1");
|
|
38399
|
+
const pesterConfigJsonPath = path21.join(baseDir, "pester.config.ps1.json");
|
|
38400
|
+
const pesterPs1Path = path21.join(baseDir, "tests.ps1");
|
|
38450
38401
|
if (fs12.existsSync(pesterConfigPath) || fs12.existsSync(pesterConfigJsonPath) || fs12.existsSync(pesterPs1Path)) {
|
|
38451
38402
|
return "pester";
|
|
38452
38403
|
}
|
|
@@ -38498,8 +38449,8 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
38498
38449
|
const testFiles = [];
|
|
38499
38450
|
for (const file3 of sourceFiles) {
|
|
38500
38451
|
const normalizedPath = file3.replace(/\\/g, "/");
|
|
38501
|
-
const basename4 =
|
|
38502
|
-
const
|
|
38452
|
+
const basename4 = path21.basename(file3);
|
|
38453
|
+
const dirname10 = path21.dirname(file3);
|
|
38503
38454
|
if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
|
|
38504
38455
|
if (!testFiles.includes(file3)) {
|
|
38505
38456
|
testFiles.push(file3);
|
|
@@ -38508,13 +38459,13 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
38508
38459
|
}
|
|
38509
38460
|
for (const _pattern of TEST_PATTERNS) {
|
|
38510
38461
|
const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
|
|
38511
|
-
const ext =
|
|
38462
|
+
const ext = path21.extname(basename4);
|
|
38512
38463
|
const possibleTestFiles = [
|
|
38513
|
-
|
|
38514
|
-
|
|
38515
|
-
|
|
38516
|
-
|
|
38517
|
-
|
|
38464
|
+
path21.join(dirname10, `${nameWithoutExt}.spec${ext}`),
|
|
38465
|
+
path21.join(dirname10, `${nameWithoutExt}.test${ext}`),
|
|
38466
|
+
path21.join(dirname10, "__tests__", `${nameWithoutExt}${ext}`),
|
|
38467
|
+
path21.join(dirname10, "tests", `${nameWithoutExt}${ext}`),
|
|
38468
|
+
path21.join(dirname10, "test", `${nameWithoutExt}${ext}`)
|
|
38518
38469
|
];
|
|
38519
38470
|
for (const testFile of possibleTestFiles) {
|
|
38520
38471
|
if (fs12.existsSync(testFile) && !testFiles.includes(testFile)) {
|
|
@@ -38534,7 +38485,7 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38534
38485
|
for (const testFile of candidateTestFiles) {
|
|
38535
38486
|
try {
|
|
38536
38487
|
const content = fs12.readFileSync(testFile, "utf-8");
|
|
38537
|
-
const testDir =
|
|
38488
|
+
const testDir = path21.dirname(testFile);
|
|
38538
38489
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
38539
38490
|
let match;
|
|
38540
38491
|
match = importRegex.exec(content);
|
|
@@ -38542,8 +38493,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38542
38493
|
const importPath = match[1];
|
|
38543
38494
|
let resolvedImport;
|
|
38544
38495
|
if (importPath.startsWith(".")) {
|
|
38545
|
-
resolvedImport =
|
|
38546
|
-
const existingExt =
|
|
38496
|
+
resolvedImport = path21.resolve(testDir, importPath);
|
|
38497
|
+
const existingExt = path21.extname(resolvedImport);
|
|
38547
38498
|
if (!existingExt) {
|
|
38548
38499
|
for (const extToTry of [
|
|
38549
38500
|
".ts",
|
|
@@ -38563,12 +38514,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38563
38514
|
} else {
|
|
38564
38515
|
continue;
|
|
38565
38516
|
}
|
|
38566
|
-
const importBasename =
|
|
38567
|
-
const importDir =
|
|
38517
|
+
const importBasename = path21.basename(resolvedImport, path21.extname(resolvedImport));
|
|
38518
|
+
const importDir = path21.dirname(resolvedImport);
|
|
38568
38519
|
for (const sourceFile of sourceFiles) {
|
|
38569
|
-
const sourceDir =
|
|
38570
|
-
const sourceBasename =
|
|
38571
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
38520
|
+
const sourceDir = path21.dirname(sourceFile);
|
|
38521
|
+
const sourceBasename = path21.basename(sourceFile, path21.extname(sourceFile));
|
|
38522
|
+
const isRelatedDir = importDir === sourceDir || importDir === path21.join(sourceDir, "__tests__") || importDir === path21.join(sourceDir, "tests") || importDir === path21.join(sourceDir, "test");
|
|
38572
38523
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
38573
38524
|
if (!testFiles.includes(testFile)) {
|
|
38574
38525
|
testFiles.push(testFile);
|
|
@@ -38583,8 +38534,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38583
38534
|
while (match !== null) {
|
|
38584
38535
|
const importPath = match[1];
|
|
38585
38536
|
if (importPath.startsWith(".")) {
|
|
38586
|
-
let resolvedImport =
|
|
38587
|
-
const existingExt =
|
|
38537
|
+
let resolvedImport = path21.resolve(testDir, importPath);
|
|
38538
|
+
const existingExt = path21.extname(resolvedImport);
|
|
38588
38539
|
if (!existingExt) {
|
|
38589
38540
|
for (const extToTry of [
|
|
38590
38541
|
".ts",
|
|
@@ -38601,12 +38552,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38601
38552
|
}
|
|
38602
38553
|
}
|
|
38603
38554
|
}
|
|
38604
|
-
const importDir =
|
|
38605
|
-
const importBasename =
|
|
38555
|
+
const importDir = path21.dirname(resolvedImport);
|
|
38556
|
+
const importBasename = path21.basename(resolvedImport, path21.extname(resolvedImport));
|
|
38606
38557
|
for (const sourceFile of sourceFiles) {
|
|
38607
|
-
const sourceDir =
|
|
38608
|
-
const sourceBasename =
|
|
38609
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
38558
|
+
const sourceDir = path21.dirname(sourceFile);
|
|
38559
|
+
const sourceBasename = path21.basename(sourceFile, path21.extname(sourceFile));
|
|
38560
|
+
const isRelatedDir = importDir === sourceDir || importDir === path21.join(sourceDir, "__tests__") || importDir === path21.join(sourceDir, "tests") || importDir === path21.join(sourceDir, "test");
|
|
38610
38561
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
38611
38562
|
if (!testFiles.includes(testFile)) {
|
|
38612
38563
|
testFiles.push(testFile);
|
|
@@ -38691,8 +38642,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
38691
38642
|
return ["mvn", "test"];
|
|
38692
38643
|
case "gradle": {
|
|
38693
38644
|
const isWindows = process.platform === "win32";
|
|
38694
|
-
const hasGradlewBat = fs12.existsSync(
|
|
38695
|
-
const hasGradlew = fs12.existsSync(
|
|
38645
|
+
const hasGradlewBat = fs12.existsSync(path21.join(baseDir, "gradlew.bat"));
|
|
38646
|
+
const hasGradlew = fs12.existsSync(path21.join(baseDir, "gradlew"));
|
|
38696
38647
|
if (hasGradlewBat && isWindows)
|
|
38697
38648
|
return ["gradlew.bat", "test"];
|
|
38698
38649
|
if (hasGradlew)
|
|
@@ -38709,7 +38660,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
38709
38660
|
"cmake-build-release",
|
|
38710
38661
|
"out"
|
|
38711
38662
|
];
|
|
38712
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(
|
|
38663
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(path21.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
38713
38664
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
38714
38665
|
}
|
|
38715
38666
|
case "swift-test":
|
|
@@ -39251,7 +39202,7 @@ var test_runner = createSwarmTool({
|
|
|
39251
39202
|
let effectiveScope = scope;
|
|
39252
39203
|
if (scope === "all") {} else if (scope === "convention") {
|
|
39253
39204
|
const sourceFiles = args.files.filter((f) => {
|
|
39254
|
-
const ext =
|
|
39205
|
+
const ext = path21.extname(f).toLowerCase();
|
|
39255
39206
|
return SOURCE_EXTENSIONS.has(ext);
|
|
39256
39207
|
});
|
|
39257
39208
|
if (sourceFiles.length === 0) {
|
|
@@ -39267,7 +39218,7 @@ var test_runner = createSwarmTool({
|
|
|
39267
39218
|
testFiles = getTestFilesFromConvention(sourceFiles);
|
|
39268
39219
|
} else if (scope === "graph") {
|
|
39269
39220
|
const sourceFiles = args.files.filter((f) => {
|
|
39270
|
-
const ext =
|
|
39221
|
+
const ext = path21.extname(f).toLowerCase();
|
|
39271
39222
|
return SOURCE_EXTENSIONS.has(ext);
|
|
39272
39223
|
});
|
|
39273
39224
|
if (sourceFiles.length === 0) {
|
|
@@ -39338,8 +39289,8 @@ function validateDirectoryPath(dir) {
|
|
|
39338
39289
|
if (dir.includes("..")) {
|
|
39339
39290
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
39340
39291
|
}
|
|
39341
|
-
const normalized =
|
|
39342
|
-
const absolutePath =
|
|
39292
|
+
const normalized = path22.normalize(dir);
|
|
39293
|
+
const absolutePath = path22.isAbsolute(normalized) ? normalized : path22.resolve(normalized);
|
|
39343
39294
|
return absolutePath;
|
|
39344
39295
|
}
|
|
39345
39296
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -39362,7 +39313,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
39362
39313
|
}
|
|
39363
39314
|
function getPackageVersion(dir) {
|
|
39364
39315
|
try {
|
|
39365
|
-
const packagePath =
|
|
39316
|
+
const packagePath = path22.join(dir, "package.json");
|
|
39366
39317
|
if (fs13.existsSync(packagePath)) {
|
|
39367
39318
|
const content = fs13.readFileSync(packagePath, "utf-8");
|
|
39368
39319
|
const pkg = JSON.parse(content);
|
|
@@ -39373,7 +39324,7 @@ function getPackageVersion(dir) {
|
|
|
39373
39324
|
}
|
|
39374
39325
|
function getChangelogVersion(dir) {
|
|
39375
39326
|
try {
|
|
39376
|
-
const changelogPath =
|
|
39327
|
+
const changelogPath = path22.join(dir, "CHANGELOG.md");
|
|
39377
39328
|
if (fs13.existsSync(changelogPath)) {
|
|
39378
39329
|
const content = fs13.readFileSync(changelogPath, "utf-8");
|
|
39379
39330
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -39387,7 +39338,7 @@ function getChangelogVersion(dir) {
|
|
|
39387
39338
|
function getVersionFileVersion(dir) {
|
|
39388
39339
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
39389
39340
|
for (const file3 of possibleFiles) {
|
|
39390
|
-
const filePath =
|
|
39341
|
+
const filePath = path22.join(dir, file3);
|
|
39391
39342
|
if (fs13.existsSync(filePath)) {
|
|
39392
39343
|
try {
|
|
39393
39344
|
const content = fs13.readFileSync(filePath, "utf-8").trim();
|
|
@@ -39882,6 +39833,144 @@ async function handlePreflightCommand(directory, _args) {
|
|
|
39882
39833
|
const report = await runPreflight(directory, 0);
|
|
39883
39834
|
return formatPreflightMarkdown(report);
|
|
39884
39835
|
}
|
|
39836
|
+
// src/knowledge/hive-promoter.ts
|
|
39837
|
+
import * as fs14 from "fs";
|
|
39838
|
+
import * as os5 from "os";
|
|
39839
|
+
import * as path23 from "path";
|
|
39840
|
+
var DANGEROUS_PATTERNS = [
|
|
39841
|
+
[/rm\s+-rf/, "rm\\s+-rf"],
|
|
39842
|
+
[/:\s*!\s*\|/, ":\\s*!\\s*\\|"],
|
|
39843
|
+
[/\|\s*sh\b/, "\\|\\s*sh\\b"],
|
|
39844
|
+
[/`[^`]*`/, "`[^`]*`"],
|
|
39845
|
+
[/\$\(/, "\\$\\("],
|
|
39846
|
+
[/;\s*rm\s+\//, ";\\s*rm\\s+\\/"],
|
|
39847
|
+
[/>\s*\/dev\//, ">\\s*\\/dev\\/"],
|
|
39848
|
+
[/\bmkfs\b/, "\\bmkfs\\b"],
|
|
39849
|
+
[/\bdd\s+if=/, "\\bdd\\s+if="],
|
|
39850
|
+
[/chmod\s+[0-7]*7[0-7]{2}/, "chmod\\s+[0-7]*7[0-7]\\{2\\}"],
|
|
39851
|
+
[/\bchown\s+-R\b/, "\\bchown\\s+-R\\b"],
|
|
39852
|
+
[/(?<!\.)\beval\s*\(/, "(?<!\\.)\\beval\\s*\\("],
|
|
39853
|
+
[/(?<!\.)\bexec\s*\(/, "(?<!\\.)\\bexec\\s*\\("]
|
|
39854
|
+
];
|
|
39855
|
+
var SHELL_COMMAND_START = /^(grep|find|ls|cat|sed|awk|curl|wget|ssh|scp|git|mv|cp|mkdir|touch|echo|printf|python|python3|node|bash|sh|zsh|apt|yum|brew)\s/;
|
|
39856
|
+
function validateLesson2(text) {
|
|
39857
|
+
if (!text || !text.trim()) {
|
|
39858
|
+
return { valid: false, reason: "Lesson text cannot be empty" };
|
|
39859
|
+
}
|
|
39860
|
+
for (const [pattern, patternSource] of DANGEROUS_PATTERNS) {
|
|
39861
|
+
if (pattern.test(text)) {
|
|
39862
|
+
return {
|
|
39863
|
+
valid: false,
|
|
39864
|
+
reason: `Dangerous pattern detected: ${patternSource}`
|
|
39865
|
+
};
|
|
39866
|
+
}
|
|
39867
|
+
}
|
|
39868
|
+
const trimmed = text.trim();
|
|
39869
|
+
if (SHELL_COMMAND_START.test(trimmed)) {
|
|
39870
|
+
const lastChar = trimmed[trimmed.length - 1];
|
|
39871
|
+
if (![".", "!", "?", ";"].includes(lastChar)) {
|
|
39872
|
+
return {
|
|
39873
|
+
valid: false,
|
|
39874
|
+
reason: "Lesson appears to contain raw shell commands"
|
|
39875
|
+
};
|
|
39876
|
+
}
|
|
39877
|
+
}
|
|
39878
|
+
return { valid: true };
|
|
39879
|
+
}
|
|
39880
|
+
function getHiveFilePath() {
|
|
39881
|
+
const platform = process.platform;
|
|
39882
|
+
const home = os5.homedir();
|
|
39883
|
+
let dataDir;
|
|
39884
|
+
if (platform === "win32") {
|
|
39885
|
+
dataDir = path23.join(process.env.LOCALAPPDATA || path23.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
39886
|
+
} else if (platform === "darwin") {
|
|
39887
|
+
dataDir = path23.join(home, "Library", "Application Support", "opencode-swarm");
|
|
39888
|
+
} else {
|
|
39889
|
+
dataDir = path23.join(process.env.XDG_DATA_HOME || path23.join(home, ".local", "share"), "opencode-swarm");
|
|
39890
|
+
}
|
|
39891
|
+
return path23.join(dataDir, "hive-knowledge.jsonl");
|
|
39892
|
+
}
|
|
39893
|
+
async function promoteToHive(_directory, lesson, category) {
|
|
39894
|
+
const trimmed = (lesson ?? "").trim();
|
|
39895
|
+
if (!trimmed) {
|
|
39896
|
+
throw new Error("Lesson text required");
|
|
39897
|
+
}
|
|
39898
|
+
const validation = validateLesson2(trimmed);
|
|
39899
|
+
if (!validation.valid) {
|
|
39900
|
+
throw new Error(`Lesson rejected by validator: ${validation.reason}`);
|
|
39901
|
+
}
|
|
39902
|
+
const hivePath = getHiveFilePath();
|
|
39903
|
+
const hiveDir = path23.dirname(hivePath);
|
|
39904
|
+
if (!fs14.existsSync(hiveDir)) {
|
|
39905
|
+
fs14.mkdirSync(hiveDir, { recursive: true });
|
|
39906
|
+
}
|
|
39907
|
+
const now = new Date;
|
|
39908
|
+
const entry = {
|
|
39909
|
+
id: `hive-manual-${now.getTime()}`,
|
|
39910
|
+
lesson: trimmed,
|
|
39911
|
+
category: category || "process",
|
|
39912
|
+
scope_tag: "global",
|
|
39913
|
+
confidence: 1,
|
|
39914
|
+
status: "promoted",
|
|
39915
|
+
promotion_source: "manual",
|
|
39916
|
+
promotedAt: now.toISOString(),
|
|
39917
|
+
retrievalOutcomes: { applied: 0, succeededAfter: 0, failedAfter: 0 }
|
|
39918
|
+
};
|
|
39919
|
+
fs14.appendFileSync(hivePath, `${JSON.stringify(entry)}
|
|
39920
|
+
`, "utf-8");
|
|
39921
|
+
const preview = `${trimmed.slice(0, 50)}${trimmed.length > 50 ? "..." : ""}`;
|
|
39922
|
+
return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
|
|
39923
|
+
}
|
|
39924
|
+
async function promoteFromSwarm(directory, lessonId) {
|
|
39925
|
+
const knowledgePath = path23.join(directory, ".swarm", "knowledge.jsonl");
|
|
39926
|
+
const entries = [];
|
|
39927
|
+
if (fs14.existsSync(knowledgePath)) {
|
|
39928
|
+
const content = fs14.readFileSync(knowledgePath, "utf-8");
|
|
39929
|
+
for (const line of content.split(`
|
|
39930
|
+
`)) {
|
|
39931
|
+
const t = line.trim();
|
|
39932
|
+
if (!t)
|
|
39933
|
+
continue;
|
|
39934
|
+
try {
|
|
39935
|
+
entries.push(JSON.parse(t));
|
|
39936
|
+
} catch {}
|
|
39937
|
+
}
|
|
39938
|
+
}
|
|
39939
|
+
const swarmEntry = entries.find((e) => e.id === lessonId);
|
|
39940
|
+
if (!swarmEntry) {
|
|
39941
|
+
throw new Error(`Lesson ${lessonId} not found in .swarm/knowledge.jsonl`);
|
|
39942
|
+
}
|
|
39943
|
+
const lessonText = typeof swarmEntry.lesson === "string" ? swarmEntry.lesson.trim() : "";
|
|
39944
|
+
if (!lessonText) {
|
|
39945
|
+
throw new Error("Lesson text required");
|
|
39946
|
+
}
|
|
39947
|
+
const validation = validateLesson2(lessonText);
|
|
39948
|
+
if (!validation.valid) {
|
|
39949
|
+
throw new Error(`Lesson rejected by validator: ${validation.reason}`);
|
|
39950
|
+
}
|
|
39951
|
+
const hivePath = getHiveFilePath();
|
|
39952
|
+
const hiveDir = path23.dirname(hivePath);
|
|
39953
|
+
if (!fs14.existsSync(hiveDir)) {
|
|
39954
|
+
fs14.mkdirSync(hiveDir, { recursive: true });
|
|
39955
|
+
}
|
|
39956
|
+
const now = new Date;
|
|
39957
|
+
const hiveEntry = {
|
|
39958
|
+
id: `hive-manual-${now.getTime()}`,
|
|
39959
|
+
lesson: lessonText,
|
|
39960
|
+
category: typeof swarmEntry.category === "string" ? swarmEntry.category : "process",
|
|
39961
|
+
scope_tag: typeof swarmEntry.scope === "string" ? swarmEntry.scope : "global",
|
|
39962
|
+
confidence: 1,
|
|
39963
|
+
status: "promoted",
|
|
39964
|
+
promotion_source: "manual",
|
|
39965
|
+
promotedAt: now.toISOString(),
|
|
39966
|
+
retrievalOutcomes: { applied: 0, succeededAfter: 0, failedAfter: 0 }
|
|
39967
|
+
};
|
|
39968
|
+
fs14.appendFileSync(hivePath, `${JSON.stringify(hiveEntry)}
|
|
39969
|
+
`, "utf-8");
|
|
39970
|
+
const preview = `${lessonText.slice(0, 50)}${lessonText.length > 50 ? "..." : ""}`;
|
|
39971
|
+
return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
|
|
39972
|
+
}
|
|
39973
|
+
|
|
39885
39974
|
// src/commands/promote.ts
|
|
39886
39975
|
async function handlePromoteCommand(directory, args) {
|
|
39887
39976
|
let category;
|
|
@@ -39904,11 +39993,7 @@ async function handlePromoteCommand(directory, args) {
|
|
|
39904
39993
|
return `Usage: /swarm promote "<lesson text>" or /swarm promote --from-swarm <id>`;
|
|
39905
39994
|
}
|
|
39906
39995
|
if (lessonText) {
|
|
39907
|
-
const validation =
|
|
39908
|
-
category: category || "process",
|
|
39909
|
-
scope: "global",
|
|
39910
|
-
confidence: 1
|
|
39911
|
-
});
|
|
39996
|
+
const validation = validateLesson2(lessonText);
|
|
39912
39997
|
if (!validation.valid) {
|
|
39913
39998
|
return `Lesson rejected by validator: ${validation.reason}`;
|
|
39914
39999
|
}
|
|
@@ -39934,7 +40019,7 @@ async function handlePromoteCommand(directory, args) {
|
|
|
39934
40019
|
}
|
|
39935
40020
|
|
|
39936
40021
|
// src/commands/reset.ts
|
|
39937
|
-
import * as
|
|
40022
|
+
import * as fs15 from "fs";
|
|
39938
40023
|
|
|
39939
40024
|
// src/background/manager.ts
|
|
39940
40025
|
init_utils();
|
|
@@ -40635,8 +40720,8 @@ async function handleResetCommand(directory, args) {
|
|
|
40635
40720
|
for (const filename of filesToReset) {
|
|
40636
40721
|
try {
|
|
40637
40722
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
40638
|
-
if (
|
|
40639
|
-
|
|
40723
|
+
if (fs15.existsSync(resolvedPath)) {
|
|
40724
|
+
fs15.unlinkSync(resolvedPath);
|
|
40640
40725
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
40641
40726
|
} else {
|
|
40642
40727
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -40653,8 +40738,8 @@ async function handleResetCommand(directory, args) {
|
|
|
40653
40738
|
}
|
|
40654
40739
|
try {
|
|
40655
40740
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
40656
|
-
if (
|
|
40657
|
-
|
|
40741
|
+
if (fs15.existsSync(summariesPath)) {
|
|
40742
|
+
fs15.rmSync(summariesPath, { recursive: true, force: true });
|
|
40658
40743
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
40659
40744
|
} else {
|
|
40660
40745
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -40674,14 +40759,14 @@ async function handleResetCommand(directory, args) {
|
|
|
40674
40759
|
|
|
40675
40760
|
// src/commands/reset-session.ts
|
|
40676
40761
|
init_utils2();
|
|
40677
|
-
import * as
|
|
40762
|
+
import * as fs16 from "fs";
|
|
40678
40763
|
import * as path24 from "path";
|
|
40679
40764
|
async function handleResetSessionCommand(directory, _args) {
|
|
40680
40765
|
const results = [];
|
|
40681
40766
|
try {
|
|
40682
40767
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
40683
|
-
if (
|
|
40684
|
-
|
|
40768
|
+
if (fs16.existsSync(statePath)) {
|
|
40769
|
+
fs16.unlinkSync(statePath);
|
|
40685
40770
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
40686
40771
|
} else {
|
|
40687
40772
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -40691,14 +40776,14 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
40691
40776
|
}
|
|
40692
40777
|
try {
|
|
40693
40778
|
const sessionDir = path24.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
40694
|
-
if (
|
|
40695
|
-
const files =
|
|
40779
|
+
if (fs16.existsSync(sessionDir)) {
|
|
40780
|
+
const files = fs16.readdirSync(sessionDir);
|
|
40696
40781
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
40697
40782
|
let deletedCount = 0;
|
|
40698
40783
|
for (const file3 of otherFiles) {
|
|
40699
40784
|
const filePath = path24.join(sessionDir, file3);
|
|
40700
|
-
if (
|
|
40701
|
-
|
|
40785
|
+
if (fs16.lstatSync(filePath).isFile()) {
|
|
40786
|
+
fs16.unlinkSync(filePath);
|
|
40702
40787
|
deletedCount++;
|
|
40703
40788
|
}
|
|
40704
40789
|
}
|
|
@@ -40803,18 +40888,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
40803
40888
|
|
|
40804
40889
|
// src/commands/rollback.ts
|
|
40805
40890
|
init_utils2();
|
|
40806
|
-
import * as
|
|
40891
|
+
import * as fs17 from "fs";
|
|
40807
40892
|
import * as path26 from "path";
|
|
40808
40893
|
async function handleRollbackCommand(directory, args) {
|
|
40809
40894
|
const phaseArg = args[0];
|
|
40810
40895
|
if (!phaseArg) {
|
|
40811
40896
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
40812
|
-
if (!
|
|
40897
|
+
if (!fs17.existsSync(manifestPath2)) {
|
|
40813
40898
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
40814
40899
|
}
|
|
40815
40900
|
let manifest2;
|
|
40816
40901
|
try {
|
|
40817
|
-
manifest2 = JSON.parse(
|
|
40902
|
+
manifest2 = JSON.parse(fs17.readFileSync(manifestPath2, "utf-8"));
|
|
40818
40903
|
} catch {
|
|
40819
40904
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
40820
40905
|
}
|
|
@@ -40836,12 +40921,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40836
40921
|
return "Error: Phase number must be a positive integer.";
|
|
40837
40922
|
}
|
|
40838
40923
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
40839
|
-
if (!
|
|
40924
|
+
if (!fs17.existsSync(manifestPath)) {
|
|
40840
40925
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
40841
40926
|
}
|
|
40842
40927
|
let manifest;
|
|
40843
40928
|
try {
|
|
40844
|
-
manifest = JSON.parse(
|
|
40929
|
+
manifest = JSON.parse(fs17.readFileSync(manifestPath, "utf-8"));
|
|
40845
40930
|
} catch {
|
|
40846
40931
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
40847
40932
|
}
|
|
@@ -40851,10 +40936,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40851
40936
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
40852
40937
|
}
|
|
40853
40938
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
40854
|
-
if (!
|
|
40939
|
+
if (!fs17.existsSync(checkpointDir)) {
|
|
40855
40940
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
40856
40941
|
}
|
|
40857
|
-
const checkpointFiles =
|
|
40942
|
+
const checkpointFiles = fs17.readdirSync(checkpointDir);
|
|
40858
40943
|
if (checkpointFiles.length === 0) {
|
|
40859
40944
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
40860
40945
|
}
|
|
@@ -40865,7 +40950,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40865
40950
|
const src = path26.join(checkpointDir, file3);
|
|
40866
40951
|
const dest = path26.join(swarmDir, file3);
|
|
40867
40952
|
try {
|
|
40868
|
-
|
|
40953
|
+
fs17.cpSync(src, dest, { recursive: true, force: true });
|
|
40869
40954
|
successes.push(file3);
|
|
40870
40955
|
} catch (error93) {
|
|
40871
40956
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -40882,7 +40967,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40882
40967
|
timestamp: new Date().toISOString()
|
|
40883
40968
|
};
|
|
40884
40969
|
try {
|
|
40885
|
-
|
|
40970
|
+
fs17.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
40886
40971
|
`);
|
|
40887
40972
|
} catch (error93) {
|
|
40888
40973
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -40925,11 +41010,11 @@ async function handleSimulateCommand(directory, args) {
|
|
|
40925
41010
|
];
|
|
40926
41011
|
const report = reportLines.filter(Boolean).join(`
|
|
40927
41012
|
`);
|
|
40928
|
-
const
|
|
41013
|
+
const fs18 = await import("fs/promises");
|
|
40929
41014
|
const path27 = await import("path");
|
|
40930
41015
|
const reportPath = path27.join(directory, ".swarm", "simulate-report.md");
|
|
40931
|
-
await
|
|
40932
|
-
await
|
|
41016
|
+
await fs18.mkdir(path27.dirname(reportPath), { recursive: true });
|
|
41017
|
+
await fs18.writeFile(reportPath, report, "utf-8");
|
|
40933
41018
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
40934
41019
|
}
|
|
40935
41020
|
|
|
@@ -41411,18 +41496,18 @@ function resolveCommand(tokens) {
|
|
|
41411
41496
|
}
|
|
41412
41497
|
|
|
41413
41498
|
// src/cli/index.ts
|
|
41414
|
-
var CONFIG_DIR = path27.join(process.env.XDG_CONFIG_HOME || path27.join(
|
|
41499
|
+
var CONFIG_DIR = path27.join(process.env.XDG_CONFIG_HOME || path27.join(os6.homedir(), ".config"), "opencode");
|
|
41415
41500
|
var OPENCODE_CONFIG_PATH = path27.join(CONFIG_DIR, "opencode.json");
|
|
41416
41501
|
var PLUGIN_CONFIG_PATH = path27.join(CONFIG_DIR, "opencode-swarm.json");
|
|
41417
41502
|
var PROMPTS_DIR = path27.join(CONFIG_DIR, "opencode-swarm");
|
|
41418
41503
|
function ensureDir(dir) {
|
|
41419
|
-
if (!
|
|
41420
|
-
|
|
41504
|
+
if (!fs18.existsSync(dir)) {
|
|
41505
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
41421
41506
|
}
|
|
41422
41507
|
}
|
|
41423
41508
|
function loadJson(filepath) {
|
|
41424
41509
|
try {
|
|
41425
|
-
const content =
|
|
41510
|
+
const content = fs18.readFileSync(filepath, "utf-8");
|
|
41426
41511
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
41427
41512
|
return JSON.parse(stripped);
|
|
41428
41513
|
} catch {
|
|
@@ -41430,7 +41515,7 @@ function loadJson(filepath) {
|
|
|
41430
41515
|
}
|
|
41431
41516
|
}
|
|
41432
41517
|
function saveJson(filepath, data) {
|
|
41433
|
-
|
|
41518
|
+
fs18.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
41434
41519
|
`, "utf-8");
|
|
41435
41520
|
}
|
|
41436
41521
|
async function install() {
|
|
@@ -41463,7 +41548,7 @@ async function install() {
|
|
|
41463
41548
|
saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
|
|
41464
41549
|
console.log("\u2713 Added opencode-swarm to OpenCode plugins");
|
|
41465
41550
|
console.log("\u2713 Disabled default OpenCode agents (explore, general)");
|
|
41466
|
-
if (!
|
|
41551
|
+
if (!fs18.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
41467
41552
|
const defaultConfig = {
|
|
41468
41553
|
agents: {
|
|
41469
41554
|
coder: { model: "opencode/minimax-m2.5-free" },
|
|
@@ -41506,7 +41591,7 @@ async function uninstall() {
|
|
|
41506
41591
|
`);
|
|
41507
41592
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
41508
41593
|
if (!opencodeConfig) {
|
|
41509
|
-
if (
|
|
41594
|
+
if (fs18.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
41510
41595
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
41511
41596
|
return 1;
|
|
41512
41597
|
} else {
|
|
@@ -41538,13 +41623,13 @@ async function uninstall() {
|
|
|
41538
41623
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
41539
41624
|
if (process.argv.includes("--clean")) {
|
|
41540
41625
|
let cleaned = false;
|
|
41541
|
-
if (
|
|
41542
|
-
|
|
41626
|
+
if (fs18.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
41627
|
+
fs18.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
41543
41628
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
41544
41629
|
cleaned = true;
|
|
41545
41630
|
}
|
|
41546
|
-
if (
|
|
41547
|
-
|
|
41631
|
+
if (fs18.existsSync(PROMPTS_DIR)) {
|
|
41632
|
+
fs18.rmSync(PROMPTS_DIR, { recursive: true });
|
|
41548
41633
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
41549
41634
|
cleaned = true;
|
|
41550
41635
|
}
|