opencode-swarm 6.86.3 → 6.86.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +77 -17
- package/dist/__tests__/cli-version.adversarial.test.d.ts +1 -0
- package/dist/__tests__/cli-version.test.d.ts +1 -0
- package/dist/cli/index.js +771 -506
- package/dist/config/schema.d.ts +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1286 -1006
- package/dist/services/diagnose-service.d.ts +1 -1
- package/dist/services/warning-buffer.d.ts +9 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -14230,11 +14230,17 @@ async function readLedgerEvents(directory) {
|
|
|
14230
14230
|
const lines = content.trim().split(`
|
|
14231
14231
|
`).filter((line) => line.trim() !== "");
|
|
14232
14232
|
const events = [];
|
|
14233
|
+
let skippedCount = 0;
|
|
14233
14234
|
for (const line of lines) {
|
|
14234
14235
|
try {
|
|
14235
14236
|
const event = JSON.parse(line);
|
|
14236
14237
|
events.push(event);
|
|
14237
|
-
} catch {
|
|
14238
|
+
} catch {
|
|
14239
|
+
skippedCount++;
|
|
14240
|
+
}
|
|
14241
|
+
}
|
|
14242
|
+
if (skippedCount > 0) {
|
|
14243
|
+
console.warn(`[ledger] Skipped ${skippedCount} malformed line(s) in plan-ledger.jsonl`);
|
|
14238
14244
|
}
|
|
14239
14245
|
events.sort((a, b) => a.seq - b.seq);
|
|
14240
14246
|
return events;
|
|
@@ -14331,10 +14337,13 @@ async function takeSnapshotEvent(directory, plan, options) {
|
|
|
14331
14337
|
}, { planHashAfter: options?.planHashAfter });
|
|
14332
14338
|
}
|
|
14333
14339
|
async function replayFromLedger(directory, _options) {
|
|
14334
|
-
const events = await
|
|
14340
|
+
const { events, truncated, badSuffix } = await readLedgerEventsWithIntegrity(directory);
|
|
14335
14341
|
if (events.length === 0) {
|
|
14336
14342
|
return null;
|
|
14337
14343
|
}
|
|
14344
|
+
if (truncated && badSuffix !== null) {
|
|
14345
|
+
await quarantineLedgerSuffix(directory, badSuffix);
|
|
14346
|
+
}
|
|
14338
14347
|
const targetPlanId = events[0].plan_id;
|
|
14339
14348
|
const relevantEvents = events.filter((e) => e.plan_id === targetPlanId);
|
|
14340
14349
|
{
|
|
@@ -14455,6 +14464,46 @@ function applyEventToPlan(plan, event) {
|
|
|
14455
14464
|
throw new Error(`applyEventToPlan: unhandled event type "${event.event_type}" at seq ${event.seq}`);
|
|
14456
14465
|
}
|
|
14457
14466
|
}
|
|
14467
|
+
async function readLedgerEventsWithIntegrity(directory) {
|
|
14468
|
+
const ledgerPath = getLedgerPath(directory);
|
|
14469
|
+
if (!fs.existsSync(ledgerPath)) {
|
|
14470
|
+
return { events: [], truncated: false, badSuffix: null };
|
|
14471
|
+
}
|
|
14472
|
+
try {
|
|
14473
|
+
const content = fs.readFileSync(ledgerPath, "utf8");
|
|
14474
|
+
const lines = content.split(`
|
|
14475
|
+
`);
|
|
14476
|
+
const events = [];
|
|
14477
|
+
let truncated = false;
|
|
14478
|
+
let badSuffix = null;
|
|
14479
|
+
for (let i = 0;i < lines.length; i++) {
|
|
14480
|
+
const line = lines[i];
|
|
14481
|
+
if (line.trim() === "") {
|
|
14482
|
+
continue;
|
|
14483
|
+
}
|
|
14484
|
+
try {
|
|
14485
|
+
const event = JSON.parse(line);
|
|
14486
|
+
events.push(event);
|
|
14487
|
+
} catch {
|
|
14488
|
+
truncated = true;
|
|
14489
|
+
badSuffix = lines.slice(i).join(`
|
|
14490
|
+
`);
|
|
14491
|
+
break;
|
|
14492
|
+
}
|
|
14493
|
+
}
|
|
14494
|
+
events.sort((a, b) => a.seq - b.seq);
|
|
14495
|
+
return { events, truncated, badSuffix };
|
|
14496
|
+
} catch {
|
|
14497
|
+
return { events: [], truncated: false, badSuffix: null };
|
|
14498
|
+
}
|
|
14499
|
+
}
|
|
14500
|
+
async function quarantineLedgerSuffix(directory, badSuffix) {
|
|
14501
|
+
try {
|
|
14502
|
+
const quarantinePath = path2.join(directory, ".swarm", "plan-ledger.quarantine");
|
|
14503
|
+
fs.writeFileSync(quarantinePath, badSuffix, "utf8");
|
|
14504
|
+
console.warn(`[ledger] Corrupted suffix quarantined to ${path2.relative(directory, quarantinePath)}`);
|
|
14505
|
+
} catch {}
|
|
14506
|
+
}
|
|
14458
14507
|
async function loadLastApprovedPlan(directory, expectedPlanId) {
|
|
14459
14508
|
const events = await readLedgerEvents(directory);
|
|
14460
14509
|
if (events.length === 0) {
|
|
@@ -17619,15 +17668,15 @@ __export(exports_config_doctor, {
|
|
|
17619
17668
|
applySafeAutoFixes: () => applySafeAutoFixes
|
|
17620
17669
|
});
|
|
17621
17670
|
import * as crypto3 from "crypto";
|
|
17622
|
-
import * as
|
|
17671
|
+
import * as fs8 from "fs";
|
|
17623
17672
|
import * as os5 from "os";
|
|
17624
|
-
import * as
|
|
17673
|
+
import * as path18 from "path";
|
|
17625
17674
|
function getUserConfigDir3() {
|
|
17626
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
17675
|
+
return process.env.XDG_CONFIG_HOME || path18.join(os5.homedir(), ".config");
|
|
17627
17676
|
}
|
|
17628
17677
|
function getConfigPaths(directory) {
|
|
17629
|
-
const userConfigPath =
|
|
17630
|
-
const projectConfigPath =
|
|
17678
|
+
const userConfigPath = path18.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
|
|
17679
|
+
const projectConfigPath = path18.join(directory, ".opencode", "opencode-swarm.json");
|
|
17631
17680
|
return { userConfigPath, projectConfigPath };
|
|
17632
17681
|
}
|
|
17633
17682
|
function computeHash(content) {
|
|
@@ -17652,9 +17701,9 @@ function isValidConfigPath(configPath, directory) {
|
|
|
17652
17701
|
const normalizedUser = userConfigPath.replace(/\\/g, "/");
|
|
17653
17702
|
const normalizedProject = projectConfigPath.replace(/\\/g, "/");
|
|
17654
17703
|
try {
|
|
17655
|
-
const resolvedConfig =
|
|
17656
|
-
const resolvedUser =
|
|
17657
|
-
const resolvedProject =
|
|
17704
|
+
const resolvedConfig = path18.resolve(configPath);
|
|
17705
|
+
const resolvedUser = path18.resolve(normalizedUser);
|
|
17706
|
+
const resolvedProject = path18.resolve(normalizedProject);
|
|
17658
17707
|
return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
|
|
17659
17708
|
} catch {
|
|
17660
17709
|
return false;
|
|
@@ -17664,19 +17713,19 @@ function createConfigBackup(directory) {
|
|
|
17664
17713
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
17665
17714
|
let configPath = projectConfigPath;
|
|
17666
17715
|
let content = null;
|
|
17667
|
-
if (
|
|
17716
|
+
if (fs8.existsSync(projectConfigPath)) {
|
|
17668
17717
|
try {
|
|
17669
|
-
content =
|
|
17718
|
+
content = fs8.readFileSync(projectConfigPath, "utf-8");
|
|
17670
17719
|
} catch (error93) {
|
|
17671
17720
|
log("[ConfigDoctor] project config read failed", {
|
|
17672
17721
|
error: error93 instanceof Error ? error93.message : String(error93)
|
|
17673
17722
|
});
|
|
17674
17723
|
}
|
|
17675
17724
|
}
|
|
17676
|
-
if (content === null &&
|
|
17725
|
+
if (content === null && fs8.existsSync(userConfigPath)) {
|
|
17677
17726
|
configPath = userConfigPath;
|
|
17678
17727
|
try {
|
|
17679
|
-
content =
|
|
17728
|
+
content = fs8.readFileSync(userConfigPath, "utf-8");
|
|
17680
17729
|
} catch (error93) {
|
|
17681
17730
|
log("[ConfigDoctor] user config read failed", {
|
|
17682
17731
|
error: error93 instanceof Error ? error93.message : String(error93)
|
|
@@ -17694,12 +17743,12 @@ function createConfigBackup(directory) {
|
|
|
17694
17743
|
};
|
|
17695
17744
|
}
|
|
17696
17745
|
function writeBackupArtifact(directory, backup) {
|
|
17697
|
-
const swarmDir =
|
|
17698
|
-
if (!
|
|
17699
|
-
|
|
17746
|
+
const swarmDir = path18.join(directory, ".swarm");
|
|
17747
|
+
if (!fs8.existsSync(swarmDir)) {
|
|
17748
|
+
fs8.mkdirSync(swarmDir, { recursive: true });
|
|
17700
17749
|
}
|
|
17701
17750
|
const backupFilename = `config-backup-${backup.createdAt}.json`;
|
|
17702
|
-
const backupPath =
|
|
17751
|
+
const backupPath = path18.join(swarmDir, backupFilename);
|
|
17703
17752
|
const artifact = {
|
|
17704
17753
|
createdAt: backup.createdAt,
|
|
17705
17754
|
configPath: backup.configPath,
|
|
@@ -17707,15 +17756,15 @@ function writeBackupArtifact(directory, backup) {
|
|
|
17707
17756
|
content: backup.content,
|
|
17708
17757
|
preview: backup.content.substring(0, 500) + (backup.content.length > 500 ? "..." : "")
|
|
17709
17758
|
};
|
|
17710
|
-
|
|
17759
|
+
fs8.writeFileSync(backupPath, JSON.stringify(artifact, null, 2), "utf-8");
|
|
17711
17760
|
return backupPath;
|
|
17712
17761
|
}
|
|
17713
17762
|
function restoreFromBackup(backupPath, directory) {
|
|
17714
|
-
if (!
|
|
17763
|
+
if (!fs8.existsSync(backupPath)) {
|
|
17715
17764
|
return null;
|
|
17716
17765
|
}
|
|
17717
17766
|
try {
|
|
17718
|
-
const artifact = JSON.parse(
|
|
17767
|
+
const artifact = JSON.parse(fs8.readFileSync(backupPath, "utf-8"));
|
|
17719
17768
|
if (!artifact.content || !artifact.configPath || !artifact.contentHash) {
|
|
17720
17769
|
return null;
|
|
17721
17770
|
}
|
|
@@ -17729,11 +17778,11 @@ function restoreFromBackup(backupPath, directory) {
|
|
|
17729
17778
|
return null;
|
|
17730
17779
|
}
|
|
17731
17780
|
const targetPath = artifact.configPath;
|
|
17732
|
-
const targetDir =
|
|
17733
|
-
if (!
|
|
17734
|
-
|
|
17781
|
+
const targetDir = path18.dirname(targetPath);
|
|
17782
|
+
if (!fs8.existsSync(targetDir)) {
|
|
17783
|
+
fs8.mkdirSync(targetDir, { recursive: true });
|
|
17735
17784
|
}
|
|
17736
|
-
|
|
17785
|
+
fs8.writeFileSync(targetPath, artifact.content, "utf-8");
|
|
17737
17786
|
return targetPath;
|
|
17738
17787
|
} catch {
|
|
17739
17788
|
return null;
|
|
@@ -17743,12 +17792,12 @@ function readConfigFromFile(directory) {
|
|
|
17743
17792
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
17744
17793
|
let configPath = projectConfigPath;
|
|
17745
17794
|
let configContent = null;
|
|
17746
|
-
if (
|
|
17795
|
+
if (fs8.existsSync(projectConfigPath)) {
|
|
17747
17796
|
configPath = projectConfigPath;
|
|
17748
|
-
configContent =
|
|
17749
|
-
} else if (
|
|
17797
|
+
configContent = fs8.readFileSync(projectConfigPath, "utf-8");
|
|
17798
|
+
} else if (fs8.existsSync(userConfigPath)) {
|
|
17750
17799
|
configPath = userConfigPath;
|
|
17751
|
-
configContent =
|
|
17800
|
+
configContent = fs8.readFileSync(userConfigPath, "utf-8");
|
|
17752
17801
|
}
|
|
17753
17802
|
if (configContent === null) {
|
|
17754
17803
|
return null;
|
|
@@ -17760,9 +17809,9 @@ function readConfigFromFile(directory) {
|
|
|
17760
17809
|
return null;
|
|
17761
17810
|
}
|
|
17762
17811
|
}
|
|
17763
|
-
function validateConfigKey(
|
|
17812
|
+
function validateConfigKey(path19, value, _config) {
|
|
17764
17813
|
const findings = [];
|
|
17765
|
-
switch (
|
|
17814
|
+
switch (path19) {
|
|
17766
17815
|
case "agents": {
|
|
17767
17816
|
if (value !== undefined) {
|
|
17768
17817
|
findings.push({
|
|
@@ -18009,27 +18058,27 @@ function validateConfigKey(path20, value, _config) {
|
|
|
18009
18058
|
}
|
|
18010
18059
|
return findings;
|
|
18011
18060
|
}
|
|
18012
|
-
function walkConfigAndValidate(obj,
|
|
18061
|
+
function walkConfigAndValidate(obj, path19, config3, findings) {
|
|
18013
18062
|
if (obj === null || obj === undefined) {
|
|
18014
18063
|
return;
|
|
18015
18064
|
}
|
|
18016
|
-
if (
|
|
18017
|
-
const keyFindings = validateConfigKey(
|
|
18065
|
+
if (path19 && typeof obj === "object" && !Array.isArray(obj)) {
|
|
18066
|
+
const keyFindings = validateConfigKey(path19, obj, config3);
|
|
18018
18067
|
findings.push(...keyFindings);
|
|
18019
18068
|
}
|
|
18020
18069
|
if (typeof obj !== "object") {
|
|
18021
|
-
const keyFindings = validateConfigKey(
|
|
18070
|
+
const keyFindings = validateConfigKey(path19, obj, config3);
|
|
18022
18071
|
findings.push(...keyFindings);
|
|
18023
18072
|
return;
|
|
18024
18073
|
}
|
|
18025
18074
|
if (Array.isArray(obj)) {
|
|
18026
18075
|
obj.forEach((item, index) => {
|
|
18027
|
-
walkConfigAndValidate(item, `${
|
|
18076
|
+
walkConfigAndValidate(item, `${path19}[${index}]`, config3, findings);
|
|
18028
18077
|
});
|
|
18029
18078
|
return;
|
|
18030
18079
|
}
|
|
18031
18080
|
for (const [key, value] of Object.entries(obj)) {
|
|
18032
|
-
const newPath =
|
|
18081
|
+
const newPath = path19 ? `${path19}.${key}` : key;
|
|
18033
18082
|
walkConfigAndValidate(value, newPath, config3, findings);
|
|
18034
18083
|
}
|
|
18035
18084
|
}
|
|
@@ -18044,9 +18093,9 @@ function runConfigDoctor(config3, directory) {
|
|
|
18044
18093
|
const hasAutoFixableIssues = findings.some((f) => f.autoFixable && f.proposedFix?.risk === "low");
|
|
18045
18094
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
18046
18095
|
let configSource = "defaults";
|
|
18047
|
-
if (
|
|
18096
|
+
if (fs8.existsSync(projectConfigPath)) {
|
|
18048
18097
|
configSource = projectConfigPath;
|
|
18049
|
-
} else if (
|
|
18098
|
+
} else if (fs8.existsSync(userConfigPath)) {
|
|
18050
18099
|
configSource = userConfigPath;
|
|
18051
18100
|
}
|
|
18052
18101
|
return {
|
|
@@ -18075,12 +18124,12 @@ function applySafeAutoFixes(directory, result) {
|
|
|
18075
18124
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
18076
18125
|
let configPath = projectConfigPath;
|
|
18077
18126
|
let configContent;
|
|
18078
|
-
if (
|
|
18127
|
+
if (fs8.existsSync(projectConfigPath)) {
|
|
18079
18128
|
configPath = projectConfigPath;
|
|
18080
|
-
configContent =
|
|
18081
|
-
} else if (
|
|
18129
|
+
configContent = fs8.readFileSync(projectConfigPath, "utf-8");
|
|
18130
|
+
} else if (fs8.existsSync(userConfigPath)) {
|
|
18082
18131
|
configPath = userConfigPath;
|
|
18083
|
-
configContent =
|
|
18132
|
+
configContent = fs8.readFileSync(userConfigPath, "utf-8");
|
|
18084
18133
|
} else {
|
|
18085
18134
|
return { appliedFixes, updatedConfigPath: null };
|
|
18086
18135
|
}
|
|
@@ -18149,22 +18198,22 @@ function applySafeAutoFixes(directory, result) {
|
|
|
18149
18198
|
}
|
|
18150
18199
|
}
|
|
18151
18200
|
if (appliedFixes.length > 0) {
|
|
18152
|
-
const configDir =
|
|
18153
|
-
if (!
|
|
18154
|
-
|
|
18201
|
+
const configDir = path18.dirname(configPath);
|
|
18202
|
+
if (!fs8.existsSync(configDir)) {
|
|
18203
|
+
fs8.mkdirSync(configDir, { recursive: true });
|
|
18155
18204
|
}
|
|
18156
|
-
|
|
18205
|
+
fs8.writeFileSync(configPath, JSON.stringify(config3, null, 2), "utf-8");
|
|
18157
18206
|
updatedConfigPath = configPath;
|
|
18158
18207
|
}
|
|
18159
18208
|
return { appliedFixes, updatedConfigPath };
|
|
18160
18209
|
}
|
|
18161
18210
|
function writeDoctorArtifact(directory, result) {
|
|
18162
|
-
const swarmDir =
|
|
18163
|
-
if (!
|
|
18164
|
-
|
|
18211
|
+
const swarmDir = path18.join(directory, ".swarm");
|
|
18212
|
+
if (!fs8.existsSync(swarmDir)) {
|
|
18213
|
+
fs8.mkdirSync(swarmDir, { recursive: true });
|
|
18165
18214
|
}
|
|
18166
18215
|
const artifactFilename = "config-doctor.json";
|
|
18167
|
-
const artifactPath =
|
|
18216
|
+
const artifactPath = path18.join(swarmDir, artifactFilename);
|
|
18168
18217
|
const guiOutput = {
|
|
18169
18218
|
timestamp: result.timestamp,
|
|
18170
18219
|
summary: result.summary,
|
|
@@ -18185,7 +18234,7 @@ function writeDoctorArtifact(directory, result) {
|
|
|
18185
18234
|
} : null
|
|
18186
18235
|
}))
|
|
18187
18236
|
};
|
|
18188
|
-
|
|
18237
|
+
fs8.writeFileSync(artifactPath, JSON.stringify(guiOutput, null, 2), "utf-8");
|
|
18189
18238
|
return artifactPath;
|
|
18190
18239
|
}
|
|
18191
18240
|
function shouldRunOnStartup(automationConfig) {
|
|
@@ -18525,9 +18574,78 @@ var init_evidence_summary_service = __esm(() => {
|
|
|
18525
18574
|
});
|
|
18526
18575
|
|
|
18527
18576
|
// src/cli/index.ts
|
|
18528
|
-
import * as
|
|
18577
|
+
import * as fs21 from "fs";
|
|
18529
18578
|
import * as os6 from "os";
|
|
18530
|
-
import * as
|
|
18579
|
+
import * as path32 from "path";
|
|
18580
|
+
// package.json
|
|
18581
|
+
var package_default = {
|
|
18582
|
+
name: "opencode-swarm",
|
|
18583
|
+
version: "6.86.6",
|
|
18584
|
+
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
18585
|
+
main: "dist/index.js",
|
|
18586
|
+
types: "dist/index.d.ts",
|
|
18587
|
+
bin: {
|
|
18588
|
+
"opencode-swarm": "./dist/cli/index.js"
|
|
18589
|
+
},
|
|
18590
|
+
type: "module",
|
|
18591
|
+
engines: {
|
|
18592
|
+
bun: ">=1.0.0"
|
|
18593
|
+
},
|
|
18594
|
+
license: "MIT",
|
|
18595
|
+
repository: {
|
|
18596
|
+
type: "git",
|
|
18597
|
+
url: "https://github.com/zaxbysauce/opencode-swarm.git"
|
|
18598
|
+
},
|
|
18599
|
+
publishConfig: {
|
|
18600
|
+
access: "public",
|
|
18601
|
+
registry: "https://registry.npmjs.org/"
|
|
18602
|
+
},
|
|
18603
|
+
keywords: [
|
|
18604
|
+
"opencode",
|
|
18605
|
+
"opencode-plugin",
|
|
18606
|
+
"ai",
|
|
18607
|
+
"agents",
|
|
18608
|
+
"orchestration",
|
|
18609
|
+
"swarm",
|
|
18610
|
+
"multi-agent",
|
|
18611
|
+
"llm"
|
|
18612
|
+
],
|
|
18613
|
+
files: [
|
|
18614
|
+
"dist",
|
|
18615
|
+
"dist/lang/grammars",
|
|
18616
|
+
"README.md",
|
|
18617
|
+
"LICENSE"
|
|
18618
|
+
],
|
|
18619
|
+
scripts: {
|
|
18620
|
+
clean: `bun -e "require('fs').rmSync('dist',{recursive:true,force:true})"`,
|
|
18621
|
+
build: "bun run clean && bun run scripts/copy-grammars.ts && bun build src/index.ts --outdir dist --target bun --format esm && bun build src/cli/index.ts --outdir dist/cli --target bun --format esm && bun run scripts/copy-grammars.ts --to-dist && tsc --emitDeclarationOnly",
|
|
18622
|
+
typecheck: "tsc --noEmit",
|
|
18623
|
+
test: "bun test",
|
|
18624
|
+
lint: "biome lint .",
|
|
18625
|
+
format: "biome format . --write",
|
|
18626
|
+
check: "biome check --write .",
|
|
18627
|
+
dev: "bun run build && opencode",
|
|
18628
|
+
prepublishOnly: "bun run build"
|
|
18629
|
+
},
|
|
18630
|
+
dependencies: {
|
|
18631
|
+
"@opencode-ai/plugin": "^1.1.53",
|
|
18632
|
+
"@opencode-ai/sdk": "^1.1.53",
|
|
18633
|
+
"@vscode/tree-sitter-wasm": "^0.3.0",
|
|
18634
|
+
"p-limit": "^7.3.0",
|
|
18635
|
+
picomatch: "^4.0.4",
|
|
18636
|
+
"proper-lockfile": "^4.1.2",
|
|
18637
|
+
"quick-lru": "^7.3.0",
|
|
18638
|
+
"web-tree-sitter": "^0.25.0",
|
|
18639
|
+
zod: "^4.1.8"
|
|
18640
|
+
},
|
|
18641
|
+
devDependencies: {
|
|
18642
|
+
"@biomejs/biome": "2.3.14",
|
|
18643
|
+
"@types/picomatch": "^4.0.3",
|
|
18644
|
+
"bun-types": "1.3.8",
|
|
18645
|
+
"js-yaml": "^4.1.1",
|
|
18646
|
+
typescript: "^5.7.3"
|
|
18647
|
+
}
|
|
18648
|
+
};
|
|
18531
18649
|
|
|
18532
18650
|
// src/commands/acknowledge-spec-drift.ts
|
|
18533
18651
|
init_utils2();
|
|
@@ -18604,71 +18722,6 @@ ${warnings.map((w) => ` - ${w}`).join(`
|
|
|
18604
18722
|
return baseMessage + warningMessage + cautionMessage;
|
|
18605
18723
|
}
|
|
18606
18724
|
|
|
18607
|
-
// src/commands/agents.ts
|
|
18608
|
-
function handleAgentsCommand(agents, guardrails) {
|
|
18609
|
-
const entries = Object.entries(agents);
|
|
18610
|
-
if (entries.length === 0) {
|
|
18611
|
-
return "No agents registered.";
|
|
18612
|
-
}
|
|
18613
|
-
const lines = [`## Registered Agents (${entries.length} total)`, ""];
|
|
18614
|
-
for (const [key, agent] of entries) {
|
|
18615
|
-
const model = agent.config.model || "default";
|
|
18616
|
-
const temp = agent.config.temperature !== undefined ? agent.config.temperature.toString() : "default";
|
|
18617
|
-
const tools = agent.config.tools || {};
|
|
18618
|
-
const isReadOnly = tools.write === false || tools.edit === false;
|
|
18619
|
-
const access = isReadOnly ? "\uD83D\uDD12 read-only" : "\u270F\uFE0F read-write";
|
|
18620
|
-
const desc = agent.description || agent.config.description || "";
|
|
18621
|
-
const hasCustomProfile = guardrails?.profiles?.[key] !== undefined;
|
|
18622
|
-
const profileIndicator = hasCustomProfile ? " | \u26A1 custom limits" : "";
|
|
18623
|
-
lines.push(`- **${key}** | model: \`${model}\` | temp: ${temp} | ${access}${profileIndicator}`);
|
|
18624
|
-
if (desc) {
|
|
18625
|
-
lines.push(` ${desc}`);
|
|
18626
|
-
}
|
|
18627
|
-
}
|
|
18628
|
-
if (guardrails?.profiles && Object.keys(guardrails.profiles).length > 0) {
|
|
18629
|
-
lines.push("", "### Guardrail Profiles", "");
|
|
18630
|
-
for (const [profileName, profile] of Object.entries(guardrails.profiles)) {
|
|
18631
|
-
const overrides = [];
|
|
18632
|
-
if (profile.max_tool_calls !== undefined) {
|
|
18633
|
-
overrides.push(`max_tool_calls=${profile.max_tool_calls}`);
|
|
18634
|
-
}
|
|
18635
|
-
if (profile.max_duration_minutes !== undefined) {
|
|
18636
|
-
overrides.push(`max_duration_minutes=${profile.max_duration_minutes}`);
|
|
18637
|
-
}
|
|
18638
|
-
if (profile.max_repetitions !== undefined) {
|
|
18639
|
-
overrides.push(`max_repetitions=${profile.max_repetitions}`);
|
|
18640
|
-
}
|
|
18641
|
-
if (profile.max_consecutive_errors !== undefined) {
|
|
18642
|
-
overrides.push(`max_consecutive_errors=${profile.max_consecutive_errors}`);
|
|
18643
|
-
}
|
|
18644
|
-
if (profile.warning_threshold !== undefined) {
|
|
18645
|
-
overrides.push(`warning_threshold=${profile.warning_threshold}`);
|
|
18646
|
-
}
|
|
18647
|
-
const overrideStr = overrides.length > 0 ? overrides.join(", ") : "no overrides";
|
|
18648
|
-
lines.push(`- **${profileName}**: ${overrideStr}`);
|
|
18649
|
-
}
|
|
18650
|
-
}
|
|
18651
|
-
return lines.join(`
|
|
18652
|
-
`);
|
|
18653
|
-
}
|
|
18654
|
-
|
|
18655
|
-
// src/commands/analyze.ts
|
|
18656
|
-
async function handleAnalyzeCommand(_directory, args) {
|
|
18657
|
-
const description = args.join(" ").trim();
|
|
18658
|
-
if (description) {
|
|
18659
|
-
return `[MODE: ANALYZE] ${description}`;
|
|
18660
|
-
}
|
|
18661
|
-
return "[MODE: ANALYZE] Please analyze the spec against the plan using MODE: ANALYZE.";
|
|
18662
|
-
}
|
|
18663
|
-
|
|
18664
|
-
// src/config/loader.ts
|
|
18665
|
-
import * as fs2 from "fs";
|
|
18666
|
-
import * as os2 from "os";
|
|
18667
|
-
import * as path4 from "path";
|
|
18668
|
-
|
|
18669
|
-
// src/config/schema.ts
|
|
18670
|
-
init_zod();
|
|
18671
|
-
|
|
18672
18725
|
// src/tools/tool-names.ts
|
|
18673
18726
|
var TOOL_NAMES = [
|
|
18674
18727
|
"diff",
|
|
@@ -18981,6 +19034,57 @@ for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
|
18981
19034
|
}
|
|
18982
19035
|
|
|
18983
19036
|
// src/config/schema.ts
|
|
19037
|
+
init_zod();
|
|
19038
|
+
var KNOWN_SWARM_PREFIXES = [
|
|
19039
|
+
"paid",
|
|
19040
|
+
"local",
|
|
19041
|
+
"cloud",
|
|
19042
|
+
"enterprise",
|
|
19043
|
+
"mega",
|
|
19044
|
+
"default",
|
|
19045
|
+
"custom",
|
|
19046
|
+
"team",
|
|
19047
|
+
"project",
|
|
19048
|
+
"swarm",
|
|
19049
|
+
"synthetic"
|
|
19050
|
+
];
|
|
19051
|
+
var SEPARATORS = ["_", "-", " "];
|
|
19052
|
+
function stripKnownSwarmPrefix(agentName) {
|
|
19053
|
+
if (!agentName)
|
|
19054
|
+
return agentName;
|
|
19055
|
+
const normalized = agentName.toLowerCase();
|
|
19056
|
+
let stripped = normalized;
|
|
19057
|
+
let previous = "";
|
|
19058
|
+
while (stripped !== previous) {
|
|
19059
|
+
previous = stripped;
|
|
19060
|
+
for (const prefix of KNOWN_SWARM_PREFIXES) {
|
|
19061
|
+
for (const sep2 of SEPARATORS) {
|
|
19062
|
+
const prefixWithSep = prefix + sep2;
|
|
19063
|
+
if (stripped.startsWith(prefixWithSep)) {
|
|
19064
|
+
stripped = stripped.slice(prefixWithSep.length);
|
|
19065
|
+
break;
|
|
19066
|
+
}
|
|
19067
|
+
}
|
|
19068
|
+
if (stripped !== previous)
|
|
19069
|
+
break;
|
|
19070
|
+
}
|
|
19071
|
+
}
|
|
19072
|
+
if (ALL_AGENT_NAMES.includes(stripped)) {
|
|
19073
|
+
return stripped;
|
|
19074
|
+
}
|
|
19075
|
+
for (const agent of ALL_AGENT_NAMES) {
|
|
19076
|
+
for (const sep2 of SEPARATORS) {
|
|
19077
|
+
const suffix = sep2 + agent;
|
|
19078
|
+
if (normalized.endsWith(suffix)) {
|
|
19079
|
+
return agent;
|
|
19080
|
+
}
|
|
19081
|
+
}
|
|
19082
|
+
if (normalized === agent) {
|
|
19083
|
+
return agent;
|
|
19084
|
+
}
|
|
19085
|
+
}
|
|
19086
|
+
return agentName;
|
|
19087
|
+
}
|
|
18984
19088
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
18985
19089
|
model: exports_external.string().optional(),
|
|
18986
19090
|
variant: exports_external.string().min(1).optional(),
|
|
@@ -19585,6 +19689,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
19585
19689
|
council: CouncilConfigSchema.optional(),
|
|
19586
19690
|
parallelization: ParallelizationConfigSchema.optional(),
|
|
19587
19691
|
turbo_mode: exports_external.boolean().default(false).optional(),
|
|
19692
|
+
quiet: exports_external.boolean().default(false).optional(),
|
|
19588
19693
|
full_auto: exports_external.object({
|
|
19589
19694
|
enabled: exports_external.boolean().default(false),
|
|
19590
19695
|
critic_model: exports_external.string().optional(),
|
|
@@ -19599,7 +19704,78 @@ var PluginConfigSchema = exports_external.object({
|
|
|
19599
19704
|
})
|
|
19600
19705
|
});
|
|
19601
19706
|
|
|
19707
|
+
// src/commands/agents.ts
|
|
19708
|
+
function handleAgentsCommand(agents, guardrails) {
|
|
19709
|
+
const entries = Object.entries(agents);
|
|
19710
|
+
if (entries.length === 0) {
|
|
19711
|
+
return "No agents registered.";
|
|
19712
|
+
}
|
|
19713
|
+
const allAgentKeys = entries.map(([key]) => key);
|
|
19714
|
+
const registeredBaseNames = allAgentKeys.map((key) => stripKnownSwarmPrefix(key)).filter((stripped) => ALL_SUBAGENT_NAMES.includes(stripped));
|
|
19715
|
+
const unregistered = ALL_SUBAGENT_NAMES.filter((name) => !registeredBaseNames.includes(name));
|
|
19716
|
+
const hasUnregistered = unregistered.length > 0;
|
|
19717
|
+
const headerLabel = hasUnregistered ? `${entries.length} registered + ${unregistered.length} unregistered` : `${entries.length} total`;
|
|
19718
|
+
const lines = [`## Registered Agents (${headerLabel})`, ""];
|
|
19719
|
+
for (const [key, agent] of entries) {
|
|
19720
|
+
const model = agent.config.model || "default";
|
|
19721
|
+
const temp = agent.config.temperature !== undefined ? agent.config.temperature.toString() : "default";
|
|
19722
|
+
const tools = agent.config.tools || {};
|
|
19723
|
+
const isReadOnly = tools.write === false || tools.edit === false;
|
|
19724
|
+
const access = isReadOnly ? "\uD83D\uDD12 read-only" : "\u270F\uFE0F read-write";
|
|
19725
|
+
const desc = agent.description || agent.config.description || "";
|
|
19726
|
+
const hasCustomProfile = guardrails?.profiles?.[key] !== undefined;
|
|
19727
|
+
const profileIndicator = hasCustomProfile ? " | \u26A1 custom limits" : "";
|
|
19728
|
+
lines.push(`- **${key}** | model: \`${model}\` | temp: ${temp} | ${access}${profileIndicator}`);
|
|
19729
|
+
if (desc) {
|
|
19730
|
+
lines.push(` ${desc}`);
|
|
19731
|
+
}
|
|
19732
|
+
}
|
|
19733
|
+
if (hasUnregistered) {
|
|
19734
|
+
lines.push("", "### Unregistered Subagents");
|
|
19735
|
+
for (const name of unregistered) {
|
|
19736
|
+
lines.push(`- **${name}** (requires configuration)`);
|
|
19737
|
+
}
|
|
19738
|
+
}
|
|
19739
|
+
if (guardrails?.profiles && Object.keys(guardrails.profiles).length > 0) {
|
|
19740
|
+
lines.push("", "### Guardrail Profiles", "");
|
|
19741
|
+
for (const [profileName, profile] of Object.entries(guardrails.profiles)) {
|
|
19742
|
+
const overrides = [];
|
|
19743
|
+
if (profile.max_tool_calls !== undefined) {
|
|
19744
|
+
overrides.push(`max_tool_calls=${profile.max_tool_calls}`);
|
|
19745
|
+
}
|
|
19746
|
+
if (profile.max_duration_minutes !== undefined) {
|
|
19747
|
+
overrides.push(`max_duration_minutes=${profile.max_duration_minutes}`);
|
|
19748
|
+
}
|
|
19749
|
+
if (profile.max_repetitions !== undefined) {
|
|
19750
|
+
overrides.push(`max_repetitions=${profile.max_repetitions}`);
|
|
19751
|
+
}
|
|
19752
|
+
if (profile.max_consecutive_errors !== undefined) {
|
|
19753
|
+
overrides.push(`max_consecutive_errors=${profile.max_consecutive_errors}`);
|
|
19754
|
+
}
|
|
19755
|
+
if (profile.warning_threshold !== undefined) {
|
|
19756
|
+
overrides.push(`warning_threshold=${profile.warning_threshold}`);
|
|
19757
|
+
}
|
|
19758
|
+
const overrideStr = overrides.length > 0 ? overrides.join(", ") : "no overrides";
|
|
19759
|
+
lines.push(`- **${profileName}**: ${overrideStr}`);
|
|
19760
|
+
}
|
|
19761
|
+
}
|
|
19762
|
+
return lines.join(`
|
|
19763
|
+
`);
|
|
19764
|
+
}
|
|
19765
|
+
|
|
19766
|
+
// src/commands/analyze.ts
|
|
19767
|
+
async function handleAnalyzeCommand(_directory, args) {
|
|
19768
|
+
const description = args.join(" ").trim();
|
|
19769
|
+
if (description) {
|
|
19770
|
+
return `[MODE: ANALYZE] ${description}`;
|
|
19771
|
+
}
|
|
19772
|
+
return "[MODE: ANALYZE] Please analyze the spec against the plan using MODE: ANALYZE.";
|
|
19773
|
+
}
|
|
19774
|
+
|
|
19602
19775
|
// src/config/loader.ts
|
|
19776
|
+
import * as fs2 from "fs";
|
|
19777
|
+
import * as os2 from "os";
|
|
19778
|
+
import * as path4 from "path";
|
|
19603
19779
|
var CONFIG_FILENAME = "opencode-swarm.json";
|
|
19604
19780
|
var MAX_CONFIG_FILE_BYTES = 102400;
|
|
19605
19781
|
function getUserConfigDir() {
|
|
@@ -20292,6 +20468,9 @@ var DeltaSpecSchema = exports_external.union([
|
|
|
20292
20468
|
SwarmSpecSchema,
|
|
20293
20469
|
SpecDeltaSchema
|
|
20294
20470
|
]);
|
|
20471
|
+
// src/services/warning-buffer.ts
|
|
20472
|
+
var deferredWarnings = [];
|
|
20473
|
+
|
|
20295
20474
|
// src/agents/index.ts
|
|
20296
20475
|
var warnedAgents = new Set;
|
|
20297
20476
|
|
|
@@ -33621,8 +33800,8 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
33621
33800
|
|
|
33622
33801
|
// src/commands/close.ts
|
|
33623
33802
|
import { execFileSync } from "child_process";
|
|
33624
|
-
import { promises as
|
|
33625
|
-
import
|
|
33803
|
+
import { promises as fs7 } from "fs";
|
|
33804
|
+
import path12 from "path";
|
|
33626
33805
|
init_manager2();
|
|
33627
33806
|
|
|
33628
33807
|
// src/git/branch.ts
|
|
@@ -34311,31 +34490,10 @@ async function runAutoPromotion(directory, config3) {
|
|
|
34311
34490
|
// src/commands/close.ts
|
|
34312
34491
|
init_utils2();
|
|
34313
34492
|
|
|
34314
|
-
// src/plan/checkpoint.ts
|
|
34315
|
-
init_plan_schema();
|
|
34316
|
-
init_ledger();
|
|
34317
|
-
init_manager();
|
|
34318
|
-
import * as fs7 from "fs";
|
|
34319
|
-
import * as path11 from "path";
|
|
34320
|
-
async function writeCheckpoint(directory) {
|
|
34321
|
-
try {
|
|
34322
|
-
const plan = await loadPlan(directory);
|
|
34323
|
-
if (!plan)
|
|
34324
|
-
return;
|
|
34325
|
-
const jsonPath = path11.join(directory, "SWARM_PLAN.json");
|
|
34326
|
-
const mdPath = path11.join(directory, "SWARM_PLAN.md");
|
|
34327
|
-
fs7.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
|
|
34328
|
-
const md = derivePlanMarkdown(plan);
|
|
34329
|
-
fs7.writeFileSync(mdPath, md, "utf8");
|
|
34330
|
-
} catch (error93) {
|
|
34331
|
-
console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
34332
|
-
}
|
|
34333
|
-
}
|
|
34334
|
-
|
|
34335
34493
|
// src/session/snapshot-writer.ts
|
|
34336
34494
|
init_utils2();
|
|
34337
34495
|
import { mkdirSync as mkdirSync7, renameSync as renameSync5 } from "fs";
|
|
34338
|
-
import * as
|
|
34496
|
+
import * as path11 from "path";
|
|
34339
34497
|
init_utils();
|
|
34340
34498
|
var _writeInFlight = Promise.resolve();
|
|
34341
34499
|
function serializeAgentSession(s) {
|
|
@@ -34426,7 +34584,7 @@ async function writeSnapshot(directory, state) {
|
|
|
34426
34584
|
}
|
|
34427
34585
|
const content = JSON.stringify(snapshot, null, 2);
|
|
34428
34586
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
34429
|
-
const dir =
|
|
34587
|
+
const dir = path11.dirname(resolvedPath);
|
|
34430
34588
|
mkdirSync7(dir, { recursive: true });
|
|
34431
34589
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
34432
34590
|
await Bun.write(tempPath, content);
|
|
@@ -34819,21 +34977,21 @@ var ACTIVE_STATE_TO_CLEAN = [
|
|
|
34819
34977
|
];
|
|
34820
34978
|
async function handleCloseCommand(directory, args) {
|
|
34821
34979
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
34822
|
-
const swarmDir =
|
|
34980
|
+
const swarmDir = path12.join(directory, ".swarm");
|
|
34823
34981
|
let planExists = false;
|
|
34824
34982
|
let planData = {
|
|
34825
|
-
title:
|
|
34983
|
+
title: path12.basename(directory) || "Ad-hoc session",
|
|
34826
34984
|
phases: []
|
|
34827
34985
|
};
|
|
34828
34986
|
try {
|
|
34829
|
-
const content = await
|
|
34987
|
+
const content = await fs7.readFile(planPath, "utf-8");
|
|
34830
34988
|
planData = JSON.parse(content);
|
|
34831
34989
|
planExists = true;
|
|
34832
34990
|
} catch (error93) {
|
|
34833
34991
|
if (error93?.code !== "ENOENT") {
|
|
34834
34992
|
return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
34835
34993
|
}
|
|
34836
|
-
const swarmDirExists = await
|
|
34994
|
+
const swarmDirExists = await fs7.access(swarmDir).then(() => true).catch(() => false);
|
|
34837
34995
|
if (!swarmDirExists) {
|
|
34838
34996
|
return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
|
|
34839
34997
|
}
|
|
@@ -34927,10 +35085,10 @@ async function handleCloseCommand(directory, args) {
|
|
|
34927
35085
|
warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
34928
35086
|
}
|
|
34929
35087
|
}
|
|
34930
|
-
const lessonsFilePath =
|
|
35088
|
+
const lessonsFilePath = path12.join(swarmDir, "close-lessons.md");
|
|
34931
35089
|
let explicitLessons = [];
|
|
34932
35090
|
try {
|
|
34933
|
-
const lessonsText = await
|
|
35091
|
+
const lessonsText = await fs7.readFile(lessonsFilePath, "utf-8");
|
|
34934
35092
|
explicitLessons = lessonsText.split(`
|
|
34935
35093
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
34936
35094
|
} catch {}
|
|
@@ -34944,7 +35102,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
34944
35102
|
console.warn("[close-command] curateAndStoreSwarm error:", error93);
|
|
34945
35103
|
}
|
|
34946
35104
|
if (curationSucceeded && explicitLessons.length > 0) {
|
|
34947
|
-
await
|
|
35105
|
+
await fs7.unlink(lessonsFilePath).catch(() => {});
|
|
34948
35106
|
}
|
|
34949
35107
|
if (planExists && !planAlreadyDone) {
|
|
34950
35108
|
for (const phase of phases) {
|
|
@@ -34964,7 +35122,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
34964
35122
|
}
|
|
34965
35123
|
}
|
|
34966
35124
|
try {
|
|
34967
|
-
await
|
|
35125
|
+
await fs7.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
|
|
34968
35126
|
} catch (error93) {
|
|
34969
35127
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
34970
35128
|
warnings.push(`Failed to persist terminal plan.json state: ${msg}`);
|
|
@@ -34973,53 +35131,53 @@ async function handleCloseCommand(directory, args) {
|
|
|
34973
35131
|
}
|
|
34974
35132
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
34975
35133
|
const suffix = Math.random().toString(36).slice(2, 8);
|
|
34976
|
-
const archiveDir =
|
|
35134
|
+
const archiveDir = path12.join(swarmDir, "archive", `swarm-${timestamp}-${suffix}`);
|
|
34977
35135
|
let archiveResult = "";
|
|
34978
35136
|
let archivedFileCount = 0;
|
|
34979
35137
|
const archivedActiveStateFiles = new Set;
|
|
34980
35138
|
try {
|
|
34981
|
-
await
|
|
35139
|
+
await fs7.mkdir(archiveDir, { recursive: true });
|
|
34982
35140
|
for (const artifact of ARCHIVE_ARTIFACTS) {
|
|
34983
|
-
const srcPath =
|
|
34984
|
-
const destPath =
|
|
35141
|
+
const srcPath = path12.join(swarmDir, artifact);
|
|
35142
|
+
const destPath = path12.join(archiveDir, artifact);
|
|
34985
35143
|
try {
|
|
34986
|
-
await
|
|
35144
|
+
await fs7.copyFile(srcPath, destPath);
|
|
34987
35145
|
archivedFileCount++;
|
|
34988
35146
|
if (ACTIVE_STATE_TO_CLEAN.includes(artifact)) {
|
|
34989
35147
|
archivedActiveStateFiles.add(artifact);
|
|
34990
35148
|
}
|
|
34991
35149
|
} catch {}
|
|
34992
35150
|
}
|
|
34993
|
-
const evidenceDir =
|
|
34994
|
-
const archiveEvidenceDir =
|
|
35151
|
+
const evidenceDir = path12.join(swarmDir, "evidence");
|
|
35152
|
+
const archiveEvidenceDir = path12.join(archiveDir, "evidence");
|
|
34995
35153
|
try {
|
|
34996
|
-
const evidenceEntries = await
|
|
35154
|
+
const evidenceEntries = await fs7.readdir(evidenceDir);
|
|
34997
35155
|
if (evidenceEntries.length > 0) {
|
|
34998
|
-
await
|
|
35156
|
+
await fs7.mkdir(archiveEvidenceDir, { recursive: true });
|
|
34999
35157
|
for (const entry of evidenceEntries) {
|
|
35000
|
-
const srcEntry =
|
|
35001
|
-
const destEntry =
|
|
35158
|
+
const srcEntry = path12.join(evidenceDir, entry);
|
|
35159
|
+
const destEntry = path12.join(archiveEvidenceDir, entry);
|
|
35002
35160
|
try {
|
|
35003
|
-
const stat = await
|
|
35161
|
+
const stat = await fs7.stat(srcEntry);
|
|
35004
35162
|
if (stat.isDirectory()) {
|
|
35005
|
-
await
|
|
35006
|
-
const subEntries = await
|
|
35163
|
+
await fs7.mkdir(destEntry, { recursive: true });
|
|
35164
|
+
const subEntries = await fs7.readdir(srcEntry);
|
|
35007
35165
|
for (const sub of subEntries) {
|
|
35008
|
-
await
|
|
35166
|
+
await fs7.copyFile(path12.join(srcEntry, sub), path12.join(destEntry, sub)).catch(() => {});
|
|
35009
35167
|
}
|
|
35010
35168
|
} else {
|
|
35011
|
-
await
|
|
35169
|
+
await fs7.copyFile(srcEntry, destEntry);
|
|
35012
35170
|
}
|
|
35013
35171
|
archivedFileCount++;
|
|
35014
35172
|
} catch {}
|
|
35015
35173
|
}
|
|
35016
35174
|
}
|
|
35017
35175
|
} catch {}
|
|
35018
|
-
const sessionStatePath =
|
|
35176
|
+
const sessionStatePath = path12.join(swarmDir, "session", "state.json");
|
|
35019
35177
|
try {
|
|
35020
|
-
const archiveSessionDir =
|
|
35021
|
-
await
|
|
35022
|
-
await
|
|
35178
|
+
const archiveSessionDir = path12.join(archiveDir, "session");
|
|
35179
|
+
await fs7.mkdir(archiveSessionDir, { recursive: true });
|
|
35180
|
+
await fs7.copyFile(sessionStatePath, path12.join(archiveSessionDir, "state.json"));
|
|
35023
35181
|
archivedFileCount++;
|
|
35024
35182
|
} catch {}
|
|
35025
35183
|
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
|
|
@@ -35042,9 +35200,9 @@ async function handleCloseCommand(directory, args) {
|
|
|
35042
35200
|
warnings.push(`Preserved ${artifact} because it was not successfully archived.`);
|
|
35043
35201
|
continue;
|
|
35044
35202
|
}
|
|
35045
|
-
const filePath =
|
|
35203
|
+
const filePath = path12.join(swarmDir, artifact);
|
|
35046
35204
|
try {
|
|
35047
|
-
await
|
|
35205
|
+
await fs7.unlink(filePath);
|
|
35048
35206
|
cleanedFiles.push(artifact);
|
|
35049
35207
|
} catch {}
|
|
35050
35208
|
}
|
|
@@ -35052,23 +35210,42 @@ async function handleCloseCommand(directory, args) {
|
|
|
35052
35210
|
warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");
|
|
35053
35211
|
}
|
|
35054
35212
|
try {
|
|
35055
|
-
const swarmFiles = await
|
|
35213
|
+
const swarmFiles = await fs7.readdir(swarmDir);
|
|
35056
35214
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
35057
35215
|
for (const backup of configBackups) {
|
|
35058
35216
|
try {
|
|
35059
|
-
await
|
|
35217
|
+
await fs7.unlink(path12.join(swarmDir, backup));
|
|
35060
35218
|
configBackupsRemoved++;
|
|
35061
35219
|
} catch {}
|
|
35062
35220
|
}
|
|
35063
35221
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
35064
35222
|
for (const sibling of ledgerSiblings) {
|
|
35065
35223
|
try {
|
|
35066
|
-
await
|
|
35224
|
+
await fs7.unlink(path12.join(swarmDir, sibling));
|
|
35067
35225
|
} catch {}
|
|
35068
35226
|
}
|
|
35069
35227
|
} catch {}
|
|
35228
|
+
let swarmPlanFilesRemoved = 0;
|
|
35229
|
+
const swarmPlanJsonPath = path12.join(directory, "SWARM_PLAN.json");
|
|
35230
|
+
const swarmPlanMdPath = path12.join(directory, "SWARM_PLAN.md");
|
|
35231
|
+
try {
|
|
35232
|
+
await fs7.unlink(swarmPlanJsonPath);
|
|
35233
|
+
swarmPlanFilesRemoved++;
|
|
35234
|
+
} catch (err) {
|
|
35235
|
+
if (err?.code !== "ENOENT") {
|
|
35236
|
+
warnings.push(`Failed to remove SWARM_PLAN.json: ${err instanceof Error ? err.message : String(err)}`);
|
|
35237
|
+
}
|
|
35238
|
+
}
|
|
35239
|
+
try {
|
|
35240
|
+
await fs7.unlink(swarmPlanMdPath);
|
|
35241
|
+
swarmPlanFilesRemoved++;
|
|
35242
|
+
} catch (err) {
|
|
35243
|
+
if (err?.code !== "ENOENT") {
|
|
35244
|
+
warnings.push(`Failed to remove SWARM_PLAN.md: ${err instanceof Error ? err.message : String(err)}`);
|
|
35245
|
+
}
|
|
35246
|
+
}
|
|
35070
35247
|
clearAllScopes(directory);
|
|
35071
|
-
const contextPath =
|
|
35248
|
+
const contextPath = path12.join(swarmDir, "context.md");
|
|
35072
35249
|
const contextContent = [
|
|
35073
35250
|
"# Context",
|
|
35074
35251
|
"",
|
|
@@ -35081,7 +35258,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
35081
35258
|
].join(`
|
|
35082
35259
|
`);
|
|
35083
35260
|
try {
|
|
35084
|
-
await
|
|
35261
|
+
await fs7.writeFile(contextPath, contextContent, "utf-8");
|
|
35085
35262
|
} catch (error93) {
|
|
35086
35263
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
35087
35264
|
warnings.push(`Failed to reset context.md: ${msg}`);
|
|
@@ -35183,6 +35360,9 @@ async function handleCloseCommand(directory, args) {
|
|
|
35183
35360
|
] : [],
|
|
35184
35361
|
"- Reset context.md for next session",
|
|
35185
35362
|
...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
|
|
35363
|
+
...swarmPlanFilesRemoved > 0 ? [
|
|
35364
|
+
`- Removed ${swarmPlanFilesRemoved} root-level SWARM_PLAN checkpoint artifact(s)`
|
|
35365
|
+
] : [],
|
|
35186
35366
|
...prunedBranches.length > 0 ? [
|
|
35187
35367
|
`- Pruned ${prunedBranches.length} stale local git branch(es): ${prunedBranches.join(", ")}`
|
|
35188
35368
|
] : [],
|
|
@@ -35212,7 +35392,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
35212
35392
|
].join(`
|
|
35213
35393
|
`);
|
|
35214
35394
|
try {
|
|
35215
|
-
await
|
|
35395
|
+
await fs7.writeFile(closeSummaryPath, summaryContent, "utf-8");
|
|
35216
35396
|
} catch (error93) {
|
|
35217
35397
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
35218
35398
|
warnings.push(`Failed to write close-summary.md: ${msg}`);
|
|
@@ -35225,7 +35405,6 @@ async function handleCloseCommand(directory, args) {
|
|
|
35225
35405
|
warnings.push(`flushPendingSnapshot failed: ${msg}`);
|
|
35226
35406
|
console.warn("[close-command] flushPendingSnapshot error:", error93);
|
|
35227
35407
|
}
|
|
35228
|
-
await writeCheckpoint(directory).catch(() => {});
|
|
35229
35408
|
const preservedClient = swarmState.opencodeClient;
|
|
35230
35409
|
const preservedFullAutoFlag = swarmState.fullAutoEnabledInConfig;
|
|
35231
35410
|
const preservedCuratorInitNames = swarmState.curatorInitAgentNames;
|
|
@@ -35269,14 +35448,14 @@ ${otherWarnings.map((w) => `- ${w}`).join(`
|
|
|
35269
35448
|
|
|
35270
35449
|
// src/commands/config.ts
|
|
35271
35450
|
import * as os4 from "os";
|
|
35272
|
-
import * as
|
|
35451
|
+
import * as path13 from "path";
|
|
35273
35452
|
function getUserConfigDir2() {
|
|
35274
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
35453
|
+
return process.env.XDG_CONFIG_HOME || path13.join(os4.homedir(), ".config");
|
|
35275
35454
|
}
|
|
35276
35455
|
async function handleConfigCommand(directory, _args) {
|
|
35277
35456
|
const config3 = loadPluginConfig(directory);
|
|
35278
|
-
const userConfigPath =
|
|
35279
|
-
const projectConfigPath =
|
|
35457
|
+
const userConfigPath = path13.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
35458
|
+
const projectConfigPath = path13.join(directory, ".opencode", "opencode-swarm.json");
|
|
35280
35459
|
const lines = [
|
|
35281
35460
|
"## Swarm Configuration",
|
|
35282
35461
|
"",
|
|
@@ -35362,7 +35541,7 @@ async function handleCouncilCommand(_directory, args) {
|
|
|
35362
35541
|
}
|
|
35363
35542
|
|
|
35364
35543
|
// src/hooks/hive-promoter.ts
|
|
35365
|
-
import
|
|
35544
|
+
import path14 from "path";
|
|
35366
35545
|
|
|
35367
35546
|
// src/background/event-bus.ts
|
|
35368
35547
|
init_utils();
|
|
@@ -35617,7 +35796,7 @@ async function promoteToHive(directory, lesson, category) {
|
|
|
35617
35796
|
schema_version: 1,
|
|
35618
35797
|
created_at: new Date().toISOString(),
|
|
35619
35798
|
updated_at: new Date().toISOString(),
|
|
35620
|
-
source_project:
|
|
35799
|
+
source_project: path14.basename(directory) || "unknown",
|
|
35621
35800
|
encounter_score: 1
|
|
35622
35801
|
};
|
|
35623
35802
|
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
@@ -35695,14 +35874,14 @@ function formatCurationSummary(summary) {
|
|
|
35695
35874
|
}
|
|
35696
35875
|
|
|
35697
35876
|
// src/commands/dark-matter.ts
|
|
35698
|
-
import
|
|
35877
|
+
import path16 from "path";
|
|
35699
35878
|
|
|
35700
35879
|
// src/tools/co-change-analyzer.ts
|
|
35701
35880
|
init_zod();
|
|
35702
35881
|
import * as child_process3 from "child_process";
|
|
35703
35882
|
import { randomUUID } from "crypto";
|
|
35704
35883
|
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
35705
|
-
import * as
|
|
35884
|
+
import * as path15 from "path";
|
|
35706
35885
|
import { promisify } from "util";
|
|
35707
35886
|
function getExecFileAsync() {
|
|
35708
35887
|
return promisify(child_process3.execFile);
|
|
@@ -35804,7 +35983,7 @@ async function scanSourceFiles(dir) {
|
|
|
35804
35983
|
try {
|
|
35805
35984
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
35806
35985
|
for (const entry of entries) {
|
|
35807
|
-
const fullPath =
|
|
35986
|
+
const fullPath = path15.join(dir, entry.name);
|
|
35808
35987
|
if (entry.isDirectory()) {
|
|
35809
35988
|
if (skipDirs.has(entry.name)) {
|
|
35810
35989
|
continue;
|
|
@@ -35812,7 +35991,7 @@ async function scanSourceFiles(dir) {
|
|
|
35812
35991
|
const subFiles = await scanSourceFiles(fullPath);
|
|
35813
35992
|
results.push(...subFiles);
|
|
35814
35993
|
} else if (entry.isFile()) {
|
|
35815
|
-
const ext =
|
|
35994
|
+
const ext = path15.extname(entry.name);
|
|
35816
35995
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
35817
35996
|
results.push(fullPath);
|
|
35818
35997
|
}
|
|
@@ -35834,8 +36013,8 @@ async function getStaticEdges(directory) {
|
|
|
35834
36013
|
continue;
|
|
35835
36014
|
}
|
|
35836
36015
|
try {
|
|
35837
|
-
const sourceDir =
|
|
35838
|
-
const resolvedPath =
|
|
36016
|
+
const sourceDir = path15.dirname(sourceFile);
|
|
36017
|
+
const resolvedPath = path15.resolve(sourceDir, importPath);
|
|
35839
36018
|
const extensions = [
|
|
35840
36019
|
"",
|
|
35841
36020
|
".ts",
|
|
@@ -35860,8 +36039,8 @@ async function getStaticEdges(directory) {
|
|
|
35860
36039
|
if (!targetFile) {
|
|
35861
36040
|
continue;
|
|
35862
36041
|
}
|
|
35863
|
-
const relSource =
|
|
35864
|
-
const relTarget =
|
|
36042
|
+
const relSource = path15.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
36043
|
+
const relTarget = path15.relative(directory, targetFile).replace(/\\/g, "/");
|
|
35865
36044
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
35866
36045
|
edges.add(key);
|
|
35867
36046
|
} catch {}
|
|
@@ -35873,7 +36052,7 @@ async function getStaticEdges(directory) {
|
|
|
35873
36052
|
function isTestImplementationPair(fileA, fileB) {
|
|
35874
36053
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
35875
36054
|
const getBaseName = (filePath) => {
|
|
35876
|
-
const base =
|
|
36055
|
+
const base = path15.basename(filePath);
|
|
35877
36056
|
for (const pattern of testPatterns) {
|
|
35878
36057
|
if (base.endsWith(pattern)) {
|
|
35879
36058
|
return base.slice(0, -pattern.length);
|
|
@@ -35883,16 +36062,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
35883
36062
|
};
|
|
35884
36063
|
const baseA = getBaseName(fileA);
|
|
35885
36064
|
const baseB = getBaseName(fileB);
|
|
35886
|
-
return baseA === baseB && baseA !==
|
|
36065
|
+
return baseA === baseB && baseA !== path15.basename(fileA) && baseA !== path15.basename(fileB);
|
|
35887
36066
|
}
|
|
35888
36067
|
function hasSharedPrefix(fileA, fileB) {
|
|
35889
|
-
const dirA =
|
|
35890
|
-
const dirB =
|
|
36068
|
+
const dirA = path15.dirname(fileA);
|
|
36069
|
+
const dirB = path15.dirname(fileB);
|
|
35891
36070
|
if (dirA !== dirB) {
|
|
35892
36071
|
return false;
|
|
35893
36072
|
}
|
|
35894
|
-
const baseA =
|
|
35895
|
-
const baseB =
|
|
36073
|
+
const baseA = path15.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
36074
|
+
const baseB = path15.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
35896
36075
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
35897
36076
|
return true;
|
|
35898
36077
|
}
|
|
@@ -35946,8 +36125,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
35946
36125
|
const entries = [];
|
|
35947
36126
|
const now = new Date().toISOString();
|
|
35948
36127
|
for (const pair of pairs.slice(0, 10)) {
|
|
35949
|
-
const baseA =
|
|
35950
|
-
const baseB =
|
|
36128
|
+
const baseA = path15.basename(pair.fileA);
|
|
36129
|
+
const baseB = path15.basename(pair.fileB);
|
|
35951
36130
|
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.`;
|
|
35952
36131
|
if (lesson.length > 280) {
|
|
35953
36132
|
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.`;
|
|
@@ -36057,7 +36236,7 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
36057
36236
|
const output = formatDarkMatterOutput(pairs);
|
|
36058
36237
|
if (pairs.length > 0) {
|
|
36059
36238
|
try {
|
|
36060
|
-
const projectName =
|
|
36239
|
+
const projectName = path16.basename(path16.resolve(directory));
|
|
36061
36240
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
36062
36241
|
if (entries.length > 0) {
|
|
36063
36242
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -36078,12 +36257,13 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
36078
36257
|
|
|
36079
36258
|
// src/services/diagnose-service.ts
|
|
36080
36259
|
import * as child_process4 from "child_process";
|
|
36081
|
-
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as
|
|
36082
|
-
import
|
|
36260
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync5 } from "fs";
|
|
36261
|
+
import path17 from "path";
|
|
36083
36262
|
import { fileURLToPath } from "url";
|
|
36084
36263
|
init_manager2();
|
|
36085
36264
|
init_utils2();
|
|
36086
36265
|
init_manager();
|
|
36266
|
+
var { version: version3 } = package_default;
|
|
36087
36267
|
function validateTaskDag(plan) {
|
|
36088
36268
|
const allTaskIds = new Set;
|
|
36089
36269
|
for (const phase of plan.phases) {
|
|
@@ -36379,7 +36559,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
36379
36559
|
};
|
|
36380
36560
|
}
|
|
36381
36561
|
async function checkConfigParseability(directory) {
|
|
36382
|
-
const configPath =
|
|
36562
|
+
const configPath = path17.join(directory, ".opencode/opencode-swarm.json");
|
|
36383
36563
|
if (!existsSync8(configPath)) {
|
|
36384
36564
|
return {
|
|
36385
36565
|
name: "Config Parseability",
|
|
@@ -36388,7 +36568,7 @@ async function checkConfigParseability(directory) {
|
|
|
36388
36568
|
};
|
|
36389
36569
|
}
|
|
36390
36570
|
try {
|
|
36391
|
-
const content =
|
|
36571
|
+
const content = readFileSync5(configPath, "utf-8");
|
|
36392
36572
|
JSON.parse(content);
|
|
36393
36573
|
return {
|
|
36394
36574
|
name: "Config Parseability",
|
|
@@ -36408,7 +36588,7 @@ function resolveGrammarDir(thisDir) {
|
|
|
36408
36588
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
36409
36589
|
const isSource = normalized.endsWith("/src/services");
|
|
36410
36590
|
const isCliBundle = normalized.endsWith("/cli");
|
|
36411
|
-
return isSource || isCliBundle ?
|
|
36591
|
+
return isSource || isCliBundle ? path17.join(thisDir, "..", "lang", "grammars") : path17.join(thisDir, "lang", "grammars");
|
|
36412
36592
|
}
|
|
36413
36593
|
async function checkGrammarWasmFiles() {
|
|
36414
36594
|
const grammarFiles = [
|
|
@@ -36432,14 +36612,14 @@ async function checkGrammarWasmFiles() {
|
|
|
36432
36612
|
"tree-sitter-ini.wasm",
|
|
36433
36613
|
"tree-sitter-regex.wasm"
|
|
36434
36614
|
];
|
|
36435
|
-
const thisDir =
|
|
36615
|
+
const thisDir = path17.dirname(fileURLToPath(import.meta.url));
|
|
36436
36616
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
36437
36617
|
const missing = [];
|
|
36438
|
-
if (!existsSync8(
|
|
36618
|
+
if (!existsSync8(path17.join(grammarDir, "tree-sitter.wasm"))) {
|
|
36439
36619
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
36440
36620
|
}
|
|
36441
36621
|
for (const file3 of grammarFiles) {
|
|
36442
|
-
if (!existsSync8(
|
|
36622
|
+
if (!existsSync8(path17.join(grammarDir, file3))) {
|
|
36443
36623
|
missing.push(file3);
|
|
36444
36624
|
}
|
|
36445
36625
|
}
|
|
@@ -36457,7 +36637,7 @@ async function checkGrammarWasmFiles() {
|
|
|
36457
36637
|
};
|
|
36458
36638
|
}
|
|
36459
36639
|
async function checkCheckpointManifest(directory) {
|
|
36460
|
-
const manifestPath =
|
|
36640
|
+
const manifestPath = path17.join(directory, ".swarm/checkpoints.json");
|
|
36461
36641
|
if (!existsSync8(manifestPath)) {
|
|
36462
36642
|
return {
|
|
36463
36643
|
name: "Checkpoint Manifest",
|
|
@@ -36466,7 +36646,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
36466
36646
|
};
|
|
36467
36647
|
}
|
|
36468
36648
|
try {
|
|
36469
|
-
const content =
|
|
36649
|
+
const content = readFileSync5(manifestPath, "utf-8");
|
|
36470
36650
|
const parsed = JSON.parse(content);
|
|
36471
36651
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
36472
36652
|
return {
|
|
@@ -36509,7 +36689,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
36509
36689
|
}
|
|
36510
36690
|
}
|
|
36511
36691
|
async function checkEventStreamIntegrity(directory) {
|
|
36512
|
-
const eventsPath =
|
|
36692
|
+
const eventsPath = path17.join(directory, ".swarm/events.jsonl");
|
|
36513
36693
|
if (!existsSync8(eventsPath)) {
|
|
36514
36694
|
return {
|
|
36515
36695
|
name: "Event Stream",
|
|
@@ -36518,7 +36698,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
36518
36698
|
};
|
|
36519
36699
|
}
|
|
36520
36700
|
try {
|
|
36521
|
-
const content =
|
|
36701
|
+
const content = readFileSync5(eventsPath, "utf-8");
|
|
36522
36702
|
const lines = content.split(`
|
|
36523
36703
|
`).filter((line) => line.trim() !== "");
|
|
36524
36704
|
let malformedCount = 0;
|
|
@@ -36550,7 +36730,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
36550
36730
|
}
|
|
36551
36731
|
}
|
|
36552
36732
|
async function checkSteeringDirectives(directory) {
|
|
36553
|
-
const eventsPath =
|
|
36733
|
+
const eventsPath = path17.join(directory, ".swarm/events.jsonl");
|
|
36554
36734
|
if (!existsSync8(eventsPath)) {
|
|
36555
36735
|
return {
|
|
36556
36736
|
name: "Steering Directives",
|
|
@@ -36559,7 +36739,7 @@ async function checkSteeringDirectives(directory) {
|
|
|
36559
36739
|
};
|
|
36560
36740
|
}
|
|
36561
36741
|
try {
|
|
36562
|
-
const content =
|
|
36742
|
+
const content = readFileSync5(eventsPath, "utf-8");
|
|
36563
36743
|
const lines = content.split(`
|
|
36564
36744
|
`).filter((line) => line.trim() !== "");
|
|
36565
36745
|
const directivesIssued = [];
|
|
@@ -36606,7 +36786,7 @@ async function checkCurator(directory) {
|
|
|
36606
36786
|
detail: "Disabled (enable via curator.enabled)"
|
|
36607
36787
|
};
|
|
36608
36788
|
}
|
|
36609
|
-
const summaryPath =
|
|
36789
|
+
const summaryPath = path17.join(directory, ".swarm/curator-summary.json");
|
|
36610
36790
|
if (!existsSync8(summaryPath)) {
|
|
36611
36791
|
return {
|
|
36612
36792
|
name: "Curator",
|
|
@@ -36615,7 +36795,7 @@ async function checkCurator(directory) {
|
|
|
36615
36795
|
};
|
|
36616
36796
|
}
|
|
36617
36797
|
try {
|
|
36618
|
-
const content =
|
|
36798
|
+
const content = readFileSync5(summaryPath, "utf-8");
|
|
36619
36799
|
const parsed = JSON.parse(content);
|
|
36620
36800
|
if (typeof parsed.schema_version !== "number" || parsed.schema_version !== 1) {
|
|
36621
36801
|
return {
|
|
@@ -36650,6 +36830,11 @@ async function checkCurator(directory) {
|
|
|
36650
36830
|
}
|
|
36651
36831
|
async function getDiagnoseData(directory) {
|
|
36652
36832
|
const checks5 = [];
|
|
36833
|
+
checks5.push({
|
|
36834
|
+
name: "Version",
|
|
36835
|
+
status: "\u2705",
|
|
36836
|
+
detail: version3
|
|
36837
|
+
});
|
|
36653
36838
|
const plan = await loadPlanJsonOnly(directory);
|
|
36654
36839
|
if (plan) {
|
|
36655
36840
|
checks5.push({
|
|
@@ -36754,7 +36939,7 @@ async function getDiagnoseData(directory) {
|
|
|
36754
36939
|
checks5.push(await checkSteeringDirectives(directory));
|
|
36755
36940
|
checks5.push(await checkCurator(directory));
|
|
36756
36941
|
try {
|
|
36757
|
-
const evidenceDir =
|
|
36942
|
+
const evidenceDir = path17.join(directory, ".swarm", "evidence");
|
|
36758
36943
|
const snapshotFiles = existsSync8(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
36759
36944
|
if (snapshotFiles.length > 0) {
|
|
36760
36945
|
const latest = snapshotFiles.sort().pop();
|
|
@@ -36777,6 +36962,13 @@ async function getDiagnoseData(directory) {
|
|
|
36777
36962
|
detail: "No snapshots yet (snapshots written on next session start)"
|
|
36778
36963
|
});
|
|
36779
36964
|
}
|
|
36965
|
+
if (deferredWarnings.length > 0) {
|
|
36966
|
+
checks5.push({
|
|
36967
|
+
name: "Deferred Warnings",
|
|
36968
|
+
status: "\u26A0\uFE0F",
|
|
36969
|
+
detail: `${deferredWarnings.length} warning(s) deferred from init (run with verbose logs for details)`
|
|
36970
|
+
});
|
|
36971
|
+
}
|
|
36780
36972
|
const passCount = checks5.filter((c) => c.status === "\u2705").length;
|
|
36781
36973
|
const totalCount = checks5.length;
|
|
36782
36974
|
const allPassed = passCount === totalCount;
|
|
@@ -36795,6 +36987,14 @@ function formatDiagnoseMarkdown(diagnose) {
|
|
|
36795
36987
|
"",
|
|
36796
36988
|
`**Result**: ${diagnose.allPassed ? "\u2705 All checks passed" : `\u26A0\uFE0F ${diagnose.passCount}/${diagnose.totalCount} checks passed`}`
|
|
36797
36989
|
];
|
|
36990
|
+
if (deferredWarnings.length > 0) {
|
|
36991
|
+
lines.push("");
|
|
36992
|
+
lines.push("## Deferred Warnings");
|
|
36993
|
+
lines.push("");
|
|
36994
|
+
for (const warning of deferredWarnings) {
|
|
36995
|
+
lines.push(`- ${warning}`);
|
|
36996
|
+
}
|
|
36997
|
+
}
|
|
36798
36998
|
return lines.join(`
|
|
36799
36999
|
`);
|
|
36800
37000
|
}
|
|
@@ -36806,16 +37006,16 @@ async function handleDiagnoseCommand(directory, _args) {
|
|
|
36806
37006
|
init_config_doctor();
|
|
36807
37007
|
|
|
36808
37008
|
// src/services/tool-doctor.ts
|
|
36809
|
-
import * as fs11 from "fs";
|
|
36810
|
-
import * as path21 from "path";
|
|
36811
|
-
|
|
36812
|
-
// src/build/discovery.ts
|
|
36813
37009
|
import * as fs10 from "fs";
|
|
36814
37010
|
import * as path20 from "path";
|
|
36815
37011
|
|
|
37012
|
+
// src/build/discovery.ts
|
|
37013
|
+
import * as fs9 from "fs";
|
|
37014
|
+
import * as path19 from "path";
|
|
37015
|
+
|
|
36816
37016
|
// src/lang/detector.ts
|
|
36817
37017
|
import { access as access2, readdir as readdir2 } from "fs/promises";
|
|
36818
|
-
import { extname as extname2, join as
|
|
37018
|
+
import { extname as extname2, join as join15 } from "path";
|
|
36819
37019
|
|
|
36820
37020
|
// src/lang/profiles.ts
|
|
36821
37021
|
class LanguageRegistry {
|
|
@@ -37795,7 +37995,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
37795
37995
|
if (detectFile.includes("*") || detectFile.includes("?"))
|
|
37796
37996
|
continue;
|
|
37797
37997
|
try {
|
|
37798
|
-
await access2(
|
|
37998
|
+
await access2(join15(dir, detectFile));
|
|
37799
37999
|
detected.add(profile.id);
|
|
37800
38000
|
break;
|
|
37801
38001
|
} catch {}
|
|
@@ -37816,7 +38016,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
37816
38016
|
const topEntries = await readdir2(projectDir, { withFileTypes: true });
|
|
37817
38017
|
for (const entry of topEntries) {
|
|
37818
38018
|
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
37819
|
-
await scanDir(
|
|
38019
|
+
await scanDir(join15(projectDir, entry.name));
|
|
37820
38020
|
}
|
|
37821
38021
|
}
|
|
37822
38022
|
} catch {}
|
|
@@ -37971,16 +38171,16 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
37971
38171
|
if (pattern.includes("*")) {
|
|
37972
38172
|
const dir = workingDir;
|
|
37973
38173
|
try {
|
|
37974
|
-
const files =
|
|
38174
|
+
const files = fs9.readdirSync(dir);
|
|
37975
38175
|
const regex = simpleGlobToRegex(pattern);
|
|
37976
38176
|
const matches = files.filter((f) => regex.test(f));
|
|
37977
38177
|
if (matches.length > 0) {
|
|
37978
|
-
return
|
|
38178
|
+
return path19.join(dir, matches[0]);
|
|
37979
38179
|
}
|
|
37980
38180
|
} catch {}
|
|
37981
38181
|
} else {
|
|
37982
|
-
const filePath =
|
|
37983
|
-
if (
|
|
38182
|
+
const filePath = path19.join(workingDir, pattern);
|
|
38183
|
+
if (fs9.existsSync(filePath)) {
|
|
37984
38184
|
return filePath;
|
|
37985
38185
|
}
|
|
37986
38186
|
}
|
|
@@ -37988,12 +38188,12 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
37988
38188
|
return null;
|
|
37989
38189
|
}
|
|
37990
38190
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
37991
|
-
const packageJsonPath =
|
|
37992
|
-
if (!
|
|
38191
|
+
const packageJsonPath = path19.join(workingDir, "package.json");
|
|
38192
|
+
if (!fs9.existsSync(packageJsonPath)) {
|
|
37993
38193
|
return [];
|
|
37994
38194
|
}
|
|
37995
38195
|
try {
|
|
37996
|
-
const content =
|
|
38196
|
+
const content = fs9.readFileSync(packageJsonPath, "utf-8");
|
|
37997
38197
|
const pkg = JSON.parse(content);
|
|
37998
38198
|
if (!pkg.scripts || typeof pkg.scripts !== "object") {
|
|
37999
38199
|
return [];
|
|
@@ -38029,8 +38229,8 @@ function findAllBuildFiles(workingDir) {
|
|
|
38029
38229
|
const regex = simpleGlobToRegex(pattern);
|
|
38030
38230
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
38031
38231
|
} else {
|
|
38032
|
-
const filePath =
|
|
38033
|
-
if (
|
|
38232
|
+
const filePath = path19.join(workingDir, pattern);
|
|
38233
|
+
if (fs9.existsSync(filePath)) {
|
|
38034
38234
|
allBuildFiles.add(filePath);
|
|
38035
38235
|
}
|
|
38036
38236
|
}
|
|
@@ -38040,9 +38240,9 @@ function findAllBuildFiles(workingDir) {
|
|
|
38040
38240
|
}
|
|
38041
38241
|
function findFilesRecursive(dir, regex, results) {
|
|
38042
38242
|
try {
|
|
38043
|
-
const entries =
|
|
38243
|
+
const entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
38044
38244
|
for (const entry of entries) {
|
|
38045
|
-
const fullPath =
|
|
38245
|
+
const fullPath = path19.join(dir, entry.name);
|
|
38046
38246
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
38047
38247
|
findFilesRecursive(fullPath, regex, results);
|
|
38048
38248
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -38065,8 +38265,8 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
|
|
|
38065
38265
|
let foundCommand = false;
|
|
38066
38266
|
for (const cmd of sortedCommands) {
|
|
38067
38267
|
if (cmd.detectFile) {
|
|
38068
|
-
const detectFilePath =
|
|
38069
|
-
if (!
|
|
38268
|
+
const detectFilePath = path19.join(workingDir, cmd.detectFile);
|
|
38269
|
+
if (!fs9.existsSync(detectFilePath)) {
|
|
38070
38270
|
continue;
|
|
38071
38271
|
}
|
|
38072
38272
|
}
|
|
@@ -38189,7 +38389,7 @@ var BINARY_CHECKLIST = [
|
|
|
38189
38389
|
function extractRegisteredToolKeys(indexPath) {
|
|
38190
38390
|
const registeredKeys = new Set;
|
|
38191
38391
|
try {
|
|
38192
|
-
const content =
|
|
38392
|
+
const content = fs10.readFileSync(indexPath, "utf-8");
|
|
38193
38393
|
const toolBlockMatch = content.match(/tool:\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/s);
|
|
38194
38394
|
if (!toolBlockMatch) {
|
|
38195
38395
|
return registeredKeys;
|
|
@@ -38240,9 +38440,9 @@ function checkBinaryReadiness() {
|
|
|
38240
38440
|
}
|
|
38241
38441
|
function runToolDoctor(_directory, pluginRoot) {
|
|
38242
38442
|
const findings = [];
|
|
38243
|
-
const resolvedPluginRoot = pluginRoot ??
|
|
38244
|
-
const indexPath =
|
|
38245
|
-
if (!
|
|
38443
|
+
const resolvedPluginRoot = pluginRoot ?? path20.resolve(import.meta.dir, "..", "..");
|
|
38444
|
+
const indexPath = path20.join(resolvedPluginRoot, "src", "index.ts");
|
|
38445
|
+
if (!fs10.existsSync(indexPath)) {
|
|
38246
38446
|
return {
|
|
38247
38447
|
findings: [
|
|
38248
38448
|
{
|
|
@@ -39162,12 +39362,12 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
39162
39362
|
}
|
|
39163
39363
|
// src/hooks/knowledge-migrator.ts
|
|
39164
39364
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
39165
|
-
import { existsSync as existsSync12, readFileSync as
|
|
39365
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
39166
39366
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
39167
|
-
import * as
|
|
39367
|
+
import * as path21 from "path";
|
|
39168
39368
|
async function migrateContextToKnowledge(directory, config3) {
|
|
39169
|
-
const sentinelPath =
|
|
39170
|
-
const contextPath =
|
|
39369
|
+
const sentinelPath = path21.join(directory, ".swarm", ".knowledge-migrated");
|
|
39370
|
+
const contextPath = path21.join(directory, ".swarm", "context.md");
|
|
39171
39371
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
39172
39372
|
if (existsSync12(sentinelPath)) {
|
|
39173
39373
|
return {
|
|
@@ -39363,16 +39563,16 @@ function truncateLesson(text) {
|
|
|
39363
39563
|
return `${text.slice(0, 277)}...`;
|
|
39364
39564
|
}
|
|
39365
39565
|
function inferProjectName(directory) {
|
|
39366
|
-
const packageJsonPath =
|
|
39566
|
+
const packageJsonPath = path21.join(directory, "package.json");
|
|
39367
39567
|
if (existsSync12(packageJsonPath)) {
|
|
39368
39568
|
try {
|
|
39369
|
-
const pkg = JSON.parse(
|
|
39569
|
+
const pkg = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
|
|
39370
39570
|
if (pkg.name && typeof pkg.name === "string") {
|
|
39371
39571
|
return pkg.name;
|
|
39372
39572
|
}
|
|
39373
39573
|
} catch {}
|
|
39374
39574
|
}
|
|
39375
|
-
return
|
|
39575
|
+
return path21.basename(directory);
|
|
39376
39576
|
}
|
|
39377
39577
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
39378
39578
|
const sentinel = {
|
|
@@ -39384,7 +39584,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
39384
39584
|
schema_version: 1,
|
|
39385
39585
|
migration_tool: "knowledge-migrator.ts"
|
|
39386
39586
|
};
|
|
39387
|
-
await mkdir3(
|
|
39587
|
+
await mkdir3(path21.dirname(sentinelPath), { recursive: true });
|
|
39388
39588
|
await writeFile4(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
39389
39589
|
}
|
|
39390
39590
|
|
|
@@ -39620,13 +39820,13 @@ async function handlePlanCommand(directory, args) {
|
|
|
39620
39820
|
// src/services/preflight-service.ts
|
|
39621
39821
|
init_manager2();
|
|
39622
39822
|
init_manager();
|
|
39623
|
-
import * as
|
|
39624
|
-
import * as
|
|
39823
|
+
import * as fs17 from "fs";
|
|
39824
|
+
import * as path28 from "path";
|
|
39625
39825
|
|
|
39626
39826
|
// src/tools/lint.ts
|
|
39627
39827
|
init_zod();
|
|
39628
|
-
import * as
|
|
39629
|
-
import * as
|
|
39828
|
+
import * as fs11 from "fs";
|
|
39829
|
+
import * as path22 from "path";
|
|
39630
39830
|
init_utils();
|
|
39631
39831
|
|
|
39632
39832
|
// src/utils/path-security.ts
|
|
@@ -39672,9 +39872,9 @@ function validateArgs(args) {
|
|
|
39672
39872
|
}
|
|
39673
39873
|
function getLinterCommand(linter, mode, projectDir) {
|
|
39674
39874
|
const isWindows = process.platform === "win32";
|
|
39675
|
-
const binDir =
|
|
39676
|
-
const biomeBin = isWindows ?
|
|
39677
|
-
const eslintBin = isWindows ?
|
|
39875
|
+
const binDir = path22.join(projectDir, "node_modules", ".bin");
|
|
39876
|
+
const biomeBin = isWindows ? path22.join(binDir, "biome.EXE") : path22.join(binDir, "biome");
|
|
39877
|
+
const eslintBin = isWindows ? path22.join(binDir, "eslint.cmd") : path22.join(binDir, "eslint");
|
|
39678
39878
|
switch (linter) {
|
|
39679
39879
|
case "biome":
|
|
39680
39880
|
if (mode === "fix") {
|
|
@@ -39690,7 +39890,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
39690
39890
|
}
|
|
39691
39891
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
39692
39892
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
39693
|
-
const gradlew =
|
|
39893
|
+
const gradlew = fs11.existsSync(path22.join(cwd, gradlewName)) ? path22.join(cwd, gradlewName) : null;
|
|
39694
39894
|
switch (linter) {
|
|
39695
39895
|
case "ruff":
|
|
39696
39896
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -39724,12 +39924,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
39724
39924
|
}
|
|
39725
39925
|
}
|
|
39726
39926
|
function detectRuff(cwd) {
|
|
39727
|
-
if (
|
|
39927
|
+
if (fs11.existsSync(path22.join(cwd, "ruff.toml")))
|
|
39728
39928
|
return isCommandAvailable("ruff");
|
|
39729
39929
|
try {
|
|
39730
|
-
const pyproject =
|
|
39731
|
-
if (
|
|
39732
|
-
const content =
|
|
39930
|
+
const pyproject = path22.join(cwd, "pyproject.toml");
|
|
39931
|
+
if (fs11.existsSync(pyproject)) {
|
|
39932
|
+
const content = fs11.readFileSync(pyproject, "utf-8");
|
|
39733
39933
|
if (content.includes("[tool.ruff]"))
|
|
39734
39934
|
return isCommandAvailable("ruff");
|
|
39735
39935
|
}
|
|
@@ -39737,21 +39937,21 @@ function detectRuff(cwd) {
|
|
|
39737
39937
|
return false;
|
|
39738
39938
|
}
|
|
39739
39939
|
function detectClippy(cwd) {
|
|
39740
|
-
return
|
|
39940
|
+
return fs11.existsSync(path22.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
39741
39941
|
}
|
|
39742
39942
|
function detectGolangciLint(cwd) {
|
|
39743
|
-
return
|
|
39943
|
+
return fs11.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
39744
39944
|
}
|
|
39745
39945
|
function detectCheckstyle(cwd) {
|
|
39746
|
-
const hasMaven =
|
|
39747
|
-
const hasGradle =
|
|
39748
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (
|
|
39946
|
+
const hasMaven = fs11.existsSync(path22.join(cwd, "pom.xml"));
|
|
39947
|
+
const hasGradle = fs11.existsSync(path22.join(cwd, "build.gradle")) || fs11.existsSync(path22.join(cwd, "build.gradle.kts"));
|
|
39948
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs11.existsSync(path22.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
39749
39949
|
return (hasMaven || hasGradle) && hasBinary;
|
|
39750
39950
|
}
|
|
39751
39951
|
function detectKtlint(cwd) {
|
|
39752
|
-
const hasKotlin =
|
|
39952
|
+
const hasKotlin = fs11.existsSync(path22.join(cwd, "build.gradle.kts")) || fs11.existsSync(path22.join(cwd, "build.gradle")) || (() => {
|
|
39753
39953
|
try {
|
|
39754
|
-
return
|
|
39954
|
+
return fs11.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
39755
39955
|
} catch {
|
|
39756
39956
|
return false;
|
|
39757
39957
|
}
|
|
@@ -39760,7 +39960,7 @@ function detectKtlint(cwd) {
|
|
|
39760
39960
|
}
|
|
39761
39961
|
function detectDotnetFormat(cwd) {
|
|
39762
39962
|
try {
|
|
39763
|
-
const files =
|
|
39963
|
+
const files = fs11.readdirSync(cwd);
|
|
39764
39964
|
const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
|
|
39765
39965
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
39766
39966
|
} catch {
|
|
@@ -39768,14 +39968,14 @@ function detectDotnetFormat(cwd) {
|
|
|
39768
39968
|
}
|
|
39769
39969
|
}
|
|
39770
39970
|
function detectCppcheck(cwd) {
|
|
39771
|
-
if (
|
|
39971
|
+
if (fs11.existsSync(path22.join(cwd, "CMakeLists.txt"))) {
|
|
39772
39972
|
return isCommandAvailable("cppcheck");
|
|
39773
39973
|
}
|
|
39774
39974
|
try {
|
|
39775
|
-
const dirsToCheck = [cwd,
|
|
39975
|
+
const dirsToCheck = [cwd, path22.join(cwd, "src")];
|
|
39776
39976
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
39777
39977
|
try {
|
|
39778
|
-
return
|
|
39978
|
+
return fs11.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
39779
39979
|
} catch {
|
|
39780
39980
|
return false;
|
|
39781
39981
|
}
|
|
@@ -39786,13 +39986,13 @@ function detectCppcheck(cwd) {
|
|
|
39786
39986
|
}
|
|
39787
39987
|
}
|
|
39788
39988
|
function detectSwiftlint(cwd) {
|
|
39789
|
-
return
|
|
39989
|
+
return fs11.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
39790
39990
|
}
|
|
39791
39991
|
function detectDartAnalyze(cwd) {
|
|
39792
|
-
return
|
|
39992
|
+
return fs11.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
39793
39993
|
}
|
|
39794
39994
|
function detectRubocop(cwd) {
|
|
39795
|
-
return (
|
|
39995
|
+
return (fs11.existsSync(path22.join(cwd, "Gemfile")) || fs11.existsSync(path22.join(cwd, "gems.rb")) || fs11.existsSync(path22.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
39796
39996
|
}
|
|
39797
39997
|
function detectAdditionalLinter(cwd) {
|
|
39798
39998
|
if (detectRuff(cwd))
|
|
@@ -39820,10 +40020,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
39820
40020
|
function findBinInAncestors(startDir, binName) {
|
|
39821
40021
|
let dir = startDir;
|
|
39822
40022
|
while (true) {
|
|
39823
|
-
const candidate =
|
|
39824
|
-
if (
|
|
40023
|
+
const candidate = path22.join(dir, "node_modules", ".bin", binName);
|
|
40024
|
+
if (fs11.existsSync(candidate))
|
|
39825
40025
|
return candidate;
|
|
39826
|
-
const parent =
|
|
40026
|
+
const parent = path22.dirname(dir);
|
|
39827
40027
|
if (parent === dir)
|
|
39828
40028
|
break;
|
|
39829
40029
|
dir = parent;
|
|
@@ -39832,11 +40032,11 @@ function findBinInAncestors(startDir, binName) {
|
|
|
39832
40032
|
}
|
|
39833
40033
|
function findBinInEnvPath(binName) {
|
|
39834
40034
|
const searchPath = process.env.PATH ?? "";
|
|
39835
|
-
for (const dir of searchPath.split(
|
|
40035
|
+
for (const dir of searchPath.split(path22.delimiter)) {
|
|
39836
40036
|
if (!dir)
|
|
39837
40037
|
continue;
|
|
39838
|
-
const candidate =
|
|
39839
|
-
if (
|
|
40038
|
+
const candidate = path22.join(dir, binName);
|
|
40039
|
+
if (fs11.existsSync(candidate))
|
|
39840
40040
|
return candidate;
|
|
39841
40041
|
}
|
|
39842
40042
|
return null;
|
|
@@ -39844,17 +40044,17 @@ function findBinInEnvPath(binName) {
|
|
|
39844
40044
|
async function detectAvailableLinter(directory) {
|
|
39845
40045
|
if (!directory)
|
|
39846
40046
|
return null;
|
|
39847
|
-
if (!
|
|
40047
|
+
if (!fs11.existsSync(directory))
|
|
39848
40048
|
return null;
|
|
39849
40049
|
const projectDir = directory;
|
|
39850
40050
|
const isWindows = process.platform === "win32";
|
|
39851
|
-
const biomeBin = isWindows ?
|
|
39852
|
-
const eslintBin = isWindows ?
|
|
40051
|
+
const biomeBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "biome.EXE") : path22.join(projectDir, "node_modules", ".bin", "biome");
|
|
40052
|
+
const eslintBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path22.join(projectDir, "node_modules", ".bin", "eslint");
|
|
39853
40053
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
39854
40054
|
if (localResult)
|
|
39855
40055
|
return localResult;
|
|
39856
|
-
const biomeAncestor = findBinInAncestors(
|
|
39857
|
-
const eslintAncestor = findBinInAncestors(
|
|
40056
|
+
const biomeAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
40057
|
+
const eslintAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
39858
40058
|
if (biomeAncestor || eslintAncestor) {
|
|
39859
40059
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
39860
40060
|
}
|
|
@@ -39877,7 +40077,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
39877
40077
|
const result = await Promise.race([biomeExit, timeout]);
|
|
39878
40078
|
if (result === "timeout") {
|
|
39879
40079
|
biomeProc.kill();
|
|
39880
|
-
} else if (biomeProc.exitCode === 0 &&
|
|
40080
|
+
} else if (biomeProc.exitCode === 0 && fs11.existsSync(biomeBin)) {
|
|
39881
40081
|
return "biome";
|
|
39882
40082
|
}
|
|
39883
40083
|
} catch {}
|
|
@@ -39891,7 +40091,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
39891
40091
|
const result = await Promise.race([eslintExit, timeout]);
|
|
39892
40092
|
if (result === "timeout") {
|
|
39893
40093
|
eslintProc.kill();
|
|
39894
|
-
} else if (eslintProc.exitCode === 0 &&
|
|
40094
|
+
} else if (eslintProc.exitCode === 0 && fs11.existsSync(eslintBin)) {
|
|
39895
40095
|
return "eslint";
|
|
39896
40096
|
}
|
|
39897
40097
|
} catch {}
|
|
@@ -40062,8 +40262,8 @@ For Rust: rustup component add clippy`
|
|
|
40062
40262
|
|
|
40063
40263
|
// src/tools/secretscan.ts
|
|
40064
40264
|
init_zod();
|
|
40065
|
-
import * as
|
|
40066
|
-
import * as
|
|
40265
|
+
import * as fs12 from "fs";
|
|
40266
|
+
import * as path23 from "path";
|
|
40067
40267
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
40068
40268
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
40069
40269
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -40290,11 +40490,11 @@ function isGlobOrPathPattern(pattern) {
|
|
|
40290
40490
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
40291
40491
|
}
|
|
40292
40492
|
function loadSecretScanIgnore(scanDir) {
|
|
40293
|
-
const ignorePath =
|
|
40493
|
+
const ignorePath = path23.join(scanDir, ".secretscanignore");
|
|
40294
40494
|
try {
|
|
40295
|
-
if (!
|
|
40495
|
+
if (!fs12.existsSync(ignorePath))
|
|
40296
40496
|
return [];
|
|
40297
|
-
const content =
|
|
40497
|
+
const content = fs12.readFileSync(ignorePath, "utf8");
|
|
40298
40498
|
const patterns = [];
|
|
40299
40499
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
40300
40500
|
const line = rawLine.trim();
|
|
@@ -40313,7 +40513,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
40313
40513
|
if (exactNames.has(entry))
|
|
40314
40514
|
return true;
|
|
40315
40515
|
for (const pattern of globPatterns) {
|
|
40316
|
-
if (
|
|
40516
|
+
if (path23.matchesGlob(relPath, pattern))
|
|
40317
40517
|
return true;
|
|
40318
40518
|
}
|
|
40319
40519
|
return false;
|
|
@@ -40334,7 +40534,7 @@ function validateDirectoryInput(dir) {
|
|
|
40334
40534
|
return null;
|
|
40335
40535
|
}
|
|
40336
40536
|
function isBinaryFile(filePath, buffer) {
|
|
40337
|
-
const ext =
|
|
40537
|
+
const ext = path23.extname(filePath).toLowerCase();
|
|
40338
40538
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
40339
40539
|
return true;
|
|
40340
40540
|
}
|
|
@@ -40409,11 +40609,11 @@ function createRedactedContext(line, findings) {
|
|
|
40409
40609
|
result += line.slice(lastEnd);
|
|
40410
40610
|
return result;
|
|
40411
40611
|
}
|
|
40412
|
-
var O_NOFOLLOW = process.platform !== "win32" ?
|
|
40612
|
+
var O_NOFOLLOW = process.platform !== "win32" ? fs12.constants.O_NOFOLLOW : undefined;
|
|
40413
40613
|
function scanFileForSecrets(filePath) {
|
|
40414
40614
|
const findings = [];
|
|
40415
40615
|
try {
|
|
40416
|
-
const lstat =
|
|
40616
|
+
const lstat = fs12.lstatSync(filePath);
|
|
40417
40617
|
if (lstat.isSymbolicLink()) {
|
|
40418
40618
|
return findings;
|
|
40419
40619
|
}
|
|
@@ -40422,14 +40622,14 @@ function scanFileForSecrets(filePath) {
|
|
|
40422
40622
|
}
|
|
40423
40623
|
let buffer;
|
|
40424
40624
|
if (O_NOFOLLOW !== undefined) {
|
|
40425
|
-
const fd =
|
|
40625
|
+
const fd = fs12.openSync(filePath, "r", O_NOFOLLOW);
|
|
40426
40626
|
try {
|
|
40427
|
-
buffer =
|
|
40627
|
+
buffer = fs12.readFileSync(fd);
|
|
40428
40628
|
} finally {
|
|
40429
|
-
|
|
40629
|
+
fs12.closeSync(fd);
|
|
40430
40630
|
}
|
|
40431
40631
|
} else {
|
|
40432
|
-
buffer =
|
|
40632
|
+
buffer = fs12.readFileSync(filePath);
|
|
40433
40633
|
}
|
|
40434
40634
|
if (isBinaryFile(filePath, buffer)) {
|
|
40435
40635
|
return findings;
|
|
@@ -40471,9 +40671,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
40471
40671
|
return false;
|
|
40472
40672
|
}
|
|
40473
40673
|
function isPathWithinScope(realPath, scanDir) {
|
|
40474
|
-
const resolvedScanDir =
|
|
40475
|
-
const resolvedRealPath =
|
|
40476
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
40674
|
+
const resolvedScanDir = path23.resolve(scanDir);
|
|
40675
|
+
const resolvedRealPath = path23.resolve(realPath);
|
|
40676
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path23.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
40477
40677
|
}
|
|
40478
40678
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
40479
40679
|
skippedDirs: 0,
|
|
@@ -40484,7 +40684,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40484
40684
|
const files = [];
|
|
40485
40685
|
let entries;
|
|
40486
40686
|
try {
|
|
40487
|
-
entries =
|
|
40687
|
+
entries = fs12.readdirSync(dir);
|
|
40488
40688
|
} catch {
|
|
40489
40689
|
stats.fileErrors++;
|
|
40490
40690
|
return files;
|
|
@@ -40499,15 +40699,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40499
40699
|
return a.localeCompare(b);
|
|
40500
40700
|
});
|
|
40501
40701
|
for (const entry of entries) {
|
|
40502
|
-
const fullPath =
|
|
40503
|
-
const relPath =
|
|
40702
|
+
const fullPath = path23.join(dir, entry);
|
|
40703
|
+
const relPath = path23.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
40504
40704
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
40505
40705
|
stats.skippedDirs++;
|
|
40506
40706
|
continue;
|
|
40507
40707
|
}
|
|
40508
40708
|
let lstat;
|
|
40509
40709
|
try {
|
|
40510
|
-
lstat =
|
|
40710
|
+
lstat = fs12.lstatSync(fullPath);
|
|
40511
40711
|
} catch {
|
|
40512
40712
|
stats.fileErrors++;
|
|
40513
40713
|
continue;
|
|
@@ -40519,7 +40719,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40519
40719
|
if (lstat.isDirectory()) {
|
|
40520
40720
|
let realPath;
|
|
40521
40721
|
try {
|
|
40522
|
-
realPath =
|
|
40722
|
+
realPath = fs12.realpathSync(fullPath);
|
|
40523
40723
|
} catch {
|
|
40524
40724
|
stats.fileErrors++;
|
|
40525
40725
|
continue;
|
|
@@ -40535,7 +40735,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40535
40735
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
40536
40736
|
files.push(...subFiles);
|
|
40537
40737
|
} else if (lstat.isFile()) {
|
|
40538
|
-
const ext =
|
|
40738
|
+
const ext = path23.extname(fullPath).toLowerCase();
|
|
40539
40739
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
40540
40740
|
files.push(fullPath);
|
|
40541
40741
|
} else {
|
|
@@ -40601,15 +40801,15 @@ var secretscan = createSwarmTool({
|
|
|
40601
40801
|
}
|
|
40602
40802
|
}
|
|
40603
40803
|
try {
|
|
40604
|
-
const _scanDirRaw =
|
|
40804
|
+
const _scanDirRaw = path23.resolve(directory);
|
|
40605
40805
|
const scanDir = (() => {
|
|
40606
40806
|
try {
|
|
40607
|
-
return
|
|
40807
|
+
return fs12.realpathSync(_scanDirRaw);
|
|
40608
40808
|
} catch {
|
|
40609
40809
|
return _scanDirRaw;
|
|
40610
40810
|
}
|
|
40611
40811
|
})();
|
|
40612
|
-
if (!
|
|
40812
|
+
if (!fs12.existsSync(scanDir)) {
|
|
40613
40813
|
const errorResult = {
|
|
40614
40814
|
error: "directory not found",
|
|
40615
40815
|
scan_dir: directory,
|
|
@@ -40620,7 +40820,7 @@ var secretscan = createSwarmTool({
|
|
|
40620
40820
|
};
|
|
40621
40821
|
return JSON.stringify(errorResult, null, 2);
|
|
40622
40822
|
}
|
|
40623
|
-
const dirStat =
|
|
40823
|
+
const dirStat = fs12.statSync(scanDir);
|
|
40624
40824
|
if (!dirStat.isDirectory()) {
|
|
40625
40825
|
const errorResult = {
|
|
40626
40826
|
error: "target must be a directory, not a file",
|
|
@@ -40671,7 +40871,7 @@ var secretscan = createSwarmTool({
|
|
|
40671
40871
|
break;
|
|
40672
40872
|
const fileFindings = scanFileForSecrets(filePath);
|
|
40673
40873
|
try {
|
|
40674
|
-
const stat2 =
|
|
40874
|
+
const stat2 = fs12.statSync(filePath);
|
|
40675
40875
|
if (stat2.size > MAX_FILE_SIZE_BYTES) {
|
|
40676
40876
|
skippedFiles++;
|
|
40677
40877
|
continue;
|
|
@@ -40760,12 +40960,12 @@ async function runSecretscan(directory) {
|
|
|
40760
40960
|
|
|
40761
40961
|
// src/tools/test-runner.ts
|
|
40762
40962
|
init_zod();
|
|
40763
|
-
import * as
|
|
40764
|
-
import * as
|
|
40963
|
+
import * as fs16 from "fs";
|
|
40964
|
+
import * as path27 from "path";
|
|
40765
40965
|
|
|
40766
40966
|
// src/test-impact/analyzer.ts
|
|
40767
|
-
import
|
|
40768
|
-
import
|
|
40967
|
+
import fs13 from "fs";
|
|
40968
|
+
import path24 from "path";
|
|
40769
40969
|
var IMPORT_REGEX_ES = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
40770
40970
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
40771
40971
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -40776,7 +40976,7 @@ function normalizePath(p) {
|
|
|
40776
40976
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
40777
40977
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
40778
40978
|
try {
|
|
40779
|
-
const stat2 =
|
|
40979
|
+
const stat2 = fs13.statSync(sourcePath);
|
|
40780
40980
|
if (stat2.mtimeMs > generatedAtMs) {
|
|
40781
40981
|
return true;
|
|
40782
40982
|
}
|
|
@@ -40790,15 +40990,15 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
40790
40990
|
if (!importPath.startsWith(".")) {
|
|
40791
40991
|
return null;
|
|
40792
40992
|
}
|
|
40793
|
-
const resolved =
|
|
40794
|
-
if (
|
|
40795
|
-
if (
|
|
40993
|
+
const resolved = path24.resolve(fromDir, importPath);
|
|
40994
|
+
if (path24.extname(resolved)) {
|
|
40995
|
+
if (fs13.existsSync(resolved) && fs13.statSync(resolved).isFile()) {
|
|
40796
40996
|
return normalizePath(resolved);
|
|
40797
40997
|
}
|
|
40798
40998
|
} else {
|
|
40799
40999
|
for (const ext of EXTENSIONS_TO_TRY) {
|
|
40800
41000
|
const withExt = resolved + ext;
|
|
40801
|
-
if (
|
|
41001
|
+
if (fs13.existsSync(withExt) && fs13.statSync(withExt).isFile()) {
|
|
40802
41002
|
return normalizePath(withExt);
|
|
40803
41003
|
}
|
|
40804
41004
|
}
|
|
@@ -40817,13 +41017,13 @@ function findTestFilesSync(cwd) {
|
|
|
40817
41017
|
function walk(dir, visitedInodes) {
|
|
40818
41018
|
let entries;
|
|
40819
41019
|
try {
|
|
40820
|
-
entries =
|
|
41020
|
+
entries = fs13.readdirSync(dir, { withFileTypes: true });
|
|
40821
41021
|
} catch {
|
|
40822
41022
|
return;
|
|
40823
41023
|
}
|
|
40824
41024
|
let dirInode;
|
|
40825
41025
|
try {
|
|
40826
|
-
dirInode =
|
|
41026
|
+
dirInode = fs13.statSync(dir).ino;
|
|
40827
41027
|
} catch {
|
|
40828
41028
|
return;
|
|
40829
41029
|
}
|
|
@@ -40836,12 +41036,12 @@ function findTestFilesSync(cwd) {
|
|
|
40836
41036
|
for (const entry of entries) {
|
|
40837
41037
|
if (entry.isDirectory()) {
|
|
40838
41038
|
if (!skipDirs.has(entry.name)) {
|
|
40839
|
-
walk(
|
|
41039
|
+
walk(path24.join(dir, entry.name), visitedInodes);
|
|
40840
41040
|
}
|
|
40841
41041
|
} else if (entry.isFile()) {
|
|
40842
41042
|
const name = entry.name;
|
|
40843
41043
|
if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
|
|
40844
|
-
testFiles.push(normalizePath(
|
|
41044
|
+
testFiles.push(normalizePath(path24.join(dir, entry.name)));
|
|
40845
41045
|
}
|
|
40846
41046
|
}
|
|
40847
41047
|
}
|
|
@@ -40871,7 +41071,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
40871
41071
|
for (const testFile of testFiles) {
|
|
40872
41072
|
let content;
|
|
40873
41073
|
try {
|
|
40874
|
-
content =
|
|
41074
|
+
content = fs13.readFileSync(testFile, "utf-8");
|
|
40875
41075
|
} catch {
|
|
40876
41076
|
continue;
|
|
40877
41077
|
}
|
|
@@ -40879,7 +41079,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
40879
41079
|
continue;
|
|
40880
41080
|
}
|
|
40881
41081
|
const imports = extractImports(content);
|
|
40882
|
-
const testDir =
|
|
41082
|
+
const testDir = path24.dirname(testFile);
|
|
40883
41083
|
for (const importPath of imports) {
|
|
40884
41084
|
const resolvedSource = resolveRelativeImport(testDir, importPath);
|
|
40885
41085
|
if (resolvedSource === null) {
|
|
@@ -40901,10 +41101,10 @@ async function buildImpactMap(cwd) {
|
|
|
40901
41101
|
return impactMap;
|
|
40902
41102
|
}
|
|
40903
41103
|
async function loadImpactMap(cwd) {
|
|
40904
|
-
const cachePath =
|
|
40905
|
-
if (
|
|
41104
|
+
const cachePath = path24.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
41105
|
+
if (fs13.existsSync(cachePath)) {
|
|
40906
41106
|
try {
|
|
40907
|
-
const content =
|
|
41107
|
+
const content = fs13.readFileSync(cachePath, "utf-8");
|
|
40908
41108
|
const data = JSON.parse(content);
|
|
40909
41109
|
const map3 = data.map;
|
|
40910
41110
|
const generatedAt = new Date(data.generatedAt).getTime();
|
|
@@ -40916,17 +41116,17 @@ async function loadImpactMap(cwd) {
|
|
|
40916
41116
|
return buildImpactMap(cwd);
|
|
40917
41117
|
}
|
|
40918
41118
|
async function saveImpactMap(cwd, impactMap) {
|
|
40919
|
-
const cacheDir =
|
|
40920
|
-
const cachePath =
|
|
40921
|
-
if (!
|
|
40922
|
-
|
|
41119
|
+
const cacheDir = path24.join(cwd, ".swarm", "cache");
|
|
41120
|
+
const cachePath = path24.join(cacheDir, "impact-map.json");
|
|
41121
|
+
if (!fs13.existsSync(cacheDir)) {
|
|
41122
|
+
fs13.mkdirSync(cacheDir, { recursive: true });
|
|
40923
41123
|
}
|
|
40924
41124
|
const data = {
|
|
40925
41125
|
generatedAt: new Date().toISOString(),
|
|
40926
41126
|
fileCount: Object.keys(impactMap).length,
|
|
40927
41127
|
map: impactMap
|
|
40928
41128
|
};
|
|
40929
|
-
|
|
41129
|
+
fs13.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
40930
41130
|
}
|
|
40931
41131
|
async function analyzeImpact(changedFiles, cwd) {
|
|
40932
41132
|
if (!Array.isArray(changedFiles)) {
|
|
@@ -40943,7 +41143,7 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
40943
41143
|
const impactedTestsSet = new Set;
|
|
40944
41144
|
const untestedFiles = [];
|
|
40945
41145
|
for (const changedFile of validFiles) {
|
|
40946
|
-
const normalizedChanged = normalizePath(
|
|
41146
|
+
const normalizedChanged = normalizePath(path24.resolve(changedFile));
|
|
40947
41147
|
const tests = impactMap[normalizedChanged];
|
|
40948
41148
|
if (tests && tests.length > 0) {
|
|
40949
41149
|
for (const test of tests) {
|
|
@@ -41189,14 +41389,14 @@ function detectFlakyTests(allHistory) {
|
|
|
41189
41389
|
}
|
|
41190
41390
|
|
|
41191
41391
|
// src/test-impact/history-store.ts
|
|
41192
|
-
import
|
|
41193
|
-
import
|
|
41392
|
+
import fs14 from "fs";
|
|
41393
|
+
import path25 from "path";
|
|
41194
41394
|
var MAX_HISTORY_PER_TEST = 20;
|
|
41195
41395
|
var MAX_ERROR_LENGTH = 500;
|
|
41196
41396
|
var MAX_STACK_LENGTH = 200;
|
|
41197
41397
|
var MAX_CHANGED_FILES = 50;
|
|
41198
41398
|
function getHistoryPath(workingDir) {
|
|
41199
|
-
return
|
|
41399
|
+
return path25.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
|
|
41200
41400
|
}
|
|
41201
41401
|
function sanitizeErrorMessage(errorMessage) {
|
|
41202
41402
|
if (errorMessage === undefined) {
|
|
@@ -41256,9 +41456,9 @@ function appendTestRun(record3, workingDir) {
|
|
|
41256
41456
|
changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
|
|
41257
41457
|
};
|
|
41258
41458
|
const historyPath = getHistoryPath(workingDir);
|
|
41259
|
-
const historyDir =
|
|
41260
|
-
if (!
|
|
41261
|
-
|
|
41459
|
+
const historyDir = path25.dirname(historyPath);
|
|
41460
|
+
if (!fs14.existsSync(historyDir)) {
|
|
41461
|
+
fs14.mkdirSync(historyDir, { recursive: true });
|
|
41262
41462
|
}
|
|
41263
41463
|
const existingRecords = readAllRecords(historyPath);
|
|
41264
41464
|
existingRecords.push(sanitizedRecord);
|
|
@@ -41283,24 +41483,24 @@ function appendTestRun(record3, workingDir) {
|
|
|
41283
41483
|
`)}
|
|
41284
41484
|
`;
|
|
41285
41485
|
const tempPath = `${historyPath}.tmp`;
|
|
41286
|
-
|
|
41287
|
-
|
|
41486
|
+
fs14.writeFileSync(tempPath, content, "utf-8");
|
|
41487
|
+
fs14.renameSync(tempPath, historyPath);
|
|
41288
41488
|
} catch (err) {
|
|
41289
41489
|
try {
|
|
41290
41490
|
const tempPath = `${historyPath}.tmp`;
|
|
41291
|
-
if (
|
|
41292
|
-
|
|
41491
|
+
if (fs14.existsSync(tempPath)) {
|
|
41492
|
+
fs14.unlinkSync(tempPath);
|
|
41293
41493
|
}
|
|
41294
41494
|
} catch {}
|
|
41295
41495
|
throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
|
|
41296
41496
|
}
|
|
41297
41497
|
}
|
|
41298
41498
|
function readAllRecords(historyPath) {
|
|
41299
|
-
if (!
|
|
41499
|
+
if (!fs14.existsSync(historyPath)) {
|
|
41300
41500
|
return [];
|
|
41301
41501
|
}
|
|
41302
41502
|
try {
|
|
41303
|
-
const content =
|
|
41503
|
+
const content = fs14.readFileSync(historyPath, "utf-8");
|
|
41304
41504
|
const lines = content.split(`
|
|
41305
41505
|
`);
|
|
41306
41506
|
const records = [];
|
|
@@ -41329,8 +41529,8 @@ function getAllHistory(workingDir) {
|
|
|
41329
41529
|
}
|
|
41330
41530
|
|
|
41331
41531
|
// src/tools/resolve-working-directory.ts
|
|
41332
|
-
import * as
|
|
41333
|
-
import * as
|
|
41532
|
+
import * as fs15 from "fs";
|
|
41533
|
+
import * as path26 from "path";
|
|
41334
41534
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
41335
41535
|
if (workingDirectory == null || workingDirectory === "") {
|
|
41336
41536
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -41350,18 +41550,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
41350
41550
|
};
|
|
41351
41551
|
}
|
|
41352
41552
|
}
|
|
41353
|
-
const normalizedDir =
|
|
41354
|
-
const pathParts = normalizedDir.split(
|
|
41553
|
+
const normalizedDir = path26.normalize(workingDirectory);
|
|
41554
|
+
const pathParts = normalizedDir.split(path26.sep);
|
|
41355
41555
|
if (pathParts.includes("..")) {
|
|
41356
41556
|
return {
|
|
41357
41557
|
success: false,
|
|
41358
41558
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
41359
41559
|
};
|
|
41360
41560
|
}
|
|
41361
|
-
const resolvedDir =
|
|
41561
|
+
const resolvedDir = path26.resolve(normalizedDir);
|
|
41362
41562
|
let statResult;
|
|
41363
41563
|
try {
|
|
41364
|
-
statResult =
|
|
41564
|
+
statResult = fs15.statSync(resolvedDir);
|
|
41365
41565
|
} catch {
|
|
41366
41566
|
return {
|
|
41367
41567
|
success: false,
|
|
@@ -41374,17 +41574,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
41374
41574
|
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
41375
41575
|
};
|
|
41376
41576
|
}
|
|
41377
|
-
const resolvedFallback =
|
|
41577
|
+
const resolvedFallback = path26.resolve(fallbackDirectory);
|
|
41378
41578
|
let fallbackExists = false;
|
|
41379
41579
|
try {
|
|
41380
|
-
|
|
41580
|
+
fs15.statSync(resolvedFallback);
|
|
41381
41581
|
fallbackExists = true;
|
|
41382
41582
|
} catch {
|
|
41383
41583
|
fallbackExists = false;
|
|
41384
41584
|
}
|
|
41385
41585
|
if (workingDirectory != null && workingDirectory !== "") {
|
|
41386
41586
|
if (fallbackExists) {
|
|
41387
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
41587
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path26.sep);
|
|
41388
41588
|
if (isSubdirectory) {
|
|
41389
41589
|
return {
|
|
41390
41590
|
success: false,
|
|
@@ -41474,19 +41674,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
41474
41674
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
41475
41675
|
}
|
|
41476
41676
|
function detectGoTest(cwd) {
|
|
41477
|
-
return
|
|
41677
|
+
return fs16.existsSync(path27.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
41478
41678
|
}
|
|
41479
41679
|
function detectJavaMaven(cwd) {
|
|
41480
|
-
return
|
|
41680
|
+
return fs16.existsSync(path27.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
41481
41681
|
}
|
|
41482
41682
|
function detectGradle(cwd) {
|
|
41483
|
-
const hasBuildFile =
|
|
41484
|
-
const hasGradlew =
|
|
41683
|
+
const hasBuildFile = fs16.existsSync(path27.join(cwd, "build.gradle")) || fs16.existsSync(path27.join(cwd, "build.gradle.kts"));
|
|
41684
|
+
const hasGradlew = fs16.existsSync(path27.join(cwd, "gradlew")) || fs16.existsSync(path27.join(cwd, "gradlew.bat"));
|
|
41485
41685
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
41486
41686
|
}
|
|
41487
41687
|
function detectDotnetTest(cwd) {
|
|
41488
41688
|
try {
|
|
41489
|
-
const files =
|
|
41689
|
+
const files = fs16.readdirSync(cwd);
|
|
41490
41690
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
41491
41691
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
41492
41692
|
} catch {
|
|
@@ -41494,32 +41694,32 @@ function detectDotnetTest(cwd) {
|
|
|
41494
41694
|
}
|
|
41495
41695
|
}
|
|
41496
41696
|
function detectCTest(cwd) {
|
|
41497
|
-
const hasSource =
|
|
41498
|
-
const hasBuildCache =
|
|
41697
|
+
const hasSource = fs16.existsSync(path27.join(cwd, "CMakeLists.txt"));
|
|
41698
|
+
const hasBuildCache = fs16.existsSync(path27.join(cwd, "CMakeCache.txt")) || fs16.existsSync(path27.join(cwd, "build", "CMakeCache.txt"));
|
|
41499
41699
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
41500
41700
|
}
|
|
41501
41701
|
function detectSwiftTest(cwd) {
|
|
41502
|
-
return
|
|
41702
|
+
return fs16.existsSync(path27.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
41503
41703
|
}
|
|
41504
41704
|
function detectDartTest(cwd) {
|
|
41505
|
-
return
|
|
41705
|
+
return fs16.existsSync(path27.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
41506
41706
|
}
|
|
41507
41707
|
function detectRSpec(cwd) {
|
|
41508
|
-
const hasRSpecFile =
|
|
41509
|
-
const hasGemfile =
|
|
41510
|
-
const hasSpecDir =
|
|
41708
|
+
const hasRSpecFile = fs16.existsSync(path27.join(cwd, ".rspec"));
|
|
41709
|
+
const hasGemfile = fs16.existsSync(path27.join(cwd, "Gemfile"));
|
|
41710
|
+
const hasSpecDir = fs16.existsSync(path27.join(cwd, "spec"));
|
|
41511
41711
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
41512
41712
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
41513
41713
|
}
|
|
41514
41714
|
function detectMinitest(cwd) {
|
|
41515
|
-
return
|
|
41715
|
+
return fs16.existsSync(path27.join(cwd, "test")) && (fs16.existsSync(path27.join(cwd, "Gemfile")) || fs16.existsSync(path27.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
41516
41716
|
}
|
|
41517
41717
|
async function detectTestFramework(cwd) {
|
|
41518
41718
|
const baseDir = cwd;
|
|
41519
41719
|
try {
|
|
41520
|
-
const packageJsonPath =
|
|
41521
|
-
if (
|
|
41522
|
-
const content =
|
|
41720
|
+
const packageJsonPath = path27.join(baseDir, "package.json");
|
|
41721
|
+
if (fs16.existsSync(packageJsonPath)) {
|
|
41722
|
+
const content = fs16.readFileSync(packageJsonPath, "utf-8");
|
|
41523
41723
|
const pkg = JSON.parse(content);
|
|
41524
41724
|
const _deps = pkg.dependencies || {};
|
|
41525
41725
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -41538,38 +41738,38 @@ async function detectTestFramework(cwd) {
|
|
|
41538
41738
|
return "jest";
|
|
41539
41739
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
41540
41740
|
return "mocha";
|
|
41541
|
-
if (
|
|
41741
|
+
if (fs16.existsSync(path27.join(baseDir, "bun.lockb")) || fs16.existsSync(path27.join(baseDir, "bun.lock"))) {
|
|
41542
41742
|
if (scripts.test?.includes("bun"))
|
|
41543
41743
|
return "bun";
|
|
41544
41744
|
}
|
|
41545
41745
|
}
|
|
41546
41746
|
} catch {}
|
|
41547
41747
|
try {
|
|
41548
|
-
const pyprojectTomlPath =
|
|
41549
|
-
const setupCfgPath =
|
|
41550
|
-
const requirementsTxtPath =
|
|
41551
|
-
if (
|
|
41552
|
-
const content =
|
|
41748
|
+
const pyprojectTomlPath = path27.join(baseDir, "pyproject.toml");
|
|
41749
|
+
const setupCfgPath = path27.join(baseDir, "setup.cfg");
|
|
41750
|
+
const requirementsTxtPath = path27.join(baseDir, "requirements.txt");
|
|
41751
|
+
if (fs16.existsSync(pyprojectTomlPath)) {
|
|
41752
|
+
const content = fs16.readFileSync(pyprojectTomlPath, "utf-8");
|
|
41553
41753
|
if (content.includes("[tool.pytest"))
|
|
41554
41754
|
return "pytest";
|
|
41555
41755
|
if (content.includes("pytest"))
|
|
41556
41756
|
return "pytest";
|
|
41557
41757
|
}
|
|
41558
|
-
if (
|
|
41559
|
-
const content =
|
|
41758
|
+
if (fs16.existsSync(setupCfgPath)) {
|
|
41759
|
+
const content = fs16.readFileSync(setupCfgPath, "utf-8");
|
|
41560
41760
|
if (content.includes("[pytest]"))
|
|
41561
41761
|
return "pytest";
|
|
41562
41762
|
}
|
|
41563
|
-
if (
|
|
41564
|
-
const content =
|
|
41763
|
+
if (fs16.existsSync(requirementsTxtPath)) {
|
|
41764
|
+
const content = fs16.readFileSync(requirementsTxtPath, "utf-8");
|
|
41565
41765
|
if (content.includes("pytest"))
|
|
41566
41766
|
return "pytest";
|
|
41567
41767
|
}
|
|
41568
41768
|
} catch {}
|
|
41569
41769
|
try {
|
|
41570
|
-
const cargoTomlPath =
|
|
41571
|
-
if (
|
|
41572
|
-
const content =
|
|
41770
|
+
const cargoTomlPath = path27.join(baseDir, "Cargo.toml");
|
|
41771
|
+
if (fs16.existsSync(cargoTomlPath)) {
|
|
41772
|
+
const content = fs16.readFileSync(cargoTomlPath, "utf-8");
|
|
41573
41773
|
if (content.includes("[dev-dependencies]")) {
|
|
41574
41774
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
41575
41775
|
return "cargo";
|
|
@@ -41578,10 +41778,10 @@ async function detectTestFramework(cwd) {
|
|
|
41578
41778
|
}
|
|
41579
41779
|
} catch {}
|
|
41580
41780
|
try {
|
|
41581
|
-
const pesterConfigPath =
|
|
41582
|
-
const pesterConfigJsonPath =
|
|
41583
|
-
const pesterPs1Path =
|
|
41584
|
-
if (
|
|
41781
|
+
const pesterConfigPath = path27.join(baseDir, "pester.config.ps1");
|
|
41782
|
+
const pesterConfigJsonPath = path27.join(baseDir, "pester.config.ps1.json");
|
|
41783
|
+
const pesterPs1Path = path27.join(baseDir, "tests.ps1");
|
|
41784
|
+
if (fs16.existsSync(pesterConfigPath) || fs16.existsSync(pesterConfigJsonPath) || fs16.existsSync(pesterPs1Path)) {
|
|
41585
41785
|
return "pester";
|
|
41586
41786
|
}
|
|
41587
41787
|
} catch {}
|
|
@@ -41623,12 +41823,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
41623
41823
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
41624
41824
|
}
|
|
41625
41825
|
function resolveWorkspacePath(file3, workingDir) {
|
|
41626
|
-
return
|
|
41826
|
+
return path27.isAbsolute(file3) ? path27.resolve(file3) : path27.resolve(workingDir, file3);
|
|
41627
41827
|
}
|
|
41628
41828
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
41629
41829
|
if (!preferRelative)
|
|
41630
41830
|
return absolutePath;
|
|
41631
|
-
return
|
|
41831
|
+
return path27.relative(workingDir, absolutePath);
|
|
41632
41832
|
}
|
|
41633
41833
|
function dedupePush(target, value) {
|
|
41634
41834
|
if (!target.includes(value)) {
|
|
@@ -41665,18 +41865,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
41665
41865
|
}
|
|
41666
41866
|
}
|
|
41667
41867
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
41668
|
-
const relativeDir =
|
|
41868
|
+
const relativeDir = path27.dirname(relativePath);
|
|
41669
41869
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
41670
41870
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
41671
|
-
const rootDir =
|
|
41672
|
-
return nestedRelativeDir ? [rootDir,
|
|
41871
|
+
const rootDir = path27.join(workingDir, dirName);
|
|
41872
|
+
return nestedRelativeDir ? [rootDir, path27.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
41673
41873
|
});
|
|
41674
41874
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
41675
41875
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
41676
|
-
directories.push(
|
|
41876
|
+
directories.push(path27.join(workingDir, "src/test/java", path27.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
41677
41877
|
}
|
|
41678
41878
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
41679
|
-
directories.push(
|
|
41879
|
+
directories.push(path27.join(workingDir, "src/test/kotlin", path27.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
41680
41880
|
}
|
|
41681
41881
|
return [...new Set(directories)];
|
|
41682
41882
|
}
|
|
@@ -41704,23 +41904,23 @@ function isLanguageSpecificTestFile(basename4) {
|
|
|
41704
41904
|
}
|
|
41705
41905
|
function isConventionTestFilePath(filePath) {
|
|
41706
41906
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
41707
|
-
const basename4 =
|
|
41907
|
+
const basename4 = path27.basename(filePath);
|
|
41708
41908
|
return hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || isLanguageSpecificTestFile(basename4) || isTestDirectoryPath(normalizedPath);
|
|
41709
41909
|
}
|
|
41710
41910
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
41711
41911
|
const testFiles = [];
|
|
41712
41912
|
for (const file3 of sourceFiles) {
|
|
41713
41913
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
41714
|
-
const relativeFile =
|
|
41715
|
-
const basename4 =
|
|
41716
|
-
const dirname11 =
|
|
41717
|
-
const preferRelativeOutput = !
|
|
41914
|
+
const relativeFile = path27.relative(workingDir, absoluteFile);
|
|
41915
|
+
const basename4 = path27.basename(absoluteFile);
|
|
41916
|
+
const dirname11 = path27.dirname(absoluteFile);
|
|
41917
|
+
const preferRelativeOutput = !path27.isAbsolute(file3);
|
|
41718
41918
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
41719
41919
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
41720
41920
|
continue;
|
|
41721
41921
|
}
|
|
41722
41922
|
const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
|
|
41723
|
-
const ext =
|
|
41923
|
+
const ext = path27.extname(basename4);
|
|
41724
41924
|
const genericTestNames = [
|
|
41725
41925
|
`${nameWithoutExt}.spec${ext}`,
|
|
41726
41926
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -41729,7 +41929,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
41729
41929
|
const colocatedCandidates = [
|
|
41730
41930
|
...genericTestNames,
|
|
41731
41931
|
...languageSpecificTestNames
|
|
41732
|
-
].map((candidateName) =>
|
|
41932
|
+
].map((candidateName) => path27.join(dirname11, candidateName));
|
|
41733
41933
|
const testDirectoryNames = [
|
|
41734
41934
|
basename4,
|
|
41735
41935
|
...genericTestNames,
|
|
@@ -41738,11 +41938,11 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
41738
41938
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
41739
41939
|
const possibleTestFiles = [
|
|
41740
41940
|
...colocatedCandidates,
|
|
41741
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
41742
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
41941
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path27.join(dirname11, dirName, candidateName))),
|
|
41942
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path27.join(candidateDir, candidateName)))
|
|
41743
41943
|
];
|
|
41744
41944
|
for (const testFile of possibleTestFiles) {
|
|
41745
|
-
if (
|
|
41945
|
+
if (fs16.existsSync(testFile)) {
|
|
41746
41946
|
dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
|
|
41747
41947
|
}
|
|
41748
41948
|
}
|
|
@@ -41759,8 +41959,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41759
41959
|
for (const testFile of candidateTestFiles) {
|
|
41760
41960
|
try {
|
|
41761
41961
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
41762
|
-
const content =
|
|
41763
|
-
const testDir =
|
|
41962
|
+
const content = fs16.readFileSync(absoluteTestFile, "utf-8");
|
|
41963
|
+
const testDir = path27.dirname(absoluteTestFile);
|
|
41764
41964
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
41765
41965
|
let match;
|
|
41766
41966
|
match = importRegex.exec(content);
|
|
@@ -41768,8 +41968,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41768
41968
|
const importPath = match[1];
|
|
41769
41969
|
let resolvedImport;
|
|
41770
41970
|
if (importPath.startsWith(".")) {
|
|
41771
|
-
resolvedImport =
|
|
41772
|
-
const existingExt =
|
|
41971
|
+
resolvedImport = path27.resolve(testDir, importPath);
|
|
41972
|
+
const existingExt = path27.extname(resolvedImport);
|
|
41773
41973
|
if (!existingExt) {
|
|
41774
41974
|
for (const extToTry of [
|
|
41775
41975
|
".ts",
|
|
@@ -41780,7 +41980,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41780
41980
|
".cjs"
|
|
41781
41981
|
]) {
|
|
41782
41982
|
const withExt = resolvedImport + extToTry;
|
|
41783
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
41983
|
+
if (absoluteSourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
|
|
41784
41984
|
resolvedImport = withExt;
|
|
41785
41985
|
break;
|
|
41786
41986
|
}
|
|
@@ -41789,12 +41989,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41789
41989
|
} else {
|
|
41790
41990
|
continue;
|
|
41791
41991
|
}
|
|
41792
|
-
const importBasename =
|
|
41793
|
-
const importDir =
|
|
41992
|
+
const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
|
|
41993
|
+
const importDir = path27.dirname(resolvedImport);
|
|
41794
41994
|
for (const sourceFile of absoluteSourceFiles) {
|
|
41795
|
-
const sourceDir =
|
|
41796
|
-
const sourceBasename =
|
|
41797
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
41995
|
+
const sourceDir = path27.dirname(sourceFile);
|
|
41996
|
+
const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
|
|
41997
|
+
const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
|
|
41798
41998
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
41799
41999
|
dedupePush(testFiles, testFile);
|
|
41800
42000
|
break;
|
|
@@ -41807,8 +42007,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41807
42007
|
while (match !== null) {
|
|
41808
42008
|
const importPath = match[1];
|
|
41809
42009
|
if (importPath.startsWith(".")) {
|
|
41810
|
-
let resolvedImport =
|
|
41811
|
-
const existingExt =
|
|
42010
|
+
let resolvedImport = path27.resolve(testDir, importPath);
|
|
42011
|
+
const existingExt = path27.extname(resolvedImport);
|
|
41812
42012
|
if (!existingExt) {
|
|
41813
42013
|
for (const extToTry of [
|
|
41814
42014
|
".ts",
|
|
@@ -41819,18 +42019,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41819
42019
|
".cjs"
|
|
41820
42020
|
]) {
|
|
41821
42021
|
const withExt = resolvedImport + extToTry;
|
|
41822
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
42022
|
+
if (absoluteSourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
|
|
41823
42023
|
resolvedImport = withExt;
|
|
41824
42024
|
break;
|
|
41825
42025
|
}
|
|
41826
42026
|
}
|
|
41827
42027
|
}
|
|
41828
|
-
const importDir =
|
|
41829
|
-
const importBasename =
|
|
42028
|
+
const importDir = path27.dirname(resolvedImport);
|
|
42029
|
+
const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
|
|
41830
42030
|
for (const sourceFile of absoluteSourceFiles) {
|
|
41831
|
-
const sourceDir =
|
|
41832
|
-
const sourceBasename =
|
|
41833
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
42031
|
+
const sourceDir = path27.dirname(sourceFile);
|
|
42032
|
+
const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
|
|
42033
|
+
const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
|
|
41834
42034
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
41835
42035
|
dedupePush(testFiles, testFile);
|
|
41836
42036
|
break;
|
|
@@ -41933,8 +42133,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
41933
42133
|
return ["mvn", "test"];
|
|
41934
42134
|
case "gradle": {
|
|
41935
42135
|
const isWindows = process.platform === "win32";
|
|
41936
|
-
const hasGradlewBat =
|
|
41937
|
-
const hasGradlew =
|
|
42136
|
+
const hasGradlewBat = fs16.existsSync(path27.join(baseDir, "gradlew.bat"));
|
|
42137
|
+
const hasGradlew = fs16.existsSync(path27.join(baseDir, "gradlew"));
|
|
41938
42138
|
if (hasGradlewBat && isWindows)
|
|
41939
42139
|
return ["gradlew.bat", "test"];
|
|
41940
42140
|
if (hasGradlew)
|
|
@@ -41951,7 +42151,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
41951
42151
|
"cmake-build-release",
|
|
41952
42152
|
"out"
|
|
41953
42153
|
];
|
|
41954
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
42154
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(path27.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
41955
42155
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
41956
42156
|
}
|
|
41957
42157
|
case "swift-test":
|
|
@@ -42579,7 +42779,7 @@ var test_runner = createSwarmTool({
|
|
|
42579
42779
|
const sourceFiles = args.files.filter((file3) => {
|
|
42580
42780
|
if (directTestFiles.includes(file3))
|
|
42581
42781
|
return false;
|
|
42582
|
-
const ext =
|
|
42782
|
+
const ext = path27.extname(file3).toLowerCase();
|
|
42583
42783
|
return SOURCE_EXTENSIONS.has(ext);
|
|
42584
42784
|
});
|
|
42585
42785
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -42614,7 +42814,7 @@ var test_runner = createSwarmTool({
|
|
|
42614
42814
|
if (isConventionTestFilePath(f)) {
|
|
42615
42815
|
return false;
|
|
42616
42816
|
}
|
|
42617
|
-
const ext =
|
|
42817
|
+
const ext = path27.extname(f).toLowerCase();
|
|
42618
42818
|
return SOURCE_EXTENSIONS.has(ext);
|
|
42619
42819
|
});
|
|
42620
42820
|
if (sourceFiles.length === 0) {
|
|
@@ -42641,7 +42841,7 @@ var test_runner = createSwarmTool({
|
|
|
42641
42841
|
if (isConventionTestFilePath(f)) {
|
|
42642
42842
|
return false;
|
|
42643
42843
|
}
|
|
42644
|
-
const ext =
|
|
42844
|
+
const ext = path27.extname(f).toLowerCase();
|
|
42645
42845
|
return SOURCE_EXTENSIONS.has(ext);
|
|
42646
42846
|
});
|
|
42647
42847
|
if (sourceFiles.length === 0) {
|
|
@@ -42659,8 +42859,8 @@ var test_runner = createSwarmTool({
|
|
|
42659
42859
|
const impactResult = await analyzeImpact(sourceFiles, workingDir);
|
|
42660
42860
|
if (impactResult.impactedTests.length > 0) {
|
|
42661
42861
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
42662
|
-
const relativePath =
|
|
42663
|
-
return
|
|
42862
|
+
const relativePath = path27.relative(workingDir, absPath);
|
|
42863
|
+
return path27.isAbsolute(relativePath) ? absPath : relativePath;
|
|
42664
42864
|
});
|
|
42665
42865
|
} else {
|
|
42666
42866
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -42753,8 +42953,8 @@ function validateDirectoryPath(dir) {
|
|
|
42753
42953
|
if (dir.includes("..")) {
|
|
42754
42954
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
42755
42955
|
}
|
|
42756
|
-
const normalized =
|
|
42757
|
-
const absolutePath =
|
|
42956
|
+
const normalized = path28.normalize(dir);
|
|
42957
|
+
const absolutePath = path28.isAbsolute(normalized) ? normalized : path28.resolve(normalized);
|
|
42758
42958
|
return absolutePath;
|
|
42759
42959
|
}
|
|
42760
42960
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -42777,9 +42977,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
42777
42977
|
}
|
|
42778
42978
|
function getPackageVersion(dir) {
|
|
42779
42979
|
try {
|
|
42780
|
-
const packagePath =
|
|
42781
|
-
if (
|
|
42782
|
-
const content =
|
|
42980
|
+
const packagePath = path28.join(dir, "package.json");
|
|
42981
|
+
if (fs17.existsSync(packagePath)) {
|
|
42982
|
+
const content = fs17.readFileSync(packagePath, "utf-8");
|
|
42783
42983
|
const pkg = JSON.parse(content);
|
|
42784
42984
|
return pkg.version ?? null;
|
|
42785
42985
|
}
|
|
@@ -42788,9 +42988,9 @@ function getPackageVersion(dir) {
|
|
|
42788
42988
|
}
|
|
42789
42989
|
function getChangelogVersion(dir) {
|
|
42790
42990
|
try {
|
|
42791
|
-
const changelogPath =
|
|
42792
|
-
if (
|
|
42793
|
-
const content =
|
|
42991
|
+
const changelogPath = path28.join(dir, "CHANGELOG.md");
|
|
42992
|
+
if (fs17.existsSync(changelogPath)) {
|
|
42993
|
+
const content = fs17.readFileSync(changelogPath, "utf-8");
|
|
42794
42994
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
42795
42995
|
if (match) {
|
|
42796
42996
|
return match[1];
|
|
@@ -42802,10 +43002,10 @@ function getChangelogVersion(dir) {
|
|
|
42802
43002
|
function getVersionFileVersion(dir) {
|
|
42803
43003
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
42804
43004
|
for (const file3 of possibleFiles) {
|
|
42805
|
-
const filePath =
|
|
42806
|
-
if (
|
|
43005
|
+
const filePath = path28.join(dir, file3);
|
|
43006
|
+
if (fs17.existsSync(filePath)) {
|
|
42807
43007
|
try {
|
|
42808
|
-
const content =
|
|
43008
|
+
const content = fs17.readFileSync(filePath, "utf-8").trim();
|
|
42809
43009
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
42810
43010
|
if (match) {
|
|
42811
43011
|
return match[1];
|
|
@@ -43129,8 +43329,8 @@ async function runEvidenceCheck(dir) {
|
|
|
43129
43329
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
43130
43330
|
const startTime = Date.now();
|
|
43131
43331
|
try {
|
|
43132
|
-
const specPath =
|
|
43133
|
-
if (!
|
|
43332
|
+
const specPath = path28.join(dir, ".swarm", "spec.md");
|
|
43333
|
+
if (!fs17.existsSync(specPath)) {
|
|
43134
43334
|
return {
|
|
43135
43335
|
type: "req_coverage",
|
|
43136
43336
|
status: "skip",
|
|
@@ -43511,7 +43711,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
43511
43711
|
}
|
|
43512
43712
|
|
|
43513
43713
|
// src/commands/reset.ts
|
|
43514
|
-
import * as
|
|
43714
|
+
import * as fs18 from "fs";
|
|
43515
43715
|
|
|
43516
43716
|
// src/background/manager.ts
|
|
43517
43717
|
init_utils();
|
|
@@ -44212,8 +44412,8 @@ async function handleResetCommand(directory, args) {
|
|
|
44212
44412
|
for (const filename of filesToReset) {
|
|
44213
44413
|
try {
|
|
44214
44414
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
44215
|
-
if (
|
|
44216
|
-
|
|
44415
|
+
if (fs18.existsSync(resolvedPath)) {
|
|
44416
|
+
fs18.unlinkSync(resolvedPath);
|
|
44217
44417
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
44218
44418
|
} else {
|
|
44219
44419
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -44230,8 +44430,8 @@ async function handleResetCommand(directory, args) {
|
|
|
44230
44430
|
}
|
|
44231
44431
|
try {
|
|
44232
44432
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
44233
|
-
if (
|
|
44234
|
-
|
|
44433
|
+
if (fs18.existsSync(summariesPath)) {
|
|
44434
|
+
fs18.rmSync(summariesPath, { recursive: true, force: true });
|
|
44235
44435
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
44236
44436
|
} else {
|
|
44237
44437
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -44251,14 +44451,14 @@ async function handleResetCommand(directory, args) {
|
|
|
44251
44451
|
|
|
44252
44452
|
// src/commands/reset-session.ts
|
|
44253
44453
|
init_utils2();
|
|
44254
|
-
import * as
|
|
44255
|
-
import * as
|
|
44454
|
+
import * as fs19 from "fs";
|
|
44455
|
+
import * as path29 from "path";
|
|
44256
44456
|
async function handleResetSessionCommand(directory, _args) {
|
|
44257
44457
|
const results = [];
|
|
44258
44458
|
try {
|
|
44259
44459
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
44260
|
-
if (
|
|
44261
|
-
|
|
44460
|
+
if (fs19.existsSync(statePath)) {
|
|
44461
|
+
fs19.unlinkSync(statePath);
|
|
44262
44462
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
44263
44463
|
} else {
|
|
44264
44464
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -44267,15 +44467,15 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
44267
44467
|
results.push("\u274C Failed to delete state.json");
|
|
44268
44468
|
}
|
|
44269
44469
|
try {
|
|
44270
|
-
const sessionDir =
|
|
44271
|
-
if (
|
|
44272
|
-
const files =
|
|
44470
|
+
const sessionDir = path29.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
44471
|
+
if (fs19.existsSync(sessionDir)) {
|
|
44472
|
+
const files = fs19.readdirSync(sessionDir);
|
|
44273
44473
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
44274
44474
|
let deletedCount = 0;
|
|
44275
44475
|
for (const file3 of otherFiles) {
|
|
44276
|
-
const filePath =
|
|
44277
|
-
if (
|
|
44278
|
-
|
|
44476
|
+
const filePath = path29.join(sessionDir, file3);
|
|
44477
|
+
if (fs19.lstatSync(filePath).isFile()) {
|
|
44478
|
+
fs19.unlinkSync(filePath);
|
|
44279
44479
|
deletedCount++;
|
|
44280
44480
|
}
|
|
44281
44481
|
}
|
|
@@ -44303,7 +44503,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
44303
44503
|
// src/summaries/manager.ts
|
|
44304
44504
|
init_utils2();
|
|
44305
44505
|
init_utils();
|
|
44306
|
-
import * as
|
|
44506
|
+
import * as path30 from "path";
|
|
44307
44507
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
44308
44508
|
function sanitizeSummaryId(id) {
|
|
44309
44509
|
if (!id || id.length === 0) {
|
|
@@ -44327,7 +44527,7 @@ function sanitizeSummaryId(id) {
|
|
|
44327
44527
|
}
|
|
44328
44528
|
async function loadFullOutput(directory, id) {
|
|
44329
44529
|
const sanitizedId = sanitizeSummaryId(id);
|
|
44330
|
-
const relativePath =
|
|
44530
|
+
const relativePath = path30.join("summaries", `${sanitizedId}.json`);
|
|
44331
44531
|
validateSwarmPath(directory, relativePath);
|
|
44332
44532
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
44333
44533
|
if (content === null) {
|
|
@@ -44379,19 +44579,21 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
44379
44579
|
}
|
|
44380
44580
|
|
|
44381
44581
|
// src/commands/rollback.ts
|
|
44582
|
+
init_plan_schema();
|
|
44382
44583
|
init_utils2();
|
|
44383
|
-
|
|
44384
|
-
import * as
|
|
44584
|
+
init_ledger();
|
|
44585
|
+
import * as fs20 from "fs";
|
|
44586
|
+
import * as path31 from "path";
|
|
44385
44587
|
async function handleRollbackCommand(directory, args) {
|
|
44386
44588
|
const phaseArg = args[0];
|
|
44387
44589
|
if (!phaseArg) {
|
|
44388
44590
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
44389
|
-
if (!
|
|
44591
|
+
if (!fs20.existsSync(manifestPath2)) {
|
|
44390
44592
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
44391
44593
|
}
|
|
44392
44594
|
let manifest2;
|
|
44393
44595
|
try {
|
|
44394
|
-
manifest2 = JSON.parse(
|
|
44596
|
+
manifest2 = JSON.parse(fs20.readFileSync(manifestPath2, "utf-8"));
|
|
44395
44597
|
} catch {
|
|
44396
44598
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
44397
44599
|
}
|
|
@@ -44413,12 +44615,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
44413
44615
|
return "Error: Phase number must be a positive integer.";
|
|
44414
44616
|
}
|
|
44415
44617
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
44416
|
-
if (!
|
|
44618
|
+
if (!fs20.existsSync(manifestPath)) {
|
|
44417
44619
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
44418
44620
|
}
|
|
44419
44621
|
let manifest;
|
|
44420
44622
|
try {
|
|
44421
|
-
manifest = JSON.parse(
|
|
44623
|
+
manifest = JSON.parse(fs20.readFileSync(manifestPath, "utf-8"));
|
|
44422
44624
|
} catch {
|
|
44423
44625
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
44424
44626
|
}
|
|
@@ -44428,28 +44630,69 @@ async function handleRollbackCommand(directory, args) {
|
|
|
44428
44630
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
44429
44631
|
}
|
|
44430
44632
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
44431
|
-
if (!
|
|
44633
|
+
if (!fs20.existsSync(checkpointDir)) {
|
|
44432
44634
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
44433
44635
|
}
|
|
44434
|
-
const checkpointFiles =
|
|
44636
|
+
const checkpointFiles = fs20.readdirSync(checkpointDir);
|
|
44435
44637
|
if (checkpointFiles.length === 0) {
|
|
44436
44638
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
44437
44639
|
}
|
|
44438
44640
|
const swarmDir = validateSwarmPath(directory, "");
|
|
44641
|
+
const EXCLUDE_FILES = new Set([
|
|
44642
|
+
"plan-ledger.jsonl",
|
|
44643
|
+
"plan-ledger.quarantine"
|
|
44644
|
+
]);
|
|
44439
44645
|
const successes = [];
|
|
44440
44646
|
const failures = [];
|
|
44441
44647
|
for (const file3 of checkpointFiles) {
|
|
44442
|
-
|
|
44443
|
-
|
|
44648
|
+
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
44649
|
+
continue;
|
|
44650
|
+
}
|
|
44651
|
+
const src = path31.join(checkpointDir, file3);
|
|
44652
|
+
const dest = path31.join(swarmDir, file3);
|
|
44444
44653
|
try {
|
|
44445
|
-
|
|
44654
|
+
fs20.cpSync(src, dest, { recursive: true, force: true });
|
|
44446
44655
|
successes.push(file3);
|
|
44447
44656
|
} catch (error93) {
|
|
44448
44657
|
failures.push({ file: file3, error: error93.message });
|
|
44449
44658
|
}
|
|
44450
44659
|
}
|
|
44451
44660
|
if (failures.length > 0) {
|
|
44452
|
-
return
|
|
44661
|
+
return [
|
|
44662
|
+
`Rollback partially completed. Successfully restored ${successes.length} files.`,
|
|
44663
|
+
`Failed on ${failures.length} files:`,
|
|
44664
|
+
...failures.map((f) => ` - ${f.file}: ${f.error}`),
|
|
44665
|
+
"",
|
|
44666
|
+
"Some files could not be restored. The .swarm/ directory may be in an inconsistent state.",
|
|
44667
|
+
"Check permissions and disk space, then retry the rollback."
|
|
44668
|
+
].join(`
|
|
44669
|
+
`);
|
|
44670
|
+
}
|
|
44671
|
+
const existingLedgerPath = path31.join(swarmDir, "plan-ledger.jsonl");
|
|
44672
|
+
if (fs20.existsSync(existingLedgerPath)) {
|
|
44673
|
+
fs20.unlinkSync(existingLedgerPath);
|
|
44674
|
+
}
|
|
44675
|
+
try {
|
|
44676
|
+
const planJsonPath = path31.join(swarmDir, "plan.json");
|
|
44677
|
+
if (fs20.existsSync(planJsonPath)) {
|
|
44678
|
+
const planRaw = fs20.readFileSync(planJsonPath, "utf-8");
|
|
44679
|
+
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
44680
|
+
const planId = `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
44681
|
+
const planHash = computePlanHash(plan);
|
|
44682
|
+
await initLedger(directory, planId, planHash, plan);
|
|
44683
|
+
await appendLedgerEvent(directory, {
|
|
44684
|
+
event_type: "plan_rebuilt",
|
|
44685
|
+
source: "rollback",
|
|
44686
|
+
plan_id: planId
|
|
44687
|
+
});
|
|
44688
|
+
}
|
|
44689
|
+
} catch (initError) {
|
|
44690
|
+
return [
|
|
44691
|
+
`Rollback restored files but failed to initialize ledger: ${initError instanceof Error ? initError.message : String(initError)}`,
|
|
44692
|
+
"The .swarm/plan.json has been restored but the ledger may be out of sync.",
|
|
44693
|
+
"Run /swarm reset-session to reinitialize the ledger."
|
|
44694
|
+
].join(`
|
|
44695
|
+
`);
|
|
44453
44696
|
}
|
|
44454
44697
|
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
44455
44698
|
const rollbackEvent = {
|
|
@@ -44459,7 +44702,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
44459
44702
|
timestamp: new Date().toISOString()
|
|
44460
44703
|
};
|
|
44461
44704
|
try {
|
|
44462
|
-
|
|
44705
|
+
fs20.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
44463
44706
|
`);
|
|
44464
44707
|
} catch (error93) {
|
|
44465
44708
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -44502,11 +44745,11 @@ async function handleSimulateCommand(directory, args) {
|
|
|
44502
44745
|
];
|
|
44503
44746
|
const report = reportLines.filter(Boolean).join(`
|
|
44504
44747
|
`);
|
|
44505
|
-
const
|
|
44506
|
-
const
|
|
44507
|
-
const reportPath =
|
|
44508
|
-
await
|
|
44509
|
-
await
|
|
44748
|
+
const fs21 = await import("fs/promises");
|
|
44749
|
+
const path32 = await import("path");
|
|
44750
|
+
const reportPath = path32.join(directory, ".swarm", "simulate-report.md");
|
|
44751
|
+
await fs21.mkdir(path32.dirname(reportPath), { recursive: true });
|
|
44752
|
+
await fs21.writeFile(reportPath, report, "utf-8");
|
|
44510
44753
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
44511
44754
|
}
|
|
44512
44755
|
|
|
@@ -45039,19 +45282,20 @@ function resolveCommand(tokens) {
|
|
|
45039
45282
|
}
|
|
45040
45283
|
|
|
45041
45284
|
// src/cli/index.ts
|
|
45042
|
-
var
|
|
45043
|
-
var
|
|
45044
|
-
var
|
|
45045
|
-
var
|
|
45046
|
-
var
|
|
45285
|
+
var { version: version4 } = package_default;
|
|
45286
|
+
var CONFIG_DIR = path32.join(process.env.XDG_CONFIG_HOME || path32.join(os6.homedir(), ".config"), "opencode");
|
|
45287
|
+
var OPENCODE_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode.json");
|
|
45288
|
+
var PLUGIN_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode-swarm.json");
|
|
45289
|
+
var PROMPTS_DIR = path32.join(CONFIG_DIR, "opencode-swarm");
|
|
45290
|
+
var OPENCODE_PLUGIN_CACHE_PATH = path32.join(process.env.XDG_CACHE_HOME || path32.join(os6.homedir(), ".cache"), "opencode", "packages", "opencode-swarm@latest");
|
|
45047
45291
|
function ensureDir(dir) {
|
|
45048
|
-
if (!
|
|
45049
|
-
|
|
45292
|
+
if (!fs21.existsSync(dir)) {
|
|
45293
|
+
fs21.mkdirSync(dir, { recursive: true });
|
|
45050
45294
|
}
|
|
45051
45295
|
}
|
|
45052
45296
|
function loadJson(filepath) {
|
|
45053
45297
|
try {
|
|
45054
|
-
const content =
|
|
45298
|
+
const content = fs21.readFileSync(filepath, "utf-8");
|
|
45055
45299
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
45056
45300
|
return JSON.parse(stripped);
|
|
45057
45301
|
} catch {
|
|
@@ -45059,15 +45303,31 @@ function loadJson(filepath) {
|
|
|
45059
45303
|
}
|
|
45060
45304
|
}
|
|
45061
45305
|
function saveJson(filepath, data) {
|
|
45062
|
-
|
|
45306
|
+
fs21.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
45063
45307
|
`, "utf-8");
|
|
45064
45308
|
}
|
|
45309
|
+
function writeProjectConfigIfMissing(cwd) {
|
|
45310
|
+
try {
|
|
45311
|
+
const opencodeDir = path32.join(cwd, ".opencode");
|
|
45312
|
+
const projectConfigPath = path32.join(opencodeDir, "opencode-swarm.json");
|
|
45313
|
+
if (fs21.existsSync(projectConfigPath)) {
|
|
45314
|
+
return;
|
|
45315
|
+
}
|
|
45316
|
+
ensureDir(opencodeDir);
|
|
45317
|
+
const starterConfig = { agents: {} };
|
|
45318
|
+
saveJson(projectConfigPath, starterConfig);
|
|
45319
|
+
console.log("\u2713 Created project config at:", projectConfigPath);
|
|
45320
|
+
} catch (error93) {
|
|
45321
|
+
console.warn("\u26A0 Could not create project config \u2014 installation will continue:");
|
|
45322
|
+
console.warn(` ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
45323
|
+
}
|
|
45324
|
+
}
|
|
45065
45325
|
async function install() {
|
|
45066
45326
|
console.log(`\uD83D\uDC1D Installing OpenCode Swarm...
|
|
45067
45327
|
`);
|
|
45068
45328
|
ensureDir(CONFIG_DIR);
|
|
45069
45329
|
ensureDir(PROMPTS_DIR);
|
|
45070
|
-
const LEGACY_CONFIG_PATH =
|
|
45330
|
+
const LEGACY_CONFIG_PATH = path32.join(CONFIG_DIR, "config.json");
|
|
45071
45331
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
45072
45332
|
if (!opencodeConfig) {
|
|
45073
45333
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|
|
@@ -45099,15 +45359,15 @@ async function install() {
|
|
|
45099
45359
|
console.log("\u2713 Added opencode-swarm to OpenCode plugins");
|
|
45100
45360
|
console.log("\u2713 Disabled default OpenCode agents (explore, general)");
|
|
45101
45361
|
try {
|
|
45102
|
-
if (
|
|
45103
|
-
|
|
45362
|
+
if (fs21.existsSync(OPENCODE_PLUGIN_CACHE_PATH)) {
|
|
45363
|
+
fs21.rmSync(OPENCODE_PLUGIN_CACHE_PATH, { recursive: true, force: true });
|
|
45104
45364
|
console.log("\u2713 Cleared opencode plugin cache (next start will fetch latest)");
|
|
45105
45365
|
}
|
|
45106
45366
|
} catch {
|
|
45107
45367
|
console.warn("\u26A0 Could not clear opencode plugin cache \u2014 you may need to delete it manually:");
|
|
45108
45368
|
console.warn(` ${OPENCODE_PLUGIN_CACHE_PATH}`);
|
|
45109
45369
|
}
|
|
45110
|
-
if (!
|
|
45370
|
+
if (!fs21.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
45111
45371
|
const defaultConfig = {
|
|
45112
45372
|
agents: {
|
|
45113
45373
|
coder: {
|
|
@@ -45182,6 +45442,7 @@ async function install() {
|
|
|
45182
45442
|
} else {
|
|
45183
45443
|
console.log("\u2713 Plugin config already exists at:", PLUGIN_CONFIG_PATH);
|
|
45184
45444
|
}
|
|
45445
|
+
writeProjectConfigIfMissing(process.cwd());
|
|
45185
45446
|
console.log(`
|
|
45186
45447
|
\uD83D\uDCC1 Configuration files:`);
|
|
45187
45448
|
console.log(` OpenCode config: ${OPENCODE_CONFIG_PATH}`);
|
|
@@ -45210,7 +45471,7 @@ async function uninstall() {
|
|
|
45210
45471
|
`);
|
|
45211
45472
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
45212
45473
|
if (!opencodeConfig) {
|
|
45213
|
-
if (
|
|
45474
|
+
if (fs21.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
45214
45475
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
45215
45476
|
return 1;
|
|
45216
45477
|
} else {
|
|
@@ -45242,13 +45503,13 @@ async function uninstall() {
|
|
|
45242
45503
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
45243
45504
|
if (process.argv.includes("--clean")) {
|
|
45244
45505
|
let cleaned = false;
|
|
45245
|
-
if (
|
|
45246
|
-
|
|
45506
|
+
if (fs21.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
45507
|
+
fs21.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
45247
45508
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
45248
45509
|
cleaned = true;
|
|
45249
45510
|
}
|
|
45250
|
-
if (
|
|
45251
|
-
|
|
45511
|
+
if (fs21.existsSync(PROMPTS_DIR)) {
|
|
45512
|
+
fs21.rmSync(PROMPTS_DIR, { recursive: true });
|
|
45252
45513
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
45253
45514
|
cleaned = true;
|
|
45254
45515
|
}
|
|
@@ -45311,6 +45572,10 @@ Examples:
|
|
|
45311
45572
|
}
|
|
45312
45573
|
async function main() {
|
|
45313
45574
|
const args = process.argv.slice(2);
|
|
45575
|
+
if (args.includes("-v") || args.includes("--version")) {
|
|
45576
|
+
console.log(`opencode-swarm ${version4}`);
|
|
45577
|
+
process.exit(0);
|
|
45578
|
+
}
|
|
45314
45579
|
if (args.includes("-h") || args.includes("--help")) {
|
|
45315
45580
|
printHelp();
|
|
45316
45581
|
process.exit(0);
|