opencode-swarm 6.44.1 → 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 +358 -309
- package/dist/index.js +709 -600
- package/dist/knowledge/hive-promoter.d.ts +23 -0
- package/dist/parallel/file-locks.d.ts +12 -5
- 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))
|
|
@@ -37330,10 +37238,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
37330
37238
|
function findBinInAncestors(startDir, binName) {
|
|
37331
37239
|
let dir = startDir;
|
|
37332
37240
|
while (true) {
|
|
37333
|
-
const candidate =
|
|
37241
|
+
const candidate = path18.join(dir, "node_modules", ".bin", binName);
|
|
37334
37242
|
if (fs9.existsSync(candidate))
|
|
37335
37243
|
return candidate;
|
|
37336
|
-
const parent =
|
|
37244
|
+
const parent = path18.dirname(dir);
|
|
37337
37245
|
if (parent === dir)
|
|
37338
37246
|
break;
|
|
37339
37247
|
dir = parent;
|
|
@@ -37342,10 +37250,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
37342
37250
|
}
|
|
37343
37251
|
function findBinInEnvPath(binName) {
|
|
37344
37252
|
const searchPath = process.env.PATH ?? "";
|
|
37345
|
-
for (const dir of searchPath.split(
|
|
37253
|
+
for (const dir of searchPath.split(path18.delimiter)) {
|
|
37346
37254
|
if (!dir)
|
|
37347
37255
|
continue;
|
|
37348
|
-
const candidate =
|
|
37256
|
+
const candidate = path18.join(dir, binName);
|
|
37349
37257
|
if (fs9.existsSync(candidate))
|
|
37350
37258
|
return candidate;
|
|
37351
37259
|
}
|
|
@@ -37358,13 +37266,13 @@ async function detectAvailableLinter(directory) {
|
|
|
37358
37266
|
return null;
|
|
37359
37267
|
const projectDir = directory;
|
|
37360
37268
|
const isWindows = process.platform === "win32";
|
|
37361
|
-
const biomeBin = isWindows ?
|
|
37362
|
-
const eslintBin = isWindows ?
|
|
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");
|
|
37363
37271
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
37364
37272
|
if (localResult)
|
|
37365
37273
|
return localResult;
|
|
37366
|
-
const biomeAncestor = findBinInAncestors(
|
|
37367
|
-
const eslintAncestor = findBinInAncestors(
|
|
37274
|
+
const biomeAncestor = findBinInAncestors(path18.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
37275
|
+
const eslintAncestor = findBinInAncestors(path18.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
37368
37276
|
if (biomeAncestor || eslintAncestor) {
|
|
37369
37277
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
37370
37278
|
}
|
|
@@ -37572,7 +37480,7 @@ For Rust: rustup component add clippy`
|
|
|
37572
37480
|
|
|
37573
37481
|
// src/tools/secretscan.ts
|
|
37574
37482
|
import * as fs10 from "fs";
|
|
37575
|
-
import * as
|
|
37483
|
+
import * as path19 from "path";
|
|
37576
37484
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
37577
37485
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
37578
37486
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -37799,7 +37707,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
37799
37707
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
37800
37708
|
}
|
|
37801
37709
|
function loadSecretScanIgnore(scanDir) {
|
|
37802
|
-
const ignorePath =
|
|
37710
|
+
const ignorePath = path19.join(scanDir, ".secretscanignore");
|
|
37803
37711
|
try {
|
|
37804
37712
|
if (!fs10.existsSync(ignorePath))
|
|
37805
37713
|
return [];
|
|
@@ -37822,7 +37730,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
37822
37730
|
if (exactNames.has(entry))
|
|
37823
37731
|
return true;
|
|
37824
37732
|
for (const pattern of globPatterns) {
|
|
37825
|
-
if (
|
|
37733
|
+
if (path19.matchesGlob(relPath, pattern))
|
|
37826
37734
|
return true;
|
|
37827
37735
|
}
|
|
37828
37736
|
return false;
|
|
@@ -37843,7 +37751,7 @@ function validateDirectoryInput(dir) {
|
|
|
37843
37751
|
return null;
|
|
37844
37752
|
}
|
|
37845
37753
|
function isBinaryFile(filePath, buffer) {
|
|
37846
|
-
const ext =
|
|
37754
|
+
const ext = path19.extname(filePath).toLowerCase();
|
|
37847
37755
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
37848
37756
|
return true;
|
|
37849
37757
|
}
|
|
@@ -37980,9 +37888,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
37980
37888
|
return false;
|
|
37981
37889
|
}
|
|
37982
37890
|
function isPathWithinScope(realPath, scanDir) {
|
|
37983
|
-
const resolvedScanDir =
|
|
37984
|
-
const resolvedRealPath =
|
|
37985
|
-
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}\\`);
|
|
37986
37894
|
}
|
|
37987
37895
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
37988
37896
|
skippedDirs: 0,
|
|
@@ -38008,8 +37916,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
38008
37916
|
return a.localeCompare(b);
|
|
38009
37917
|
});
|
|
38010
37918
|
for (const entry of entries) {
|
|
38011
|
-
const fullPath =
|
|
38012
|
-
const relPath =
|
|
37919
|
+
const fullPath = path19.join(dir, entry);
|
|
37920
|
+
const relPath = path19.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
38013
37921
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
38014
37922
|
stats.skippedDirs++;
|
|
38015
37923
|
continue;
|
|
@@ -38044,7 +37952,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
38044
37952
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
38045
37953
|
files.push(...subFiles);
|
|
38046
37954
|
} else if (lstat.isFile()) {
|
|
38047
|
-
const ext =
|
|
37955
|
+
const ext = path19.extname(fullPath).toLowerCase();
|
|
38048
37956
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
38049
37957
|
files.push(fullPath);
|
|
38050
37958
|
} else {
|
|
@@ -38110,7 +38018,14 @@ var secretscan = createSwarmTool({
|
|
|
38110
38018
|
}
|
|
38111
38019
|
}
|
|
38112
38020
|
try {
|
|
38113
|
-
const
|
|
38021
|
+
const _scanDirRaw = path19.resolve(directory);
|
|
38022
|
+
const scanDir = (() => {
|
|
38023
|
+
try {
|
|
38024
|
+
return fs10.realpathSync(_scanDirRaw);
|
|
38025
|
+
} catch {
|
|
38026
|
+
return _scanDirRaw;
|
|
38027
|
+
}
|
|
38028
|
+
})();
|
|
38114
38029
|
if (!fs10.existsSync(scanDir)) {
|
|
38115
38030
|
const errorResult = {
|
|
38116
38031
|
error: "directory not found",
|
|
@@ -38261,11 +38176,11 @@ async function runSecretscan(directory) {
|
|
|
38261
38176
|
|
|
38262
38177
|
// src/tools/test-runner.ts
|
|
38263
38178
|
import * as fs12 from "fs";
|
|
38264
|
-
import * as
|
|
38179
|
+
import * as path21 from "path";
|
|
38265
38180
|
|
|
38266
38181
|
// src/tools/resolve-working-directory.ts
|
|
38267
38182
|
import * as fs11 from "fs";
|
|
38268
|
-
import * as
|
|
38183
|
+
import * as path20 from "path";
|
|
38269
38184
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
38270
38185
|
if (workingDirectory == null || workingDirectory === "") {
|
|
38271
38186
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -38285,15 +38200,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
38285
38200
|
};
|
|
38286
38201
|
}
|
|
38287
38202
|
}
|
|
38288
|
-
const normalizedDir =
|
|
38289
|
-
const pathParts = normalizedDir.split(
|
|
38203
|
+
const normalizedDir = path20.normalize(workingDirectory);
|
|
38204
|
+
const pathParts = normalizedDir.split(path20.sep);
|
|
38290
38205
|
if (pathParts.includes("..")) {
|
|
38291
38206
|
return {
|
|
38292
38207
|
success: false,
|
|
38293
38208
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
38294
38209
|
};
|
|
38295
38210
|
}
|
|
38296
|
-
const resolvedDir =
|
|
38211
|
+
const resolvedDir = path20.resolve(normalizedDir);
|
|
38297
38212
|
try {
|
|
38298
38213
|
const realPath = fs11.realpathSync(resolvedDir);
|
|
38299
38214
|
return { success: true, directory: realPath };
|
|
@@ -38376,14 +38291,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
38376
38291
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
38377
38292
|
}
|
|
38378
38293
|
function detectGoTest(cwd) {
|
|
38379
|
-
return fs12.existsSync(
|
|
38294
|
+
return fs12.existsSync(path21.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
38380
38295
|
}
|
|
38381
38296
|
function detectJavaMaven(cwd) {
|
|
38382
|
-
return fs12.existsSync(
|
|
38297
|
+
return fs12.existsSync(path21.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
38383
38298
|
}
|
|
38384
38299
|
function detectGradle(cwd) {
|
|
38385
|
-
const hasBuildFile = fs12.existsSync(
|
|
38386
|
-
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"));
|
|
38387
38302
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
38388
38303
|
}
|
|
38389
38304
|
function detectDotnetTest(cwd) {
|
|
@@ -38396,30 +38311,30 @@ function detectDotnetTest(cwd) {
|
|
|
38396
38311
|
}
|
|
38397
38312
|
}
|
|
38398
38313
|
function detectCTest(cwd) {
|
|
38399
|
-
const hasSource = fs12.existsSync(
|
|
38400
|
-
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"));
|
|
38401
38316
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
38402
38317
|
}
|
|
38403
38318
|
function detectSwiftTest(cwd) {
|
|
38404
|
-
return fs12.existsSync(
|
|
38319
|
+
return fs12.existsSync(path21.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
38405
38320
|
}
|
|
38406
38321
|
function detectDartTest(cwd) {
|
|
38407
|
-
return fs12.existsSync(
|
|
38322
|
+
return fs12.existsSync(path21.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
38408
38323
|
}
|
|
38409
38324
|
function detectRSpec(cwd) {
|
|
38410
|
-
const hasRSpecFile = fs12.existsSync(
|
|
38411
|
-
const hasGemfile = fs12.existsSync(
|
|
38412
|
-
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"));
|
|
38413
38328
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
38414
38329
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
38415
38330
|
}
|
|
38416
38331
|
function detectMinitest(cwd) {
|
|
38417
|
-
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");
|
|
38418
38333
|
}
|
|
38419
38334
|
async function detectTestFramework(cwd) {
|
|
38420
38335
|
const baseDir = cwd;
|
|
38421
38336
|
try {
|
|
38422
|
-
const packageJsonPath =
|
|
38337
|
+
const packageJsonPath = path21.join(baseDir, "package.json");
|
|
38423
38338
|
if (fs12.existsSync(packageJsonPath)) {
|
|
38424
38339
|
const content = fs12.readFileSync(packageJsonPath, "utf-8");
|
|
38425
38340
|
const pkg = JSON.parse(content);
|
|
@@ -38440,16 +38355,16 @@ async function detectTestFramework(cwd) {
|
|
|
38440
38355
|
return "jest";
|
|
38441
38356
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
38442
38357
|
return "mocha";
|
|
38443
|
-
if (fs12.existsSync(
|
|
38358
|
+
if (fs12.existsSync(path21.join(baseDir, "bun.lockb")) || fs12.existsSync(path21.join(baseDir, "bun.lock"))) {
|
|
38444
38359
|
if (scripts.test?.includes("bun"))
|
|
38445
38360
|
return "bun";
|
|
38446
38361
|
}
|
|
38447
38362
|
}
|
|
38448
38363
|
} catch {}
|
|
38449
38364
|
try {
|
|
38450
|
-
const pyprojectTomlPath =
|
|
38451
|
-
const setupCfgPath =
|
|
38452
|
-
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");
|
|
38453
38368
|
if (fs12.existsSync(pyprojectTomlPath)) {
|
|
38454
38369
|
const content = fs12.readFileSync(pyprojectTomlPath, "utf-8");
|
|
38455
38370
|
if (content.includes("[tool.pytest"))
|
|
@@ -38469,7 +38384,7 @@ async function detectTestFramework(cwd) {
|
|
|
38469
38384
|
}
|
|
38470
38385
|
} catch {}
|
|
38471
38386
|
try {
|
|
38472
|
-
const cargoTomlPath =
|
|
38387
|
+
const cargoTomlPath = path21.join(baseDir, "Cargo.toml");
|
|
38473
38388
|
if (fs12.existsSync(cargoTomlPath)) {
|
|
38474
38389
|
const content = fs12.readFileSync(cargoTomlPath, "utf-8");
|
|
38475
38390
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -38480,9 +38395,9 @@ async function detectTestFramework(cwd) {
|
|
|
38480
38395
|
}
|
|
38481
38396
|
} catch {}
|
|
38482
38397
|
try {
|
|
38483
|
-
const pesterConfigPath =
|
|
38484
|
-
const pesterConfigJsonPath =
|
|
38485
|
-
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");
|
|
38486
38401
|
if (fs12.existsSync(pesterConfigPath) || fs12.existsSync(pesterConfigJsonPath) || fs12.existsSync(pesterPs1Path)) {
|
|
38487
38402
|
return "pester";
|
|
38488
38403
|
}
|
|
@@ -38534,8 +38449,8 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
38534
38449
|
const testFiles = [];
|
|
38535
38450
|
for (const file3 of sourceFiles) {
|
|
38536
38451
|
const normalizedPath = file3.replace(/\\/g, "/");
|
|
38537
|
-
const basename4 =
|
|
38538
|
-
const dirname10 =
|
|
38452
|
+
const basename4 = path21.basename(file3);
|
|
38453
|
+
const dirname10 = path21.dirname(file3);
|
|
38539
38454
|
if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
|
|
38540
38455
|
if (!testFiles.includes(file3)) {
|
|
38541
38456
|
testFiles.push(file3);
|
|
@@ -38544,13 +38459,13 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
38544
38459
|
}
|
|
38545
38460
|
for (const _pattern of TEST_PATTERNS) {
|
|
38546
38461
|
const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
|
|
38547
|
-
const ext =
|
|
38462
|
+
const ext = path21.extname(basename4);
|
|
38548
38463
|
const possibleTestFiles = [
|
|
38549
|
-
|
|
38550
|
-
|
|
38551
|
-
|
|
38552
|
-
|
|
38553
|
-
|
|
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}`)
|
|
38554
38469
|
];
|
|
38555
38470
|
for (const testFile of possibleTestFiles) {
|
|
38556
38471
|
if (fs12.existsSync(testFile) && !testFiles.includes(testFile)) {
|
|
@@ -38570,7 +38485,7 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38570
38485
|
for (const testFile of candidateTestFiles) {
|
|
38571
38486
|
try {
|
|
38572
38487
|
const content = fs12.readFileSync(testFile, "utf-8");
|
|
38573
|
-
const testDir =
|
|
38488
|
+
const testDir = path21.dirname(testFile);
|
|
38574
38489
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
38575
38490
|
let match;
|
|
38576
38491
|
match = importRegex.exec(content);
|
|
@@ -38578,8 +38493,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38578
38493
|
const importPath = match[1];
|
|
38579
38494
|
let resolvedImport;
|
|
38580
38495
|
if (importPath.startsWith(".")) {
|
|
38581
|
-
resolvedImport =
|
|
38582
|
-
const existingExt =
|
|
38496
|
+
resolvedImport = path21.resolve(testDir, importPath);
|
|
38497
|
+
const existingExt = path21.extname(resolvedImport);
|
|
38583
38498
|
if (!existingExt) {
|
|
38584
38499
|
for (const extToTry of [
|
|
38585
38500
|
".ts",
|
|
@@ -38599,12 +38514,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38599
38514
|
} else {
|
|
38600
38515
|
continue;
|
|
38601
38516
|
}
|
|
38602
|
-
const importBasename =
|
|
38603
|
-
const importDir =
|
|
38517
|
+
const importBasename = path21.basename(resolvedImport, path21.extname(resolvedImport));
|
|
38518
|
+
const importDir = path21.dirname(resolvedImport);
|
|
38604
38519
|
for (const sourceFile of sourceFiles) {
|
|
38605
|
-
const sourceDir =
|
|
38606
|
-
const sourceBasename =
|
|
38607
|
-
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");
|
|
38608
38523
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
38609
38524
|
if (!testFiles.includes(testFile)) {
|
|
38610
38525
|
testFiles.push(testFile);
|
|
@@ -38619,8 +38534,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38619
38534
|
while (match !== null) {
|
|
38620
38535
|
const importPath = match[1];
|
|
38621
38536
|
if (importPath.startsWith(".")) {
|
|
38622
|
-
let resolvedImport =
|
|
38623
|
-
const existingExt =
|
|
38537
|
+
let resolvedImport = path21.resolve(testDir, importPath);
|
|
38538
|
+
const existingExt = path21.extname(resolvedImport);
|
|
38624
38539
|
if (!existingExt) {
|
|
38625
38540
|
for (const extToTry of [
|
|
38626
38541
|
".ts",
|
|
@@ -38637,12 +38552,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38637
38552
|
}
|
|
38638
38553
|
}
|
|
38639
38554
|
}
|
|
38640
|
-
const importDir =
|
|
38641
|
-
const importBasename =
|
|
38555
|
+
const importDir = path21.dirname(resolvedImport);
|
|
38556
|
+
const importBasename = path21.basename(resolvedImport, path21.extname(resolvedImport));
|
|
38642
38557
|
for (const sourceFile of sourceFiles) {
|
|
38643
|
-
const sourceDir =
|
|
38644
|
-
const sourceBasename =
|
|
38645
|
-
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");
|
|
38646
38561
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
38647
38562
|
if (!testFiles.includes(testFile)) {
|
|
38648
38563
|
testFiles.push(testFile);
|
|
@@ -38727,8 +38642,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
38727
38642
|
return ["mvn", "test"];
|
|
38728
38643
|
case "gradle": {
|
|
38729
38644
|
const isWindows = process.platform === "win32";
|
|
38730
|
-
const hasGradlewBat = fs12.existsSync(
|
|
38731
|
-
const hasGradlew = fs12.existsSync(
|
|
38645
|
+
const hasGradlewBat = fs12.existsSync(path21.join(baseDir, "gradlew.bat"));
|
|
38646
|
+
const hasGradlew = fs12.existsSync(path21.join(baseDir, "gradlew"));
|
|
38732
38647
|
if (hasGradlewBat && isWindows)
|
|
38733
38648
|
return ["gradlew.bat", "test"];
|
|
38734
38649
|
if (hasGradlew)
|
|
@@ -38745,7 +38660,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
38745
38660
|
"cmake-build-release",
|
|
38746
38661
|
"out"
|
|
38747
38662
|
];
|
|
38748
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(
|
|
38663
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(path21.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
38749
38664
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
38750
38665
|
}
|
|
38751
38666
|
case "swift-test":
|
|
@@ -39287,7 +39202,7 @@ var test_runner = createSwarmTool({
|
|
|
39287
39202
|
let effectiveScope = scope;
|
|
39288
39203
|
if (scope === "all") {} else if (scope === "convention") {
|
|
39289
39204
|
const sourceFiles = args.files.filter((f) => {
|
|
39290
|
-
const ext =
|
|
39205
|
+
const ext = path21.extname(f).toLowerCase();
|
|
39291
39206
|
return SOURCE_EXTENSIONS.has(ext);
|
|
39292
39207
|
});
|
|
39293
39208
|
if (sourceFiles.length === 0) {
|
|
@@ -39303,7 +39218,7 @@ var test_runner = createSwarmTool({
|
|
|
39303
39218
|
testFiles = getTestFilesFromConvention(sourceFiles);
|
|
39304
39219
|
} else if (scope === "graph") {
|
|
39305
39220
|
const sourceFiles = args.files.filter((f) => {
|
|
39306
|
-
const ext =
|
|
39221
|
+
const ext = path21.extname(f).toLowerCase();
|
|
39307
39222
|
return SOURCE_EXTENSIONS.has(ext);
|
|
39308
39223
|
});
|
|
39309
39224
|
if (sourceFiles.length === 0) {
|
|
@@ -39374,8 +39289,8 @@ function validateDirectoryPath(dir) {
|
|
|
39374
39289
|
if (dir.includes("..")) {
|
|
39375
39290
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
39376
39291
|
}
|
|
39377
|
-
const normalized =
|
|
39378
|
-
const absolutePath =
|
|
39292
|
+
const normalized = path22.normalize(dir);
|
|
39293
|
+
const absolutePath = path22.isAbsolute(normalized) ? normalized : path22.resolve(normalized);
|
|
39379
39294
|
return absolutePath;
|
|
39380
39295
|
}
|
|
39381
39296
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -39398,7 +39313,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
39398
39313
|
}
|
|
39399
39314
|
function getPackageVersion(dir) {
|
|
39400
39315
|
try {
|
|
39401
|
-
const packagePath =
|
|
39316
|
+
const packagePath = path22.join(dir, "package.json");
|
|
39402
39317
|
if (fs13.existsSync(packagePath)) {
|
|
39403
39318
|
const content = fs13.readFileSync(packagePath, "utf-8");
|
|
39404
39319
|
const pkg = JSON.parse(content);
|
|
@@ -39409,7 +39324,7 @@ function getPackageVersion(dir) {
|
|
|
39409
39324
|
}
|
|
39410
39325
|
function getChangelogVersion(dir) {
|
|
39411
39326
|
try {
|
|
39412
|
-
const changelogPath =
|
|
39327
|
+
const changelogPath = path22.join(dir, "CHANGELOG.md");
|
|
39413
39328
|
if (fs13.existsSync(changelogPath)) {
|
|
39414
39329
|
const content = fs13.readFileSync(changelogPath, "utf-8");
|
|
39415
39330
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -39423,7 +39338,7 @@ function getChangelogVersion(dir) {
|
|
|
39423
39338
|
function getVersionFileVersion(dir) {
|
|
39424
39339
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
39425
39340
|
for (const file3 of possibleFiles) {
|
|
39426
|
-
const filePath =
|
|
39341
|
+
const filePath = path22.join(dir, file3);
|
|
39427
39342
|
if (fs13.existsSync(filePath)) {
|
|
39428
39343
|
try {
|
|
39429
39344
|
const content = fs13.readFileSync(filePath, "utf-8").trim();
|
|
@@ -39918,6 +39833,144 @@ async function handlePreflightCommand(directory, _args) {
|
|
|
39918
39833
|
const report = await runPreflight(directory, 0);
|
|
39919
39834
|
return formatPreflightMarkdown(report);
|
|
39920
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
|
+
|
|
39921
39974
|
// src/commands/promote.ts
|
|
39922
39975
|
async function handlePromoteCommand(directory, args) {
|
|
39923
39976
|
let category;
|
|
@@ -39940,11 +39993,7 @@ async function handlePromoteCommand(directory, args) {
|
|
|
39940
39993
|
return `Usage: /swarm promote "<lesson text>" or /swarm promote --from-swarm <id>`;
|
|
39941
39994
|
}
|
|
39942
39995
|
if (lessonText) {
|
|
39943
|
-
const validation =
|
|
39944
|
-
category: category || "process",
|
|
39945
|
-
scope: "global",
|
|
39946
|
-
confidence: 1
|
|
39947
|
-
});
|
|
39996
|
+
const validation = validateLesson2(lessonText);
|
|
39948
39997
|
if (!validation.valid) {
|
|
39949
39998
|
return `Lesson rejected by validator: ${validation.reason}`;
|
|
39950
39999
|
}
|
|
@@ -39970,7 +40019,7 @@ async function handlePromoteCommand(directory, args) {
|
|
|
39970
40019
|
}
|
|
39971
40020
|
|
|
39972
40021
|
// src/commands/reset.ts
|
|
39973
|
-
import * as
|
|
40022
|
+
import * as fs15 from "fs";
|
|
39974
40023
|
|
|
39975
40024
|
// src/background/manager.ts
|
|
39976
40025
|
init_utils();
|
|
@@ -40671,8 +40720,8 @@ async function handleResetCommand(directory, args) {
|
|
|
40671
40720
|
for (const filename of filesToReset) {
|
|
40672
40721
|
try {
|
|
40673
40722
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
40674
|
-
if (
|
|
40675
|
-
|
|
40723
|
+
if (fs15.existsSync(resolvedPath)) {
|
|
40724
|
+
fs15.unlinkSync(resolvedPath);
|
|
40676
40725
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
40677
40726
|
} else {
|
|
40678
40727
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -40689,8 +40738,8 @@ async function handleResetCommand(directory, args) {
|
|
|
40689
40738
|
}
|
|
40690
40739
|
try {
|
|
40691
40740
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
40692
|
-
if (
|
|
40693
|
-
|
|
40741
|
+
if (fs15.existsSync(summariesPath)) {
|
|
40742
|
+
fs15.rmSync(summariesPath, { recursive: true, force: true });
|
|
40694
40743
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
40695
40744
|
} else {
|
|
40696
40745
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -40710,14 +40759,14 @@ async function handleResetCommand(directory, args) {
|
|
|
40710
40759
|
|
|
40711
40760
|
// src/commands/reset-session.ts
|
|
40712
40761
|
init_utils2();
|
|
40713
|
-
import * as
|
|
40762
|
+
import * as fs16 from "fs";
|
|
40714
40763
|
import * as path24 from "path";
|
|
40715
40764
|
async function handleResetSessionCommand(directory, _args) {
|
|
40716
40765
|
const results = [];
|
|
40717
40766
|
try {
|
|
40718
40767
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
40719
|
-
if (
|
|
40720
|
-
|
|
40768
|
+
if (fs16.existsSync(statePath)) {
|
|
40769
|
+
fs16.unlinkSync(statePath);
|
|
40721
40770
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
40722
40771
|
} else {
|
|
40723
40772
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -40727,14 +40776,14 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
40727
40776
|
}
|
|
40728
40777
|
try {
|
|
40729
40778
|
const sessionDir = path24.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
40730
|
-
if (
|
|
40731
|
-
const files =
|
|
40779
|
+
if (fs16.existsSync(sessionDir)) {
|
|
40780
|
+
const files = fs16.readdirSync(sessionDir);
|
|
40732
40781
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
40733
40782
|
let deletedCount = 0;
|
|
40734
40783
|
for (const file3 of otherFiles) {
|
|
40735
40784
|
const filePath = path24.join(sessionDir, file3);
|
|
40736
|
-
if (
|
|
40737
|
-
|
|
40785
|
+
if (fs16.lstatSync(filePath).isFile()) {
|
|
40786
|
+
fs16.unlinkSync(filePath);
|
|
40738
40787
|
deletedCount++;
|
|
40739
40788
|
}
|
|
40740
40789
|
}
|
|
@@ -40839,18 +40888,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
40839
40888
|
|
|
40840
40889
|
// src/commands/rollback.ts
|
|
40841
40890
|
init_utils2();
|
|
40842
|
-
import * as
|
|
40891
|
+
import * as fs17 from "fs";
|
|
40843
40892
|
import * as path26 from "path";
|
|
40844
40893
|
async function handleRollbackCommand(directory, args) {
|
|
40845
40894
|
const phaseArg = args[0];
|
|
40846
40895
|
if (!phaseArg) {
|
|
40847
40896
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
40848
|
-
if (!
|
|
40897
|
+
if (!fs17.existsSync(manifestPath2)) {
|
|
40849
40898
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
40850
40899
|
}
|
|
40851
40900
|
let manifest2;
|
|
40852
40901
|
try {
|
|
40853
|
-
manifest2 = JSON.parse(
|
|
40902
|
+
manifest2 = JSON.parse(fs17.readFileSync(manifestPath2, "utf-8"));
|
|
40854
40903
|
} catch {
|
|
40855
40904
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
40856
40905
|
}
|
|
@@ -40872,12 +40921,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40872
40921
|
return "Error: Phase number must be a positive integer.";
|
|
40873
40922
|
}
|
|
40874
40923
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
40875
|
-
if (!
|
|
40924
|
+
if (!fs17.existsSync(manifestPath)) {
|
|
40876
40925
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
40877
40926
|
}
|
|
40878
40927
|
let manifest;
|
|
40879
40928
|
try {
|
|
40880
|
-
manifest = JSON.parse(
|
|
40929
|
+
manifest = JSON.parse(fs17.readFileSync(manifestPath, "utf-8"));
|
|
40881
40930
|
} catch {
|
|
40882
40931
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
40883
40932
|
}
|
|
@@ -40887,10 +40936,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40887
40936
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
40888
40937
|
}
|
|
40889
40938
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
40890
|
-
if (!
|
|
40939
|
+
if (!fs17.existsSync(checkpointDir)) {
|
|
40891
40940
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
40892
40941
|
}
|
|
40893
|
-
const checkpointFiles =
|
|
40942
|
+
const checkpointFiles = fs17.readdirSync(checkpointDir);
|
|
40894
40943
|
if (checkpointFiles.length === 0) {
|
|
40895
40944
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
40896
40945
|
}
|
|
@@ -40901,7 +40950,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40901
40950
|
const src = path26.join(checkpointDir, file3);
|
|
40902
40951
|
const dest = path26.join(swarmDir, file3);
|
|
40903
40952
|
try {
|
|
40904
|
-
|
|
40953
|
+
fs17.cpSync(src, dest, { recursive: true, force: true });
|
|
40905
40954
|
successes.push(file3);
|
|
40906
40955
|
} catch (error93) {
|
|
40907
40956
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -40918,7 +40967,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40918
40967
|
timestamp: new Date().toISOString()
|
|
40919
40968
|
};
|
|
40920
40969
|
try {
|
|
40921
|
-
|
|
40970
|
+
fs17.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
40922
40971
|
`);
|
|
40923
40972
|
} catch (error93) {
|
|
40924
40973
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -40961,11 +41010,11 @@ async function handleSimulateCommand(directory, args) {
|
|
|
40961
41010
|
];
|
|
40962
41011
|
const report = reportLines.filter(Boolean).join(`
|
|
40963
41012
|
`);
|
|
40964
|
-
const
|
|
41013
|
+
const fs18 = await import("fs/promises");
|
|
40965
41014
|
const path27 = await import("path");
|
|
40966
41015
|
const reportPath = path27.join(directory, ".swarm", "simulate-report.md");
|
|
40967
|
-
await
|
|
40968
|
-
await
|
|
41016
|
+
await fs18.mkdir(path27.dirname(reportPath), { recursive: true });
|
|
41017
|
+
await fs18.writeFile(reportPath, report, "utf-8");
|
|
40969
41018
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
40970
41019
|
}
|
|
40971
41020
|
|
|
@@ -41447,18 +41496,18 @@ function resolveCommand(tokens) {
|
|
|
41447
41496
|
}
|
|
41448
41497
|
|
|
41449
41498
|
// src/cli/index.ts
|
|
41450
|
-
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");
|
|
41451
41500
|
var OPENCODE_CONFIG_PATH = path27.join(CONFIG_DIR, "opencode.json");
|
|
41452
41501
|
var PLUGIN_CONFIG_PATH = path27.join(CONFIG_DIR, "opencode-swarm.json");
|
|
41453
41502
|
var PROMPTS_DIR = path27.join(CONFIG_DIR, "opencode-swarm");
|
|
41454
41503
|
function ensureDir(dir) {
|
|
41455
|
-
if (!
|
|
41456
|
-
|
|
41504
|
+
if (!fs18.existsSync(dir)) {
|
|
41505
|
+
fs18.mkdirSync(dir, { recursive: true });
|
|
41457
41506
|
}
|
|
41458
41507
|
}
|
|
41459
41508
|
function loadJson(filepath) {
|
|
41460
41509
|
try {
|
|
41461
|
-
const content =
|
|
41510
|
+
const content = fs18.readFileSync(filepath, "utf-8");
|
|
41462
41511
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
41463
41512
|
return JSON.parse(stripped);
|
|
41464
41513
|
} catch {
|
|
@@ -41466,7 +41515,7 @@ function loadJson(filepath) {
|
|
|
41466
41515
|
}
|
|
41467
41516
|
}
|
|
41468
41517
|
function saveJson(filepath, data) {
|
|
41469
|
-
|
|
41518
|
+
fs18.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
41470
41519
|
`, "utf-8");
|
|
41471
41520
|
}
|
|
41472
41521
|
async function install() {
|
|
@@ -41499,7 +41548,7 @@ async function install() {
|
|
|
41499
41548
|
saveJson(OPENCODE_CONFIG_PATH, opencodeConfig);
|
|
41500
41549
|
console.log("\u2713 Added opencode-swarm to OpenCode plugins");
|
|
41501
41550
|
console.log("\u2713 Disabled default OpenCode agents (explore, general)");
|
|
41502
|
-
if (!
|
|
41551
|
+
if (!fs18.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
41503
41552
|
const defaultConfig = {
|
|
41504
41553
|
agents: {
|
|
41505
41554
|
coder: { model: "opencode/minimax-m2.5-free" },
|
|
@@ -41542,7 +41591,7 @@ async function uninstall() {
|
|
|
41542
41591
|
`);
|
|
41543
41592
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
41544
41593
|
if (!opencodeConfig) {
|
|
41545
|
-
if (
|
|
41594
|
+
if (fs18.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
41546
41595
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
41547
41596
|
return 1;
|
|
41548
41597
|
} else {
|
|
@@ -41574,13 +41623,13 @@ async function uninstall() {
|
|
|
41574
41623
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
41575
41624
|
if (process.argv.includes("--clean")) {
|
|
41576
41625
|
let cleaned = false;
|
|
41577
|
-
if (
|
|
41578
|
-
|
|
41626
|
+
if (fs18.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
41627
|
+
fs18.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
41579
41628
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
41580
41629
|
cleaned = true;
|
|
41581
41630
|
}
|
|
41582
|
-
if (
|
|
41583
|
-
|
|
41631
|
+
if (fs18.existsSync(PROMPTS_DIR)) {
|
|
41632
|
+
fs18.rmSync(PROMPTS_DIR, { recursive: true });
|
|
41584
41633
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
41585
41634
|
cleaned = true;
|
|
41586
41635
|
}
|