opencode-swarm 6.86.5 → 6.86.7
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 +686 -512
- package/dist/config/schema.d.ts +3 -0
- package/dist/council/types.d.ts +5 -1
- package/dist/db/qa-gate-profile.d.ts +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1320 -1057
- package/dist/services/diagnose-service.d.ts +1 -1
- package/dist/services/warning-buffer.d.ts +9 -0
- package/dist/state.d.ts +16 -3
- package/dist/tools/convene-council.d.ts +10 -5
- package/dist/tools/declare-council-criteria.d.ts +1 -1
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/tool-names.d.ts +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -17668,15 +17668,15 @@ __export(exports_config_doctor, {
|
|
|
17668
17668
|
applySafeAutoFixes: () => applySafeAutoFixes
|
|
17669
17669
|
});
|
|
17670
17670
|
import * as crypto3 from "crypto";
|
|
17671
|
-
import * as
|
|
17671
|
+
import * as fs8 from "fs";
|
|
17672
17672
|
import * as os5 from "os";
|
|
17673
|
-
import * as
|
|
17673
|
+
import * as path18 from "path";
|
|
17674
17674
|
function getUserConfigDir3() {
|
|
17675
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
17675
|
+
return process.env.XDG_CONFIG_HOME || path18.join(os5.homedir(), ".config");
|
|
17676
17676
|
}
|
|
17677
17677
|
function getConfigPaths(directory) {
|
|
17678
|
-
const userConfigPath =
|
|
17679
|
-
const projectConfigPath =
|
|
17678
|
+
const userConfigPath = path18.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
|
|
17679
|
+
const projectConfigPath = path18.join(directory, ".opencode", "opencode-swarm.json");
|
|
17680
17680
|
return { userConfigPath, projectConfigPath };
|
|
17681
17681
|
}
|
|
17682
17682
|
function computeHash(content) {
|
|
@@ -17701,9 +17701,9 @@ function isValidConfigPath(configPath, directory) {
|
|
|
17701
17701
|
const normalizedUser = userConfigPath.replace(/\\/g, "/");
|
|
17702
17702
|
const normalizedProject = projectConfigPath.replace(/\\/g, "/");
|
|
17703
17703
|
try {
|
|
17704
|
-
const resolvedConfig =
|
|
17705
|
-
const resolvedUser =
|
|
17706
|
-
const resolvedProject =
|
|
17704
|
+
const resolvedConfig = path18.resolve(configPath);
|
|
17705
|
+
const resolvedUser = path18.resolve(normalizedUser);
|
|
17706
|
+
const resolvedProject = path18.resolve(normalizedProject);
|
|
17707
17707
|
return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
|
|
17708
17708
|
} catch {
|
|
17709
17709
|
return false;
|
|
@@ -17713,19 +17713,19 @@ function createConfigBackup(directory) {
|
|
|
17713
17713
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
17714
17714
|
let configPath = projectConfigPath;
|
|
17715
17715
|
let content = null;
|
|
17716
|
-
if (
|
|
17716
|
+
if (fs8.existsSync(projectConfigPath)) {
|
|
17717
17717
|
try {
|
|
17718
|
-
content =
|
|
17718
|
+
content = fs8.readFileSync(projectConfigPath, "utf-8");
|
|
17719
17719
|
} catch (error93) {
|
|
17720
17720
|
log("[ConfigDoctor] project config read failed", {
|
|
17721
17721
|
error: error93 instanceof Error ? error93.message : String(error93)
|
|
17722
17722
|
});
|
|
17723
17723
|
}
|
|
17724
17724
|
}
|
|
17725
|
-
if (content === null &&
|
|
17725
|
+
if (content === null && fs8.existsSync(userConfigPath)) {
|
|
17726
17726
|
configPath = userConfigPath;
|
|
17727
17727
|
try {
|
|
17728
|
-
content =
|
|
17728
|
+
content = fs8.readFileSync(userConfigPath, "utf-8");
|
|
17729
17729
|
} catch (error93) {
|
|
17730
17730
|
log("[ConfigDoctor] user config read failed", {
|
|
17731
17731
|
error: error93 instanceof Error ? error93.message : String(error93)
|
|
@@ -17743,12 +17743,12 @@ function createConfigBackup(directory) {
|
|
|
17743
17743
|
};
|
|
17744
17744
|
}
|
|
17745
17745
|
function writeBackupArtifact(directory, backup) {
|
|
17746
|
-
const swarmDir =
|
|
17747
|
-
if (!
|
|
17748
|
-
|
|
17746
|
+
const swarmDir = path18.join(directory, ".swarm");
|
|
17747
|
+
if (!fs8.existsSync(swarmDir)) {
|
|
17748
|
+
fs8.mkdirSync(swarmDir, { recursive: true });
|
|
17749
17749
|
}
|
|
17750
17750
|
const backupFilename = `config-backup-${backup.createdAt}.json`;
|
|
17751
|
-
const backupPath =
|
|
17751
|
+
const backupPath = path18.join(swarmDir, backupFilename);
|
|
17752
17752
|
const artifact = {
|
|
17753
17753
|
createdAt: backup.createdAt,
|
|
17754
17754
|
configPath: backup.configPath,
|
|
@@ -17756,15 +17756,15 @@ function writeBackupArtifact(directory, backup) {
|
|
|
17756
17756
|
content: backup.content,
|
|
17757
17757
|
preview: backup.content.substring(0, 500) + (backup.content.length > 500 ? "..." : "")
|
|
17758
17758
|
};
|
|
17759
|
-
|
|
17759
|
+
fs8.writeFileSync(backupPath, JSON.stringify(artifact, null, 2), "utf-8");
|
|
17760
17760
|
return backupPath;
|
|
17761
17761
|
}
|
|
17762
17762
|
function restoreFromBackup(backupPath, directory) {
|
|
17763
|
-
if (!
|
|
17763
|
+
if (!fs8.existsSync(backupPath)) {
|
|
17764
17764
|
return null;
|
|
17765
17765
|
}
|
|
17766
17766
|
try {
|
|
17767
|
-
const artifact = JSON.parse(
|
|
17767
|
+
const artifact = JSON.parse(fs8.readFileSync(backupPath, "utf-8"));
|
|
17768
17768
|
if (!artifact.content || !artifact.configPath || !artifact.contentHash) {
|
|
17769
17769
|
return null;
|
|
17770
17770
|
}
|
|
@@ -17778,11 +17778,11 @@ function restoreFromBackup(backupPath, directory) {
|
|
|
17778
17778
|
return null;
|
|
17779
17779
|
}
|
|
17780
17780
|
const targetPath = artifact.configPath;
|
|
17781
|
-
const targetDir =
|
|
17782
|
-
if (!
|
|
17783
|
-
|
|
17781
|
+
const targetDir = path18.dirname(targetPath);
|
|
17782
|
+
if (!fs8.existsSync(targetDir)) {
|
|
17783
|
+
fs8.mkdirSync(targetDir, { recursive: true });
|
|
17784
17784
|
}
|
|
17785
|
-
|
|
17785
|
+
fs8.writeFileSync(targetPath, artifact.content, "utf-8");
|
|
17786
17786
|
return targetPath;
|
|
17787
17787
|
} catch {
|
|
17788
17788
|
return null;
|
|
@@ -17792,12 +17792,12 @@ function readConfigFromFile(directory) {
|
|
|
17792
17792
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
17793
17793
|
let configPath = projectConfigPath;
|
|
17794
17794
|
let configContent = null;
|
|
17795
|
-
if (
|
|
17795
|
+
if (fs8.existsSync(projectConfigPath)) {
|
|
17796
17796
|
configPath = projectConfigPath;
|
|
17797
|
-
configContent =
|
|
17798
|
-
} else if (
|
|
17797
|
+
configContent = fs8.readFileSync(projectConfigPath, "utf-8");
|
|
17798
|
+
} else if (fs8.existsSync(userConfigPath)) {
|
|
17799
17799
|
configPath = userConfigPath;
|
|
17800
|
-
configContent =
|
|
17800
|
+
configContent = fs8.readFileSync(userConfigPath, "utf-8");
|
|
17801
17801
|
}
|
|
17802
17802
|
if (configContent === null) {
|
|
17803
17803
|
return null;
|
|
@@ -17809,9 +17809,9 @@ function readConfigFromFile(directory) {
|
|
|
17809
17809
|
return null;
|
|
17810
17810
|
}
|
|
17811
17811
|
}
|
|
17812
|
-
function validateConfigKey(
|
|
17812
|
+
function validateConfigKey(path19, value, _config) {
|
|
17813
17813
|
const findings = [];
|
|
17814
|
-
switch (
|
|
17814
|
+
switch (path19) {
|
|
17815
17815
|
case "agents": {
|
|
17816
17816
|
if (value !== undefined) {
|
|
17817
17817
|
findings.push({
|
|
@@ -18058,27 +18058,27 @@ function validateConfigKey(path20, value, _config) {
|
|
|
18058
18058
|
}
|
|
18059
18059
|
return findings;
|
|
18060
18060
|
}
|
|
18061
|
-
function walkConfigAndValidate(obj,
|
|
18061
|
+
function walkConfigAndValidate(obj, path19, config3, findings) {
|
|
18062
18062
|
if (obj === null || obj === undefined) {
|
|
18063
18063
|
return;
|
|
18064
18064
|
}
|
|
18065
|
-
if (
|
|
18066
|
-
const keyFindings = validateConfigKey(
|
|
18065
|
+
if (path19 && typeof obj === "object" && !Array.isArray(obj)) {
|
|
18066
|
+
const keyFindings = validateConfigKey(path19, obj, config3);
|
|
18067
18067
|
findings.push(...keyFindings);
|
|
18068
18068
|
}
|
|
18069
18069
|
if (typeof obj !== "object") {
|
|
18070
|
-
const keyFindings = validateConfigKey(
|
|
18070
|
+
const keyFindings = validateConfigKey(path19, obj, config3);
|
|
18071
18071
|
findings.push(...keyFindings);
|
|
18072
18072
|
return;
|
|
18073
18073
|
}
|
|
18074
18074
|
if (Array.isArray(obj)) {
|
|
18075
18075
|
obj.forEach((item, index) => {
|
|
18076
|
-
walkConfigAndValidate(item, `${
|
|
18076
|
+
walkConfigAndValidate(item, `${path19}[${index}]`, config3, findings);
|
|
18077
18077
|
});
|
|
18078
18078
|
return;
|
|
18079
18079
|
}
|
|
18080
18080
|
for (const [key, value] of Object.entries(obj)) {
|
|
18081
|
-
const newPath =
|
|
18081
|
+
const newPath = path19 ? `${path19}.${key}` : key;
|
|
18082
18082
|
walkConfigAndValidate(value, newPath, config3, findings);
|
|
18083
18083
|
}
|
|
18084
18084
|
}
|
|
@@ -18093,9 +18093,9 @@ function runConfigDoctor(config3, directory) {
|
|
|
18093
18093
|
const hasAutoFixableIssues = findings.some((f) => f.autoFixable && f.proposedFix?.risk === "low");
|
|
18094
18094
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
18095
18095
|
let configSource = "defaults";
|
|
18096
|
-
if (
|
|
18096
|
+
if (fs8.existsSync(projectConfigPath)) {
|
|
18097
18097
|
configSource = projectConfigPath;
|
|
18098
|
-
} else if (
|
|
18098
|
+
} else if (fs8.existsSync(userConfigPath)) {
|
|
18099
18099
|
configSource = userConfigPath;
|
|
18100
18100
|
}
|
|
18101
18101
|
return {
|
|
@@ -18124,12 +18124,12 @@ function applySafeAutoFixes(directory, result) {
|
|
|
18124
18124
|
const { userConfigPath, projectConfigPath } = getConfigPaths(directory);
|
|
18125
18125
|
let configPath = projectConfigPath;
|
|
18126
18126
|
let configContent;
|
|
18127
|
-
if (
|
|
18127
|
+
if (fs8.existsSync(projectConfigPath)) {
|
|
18128
18128
|
configPath = projectConfigPath;
|
|
18129
|
-
configContent =
|
|
18130
|
-
} else if (
|
|
18129
|
+
configContent = fs8.readFileSync(projectConfigPath, "utf-8");
|
|
18130
|
+
} else if (fs8.existsSync(userConfigPath)) {
|
|
18131
18131
|
configPath = userConfigPath;
|
|
18132
|
-
configContent =
|
|
18132
|
+
configContent = fs8.readFileSync(userConfigPath, "utf-8");
|
|
18133
18133
|
} else {
|
|
18134
18134
|
return { appliedFixes, updatedConfigPath: null };
|
|
18135
18135
|
}
|
|
@@ -18198,22 +18198,22 @@ function applySafeAutoFixes(directory, result) {
|
|
|
18198
18198
|
}
|
|
18199
18199
|
}
|
|
18200
18200
|
if (appliedFixes.length > 0) {
|
|
18201
|
-
const configDir =
|
|
18202
|
-
if (!
|
|
18203
|
-
|
|
18201
|
+
const configDir = path18.dirname(configPath);
|
|
18202
|
+
if (!fs8.existsSync(configDir)) {
|
|
18203
|
+
fs8.mkdirSync(configDir, { recursive: true });
|
|
18204
18204
|
}
|
|
18205
|
-
|
|
18205
|
+
fs8.writeFileSync(configPath, JSON.stringify(config3, null, 2), "utf-8");
|
|
18206
18206
|
updatedConfigPath = configPath;
|
|
18207
18207
|
}
|
|
18208
18208
|
return { appliedFixes, updatedConfigPath };
|
|
18209
18209
|
}
|
|
18210
18210
|
function writeDoctorArtifact(directory, result) {
|
|
18211
|
-
const swarmDir =
|
|
18212
|
-
if (!
|
|
18213
|
-
|
|
18211
|
+
const swarmDir = path18.join(directory, ".swarm");
|
|
18212
|
+
if (!fs8.existsSync(swarmDir)) {
|
|
18213
|
+
fs8.mkdirSync(swarmDir, { recursive: true });
|
|
18214
18214
|
}
|
|
18215
18215
|
const artifactFilename = "config-doctor.json";
|
|
18216
|
-
const artifactPath =
|
|
18216
|
+
const artifactPath = path18.join(swarmDir, artifactFilename);
|
|
18217
18217
|
const guiOutput = {
|
|
18218
18218
|
timestamp: result.timestamp,
|
|
18219
18219
|
summary: result.summary,
|
|
@@ -18234,7 +18234,7 @@ function writeDoctorArtifact(directory, result) {
|
|
|
18234
18234
|
} : null
|
|
18235
18235
|
}))
|
|
18236
18236
|
};
|
|
18237
|
-
|
|
18237
|
+
fs8.writeFileSync(artifactPath, JSON.stringify(guiOutput, null, 2), "utf-8");
|
|
18238
18238
|
return artifactPath;
|
|
18239
18239
|
}
|
|
18240
18240
|
function shouldRunOnStartup(automationConfig) {
|
|
@@ -18574,9 +18574,78 @@ var init_evidence_summary_service = __esm(() => {
|
|
|
18574
18574
|
});
|
|
18575
18575
|
|
|
18576
18576
|
// src/cli/index.ts
|
|
18577
|
-
import * as
|
|
18577
|
+
import * as fs21 from "fs";
|
|
18578
18578
|
import * as os6 from "os";
|
|
18579
|
-
import * as
|
|
18579
|
+
import * as path32 from "path";
|
|
18580
|
+
// package.json
|
|
18581
|
+
var package_default = {
|
|
18582
|
+
name: "opencode-swarm",
|
|
18583
|
+
version: "6.86.7",
|
|
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
|
+
};
|
|
18580
18649
|
|
|
18581
18650
|
// src/commands/acknowledge-spec-drift.ts
|
|
18582
18651
|
init_utils2();
|
|
@@ -18653,71 +18722,6 @@ ${warnings.map((w) => ` - ${w}`).join(`
|
|
|
18653
18722
|
return baseMessage + warningMessage + cautionMessage;
|
|
18654
18723
|
}
|
|
18655
18724
|
|
|
18656
|
-
// src/commands/agents.ts
|
|
18657
|
-
function handleAgentsCommand(agents, guardrails) {
|
|
18658
|
-
const entries = Object.entries(agents);
|
|
18659
|
-
if (entries.length === 0) {
|
|
18660
|
-
return "No agents registered.";
|
|
18661
|
-
}
|
|
18662
|
-
const lines = [`## Registered Agents (${entries.length} total)`, ""];
|
|
18663
|
-
for (const [key, agent] of entries) {
|
|
18664
|
-
const model = agent.config.model || "default";
|
|
18665
|
-
const temp = agent.config.temperature !== undefined ? agent.config.temperature.toString() : "default";
|
|
18666
|
-
const tools = agent.config.tools || {};
|
|
18667
|
-
const isReadOnly = tools.write === false || tools.edit === false;
|
|
18668
|
-
const access = isReadOnly ? "\uD83D\uDD12 read-only" : "\u270F\uFE0F read-write";
|
|
18669
|
-
const desc = agent.description || agent.config.description || "";
|
|
18670
|
-
const hasCustomProfile = guardrails?.profiles?.[key] !== undefined;
|
|
18671
|
-
const profileIndicator = hasCustomProfile ? " | \u26A1 custom limits" : "";
|
|
18672
|
-
lines.push(`- **${key}** | model: \`${model}\` | temp: ${temp} | ${access}${profileIndicator}`);
|
|
18673
|
-
if (desc) {
|
|
18674
|
-
lines.push(` ${desc}`);
|
|
18675
|
-
}
|
|
18676
|
-
}
|
|
18677
|
-
if (guardrails?.profiles && Object.keys(guardrails.profiles).length > 0) {
|
|
18678
|
-
lines.push("", "### Guardrail Profiles", "");
|
|
18679
|
-
for (const [profileName, profile] of Object.entries(guardrails.profiles)) {
|
|
18680
|
-
const overrides = [];
|
|
18681
|
-
if (profile.max_tool_calls !== undefined) {
|
|
18682
|
-
overrides.push(`max_tool_calls=${profile.max_tool_calls}`);
|
|
18683
|
-
}
|
|
18684
|
-
if (profile.max_duration_minutes !== undefined) {
|
|
18685
|
-
overrides.push(`max_duration_minutes=${profile.max_duration_minutes}`);
|
|
18686
|
-
}
|
|
18687
|
-
if (profile.max_repetitions !== undefined) {
|
|
18688
|
-
overrides.push(`max_repetitions=${profile.max_repetitions}`);
|
|
18689
|
-
}
|
|
18690
|
-
if (profile.max_consecutive_errors !== undefined) {
|
|
18691
|
-
overrides.push(`max_consecutive_errors=${profile.max_consecutive_errors}`);
|
|
18692
|
-
}
|
|
18693
|
-
if (profile.warning_threshold !== undefined) {
|
|
18694
|
-
overrides.push(`warning_threshold=${profile.warning_threshold}`);
|
|
18695
|
-
}
|
|
18696
|
-
const overrideStr = overrides.length > 0 ? overrides.join(", ") : "no overrides";
|
|
18697
|
-
lines.push(`- **${profileName}**: ${overrideStr}`);
|
|
18698
|
-
}
|
|
18699
|
-
}
|
|
18700
|
-
return lines.join(`
|
|
18701
|
-
`);
|
|
18702
|
-
}
|
|
18703
|
-
|
|
18704
|
-
// src/commands/analyze.ts
|
|
18705
|
-
async function handleAnalyzeCommand(_directory, args) {
|
|
18706
|
-
const description = args.join(" ").trim();
|
|
18707
|
-
if (description) {
|
|
18708
|
-
return `[MODE: ANALYZE] ${description}`;
|
|
18709
|
-
}
|
|
18710
|
-
return "[MODE: ANALYZE] Please analyze the spec against the plan using MODE: ANALYZE.";
|
|
18711
|
-
}
|
|
18712
|
-
|
|
18713
|
-
// src/config/loader.ts
|
|
18714
|
-
import * as fs2 from "fs";
|
|
18715
|
-
import * as os2 from "os";
|
|
18716
|
-
import * as path4 from "path";
|
|
18717
|
-
|
|
18718
|
-
// src/config/schema.ts
|
|
18719
|
-
init_zod();
|
|
18720
|
-
|
|
18721
18725
|
// src/tools/tool-names.ts
|
|
18722
18726
|
var TOOL_NAMES = [
|
|
18723
18727
|
"diff",
|
|
@@ -18738,7 +18742,7 @@ var TOOL_NAMES = [
|
|
|
18738
18742
|
"evidence_check",
|
|
18739
18743
|
"check_gate_status",
|
|
18740
18744
|
"completion_verify",
|
|
18741
|
-
"
|
|
18745
|
+
"submit_council_verdicts",
|
|
18742
18746
|
"declare_council_criteria",
|
|
18743
18747
|
"sbom_generate",
|
|
18744
18748
|
"checkpoint",
|
|
@@ -18818,7 +18822,7 @@ var AGENT_TOOL_MAP = {
|
|
|
18818
18822
|
"check_gate_status",
|
|
18819
18823
|
"completion_verify",
|
|
18820
18824
|
"complexity_hotspots",
|
|
18821
|
-
"
|
|
18825
|
+
"submit_council_verdicts",
|
|
18822
18826
|
"declare_council_criteria",
|
|
18823
18827
|
"detect_domains",
|
|
18824
18828
|
"evidence_check",
|
|
@@ -19030,6 +19034,57 @@ for (const [agentName, tools] of Object.entries(AGENT_TOOL_MAP)) {
|
|
|
19030
19034
|
}
|
|
19031
19035
|
|
|
19032
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
|
+
}
|
|
19033
19088
|
var AgentOverrideConfigSchema = exports_external.object({
|
|
19034
19089
|
model: exports_external.string().optional(),
|
|
19035
19090
|
variant: exports_external.string().min(1).optional(),
|
|
@@ -19569,7 +19624,8 @@ var CouncilConfigSchema = exports_external.object({
|
|
|
19569
19624
|
maxRounds: exports_external.number().int().min(1).max(10).default(3),
|
|
19570
19625
|
parallelTimeoutMs: exports_external.number().int().min(5000).max(120000).default(30000),
|
|
19571
19626
|
vetoPriority: exports_external.boolean().default(true),
|
|
19572
|
-
requireAllMembers: exports_external.boolean().default(false).describe("When true,
|
|
19627
|
+
requireAllMembers: exports_external.boolean().default(false).describe("When true, submit_council_verdicts rejects if fewer than 5 member verdicts are provided. Equivalent to minimumMembers: 5."),
|
|
19628
|
+
minimumMembers: exports_external.number().int().min(1).max(5).default(3).describe("Minimum distinct council member verdicts required for synthesis. Default 3. Set to 1 to disable quorum enforcement. requireAllMembers: true overrides this to 5 (stricter constraint wins)."),
|
|
19573
19629
|
escalateOnMaxRounds: exports_external.string().optional().describe("Optional webhook URL or handler name invoked when maxRounds is reached without APPROVE. Declared for forward compatibility; no behavior is implemented yet."),
|
|
19574
19630
|
general: GeneralCouncilConfigSchema.optional()
|
|
19575
19631
|
}).strict();
|
|
@@ -19634,6 +19690,7 @@ var PluginConfigSchema = exports_external.object({
|
|
|
19634
19690
|
council: CouncilConfigSchema.optional(),
|
|
19635
19691
|
parallelization: ParallelizationConfigSchema.optional(),
|
|
19636
19692
|
turbo_mode: exports_external.boolean().default(false).optional(),
|
|
19693
|
+
quiet: exports_external.boolean().default(false).optional(),
|
|
19637
19694
|
full_auto: exports_external.object({
|
|
19638
19695
|
enabled: exports_external.boolean().default(false),
|
|
19639
19696
|
critic_model: exports_external.string().optional(),
|
|
@@ -19648,7 +19705,78 @@ var PluginConfigSchema = exports_external.object({
|
|
|
19648
19705
|
})
|
|
19649
19706
|
});
|
|
19650
19707
|
|
|
19708
|
+
// src/commands/agents.ts
|
|
19709
|
+
function handleAgentsCommand(agents, guardrails) {
|
|
19710
|
+
const entries = Object.entries(agents);
|
|
19711
|
+
if (entries.length === 0) {
|
|
19712
|
+
return "No agents registered.";
|
|
19713
|
+
}
|
|
19714
|
+
const allAgentKeys = entries.map(([key]) => key);
|
|
19715
|
+
const registeredBaseNames = allAgentKeys.map((key) => stripKnownSwarmPrefix(key)).filter((stripped) => ALL_SUBAGENT_NAMES.includes(stripped));
|
|
19716
|
+
const unregistered = ALL_SUBAGENT_NAMES.filter((name) => !registeredBaseNames.includes(name));
|
|
19717
|
+
const hasUnregistered = unregistered.length > 0;
|
|
19718
|
+
const headerLabel = hasUnregistered ? `${entries.length} registered + ${unregistered.length} unregistered` : `${entries.length} total`;
|
|
19719
|
+
const lines = [`## Registered Agents (${headerLabel})`, ""];
|
|
19720
|
+
for (const [key, agent] of entries) {
|
|
19721
|
+
const model = agent.config.model || "default";
|
|
19722
|
+
const temp = agent.config.temperature !== undefined ? agent.config.temperature.toString() : "default";
|
|
19723
|
+
const tools = agent.config.tools || {};
|
|
19724
|
+
const isReadOnly = tools.write === false || tools.edit === false;
|
|
19725
|
+
const access = isReadOnly ? "\uD83D\uDD12 read-only" : "\u270F\uFE0F read-write";
|
|
19726
|
+
const desc = agent.description || agent.config.description || "";
|
|
19727
|
+
const hasCustomProfile = guardrails?.profiles?.[key] !== undefined;
|
|
19728
|
+
const profileIndicator = hasCustomProfile ? " | \u26A1 custom limits" : "";
|
|
19729
|
+
lines.push(`- **${key}** | model: \`${model}\` | temp: ${temp} | ${access}${profileIndicator}`);
|
|
19730
|
+
if (desc) {
|
|
19731
|
+
lines.push(` ${desc}`);
|
|
19732
|
+
}
|
|
19733
|
+
}
|
|
19734
|
+
if (hasUnregistered) {
|
|
19735
|
+
lines.push("", "### Unregistered Subagents");
|
|
19736
|
+
for (const name of unregistered) {
|
|
19737
|
+
lines.push(`- **${name}** (requires configuration)`);
|
|
19738
|
+
}
|
|
19739
|
+
}
|
|
19740
|
+
if (guardrails?.profiles && Object.keys(guardrails.profiles).length > 0) {
|
|
19741
|
+
lines.push("", "### Guardrail Profiles", "");
|
|
19742
|
+
for (const [profileName, profile] of Object.entries(guardrails.profiles)) {
|
|
19743
|
+
const overrides = [];
|
|
19744
|
+
if (profile.max_tool_calls !== undefined) {
|
|
19745
|
+
overrides.push(`max_tool_calls=${profile.max_tool_calls}`);
|
|
19746
|
+
}
|
|
19747
|
+
if (profile.max_duration_minutes !== undefined) {
|
|
19748
|
+
overrides.push(`max_duration_minutes=${profile.max_duration_minutes}`);
|
|
19749
|
+
}
|
|
19750
|
+
if (profile.max_repetitions !== undefined) {
|
|
19751
|
+
overrides.push(`max_repetitions=${profile.max_repetitions}`);
|
|
19752
|
+
}
|
|
19753
|
+
if (profile.max_consecutive_errors !== undefined) {
|
|
19754
|
+
overrides.push(`max_consecutive_errors=${profile.max_consecutive_errors}`);
|
|
19755
|
+
}
|
|
19756
|
+
if (profile.warning_threshold !== undefined) {
|
|
19757
|
+
overrides.push(`warning_threshold=${profile.warning_threshold}`);
|
|
19758
|
+
}
|
|
19759
|
+
const overrideStr = overrides.length > 0 ? overrides.join(", ") : "no overrides";
|
|
19760
|
+
lines.push(`- **${profileName}**: ${overrideStr}`);
|
|
19761
|
+
}
|
|
19762
|
+
}
|
|
19763
|
+
return lines.join(`
|
|
19764
|
+
`);
|
|
19765
|
+
}
|
|
19766
|
+
|
|
19767
|
+
// src/commands/analyze.ts
|
|
19768
|
+
async function handleAnalyzeCommand(_directory, args) {
|
|
19769
|
+
const description = args.join(" ").trim();
|
|
19770
|
+
if (description) {
|
|
19771
|
+
return `[MODE: ANALYZE] ${description}`;
|
|
19772
|
+
}
|
|
19773
|
+
return "[MODE: ANALYZE] Please analyze the spec against the plan using MODE: ANALYZE.";
|
|
19774
|
+
}
|
|
19775
|
+
|
|
19651
19776
|
// src/config/loader.ts
|
|
19777
|
+
import * as fs2 from "fs";
|
|
19778
|
+
import * as os2 from "os";
|
|
19779
|
+
import * as path4 from "path";
|
|
19652
19780
|
var CONFIG_FILENAME = "opencode-swarm.json";
|
|
19653
19781
|
var MAX_CONFIG_FILE_BYTES = 102400;
|
|
19654
19782
|
function getUserConfigDir() {
|
|
@@ -20341,6 +20469,9 @@ var DeltaSpecSchema = exports_external.union([
|
|
|
20341
20469
|
SwarmSpecSchema,
|
|
20342
20470
|
SpecDeltaSchema
|
|
20343
20471
|
]);
|
|
20472
|
+
// src/services/warning-buffer.ts
|
|
20473
|
+
var deferredWarnings = [];
|
|
20474
|
+
|
|
20344
20475
|
// src/agents/index.ts
|
|
20345
20476
|
var warnedAgents = new Set;
|
|
20346
20477
|
|
|
@@ -33670,8 +33801,8 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
33670
33801
|
|
|
33671
33802
|
// src/commands/close.ts
|
|
33672
33803
|
import { execFileSync } from "child_process";
|
|
33673
|
-
import { promises as
|
|
33674
|
-
import
|
|
33804
|
+
import { promises as fs7 } from "fs";
|
|
33805
|
+
import path12 from "path";
|
|
33675
33806
|
init_manager2();
|
|
33676
33807
|
|
|
33677
33808
|
// src/git/branch.ts
|
|
@@ -34360,31 +34491,10 @@ async function runAutoPromotion(directory, config3) {
|
|
|
34360
34491
|
// src/commands/close.ts
|
|
34361
34492
|
init_utils2();
|
|
34362
34493
|
|
|
34363
|
-
// src/plan/checkpoint.ts
|
|
34364
|
-
init_plan_schema();
|
|
34365
|
-
init_ledger();
|
|
34366
|
-
init_manager();
|
|
34367
|
-
import * as fs7 from "fs";
|
|
34368
|
-
import * as path11 from "path";
|
|
34369
|
-
async function writeCheckpoint(directory) {
|
|
34370
|
-
try {
|
|
34371
|
-
const plan = await loadPlan(directory);
|
|
34372
|
-
if (!plan)
|
|
34373
|
-
return;
|
|
34374
|
-
const jsonPath = path11.join(directory, "SWARM_PLAN.json");
|
|
34375
|
-
const mdPath = path11.join(directory, "SWARM_PLAN.md");
|
|
34376
|
-
fs7.writeFileSync(jsonPath, JSON.stringify(plan, null, 2), "utf8");
|
|
34377
|
-
const md = derivePlanMarkdown(plan);
|
|
34378
|
-
fs7.writeFileSync(mdPath, md, "utf8");
|
|
34379
|
-
} catch (error93) {
|
|
34380
|
-
console.warn(`[checkpoint] Failed to write SWARM_PLAN checkpoint: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
34381
|
-
}
|
|
34382
|
-
}
|
|
34383
|
-
|
|
34384
34494
|
// src/session/snapshot-writer.ts
|
|
34385
34495
|
init_utils2();
|
|
34386
34496
|
import { mkdirSync as mkdirSync7, renameSync as renameSync5 } from "fs";
|
|
34387
|
-
import * as
|
|
34497
|
+
import * as path11 from "path";
|
|
34388
34498
|
init_utils();
|
|
34389
34499
|
var _writeInFlight = Promise.resolve();
|
|
34390
34500
|
function serializeAgentSession(s) {
|
|
@@ -34475,7 +34585,7 @@ async function writeSnapshot(directory, state) {
|
|
|
34475
34585
|
}
|
|
34476
34586
|
const content = JSON.stringify(snapshot, null, 2);
|
|
34477
34587
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
34478
|
-
const dir =
|
|
34588
|
+
const dir = path11.dirname(resolvedPath);
|
|
34479
34589
|
mkdirSync7(dir, { recursive: true });
|
|
34480
34590
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
34481
34591
|
await Bun.write(tempPath, content);
|
|
@@ -34868,21 +34978,21 @@ var ACTIVE_STATE_TO_CLEAN = [
|
|
|
34868
34978
|
];
|
|
34869
34979
|
async function handleCloseCommand(directory, args) {
|
|
34870
34980
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
34871
|
-
const swarmDir =
|
|
34981
|
+
const swarmDir = path12.join(directory, ".swarm");
|
|
34872
34982
|
let planExists = false;
|
|
34873
34983
|
let planData = {
|
|
34874
|
-
title:
|
|
34984
|
+
title: path12.basename(directory) || "Ad-hoc session",
|
|
34875
34985
|
phases: []
|
|
34876
34986
|
};
|
|
34877
34987
|
try {
|
|
34878
|
-
const content = await
|
|
34988
|
+
const content = await fs7.readFile(planPath, "utf-8");
|
|
34879
34989
|
planData = JSON.parse(content);
|
|
34880
34990
|
planExists = true;
|
|
34881
34991
|
} catch (error93) {
|
|
34882
34992
|
if (error93?.code !== "ENOENT") {
|
|
34883
34993
|
return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
34884
34994
|
}
|
|
34885
|
-
const swarmDirExists = await
|
|
34995
|
+
const swarmDirExists = await fs7.access(swarmDir).then(() => true).catch(() => false);
|
|
34886
34996
|
if (!swarmDirExists) {
|
|
34887
34997
|
return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
|
|
34888
34998
|
}
|
|
@@ -34976,10 +35086,10 @@ async function handleCloseCommand(directory, args) {
|
|
|
34976
35086
|
warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
34977
35087
|
}
|
|
34978
35088
|
}
|
|
34979
|
-
const lessonsFilePath =
|
|
35089
|
+
const lessonsFilePath = path12.join(swarmDir, "close-lessons.md");
|
|
34980
35090
|
let explicitLessons = [];
|
|
34981
35091
|
try {
|
|
34982
|
-
const lessonsText = await
|
|
35092
|
+
const lessonsText = await fs7.readFile(lessonsFilePath, "utf-8");
|
|
34983
35093
|
explicitLessons = lessonsText.split(`
|
|
34984
35094
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
34985
35095
|
} catch {}
|
|
@@ -34993,7 +35103,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
34993
35103
|
console.warn("[close-command] curateAndStoreSwarm error:", error93);
|
|
34994
35104
|
}
|
|
34995
35105
|
if (curationSucceeded && explicitLessons.length > 0) {
|
|
34996
|
-
await
|
|
35106
|
+
await fs7.unlink(lessonsFilePath).catch(() => {});
|
|
34997
35107
|
}
|
|
34998
35108
|
if (planExists && !planAlreadyDone) {
|
|
34999
35109
|
for (const phase of phases) {
|
|
@@ -35013,7 +35123,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
35013
35123
|
}
|
|
35014
35124
|
}
|
|
35015
35125
|
try {
|
|
35016
|
-
await
|
|
35126
|
+
await fs7.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
|
|
35017
35127
|
} catch (error93) {
|
|
35018
35128
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
35019
35129
|
warnings.push(`Failed to persist terminal plan.json state: ${msg}`);
|
|
@@ -35022,53 +35132,53 @@ async function handleCloseCommand(directory, args) {
|
|
|
35022
35132
|
}
|
|
35023
35133
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
35024
35134
|
const suffix = Math.random().toString(36).slice(2, 8);
|
|
35025
|
-
const archiveDir =
|
|
35135
|
+
const archiveDir = path12.join(swarmDir, "archive", `swarm-${timestamp}-${suffix}`);
|
|
35026
35136
|
let archiveResult = "";
|
|
35027
35137
|
let archivedFileCount = 0;
|
|
35028
35138
|
const archivedActiveStateFiles = new Set;
|
|
35029
35139
|
try {
|
|
35030
|
-
await
|
|
35140
|
+
await fs7.mkdir(archiveDir, { recursive: true });
|
|
35031
35141
|
for (const artifact of ARCHIVE_ARTIFACTS) {
|
|
35032
|
-
const srcPath =
|
|
35033
|
-
const destPath =
|
|
35142
|
+
const srcPath = path12.join(swarmDir, artifact);
|
|
35143
|
+
const destPath = path12.join(archiveDir, artifact);
|
|
35034
35144
|
try {
|
|
35035
|
-
await
|
|
35145
|
+
await fs7.copyFile(srcPath, destPath);
|
|
35036
35146
|
archivedFileCount++;
|
|
35037
35147
|
if (ACTIVE_STATE_TO_CLEAN.includes(artifact)) {
|
|
35038
35148
|
archivedActiveStateFiles.add(artifact);
|
|
35039
35149
|
}
|
|
35040
35150
|
} catch {}
|
|
35041
35151
|
}
|
|
35042
|
-
const evidenceDir =
|
|
35043
|
-
const archiveEvidenceDir =
|
|
35152
|
+
const evidenceDir = path12.join(swarmDir, "evidence");
|
|
35153
|
+
const archiveEvidenceDir = path12.join(archiveDir, "evidence");
|
|
35044
35154
|
try {
|
|
35045
|
-
const evidenceEntries = await
|
|
35155
|
+
const evidenceEntries = await fs7.readdir(evidenceDir);
|
|
35046
35156
|
if (evidenceEntries.length > 0) {
|
|
35047
|
-
await
|
|
35157
|
+
await fs7.mkdir(archiveEvidenceDir, { recursive: true });
|
|
35048
35158
|
for (const entry of evidenceEntries) {
|
|
35049
|
-
const srcEntry =
|
|
35050
|
-
const destEntry =
|
|
35159
|
+
const srcEntry = path12.join(evidenceDir, entry);
|
|
35160
|
+
const destEntry = path12.join(archiveEvidenceDir, entry);
|
|
35051
35161
|
try {
|
|
35052
|
-
const stat = await
|
|
35162
|
+
const stat = await fs7.stat(srcEntry);
|
|
35053
35163
|
if (stat.isDirectory()) {
|
|
35054
|
-
await
|
|
35055
|
-
const subEntries = await
|
|
35164
|
+
await fs7.mkdir(destEntry, { recursive: true });
|
|
35165
|
+
const subEntries = await fs7.readdir(srcEntry);
|
|
35056
35166
|
for (const sub of subEntries) {
|
|
35057
|
-
await
|
|
35167
|
+
await fs7.copyFile(path12.join(srcEntry, sub), path12.join(destEntry, sub)).catch(() => {});
|
|
35058
35168
|
}
|
|
35059
35169
|
} else {
|
|
35060
|
-
await
|
|
35170
|
+
await fs7.copyFile(srcEntry, destEntry);
|
|
35061
35171
|
}
|
|
35062
35172
|
archivedFileCount++;
|
|
35063
35173
|
} catch {}
|
|
35064
35174
|
}
|
|
35065
35175
|
}
|
|
35066
35176
|
} catch {}
|
|
35067
|
-
const sessionStatePath =
|
|
35177
|
+
const sessionStatePath = path12.join(swarmDir, "session", "state.json");
|
|
35068
35178
|
try {
|
|
35069
|
-
const archiveSessionDir =
|
|
35070
|
-
await
|
|
35071
|
-
await
|
|
35179
|
+
const archiveSessionDir = path12.join(archiveDir, "session");
|
|
35180
|
+
await fs7.mkdir(archiveSessionDir, { recursive: true });
|
|
35181
|
+
await fs7.copyFile(sessionStatePath, path12.join(archiveSessionDir, "state.json"));
|
|
35072
35182
|
archivedFileCount++;
|
|
35073
35183
|
} catch {}
|
|
35074
35184
|
archiveResult = `Archived ${archivedFileCount} artifact(s) to .swarm/archive/swarm-${timestamp}/`;
|
|
@@ -35091,9 +35201,9 @@ async function handleCloseCommand(directory, args) {
|
|
|
35091
35201
|
warnings.push(`Preserved ${artifact} because it was not successfully archived.`);
|
|
35092
35202
|
continue;
|
|
35093
35203
|
}
|
|
35094
|
-
const filePath =
|
|
35204
|
+
const filePath = path12.join(swarmDir, artifact);
|
|
35095
35205
|
try {
|
|
35096
|
-
await
|
|
35206
|
+
await fs7.unlink(filePath);
|
|
35097
35207
|
cleanedFiles.push(artifact);
|
|
35098
35208
|
} catch {}
|
|
35099
35209
|
}
|
|
@@ -35101,23 +35211,42 @@ async function handleCloseCommand(directory, args) {
|
|
|
35101
35211
|
warnings.push("Skipped active-state cleanup because no active-state files were archived. Files preserved to prevent data loss.");
|
|
35102
35212
|
}
|
|
35103
35213
|
try {
|
|
35104
|
-
const swarmFiles = await
|
|
35214
|
+
const swarmFiles = await fs7.readdir(swarmDir);
|
|
35105
35215
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
35106
35216
|
for (const backup of configBackups) {
|
|
35107
35217
|
try {
|
|
35108
|
-
await
|
|
35218
|
+
await fs7.unlink(path12.join(swarmDir, backup));
|
|
35109
35219
|
configBackupsRemoved++;
|
|
35110
35220
|
} catch {}
|
|
35111
35221
|
}
|
|
35112
35222
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
35113
35223
|
for (const sibling of ledgerSiblings) {
|
|
35114
35224
|
try {
|
|
35115
|
-
await
|
|
35225
|
+
await fs7.unlink(path12.join(swarmDir, sibling));
|
|
35116
35226
|
} catch {}
|
|
35117
35227
|
}
|
|
35118
35228
|
} catch {}
|
|
35229
|
+
let swarmPlanFilesRemoved = 0;
|
|
35230
|
+
const swarmPlanJsonPath = path12.join(directory, "SWARM_PLAN.json");
|
|
35231
|
+
const swarmPlanMdPath = path12.join(directory, "SWARM_PLAN.md");
|
|
35232
|
+
try {
|
|
35233
|
+
await fs7.unlink(swarmPlanJsonPath);
|
|
35234
|
+
swarmPlanFilesRemoved++;
|
|
35235
|
+
} catch (err) {
|
|
35236
|
+
if (err?.code !== "ENOENT") {
|
|
35237
|
+
warnings.push(`Failed to remove SWARM_PLAN.json: ${err instanceof Error ? err.message : String(err)}`);
|
|
35238
|
+
}
|
|
35239
|
+
}
|
|
35240
|
+
try {
|
|
35241
|
+
await fs7.unlink(swarmPlanMdPath);
|
|
35242
|
+
swarmPlanFilesRemoved++;
|
|
35243
|
+
} catch (err) {
|
|
35244
|
+
if (err?.code !== "ENOENT") {
|
|
35245
|
+
warnings.push(`Failed to remove SWARM_PLAN.md: ${err instanceof Error ? err.message : String(err)}`);
|
|
35246
|
+
}
|
|
35247
|
+
}
|
|
35119
35248
|
clearAllScopes(directory);
|
|
35120
|
-
const contextPath =
|
|
35249
|
+
const contextPath = path12.join(swarmDir, "context.md");
|
|
35121
35250
|
const contextContent = [
|
|
35122
35251
|
"# Context",
|
|
35123
35252
|
"",
|
|
@@ -35130,7 +35259,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
35130
35259
|
].join(`
|
|
35131
35260
|
`);
|
|
35132
35261
|
try {
|
|
35133
|
-
await
|
|
35262
|
+
await fs7.writeFile(contextPath, contextContent, "utf-8");
|
|
35134
35263
|
} catch (error93) {
|
|
35135
35264
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
35136
35265
|
warnings.push(`Failed to reset context.md: ${msg}`);
|
|
@@ -35232,6 +35361,9 @@ async function handleCloseCommand(directory, args) {
|
|
|
35232
35361
|
] : [],
|
|
35233
35362
|
"- Reset context.md for next session",
|
|
35234
35363
|
...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
|
|
35364
|
+
...swarmPlanFilesRemoved > 0 ? [
|
|
35365
|
+
`- Removed ${swarmPlanFilesRemoved} root-level SWARM_PLAN checkpoint artifact(s)`
|
|
35366
|
+
] : [],
|
|
35235
35367
|
...prunedBranches.length > 0 ? [
|
|
35236
35368
|
`- Pruned ${prunedBranches.length} stale local git branch(es): ${prunedBranches.join(", ")}`
|
|
35237
35369
|
] : [],
|
|
@@ -35261,7 +35393,7 @@ async function handleCloseCommand(directory, args) {
|
|
|
35261
35393
|
].join(`
|
|
35262
35394
|
`);
|
|
35263
35395
|
try {
|
|
35264
|
-
await
|
|
35396
|
+
await fs7.writeFile(closeSummaryPath, summaryContent, "utf-8");
|
|
35265
35397
|
} catch (error93) {
|
|
35266
35398
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
35267
35399
|
warnings.push(`Failed to write close-summary.md: ${msg}`);
|
|
@@ -35274,7 +35406,6 @@ async function handleCloseCommand(directory, args) {
|
|
|
35274
35406
|
warnings.push(`flushPendingSnapshot failed: ${msg}`);
|
|
35275
35407
|
console.warn("[close-command] flushPendingSnapshot error:", error93);
|
|
35276
35408
|
}
|
|
35277
|
-
await writeCheckpoint(directory).catch(() => {});
|
|
35278
35409
|
const preservedClient = swarmState.opencodeClient;
|
|
35279
35410
|
const preservedFullAutoFlag = swarmState.fullAutoEnabledInConfig;
|
|
35280
35411
|
const preservedCuratorInitNames = swarmState.curatorInitAgentNames;
|
|
@@ -35318,14 +35449,14 @@ ${otherWarnings.map((w) => `- ${w}`).join(`
|
|
|
35318
35449
|
|
|
35319
35450
|
// src/commands/config.ts
|
|
35320
35451
|
import * as os4 from "os";
|
|
35321
|
-
import * as
|
|
35452
|
+
import * as path13 from "path";
|
|
35322
35453
|
function getUserConfigDir2() {
|
|
35323
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
35454
|
+
return process.env.XDG_CONFIG_HOME || path13.join(os4.homedir(), ".config");
|
|
35324
35455
|
}
|
|
35325
35456
|
async function handleConfigCommand(directory, _args) {
|
|
35326
35457
|
const config3 = loadPluginConfig(directory);
|
|
35327
|
-
const userConfigPath =
|
|
35328
|
-
const projectConfigPath =
|
|
35458
|
+
const userConfigPath = path13.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
35459
|
+
const projectConfigPath = path13.join(directory, ".opencode", "opencode-swarm.json");
|
|
35329
35460
|
const lines = [
|
|
35330
35461
|
"## Swarm Configuration",
|
|
35331
35462
|
"",
|
|
@@ -35411,7 +35542,7 @@ async function handleCouncilCommand(_directory, args) {
|
|
|
35411
35542
|
}
|
|
35412
35543
|
|
|
35413
35544
|
// src/hooks/hive-promoter.ts
|
|
35414
|
-
import
|
|
35545
|
+
import path14 from "path";
|
|
35415
35546
|
|
|
35416
35547
|
// src/background/event-bus.ts
|
|
35417
35548
|
init_utils();
|
|
@@ -35666,7 +35797,7 @@ async function promoteToHive(directory, lesson, category) {
|
|
|
35666
35797
|
schema_version: 1,
|
|
35667
35798
|
created_at: new Date().toISOString(),
|
|
35668
35799
|
updated_at: new Date().toISOString(),
|
|
35669
|
-
source_project:
|
|
35800
|
+
source_project: path14.basename(directory) || "unknown",
|
|
35670
35801
|
encounter_score: 1
|
|
35671
35802
|
};
|
|
35672
35803
|
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
@@ -35744,14 +35875,14 @@ function formatCurationSummary(summary) {
|
|
|
35744
35875
|
}
|
|
35745
35876
|
|
|
35746
35877
|
// src/commands/dark-matter.ts
|
|
35747
|
-
import
|
|
35878
|
+
import path16 from "path";
|
|
35748
35879
|
|
|
35749
35880
|
// src/tools/co-change-analyzer.ts
|
|
35750
35881
|
init_zod();
|
|
35751
35882
|
import * as child_process3 from "child_process";
|
|
35752
35883
|
import { randomUUID } from "crypto";
|
|
35753
35884
|
import { readdir, readFile as readFile3, stat } from "fs/promises";
|
|
35754
|
-
import * as
|
|
35885
|
+
import * as path15 from "path";
|
|
35755
35886
|
import { promisify } from "util";
|
|
35756
35887
|
function getExecFileAsync() {
|
|
35757
35888
|
return promisify(child_process3.execFile);
|
|
@@ -35853,7 +35984,7 @@ async function scanSourceFiles(dir) {
|
|
|
35853
35984
|
try {
|
|
35854
35985
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
35855
35986
|
for (const entry of entries) {
|
|
35856
|
-
const fullPath =
|
|
35987
|
+
const fullPath = path15.join(dir, entry.name);
|
|
35857
35988
|
if (entry.isDirectory()) {
|
|
35858
35989
|
if (skipDirs.has(entry.name)) {
|
|
35859
35990
|
continue;
|
|
@@ -35861,7 +35992,7 @@ async function scanSourceFiles(dir) {
|
|
|
35861
35992
|
const subFiles = await scanSourceFiles(fullPath);
|
|
35862
35993
|
results.push(...subFiles);
|
|
35863
35994
|
} else if (entry.isFile()) {
|
|
35864
|
-
const ext =
|
|
35995
|
+
const ext = path15.extname(entry.name);
|
|
35865
35996
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
35866
35997
|
results.push(fullPath);
|
|
35867
35998
|
}
|
|
@@ -35883,8 +36014,8 @@ async function getStaticEdges(directory) {
|
|
|
35883
36014
|
continue;
|
|
35884
36015
|
}
|
|
35885
36016
|
try {
|
|
35886
|
-
const sourceDir =
|
|
35887
|
-
const resolvedPath =
|
|
36017
|
+
const sourceDir = path15.dirname(sourceFile);
|
|
36018
|
+
const resolvedPath = path15.resolve(sourceDir, importPath);
|
|
35888
36019
|
const extensions = [
|
|
35889
36020
|
"",
|
|
35890
36021
|
".ts",
|
|
@@ -35909,8 +36040,8 @@ async function getStaticEdges(directory) {
|
|
|
35909
36040
|
if (!targetFile) {
|
|
35910
36041
|
continue;
|
|
35911
36042
|
}
|
|
35912
|
-
const relSource =
|
|
35913
|
-
const relTarget =
|
|
36043
|
+
const relSource = path15.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
36044
|
+
const relTarget = path15.relative(directory, targetFile).replace(/\\/g, "/");
|
|
35914
36045
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
35915
36046
|
edges.add(key);
|
|
35916
36047
|
} catch {}
|
|
@@ -35922,7 +36053,7 @@ async function getStaticEdges(directory) {
|
|
|
35922
36053
|
function isTestImplementationPair(fileA, fileB) {
|
|
35923
36054
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
35924
36055
|
const getBaseName = (filePath) => {
|
|
35925
|
-
const base =
|
|
36056
|
+
const base = path15.basename(filePath);
|
|
35926
36057
|
for (const pattern of testPatterns) {
|
|
35927
36058
|
if (base.endsWith(pattern)) {
|
|
35928
36059
|
return base.slice(0, -pattern.length);
|
|
@@ -35932,16 +36063,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
35932
36063
|
};
|
|
35933
36064
|
const baseA = getBaseName(fileA);
|
|
35934
36065
|
const baseB = getBaseName(fileB);
|
|
35935
|
-
return baseA === baseB && baseA !==
|
|
36066
|
+
return baseA === baseB && baseA !== path15.basename(fileA) && baseA !== path15.basename(fileB);
|
|
35936
36067
|
}
|
|
35937
36068
|
function hasSharedPrefix(fileA, fileB) {
|
|
35938
|
-
const dirA =
|
|
35939
|
-
const dirB =
|
|
36069
|
+
const dirA = path15.dirname(fileA);
|
|
36070
|
+
const dirB = path15.dirname(fileB);
|
|
35940
36071
|
if (dirA !== dirB) {
|
|
35941
36072
|
return false;
|
|
35942
36073
|
}
|
|
35943
|
-
const baseA =
|
|
35944
|
-
const baseB =
|
|
36074
|
+
const baseA = path15.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
36075
|
+
const baseB = path15.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
35945
36076
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
35946
36077
|
return true;
|
|
35947
36078
|
}
|
|
@@ -35995,8 +36126,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
35995
36126
|
const entries = [];
|
|
35996
36127
|
const now = new Date().toISOString();
|
|
35997
36128
|
for (const pair of pairs.slice(0, 10)) {
|
|
35998
|
-
const baseA =
|
|
35999
|
-
const baseB =
|
|
36129
|
+
const baseA = path15.basename(pair.fileA);
|
|
36130
|
+
const baseB = path15.basename(pair.fileB);
|
|
36000
36131
|
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.`;
|
|
36001
36132
|
if (lesson.length > 280) {
|
|
36002
36133
|
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.`;
|
|
@@ -36106,7 +36237,7 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
36106
36237
|
const output = formatDarkMatterOutput(pairs);
|
|
36107
36238
|
if (pairs.length > 0) {
|
|
36108
36239
|
try {
|
|
36109
|
-
const projectName =
|
|
36240
|
+
const projectName = path16.basename(path16.resolve(directory));
|
|
36110
36241
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
36111
36242
|
if (entries.length > 0) {
|
|
36112
36243
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -36127,12 +36258,13 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
36127
36258
|
|
|
36128
36259
|
// src/services/diagnose-service.ts
|
|
36129
36260
|
import * as child_process4 from "child_process";
|
|
36130
|
-
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as
|
|
36131
|
-
import
|
|
36261
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4, readFileSync as readFileSync5, statSync as statSync5 } from "fs";
|
|
36262
|
+
import path17 from "path";
|
|
36132
36263
|
import { fileURLToPath } from "url";
|
|
36133
36264
|
init_manager2();
|
|
36134
36265
|
init_utils2();
|
|
36135
36266
|
init_manager();
|
|
36267
|
+
var { version: version3 } = package_default;
|
|
36136
36268
|
function validateTaskDag(plan) {
|
|
36137
36269
|
const allTaskIds = new Set;
|
|
36138
36270
|
for (const phase of plan.phases) {
|
|
@@ -36428,7 +36560,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
36428
36560
|
};
|
|
36429
36561
|
}
|
|
36430
36562
|
async function checkConfigParseability(directory) {
|
|
36431
|
-
const configPath =
|
|
36563
|
+
const configPath = path17.join(directory, ".opencode/opencode-swarm.json");
|
|
36432
36564
|
if (!existsSync8(configPath)) {
|
|
36433
36565
|
return {
|
|
36434
36566
|
name: "Config Parseability",
|
|
@@ -36437,7 +36569,7 @@ async function checkConfigParseability(directory) {
|
|
|
36437
36569
|
};
|
|
36438
36570
|
}
|
|
36439
36571
|
try {
|
|
36440
|
-
const content =
|
|
36572
|
+
const content = readFileSync5(configPath, "utf-8");
|
|
36441
36573
|
JSON.parse(content);
|
|
36442
36574
|
return {
|
|
36443
36575
|
name: "Config Parseability",
|
|
@@ -36457,7 +36589,7 @@ function resolveGrammarDir(thisDir) {
|
|
|
36457
36589
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
36458
36590
|
const isSource = normalized.endsWith("/src/services");
|
|
36459
36591
|
const isCliBundle = normalized.endsWith("/cli");
|
|
36460
|
-
return isSource || isCliBundle ?
|
|
36592
|
+
return isSource || isCliBundle ? path17.join(thisDir, "..", "lang", "grammars") : path17.join(thisDir, "lang", "grammars");
|
|
36461
36593
|
}
|
|
36462
36594
|
async function checkGrammarWasmFiles() {
|
|
36463
36595
|
const grammarFiles = [
|
|
@@ -36481,14 +36613,14 @@ async function checkGrammarWasmFiles() {
|
|
|
36481
36613
|
"tree-sitter-ini.wasm",
|
|
36482
36614
|
"tree-sitter-regex.wasm"
|
|
36483
36615
|
];
|
|
36484
|
-
const thisDir =
|
|
36616
|
+
const thisDir = path17.dirname(fileURLToPath(import.meta.url));
|
|
36485
36617
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
36486
36618
|
const missing = [];
|
|
36487
|
-
if (!existsSync8(
|
|
36619
|
+
if (!existsSync8(path17.join(grammarDir, "tree-sitter.wasm"))) {
|
|
36488
36620
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
36489
36621
|
}
|
|
36490
36622
|
for (const file3 of grammarFiles) {
|
|
36491
|
-
if (!existsSync8(
|
|
36623
|
+
if (!existsSync8(path17.join(grammarDir, file3))) {
|
|
36492
36624
|
missing.push(file3);
|
|
36493
36625
|
}
|
|
36494
36626
|
}
|
|
@@ -36506,7 +36638,7 @@ async function checkGrammarWasmFiles() {
|
|
|
36506
36638
|
};
|
|
36507
36639
|
}
|
|
36508
36640
|
async function checkCheckpointManifest(directory) {
|
|
36509
|
-
const manifestPath =
|
|
36641
|
+
const manifestPath = path17.join(directory, ".swarm/checkpoints.json");
|
|
36510
36642
|
if (!existsSync8(manifestPath)) {
|
|
36511
36643
|
return {
|
|
36512
36644
|
name: "Checkpoint Manifest",
|
|
@@ -36515,7 +36647,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
36515
36647
|
};
|
|
36516
36648
|
}
|
|
36517
36649
|
try {
|
|
36518
|
-
const content =
|
|
36650
|
+
const content = readFileSync5(manifestPath, "utf-8");
|
|
36519
36651
|
const parsed = JSON.parse(content);
|
|
36520
36652
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
36521
36653
|
return {
|
|
@@ -36558,7 +36690,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
36558
36690
|
}
|
|
36559
36691
|
}
|
|
36560
36692
|
async function checkEventStreamIntegrity(directory) {
|
|
36561
|
-
const eventsPath =
|
|
36693
|
+
const eventsPath = path17.join(directory, ".swarm/events.jsonl");
|
|
36562
36694
|
if (!existsSync8(eventsPath)) {
|
|
36563
36695
|
return {
|
|
36564
36696
|
name: "Event Stream",
|
|
@@ -36567,7 +36699,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
36567
36699
|
};
|
|
36568
36700
|
}
|
|
36569
36701
|
try {
|
|
36570
|
-
const content =
|
|
36702
|
+
const content = readFileSync5(eventsPath, "utf-8");
|
|
36571
36703
|
const lines = content.split(`
|
|
36572
36704
|
`).filter((line) => line.trim() !== "");
|
|
36573
36705
|
let malformedCount = 0;
|
|
@@ -36599,7 +36731,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
36599
36731
|
}
|
|
36600
36732
|
}
|
|
36601
36733
|
async function checkSteeringDirectives(directory) {
|
|
36602
|
-
const eventsPath =
|
|
36734
|
+
const eventsPath = path17.join(directory, ".swarm/events.jsonl");
|
|
36603
36735
|
if (!existsSync8(eventsPath)) {
|
|
36604
36736
|
return {
|
|
36605
36737
|
name: "Steering Directives",
|
|
@@ -36608,7 +36740,7 @@ async function checkSteeringDirectives(directory) {
|
|
|
36608
36740
|
};
|
|
36609
36741
|
}
|
|
36610
36742
|
try {
|
|
36611
|
-
const content =
|
|
36743
|
+
const content = readFileSync5(eventsPath, "utf-8");
|
|
36612
36744
|
const lines = content.split(`
|
|
36613
36745
|
`).filter((line) => line.trim() !== "");
|
|
36614
36746
|
const directivesIssued = [];
|
|
@@ -36655,7 +36787,7 @@ async function checkCurator(directory) {
|
|
|
36655
36787
|
detail: "Disabled (enable via curator.enabled)"
|
|
36656
36788
|
};
|
|
36657
36789
|
}
|
|
36658
|
-
const summaryPath =
|
|
36790
|
+
const summaryPath = path17.join(directory, ".swarm/curator-summary.json");
|
|
36659
36791
|
if (!existsSync8(summaryPath)) {
|
|
36660
36792
|
return {
|
|
36661
36793
|
name: "Curator",
|
|
@@ -36664,7 +36796,7 @@ async function checkCurator(directory) {
|
|
|
36664
36796
|
};
|
|
36665
36797
|
}
|
|
36666
36798
|
try {
|
|
36667
|
-
const content =
|
|
36799
|
+
const content = readFileSync5(summaryPath, "utf-8");
|
|
36668
36800
|
const parsed = JSON.parse(content);
|
|
36669
36801
|
if (typeof parsed.schema_version !== "number" || parsed.schema_version !== 1) {
|
|
36670
36802
|
return {
|
|
@@ -36699,6 +36831,11 @@ async function checkCurator(directory) {
|
|
|
36699
36831
|
}
|
|
36700
36832
|
async function getDiagnoseData(directory) {
|
|
36701
36833
|
const checks5 = [];
|
|
36834
|
+
checks5.push({
|
|
36835
|
+
name: "Version",
|
|
36836
|
+
status: "\u2705",
|
|
36837
|
+
detail: version3
|
|
36838
|
+
});
|
|
36702
36839
|
const plan = await loadPlanJsonOnly(directory);
|
|
36703
36840
|
if (plan) {
|
|
36704
36841
|
checks5.push({
|
|
@@ -36803,7 +36940,7 @@ async function getDiagnoseData(directory) {
|
|
|
36803
36940
|
checks5.push(await checkSteeringDirectives(directory));
|
|
36804
36941
|
checks5.push(await checkCurator(directory));
|
|
36805
36942
|
try {
|
|
36806
|
-
const evidenceDir =
|
|
36943
|
+
const evidenceDir = path17.join(directory, ".swarm", "evidence");
|
|
36807
36944
|
const snapshotFiles = existsSync8(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
36808
36945
|
if (snapshotFiles.length > 0) {
|
|
36809
36946
|
const latest = snapshotFiles.sort().pop();
|
|
@@ -36826,6 +36963,13 @@ async function getDiagnoseData(directory) {
|
|
|
36826
36963
|
detail: "No snapshots yet (snapshots written on next session start)"
|
|
36827
36964
|
});
|
|
36828
36965
|
}
|
|
36966
|
+
if (deferredWarnings.length > 0) {
|
|
36967
|
+
checks5.push({
|
|
36968
|
+
name: "Deferred Warnings",
|
|
36969
|
+
status: "\u26A0\uFE0F",
|
|
36970
|
+
detail: `${deferredWarnings.length} warning(s) deferred from init (run with verbose logs for details)`
|
|
36971
|
+
});
|
|
36972
|
+
}
|
|
36829
36973
|
const passCount = checks5.filter((c) => c.status === "\u2705").length;
|
|
36830
36974
|
const totalCount = checks5.length;
|
|
36831
36975
|
const allPassed = passCount === totalCount;
|
|
@@ -36844,6 +36988,14 @@ function formatDiagnoseMarkdown(diagnose) {
|
|
|
36844
36988
|
"",
|
|
36845
36989
|
`**Result**: ${diagnose.allPassed ? "\u2705 All checks passed" : `\u26A0\uFE0F ${diagnose.passCount}/${diagnose.totalCount} checks passed`}`
|
|
36846
36990
|
];
|
|
36991
|
+
if (deferredWarnings.length > 0) {
|
|
36992
|
+
lines.push("");
|
|
36993
|
+
lines.push("## Deferred Warnings");
|
|
36994
|
+
lines.push("");
|
|
36995
|
+
for (const warning of deferredWarnings) {
|
|
36996
|
+
lines.push(`- ${warning}`);
|
|
36997
|
+
}
|
|
36998
|
+
}
|
|
36847
36999
|
return lines.join(`
|
|
36848
37000
|
`);
|
|
36849
37001
|
}
|
|
@@ -36855,16 +37007,16 @@ async function handleDiagnoseCommand(directory, _args) {
|
|
|
36855
37007
|
init_config_doctor();
|
|
36856
37008
|
|
|
36857
37009
|
// src/services/tool-doctor.ts
|
|
36858
|
-
import * as fs11 from "fs";
|
|
36859
|
-
import * as path21 from "path";
|
|
36860
|
-
|
|
36861
|
-
// src/build/discovery.ts
|
|
36862
37010
|
import * as fs10 from "fs";
|
|
36863
37011
|
import * as path20 from "path";
|
|
36864
37012
|
|
|
37013
|
+
// src/build/discovery.ts
|
|
37014
|
+
import * as fs9 from "fs";
|
|
37015
|
+
import * as path19 from "path";
|
|
37016
|
+
|
|
36865
37017
|
// src/lang/detector.ts
|
|
36866
37018
|
import { access as access2, readdir as readdir2 } from "fs/promises";
|
|
36867
|
-
import { extname as extname2, join as
|
|
37019
|
+
import { extname as extname2, join as join15 } from "path";
|
|
36868
37020
|
|
|
36869
37021
|
// src/lang/profiles.ts
|
|
36870
37022
|
class LanguageRegistry {
|
|
@@ -37844,7 +37996,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
37844
37996
|
if (detectFile.includes("*") || detectFile.includes("?"))
|
|
37845
37997
|
continue;
|
|
37846
37998
|
try {
|
|
37847
|
-
await access2(
|
|
37999
|
+
await access2(join15(dir, detectFile));
|
|
37848
38000
|
detected.add(profile.id);
|
|
37849
38001
|
break;
|
|
37850
38002
|
} catch {}
|
|
@@ -37865,7 +38017,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
37865
38017
|
const topEntries = await readdir2(projectDir, { withFileTypes: true });
|
|
37866
38018
|
for (const entry of topEntries) {
|
|
37867
38019
|
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
37868
|
-
await scanDir(
|
|
38020
|
+
await scanDir(join15(projectDir, entry.name));
|
|
37869
38021
|
}
|
|
37870
38022
|
}
|
|
37871
38023
|
} catch {}
|
|
@@ -38020,16 +38172,16 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
38020
38172
|
if (pattern.includes("*")) {
|
|
38021
38173
|
const dir = workingDir;
|
|
38022
38174
|
try {
|
|
38023
|
-
const files =
|
|
38175
|
+
const files = fs9.readdirSync(dir);
|
|
38024
38176
|
const regex = simpleGlobToRegex(pattern);
|
|
38025
38177
|
const matches = files.filter((f) => regex.test(f));
|
|
38026
38178
|
if (matches.length > 0) {
|
|
38027
|
-
return
|
|
38179
|
+
return path19.join(dir, matches[0]);
|
|
38028
38180
|
}
|
|
38029
38181
|
} catch {}
|
|
38030
38182
|
} else {
|
|
38031
|
-
const filePath =
|
|
38032
|
-
if (
|
|
38183
|
+
const filePath = path19.join(workingDir, pattern);
|
|
38184
|
+
if (fs9.existsSync(filePath)) {
|
|
38033
38185
|
return filePath;
|
|
38034
38186
|
}
|
|
38035
38187
|
}
|
|
@@ -38037,12 +38189,12 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
38037
38189
|
return null;
|
|
38038
38190
|
}
|
|
38039
38191
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
38040
|
-
const packageJsonPath =
|
|
38041
|
-
if (!
|
|
38192
|
+
const packageJsonPath = path19.join(workingDir, "package.json");
|
|
38193
|
+
if (!fs9.existsSync(packageJsonPath)) {
|
|
38042
38194
|
return [];
|
|
38043
38195
|
}
|
|
38044
38196
|
try {
|
|
38045
|
-
const content =
|
|
38197
|
+
const content = fs9.readFileSync(packageJsonPath, "utf-8");
|
|
38046
38198
|
const pkg = JSON.parse(content);
|
|
38047
38199
|
if (!pkg.scripts || typeof pkg.scripts !== "object") {
|
|
38048
38200
|
return [];
|
|
@@ -38078,8 +38230,8 @@ function findAllBuildFiles(workingDir) {
|
|
|
38078
38230
|
const regex = simpleGlobToRegex(pattern);
|
|
38079
38231
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
38080
38232
|
} else {
|
|
38081
|
-
const filePath =
|
|
38082
|
-
if (
|
|
38233
|
+
const filePath = path19.join(workingDir, pattern);
|
|
38234
|
+
if (fs9.existsSync(filePath)) {
|
|
38083
38235
|
allBuildFiles.add(filePath);
|
|
38084
38236
|
}
|
|
38085
38237
|
}
|
|
@@ -38089,9 +38241,9 @@ function findAllBuildFiles(workingDir) {
|
|
|
38089
38241
|
}
|
|
38090
38242
|
function findFilesRecursive(dir, regex, results) {
|
|
38091
38243
|
try {
|
|
38092
|
-
const entries =
|
|
38244
|
+
const entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
38093
38245
|
for (const entry of entries) {
|
|
38094
|
-
const fullPath =
|
|
38246
|
+
const fullPath = path19.join(dir, entry.name);
|
|
38095
38247
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
38096
38248
|
findFilesRecursive(fullPath, regex, results);
|
|
38097
38249
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -38114,8 +38266,8 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
|
|
|
38114
38266
|
let foundCommand = false;
|
|
38115
38267
|
for (const cmd of sortedCommands) {
|
|
38116
38268
|
if (cmd.detectFile) {
|
|
38117
|
-
const detectFilePath =
|
|
38118
|
-
if (!
|
|
38269
|
+
const detectFilePath = path19.join(workingDir, cmd.detectFile);
|
|
38270
|
+
if (!fs9.existsSync(detectFilePath)) {
|
|
38119
38271
|
continue;
|
|
38120
38272
|
}
|
|
38121
38273
|
}
|
|
@@ -38238,7 +38390,7 @@ var BINARY_CHECKLIST = [
|
|
|
38238
38390
|
function extractRegisteredToolKeys(indexPath) {
|
|
38239
38391
|
const registeredKeys = new Set;
|
|
38240
38392
|
try {
|
|
38241
|
-
const content =
|
|
38393
|
+
const content = fs10.readFileSync(indexPath, "utf-8");
|
|
38242
38394
|
const toolBlockMatch = content.match(/tool:\s*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}/s);
|
|
38243
38395
|
if (!toolBlockMatch) {
|
|
38244
38396
|
return registeredKeys;
|
|
@@ -38289,9 +38441,9 @@ function checkBinaryReadiness() {
|
|
|
38289
38441
|
}
|
|
38290
38442
|
function runToolDoctor(_directory, pluginRoot) {
|
|
38291
38443
|
const findings = [];
|
|
38292
|
-
const resolvedPluginRoot = pluginRoot ??
|
|
38293
|
-
const indexPath =
|
|
38294
|
-
if (!
|
|
38444
|
+
const resolvedPluginRoot = pluginRoot ?? path20.resolve(import.meta.dir, "..", "..");
|
|
38445
|
+
const indexPath = path20.join(resolvedPluginRoot, "src", "index.ts");
|
|
38446
|
+
if (!fs10.existsSync(indexPath)) {
|
|
38295
38447
|
return {
|
|
38296
38448
|
findings: [
|
|
38297
38449
|
{
|
|
@@ -39211,12 +39363,12 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
39211
39363
|
}
|
|
39212
39364
|
// src/hooks/knowledge-migrator.ts
|
|
39213
39365
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
39214
|
-
import { existsSync as existsSync12, readFileSync as
|
|
39366
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
39215
39367
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
39216
|
-
import * as
|
|
39368
|
+
import * as path21 from "path";
|
|
39217
39369
|
async function migrateContextToKnowledge(directory, config3) {
|
|
39218
|
-
const sentinelPath =
|
|
39219
|
-
const contextPath =
|
|
39370
|
+
const sentinelPath = path21.join(directory, ".swarm", ".knowledge-migrated");
|
|
39371
|
+
const contextPath = path21.join(directory, ".swarm", "context.md");
|
|
39220
39372
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
39221
39373
|
if (existsSync12(sentinelPath)) {
|
|
39222
39374
|
return {
|
|
@@ -39412,16 +39564,16 @@ function truncateLesson(text) {
|
|
|
39412
39564
|
return `${text.slice(0, 277)}...`;
|
|
39413
39565
|
}
|
|
39414
39566
|
function inferProjectName(directory) {
|
|
39415
|
-
const packageJsonPath =
|
|
39567
|
+
const packageJsonPath = path21.join(directory, "package.json");
|
|
39416
39568
|
if (existsSync12(packageJsonPath)) {
|
|
39417
39569
|
try {
|
|
39418
|
-
const pkg = JSON.parse(
|
|
39570
|
+
const pkg = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
|
|
39419
39571
|
if (pkg.name && typeof pkg.name === "string") {
|
|
39420
39572
|
return pkg.name;
|
|
39421
39573
|
}
|
|
39422
39574
|
} catch {}
|
|
39423
39575
|
}
|
|
39424
|
-
return
|
|
39576
|
+
return path21.basename(directory);
|
|
39425
39577
|
}
|
|
39426
39578
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
39427
39579
|
const sentinel = {
|
|
@@ -39433,7 +39585,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
39433
39585
|
schema_version: 1,
|
|
39434
39586
|
migration_tool: "knowledge-migrator.ts"
|
|
39435
39587
|
};
|
|
39436
|
-
await mkdir3(
|
|
39588
|
+
await mkdir3(path21.dirname(sentinelPath), { recursive: true });
|
|
39437
39589
|
await writeFile4(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
39438
39590
|
}
|
|
39439
39591
|
|
|
@@ -39669,13 +39821,13 @@ async function handlePlanCommand(directory, args) {
|
|
|
39669
39821
|
// src/services/preflight-service.ts
|
|
39670
39822
|
init_manager2();
|
|
39671
39823
|
init_manager();
|
|
39672
|
-
import * as
|
|
39673
|
-
import * as
|
|
39824
|
+
import * as fs17 from "fs";
|
|
39825
|
+
import * as path28 from "path";
|
|
39674
39826
|
|
|
39675
39827
|
// src/tools/lint.ts
|
|
39676
39828
|
init_zod();
|
|
39677
|
-
import * as
|
|
39678
|
-
import * as
|
|
39829
|
+
import * as fs11 from "fs";
|
|
39830
|
+
import * as path22 from "path";
|
|
39679
39831
|
init_utils();
|
|
39680
39832
|
|
|
39681
39833
|
// src/utils/path-security.ts
|
|
@@ -39721,9 +39873,9 @@ function validateArgs(args) {
|
|
|
39721
39873
|
}
|
|
39722
39874
|
function getLinterCommand(linter, mode, projectDir) {
|
|
39723
39875
|
const isWindows = process.platform === "win32";
|
|
39724
|
-
const binDir =
|
|
39725
|
-
const biomeBin = isWindows ?
|
|
39726
|
-
const eslintBin = isWindows ?
|
|
39876
|
+
const binDir = path22.join(projectDir, "node_modules", ".bin");
|
|
39877
|
+
const biomeBin = isWindows ? path22.join(binDir, "biome.EXE") : path22.join(binDir, "biome");
|
|
39878
|
+
const eslintBin = isWindows ? path22.join(binDir, "eslint.cmd") : path22.join(binDir, "eslint");
|
|
39727
39879
|
switch (linter) {
|
|
39728
39880
|
case "biome":
|
|
39729
39881
|
if (mode === "fix") {
|
|
@@ -39739,7 +39891,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
39739
39891
|
}
|
|
39740
39892
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
39741
39893
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
39742
|
-
const gradlew =
|
|
39894
|
+
const gradlew = fs11.existsSync(path22.join(cwd, gradlewName)) ? path22.join(cwd, gradlewName) : null;
|
|
39743
39895
|
switch (linter) {
|
|
39744
39896
|
case "ruff":
|
|
39745
39897
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -39773,12 +39925,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
39773
39925
|
}
|
|
39774
39926
|
}
|
|
39775
39927
|
function detectRuff(cwd) {
|
|
39776
|
-
if (
|
|
39928
|
+
if (fs11.existsSync(path22.join(cwd, "ruff.toml")))
|
|
39777
39929
|
return isCommandAvailable("ruff");
|
|
39778
39930
|
try {
|
|
39779
|
-
const pyproject =
|
|
39780
|
-
if (
|
|
39781
|
-
const content =
|
|
39931
|
+
const pyproject = path22.join(cwd, "pyproject.toml");
|
|
39932
|
+
if (fs11.existsSync(pyproject)) {
|
|
39933
|
+
const content = fs11.readFileSync(pyproject, "utf-8");
|
|
39782
39934
|
if (content.includes("[tool.ruff]"))
|
|
39783
39935
|
return isCommandAvailable("ruff");
|
|
39784
39936
|
}
|
|
@@ -39786,21 +39938,21 @@ function detectRuff(cwd) {
|
|
|
39786
39938
|
return false;
|
|
39787
39939
|
}
|
|
39788
39940
|
function detectClippy(cwd) {
|
|
39789
|
-
return
|
|
39941
|
+
return fs11.existsSync(path22.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
39790
39942
|
}
|
|
39791
39943
|
function detectGolangciLint(cwd) {
|
|
39792
|
-
return
|
|
39944
|
+
return fs11.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
39793
39945
|
}
|
|
39794
39946
|
function detectCheckstyle(cwd) {
|
|
39795
|
-
const hasMaven =
|
|
39796
|
-
const hasGradle =
|
|
39797
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (
|
|
39947
|
+
const hasMaven = fs11.existsSync(path22.join(cwd, "pom.xml"));
|
|
39948
|
+
const hasGradle = fs11.existsSync(path22.join(cwd, "build.gradle")) || fs11.existsSync(path22.join(cwd, "build.gradle.kts"));
|
|
39949
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs11.existsSync(path22.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
39798
39950
|
return (hasMaven || hasGradle) && hasBinary;
|
|
39799
39951
|
}
|
|
39800
39952
|
function detectKtlint(cwd) {
|
|
39801
|
-
const hasKotlin =
|
|
39953
|
+
const hasKotlin = fs11.existsSync(path22.join(cwd, "build.gradle.kts")) || fs11.existsSync(path22.join(cwd, "build.gradle")) || (() => {
|
|
39802
39954
|
try {
|
|
39803
|
-
return
|
|
39955
|
+
return fs11.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
39804
39956
|
} catch {
|
|
39805
39957
|
return false;
|
|
39806
39958
|
}
|
|
@@ -39809,7 +39961,7 @@ function detectKtlint(cwd) {
|
|
|
39809
39961
|
}
|
|
39810
39962
|
function detectDotnetFormat(cwd) {
|
|
39811
39963
|
try {
|
|
39812
|
-
const files =
|
|
39964
|
+
const files = fs11.readdirSync(cwd);
|
|
39813
39965
|
const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
|
|
39814
39966
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
39815
39967
|
} catch {
|
|
@@ -39817,14 +39969,14 @@ function detectDotnetFormat(cwd) {
|
|
|
39817
39969
|
}
|
|
39818
39970
|
}
|
|
39819
39971
|
function detectCppcheck(cwd) {
|
|
39820
|
-
if (
|
|
39972
|
+
if (fs11.existsSync(path22.join(cwd, "CMakeLists.txt"))) {
|
|
39821
39973
|
return isCommandAvailable("cppcheck");
|
|
39822
39974
|
}
|
|
39823
39975
|
try {
|
|
39824
|
-
const dirsToCheck = [cwd,
|
|
39976
|
+
const dirsToCheck = [cwd, path22.join(cwd, "src")];
|
|
39825
39977
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
39826
39978
|
try {
|
|
39827
|
-
return
|
|
39979
|
+
return fs11.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
39828
39980
|
} catch {
|
|
39829
39981
|
return false;
|
|
39830
39982
|
}
|
|
@@ -39835,13 +39987,13 @@ function detectCppcheck(cwd) {
|
|
|
39835
39987
|
}
|
|
39836
39988
|
}
|
|
39837
39989
|
function detectSwiftlint(cwd) {
|
|
39838
|
-
return
|
|
39990
|
+
return fs11.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
39839
39991
|
}
|
|
39840
39992
|
function detectDartAnalyze(cwd) {
|
|
39841
|
-
return
|
|
39993
|
+
return fs11.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
39842
39994
|
}
|
|
39843
39995
|
function detectRubocop(cwd) {
|
|
39844
|
-
return (
|
|
39996
|
+
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"));
|
|
39845
39997
|
}
|
|
39846
39998
|
function detectAdditionalLinter(cwd) {
|
|
39847
39999
|
if (detectRuff(cwd))
|
|
@@ -39869,10 +40021,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
39869
40021
|
function findBinInAncestors(startDir, binName) {
|
|
39870
40022
|
let dir = startDir;
|
|
39871
40023
|
while (true) {
|
|
39872
|
-
const candidate =
|
|
39873
|
-
if (
|
|
40024
|
+
const candidate = path22.join(dir, "node_modules", ".bin", binName);
|
|
40025
|
+
if (fs11.existsSync(candidate))
|
|
39874
40026
|
return candidate;
|
|
39875
|
-
const parent =
|
|
40027
|
+
const parent = path22.dirname(dir);
|
|
39876
40028
|
if (parent === dir)
|
|
39877
40029
|
break;
|
|
39878
40030
|
dir = parent;
|
|
@@ -39881,11 +40033,11 @@ function findBinInAncestors(startDir, binName) {
|
|
|
39881
40033
|
}
|
|
39882
40034
|
function findBinInEnvPath(binName) {
|
|
39883
40035
|
const searchPath = process.env.PATH ?? "";
|
|
39884
|
-
for (const dir of searchPath.split(
|
|
40036
|
+
for (const dir of searchPath.split(path22.delimiter)) {
|
|
39885
40037
|
if (!dir)
|
|
39886
40038
|
continue;
|
|
39887
|
-
const candidate =
|
|
39888
|
-
if (
|
|
40039
|
+
const candidate = path22.join(dir, binName);
|
|
40040
|
+
if (fs11.existsSync(candidate))
|
|
39889
40041
|
return candidate;
|
|
39890
40042
|
}
|
|
39891
40043
|
return null;
|
|
@@ -39893,17 +40045,17 @@ function findBinInEnvPath(binName) {
|
|
|
39893
40045
|
async function detectAvailableLinter(directory) {
|
|
39894
40046
|
if (!directory)
|
|
39895
40047
|
return null;
|
|
39896
|
-
if (!
|
|
40048
|
+
if (!fs11.existsSync(directory))
|
|
39897
40049
|
return null;
|
|
39898
40050
|
const projectDir = directory;
|
|
39899
40051
|
const isWindows = process.platform === "win32";
|
|
39900
|
-
const biomeBin = isWindows ?
|
|
39901
|
-
const eslintBin = isWindows ?
|
|
40052
|
+
const biomeBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "biome.EXE") : path22.join(projectDir, "node_modules", ".bin", "biome");
|
|
40053
|
+
const eslintBin = isWindows ? path22.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path22.join(projectDir, "node_modules", ".bin", "eslint");
|
|
39902
40054
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
39903
40055
|
if (localResult)
|
|
39904
40056
|
return localResult;
|
|
39905
|
-
const biomeAncestor = findBinInAncestors(
|
|
39906
|
-
const eslintAncestor = findBinInAncestors(
|
|
40057
|
+
const biomeAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
40058
|
+
const eslintAncestor = findBinInAncestors(path22.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
39907
40059
|
if (biomeAncestor || eslintAncestor) {
|
|
39908
40060
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
39909
40061
|
}
|
|
@@ -39926,7 +40078,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
39926
40078
|
const result = await Promise.race([biomeExit, timeout]);
|
|
39927
40079
|
if (result === "timeout") {
|
|
39928
40080
|
biomeProc.kill();
|
|
39929
|
-
} else if (biomeProc.exitCode === 0 &&
|
|
40081
|
+
} else if (biomeProc.exitCode === 0 && fs11.existsSync(biomeBin)) {
|
|
39930
40082
|
return "biome";
|
|
39931
40083
|
}
|
|
39932
40084
|
} catch {}
|
|
@@ -39940,7 +40092,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
39940
40092
|
const result = await Promise.race([eslintExit, timeout]);
|
|
39941
40093
|
if (result === "timeout") {
|
|
39942
40094
|
eslintProc.kill();
|
|
39943
|
-
} else if (eslintProc.exitCode === 0 &&
|
|
40095
|
+
} else if (eslintProc.exitCode === 0 && fs11.existsSync(eslintBin)) {
|
|
39944
40096
|
return "eslint";
|
|
39945
40097
|
}
|
|
39946
40098
|
} catch {}
|
|
@@ -40111,8 +40263,8 @@ For Rust: rustup component add clippy`
|
|
|
40111
40263
|
|
|
40112
40264
|
// src/tools/secretscan.ts
|
|
40113
40265
|
init_zod();
|
|
40114
|
-
import * as
|
|
40115
|
-
import * as
|
|
40266
|
+
import * as fs12 from "fs";
|
|
40267
|
+
import * as path23 from "path";
|
|
40116
40268
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
40117
40269
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
40118
40270
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -40339,11 +40491,11 @@ function isGlobOrPathPattern(pattern) {
|
|
|
40339
40491
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
40340
40492
|
}
|
|
40341
40493
|
function loadSecretScanIgnore(scanDir) {
|
|
40342
|
-
const ignorePath =
|
|
40494
|
+
const ignorePath = path23.join(scanDir, ".secretscanignore");
|
|
40343
40495
|
try {
|
|
40344
|
-
if (!
|
|
40496
|
+
if (!fs12.existsSync(ignorePath))
|
|
40345
40497
|
return [];
|
|
40346
|
-
const content =
|
|
40498
|
+
const content = fs12.readFileSync(ignorePath, "utf8");
|
|
40347
40499
|
const patterns = [];
|
|
40348
40500
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
40349
40501
|
const line = rawLine.trim();
|
|
@@ -40362,7 +40514,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
40362
40514
|
if (exactNames.has(entry))
|
|
40363
40515
|
return true;
|
|
40364
40516
|
for (const pattern of globPatterns) {
|
|
40365
|
-
if (
|
|
40517
|
+
if (path23.matchesGlob(relPath, pattern))
|
|
40366
40518
|
return true;
|
|
40367
40519
|
}
|
|
40368
40520
|
return false;
|
|
@@ -40383,7 +40535,7 @@ function validateDirectoryInput(dir) {
|
|
|
40383
40535
|
return null;
|
|
40384
40536
|
}
|
|
40385
40537
|
function isBinaryFile(filePath, buffer) {
|
|
40386
|
-
const ext =
|
|
40538
|
+
const ext = path23.extname(filePath).toLowerCase();
|
|
40387
40539
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
40388
40540
|
return true;
|
|
40389
40541
|
}
|
|
@@ -40458,11 +40610,11 @@ function createRedactedContext(line, findings) {
|
|
|
40458
40610
|
result += line.slice(lastEnd);
|
|
40459
40611
|
return result;
|
|
40460
40612
|
}
|
|
40461
|
-
var O_NOFOLLOW = process.platform !== "win32" ?
|
|
40613
|
+
var O_NOFOLLOW = process.platform !== "win32" ? fs12.constants.O_NOFOLLOW : undefined;
|
|
40462
40614
|
function scanFileForSecrets(filePath) {
|
|
40463
40615
|
const findings = [];
|
|
40464
40616
|
try {
|
|
40465
|
-
const lstat =
|
|
40617
|
+
const lstat = fs12.lstatSync(filePath);
|
|
40466
40618
|
if (lstat.isSymbolicLink()) {
|
|
40467
40619
|
return findings;
|
|
40468
40620
|
}
|
|
@@ -40471,14 +40623,14 @@ function scanFileForSecrets(filePath) {
|
|
|
40471
40623
|
}
|
|
40472
40624
|
let buffer;
|
|
40473
40625
|
if (O_NOFOLLOW !== undefined) {
|
|
40474
|
-
const fd =
|
|
40626
|
+
const fd = fs12.openSync(filePath, "r", O_NOFOLLOW);
|
|
40475
40627
|
try {
|
|
40476
|
-
buffer =
|
|
40628
|
+
buffer = fs12.readFileSync(fd);
|
|
40477
40629
|
} finally {
|
|
40478
|
-
|
|
40630
|
+
fs12.closeSync(fd);
|
|
40479
40631
|
}
|
|
40480
40632
|
} else {
|
|
40481
|
-
buffer =
|
|
40633
|
+
buffer = fs12.readFileSync(filePath);
|
|
40482
40634
|
}
|
|
40483
40635
|
if (isBinaryFile(filePath, buffer)) {
|
|
40484
40636
|
return findings;
|
|
@@ -40520,9 +40672,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
40520
40672
|
return false;
|
|
40521
40673
|
}
|
|
40522
40674
|
function isPathWithinScope(realPath, scanDir) {
|
|
40523
|
-
const resolvedScanDir =
|
|
40524
|
-
const resolvedRealPath =
|
|
40525
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
40675
|
+
const resolvedScanDir = path23.resolve(scanDir);
|
|
40676
|
+
const resolvedRealPath = path23.resolve(realPath);
|
|
40677
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path23.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
40526
40678
|
}
|
|
40527
40679
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
40528
40680
|
skippedDirs: 0,
|
|
@@ -40533,7 +40685,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40533
40685
|
const files = [];
|
|
40534
40686
|
let entries;
|
|
40535
40687
|
try {
|
|
40536
|
-
entries =
|
|
40688
|
+
entries = fs12.readdirSync(dir);
|
|
40537
40689
|
} catch {
|
|
40538
40690
|
stats.fileErrors++;
|
|
40539
40691
|
return files;
|
|
@@ -40548,15 +40700,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40548
40700
|
return a.localeCompare(b);
|
|
40549
40701
|
});
|
|
40550
40702
|
for (const entry of entries) {
|
|
40551
|
-
const fullPath =
|
|
40552
|
-
const relPath =
|
|
40703
|
+
const fullPath = path23.join(dir, entry);
|
|
40704
|
+
const relPath = path23.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
40553
40705
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
40554
40706
|
stats.skippedDirs++;
|
|
40555
40707
|
continue;
|
|
40556
40708
|
}
|
|
40557
40709
|
let lstat;
|
|
40558
40710
|
try {
|
|
40559
|
-
lstat =
|
|
40711
|
+
lstat = fs12.lstatSync(fullPath);
|
|
40560
40712
|
} catch {
|
|
40561
40713
|
stats.fileErrors++;
|
|
40562
40714
|
continue;
|
|
@@ -40568,7 +40720,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40568
40720
|
if (lstat.isDirectory()) {
|
|
40569
40721
|
let realPath;
|
|
40570
40722
|
try {
|
|
40571
|
-
realPath =
|
|
40723
|
+
realPath = fs12.realpathSync(fullPath);
|
|
40572
40724
|
} catch {
|
|
40573
40725
|
stats.fileErrors++;
|
|
40574
40726
|
continue;
|
|
@@ -40584,7 +40736,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
40584
40736
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
40585
40737
|
files.push(...subFiles);
|
|
40586
40738
|
} else if (lstat.isFile()) {
|
|
40587
|
-
const ext =
|
|
40739
|
+
const ext = path23.extname(fullPath).toLowerCase();
|
|
40588
40740
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
40589
40741
|
files.push(fullPath);
|
|
40590
40742
|
} else {
|
|
@@ -40650,15 +40802,15 @@ var secretscan = createSwarmTool({
|
|
|
40650
40802
|
}
|
|
40651
40803
|
}
|
|
40652
40804
|
try {
|
|
40653
|
-
const _scanDirRaw =
|
|
40805
|
+
const _scanDirRaw = path23.resolve(directory);
|
|
40654
40806
|
const scanDir = (() => {
|
|
40655
40807
|
try {
|
|
40656
|
-
return
|
|
40808
|
+
return fs12.realpathSync(_scanDirRaw);
|
|
40657
40809
|
} catch {
|
|
40658
40810
|
return _scanDirRaw;
|
|
40659
40811
|
}
|
|
40660
40812
|
})();
|
|
40661
|
-
if (!
|
|
40813
|
+
if (!fs12.existsSync(scanDir)) {
|
|
40662
40814
|
const errorResult = {
|
|
40663
40815
|
error: "directory not found",
|
|
40664
40816
|
scan_dir: directory,
|
|
@@ -40669,7 +40821,7 @@ var secretscan = createSwarmTool({
|
|
|
40669
40821
|
};
|
|
40670
40822
|
return JSON.stringify(errorResult, null, 2);
|
|
40671
40823
|
}
|
|
40672
|
-
const dirStat =
|
|
40824
|
+
const dirStat = fs12.statSync(scanDir);
|
|
40673
40825
|
if (!dirStat.isDirectory()) {
|
|
40674
40826
|
const errorResult = {
|
|
40675
40827
|
error: "target must be a directory, not a file",
|
|
@@ -40720,7 +40872,7 @@ var secretscan = createSwarmTool({
|
|
|
40720
40872
|
break;
|
|
40721
40873
|
const fileFindings = scanFileForSecrets(filePath);
|
|
40722
40874
|
try {
|
|
40723
|
-
const stat2 =
|
|
40875
|
+
const stat2 = fs12.statSync(filePath);
|
|
40724
40876
|
if (stat2.size > MAX_FILE_SIZE_BYTES) {
|
|
40725
40877
|
skippedFiles++;
|
|
40726
40878
|
continue;
|
|
@@ -40809,12 +40961,12 @@ async function runSecretscan(directory) {
|
|
|
40809
40961
|
|
|
40810
40962
|
// src/tools/test-runner.ts
|
|
40811
40963
|
init_zod();
|
|
40812
|
-
import * as
|
|
40813
|
-
import * as
|
|
40964
|
+
import * as fs16 from "fs";
|
|
40965
|
+
import * as path27 from "path";
|
|
40814
40966
|
|
|
40815
40967
|
// src/test-impact/analyzer.ts
|
|
40816
|
-
import
|
|
40817
|
-
import
|
|
40968
|
+
import fs13 from "fs";
|
|
40969
|
+
import path24 from "path";
|
|
40818
40970
|
var IMPORT_REGEX_ES = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
40819
40971
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
40820
40972
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -40825,7 +40977,7 @@ function normalizePath(p) {
|
|
|
40825
40977
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
40826
40978
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
40827
40979
|
try {
|
|
40828
|
-
const stat2 =
|
|
40980
|
+
const stat2 = fs13.statSync(sourcePath);
|
|
40829
40981
|
if (stat2.mtimeMs > generatedAtMs) {
|
|
40830
40982
|
return true;
|
|
40831
40983
|
}
|
|
@@ -40839,15 +40991,15 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
40839
40991
|
if (!importPath.startsWith(".")) {
|
|
40840
40992
|
return null;
|
|
40841
40993
|
}
|
|
40842
|
-
const resolved =
|
|
40843
|
-
if (
|
|
40844
|
-
if (
|
|
40994
|
+
const resolved = path24.resolve(fromDir, importPath);
|
|
40995
|
+
if (path24.extname(resolved)) {
|
|
40996
|
+
if (fs13.existsSync(resolved) && fs13.statSync(resolved).isFile()) {
|
|
40845
40997
|
return normalizePath(resolved);
|
|
40846
40998
|
}
|
|
40847
40999
|
} else {
|
|
40848
41000
|
for (const ext of EXTENSIONS_TO_TRY) {
|
|
40849
41001
|
const withExt = resolved + ext;
|
|
40850
|
-
if (
|
|
41002
|
+
if (fs13.existsSync(withExt) && fs13.statSync(withExt).isFile()) {
|
|
40851
41003
|
return normalizePath(withExt);
|
|
40852
41004
|
}
|
|
40853
41005
|
}
|
|
@@ -40866,13 +41018,13 @@ function findTestFilesSync(cwd) {
|
|
|
40866
41018
|
function walk(dir, visitedInodes) {
|
|
40867
41019
|
let entries;
|
|
40868
41020
|
try {
|
|
40869
|
-
entries =
|
|
41021
|
+
entries = fs13.readdirSync(dir, { withFileTypes: true });
|
|
40870
41022
|
} catch {
|
|
40871
41023
|
return;
|
|
40872
41024
|
}
|
|
40873
41025
|
let dirInode;
|
|
40874
41026
|
try {
|
|
40875
|
-
dirInode =
|
|
41027
|
+
dirInode = fs13.statSync(dir).ino;
|
|
40876
41028
|
} catch {
|
|
40877
41029
|
return;
|
|
40878
41030
|
}
|
|
@@ -40885,12 +41037,12 @@ function findTestFilesSync(cwd) {
|
|
|
40885
41037
|
for (const entry of entries) {
|
|
40886
41038
|
if (entry.isDirectory()) {
|
|
40887
41039
|
if (!skipDirs.has(entry.name)) {
|
|
40888
|
-
walk(
|
|
41040
|
+
walk(path24.join(dir, entry.name), visitedInodes);
|
|
40889
41041
|
}
|
|
40890
41042
|
} else if (entry.isFile()) {
|
|
40891
41043
|
const name = entry.name;
|
|
40892
41044
|
if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
|
|
40893
|
-
testFiles.push(normalizePath(
|
|
41045
|
+
testFiles.push(normalizePath(path24.join(dir, entry.name)));
|
|
40894
41046
|
}
|
|
40895
41047
|
}
|
|
40896
41048
|
}
|
|
@@ -40920,7 +41072,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
40920
41072
|
for (const testFile of testFiles) {
|
|
40921
41073
|
let content;
|
|
40922
41074
|
try {
|
|
40923
|
-
content =
|
|
41075
|
+
content = fs13.readFileSync(testFile, "utf-8");
|
|
40924
41076
|
} catch {
|
|
40925
41077
|
continue;
|
|
40926
41078
|
}
|
|
@@ -40928,7 +41080,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
40928
41080
|
continue;
|
|
40929
41081
|
}
|
|
40930
41082
|
const imports = extractImports(content);
|
|
40931
|
-
const testDir =
|
|
41083
|
+
const testDir = path24.dirname(testFile);
|
|
40932
41084
|
for (const importPath of imports) {
|
|
40933
41085
|
const resolvedSource = resolveRelativeImport(testDir, importPath);
|
|
40934
41086
|
if (resolvedSource === null) {
|
|
@@ -40950,10 +41102,10 @@ async function buildImpactMap(cwd) {
|
|
|
40950
41102
|
return impactMap;
|
|
40951
41103
|
}
|
|
40952
41104
|
async function loadImpactMap(cwd) {
|
|
40953
|
-
const cachePath =
|
|
40954
|
-
if (
|
|
41105
|
+
const cachePath = path24.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
41106
|
+
if (fs13.existsSync(cachePath)) {
|
|
40955
41107
|
try {
|
|
40956
|
-
const content =
|
|
41108
|
+
const content = fs13.readFileSync(cachePath, "utf-8");
|
|
40957
41109
|
const data = JSON.parse(content);
|
|
40958
41110
|
const map3 = data.map;
|
|
40959
41111
|
const generatedAt = new Date(data.generatedAt).getTime();
|
|
@@ -40965,17 +41117,17 @@ async function loadImpactMap(cwd) {
|
|
|
40965
41117
|
return buildImpactMap(cwd);
|
|
40966
41118
|
}
|
|
40967
41119
|
async function saveImpactMap(cwd, impactMap) {
|
|
40968
|
-
const cacheDir =
|
|
40969
|
-
const cachePath =
|
|
40970
|
-
if (!
|
|
40971
|
-
|
|
41120
|
+
const cacheDir = path24.join(cwd, ".swarm", "cache");
|
|
41121
|
+
const cachePath = path24.join(cacheDir, "impact-map.json");
|
|
41122
|
+
if (!fs13.existsSync(cacheDir)) {
|
|
41123
|
+
fs13.mkdirSync(cacheDir, { recursive: true });
|
|
40972
41124
|
}
|
|
40973
41125
|
const data = {
|
|
40974
41126
|
generatedAt: new Date().toISOString(),
|
|
40975
41127
|
fileCount: Object.keys(impactMap).length,
|
|
40976
41128
|
map: impactMap
|
|
40977
41129
|
};
|
|
40978
|
-
|
|
41130
|
+
fs13.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
40979
41131
|
}
|
|
40980
41132
|
async function analyzeImpact(changedFiles, cwd) {
|
|
40981
41133
|
if (!Array.isArray(changedFiles)) {
|
|
@@ -40992,7 +41144,7 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
40992
41144
|
const impactedTestsSet = new Set;
|
|
40993
41145
|
const untestedFiles = [];
|
|
40994
41146
|
for (const changedFile of validFiles) {
|
|
40995
|
-
const normalizedChanged = normalizePath(
|
|
41147
|
+
const normalizedChanged = normalizePath(path24.resolve(changedFile));
|
|
40996
41148
|
const tests = impactMap[normalizedChanged];
|
|
40997
41149
|
if (tests && tests.length > 0) {
|
|
40998
41150
|
for (const test of tests) {
|
|
@@ -41238,14 +41390,14 @@ function detectFlakyTests(allHistory) {
|
|
|
41238
41390
|
}
|
|
41239
41391
|
|
|
41240
41392
|
// src/test-impact/history-store.ts
|
|
41241
|
-
import
|
|
41242
|
-
import
|
|
41393
|
+
import fs14 from "fs";
|
|
41394
|
+
import path25 from "path";
|
|
41243
41395
|
var MAX_HISTORY_PER_TEST = 20;
|
|
41244
41396
|
var MAX_ERROR_LENGTH = 500;
|
|
41245
41397
|
var MAX_STACK_LENGTH = 200;
|
|
41246
41398
|
var MAX_CHANGED_FILES = 50;
|
|
41247
41399
|
function getHistoryPath(workingDir) {
|
|
41248
|
-
return
|
|
41400
|
+
return path25.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
|
|
41249
41401
|
}
|
|
41250
41402
|
function sanitizeErrorMessage(errorMessage) {
|
|
41251
41403
|
if (errorMessage === undefined) {
|
|
@@ -41305,9 +41457,9 @@ function appendTestRun(record3, workingDir) {
|
|
|
41305
41457
|
changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
|
|
41306
41458
|
};
|
|
41307
41459
|
const historyPath = getHistoryPath(workingDir);
|
|
41308
|
-
const historyDir =
|
|
41309
|
-
if (!
|
|
41310
|
-
|
|
41460
|
+
const historyDir = path25.dirname(historyPath);
|
|
41461
|
+
if (!fs14.existsSync(historyDir)) {
|
|
41462
|
+
fs14.mkdirSync(historyDir, { recursive: true });
|
|
41311
41463
|
}
|
|
41312
41464
|
const existingRecords = readAllRecords(historyPath);
|
|
41313
41465
|
existingRecords.push(sanitizedRecord);
|
|
@@ -41332,24 +41484,24 @@ function appendTestRun(record3, workingDir) {
|
|
|
41332
41484
|
`)}
|
|
41333
41485
|
`;
|
|
41334
41486
|
const tempPath = `${historyPath}.tmp`;
|
|
41335
|
-
|
|
41336
|
-
|
|
41487
|
+
fs14.writeFileSync(tempPath, content, "utf-8");
|
|
41488
|
+
fs14.renameSync(tempPath, historyPath);
|
|
41337
41489
|
} catch (err) {
|
|
41338
41490
|
try {
|
|
41339
41491
|
const tempPath = `${historyPath}.tmp`;
|
|
41340
|
-
if (
|
|
41341
|
-
|
|
41492
|
+
if (fs14.existsSync(tempPath)) {
|
|
41493
|
+
fs14.unlinkSync(tempPath);
|
|
41342
41494
|
}
|
|
41343
41495
|
} catch {}
|
|
41344
41496
|
throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
|
|
41345
41497
|
}
|
|
41346
41498
|
}
|
|
41347
41499
|
function readAllRecords(historyPath) {
|
|
41348
|
-
if (!
|
|
41500
|
+
if (!fs14.existsSync(historyPath)) {
|
|
41349
41501
|
return [];
|
|
41350
41502
|
}
|
|
41351
41503
|
try {
|
|
41352
|
-
const content =
|
|
41504
|
+
const content = fs14.readFileSync(historyPath, "utf-8");
|
|
41353
41505
|
const lines = content.split(`
|
|
41354
41506
|
`);
|
|
41355
41507
|
const records = [];
|
|
@@ -41378,8 +41530,8 @@ function getAllHistory(workingDir) {
|
|
|
41378
41530
|
}
|
|
41379
41531
|
|
|
41380
41532
|
// src/tools/resolve-working-directory.ts
|
|
41381
|
-
import * as
|
|
41382
|
-
import * as
|
|
41533
|
+
import * as fs15 from "fs";
|
|
41534
|
+
import * as path26 from "path";
|
|
41383
41535
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
41384
41536
|
if (workingDirectory == null || workingDirectory === "") {
|
|
41385
41537
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -41399,18 +41551,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
41399
41551
|
};
|
|
41400
41552
|
}
|
|
41401
41553
|
}
|
|
41402
|
-
const normalizedDir =
|
|
41403
|
-
const pathParts = normalizedDir.split(
|
|
41554
|
+
const normalizedDir = path26.normalize(workingDirectory);
|
|
41555
|
+
const pathParts = normalizedDir.split(path26.sep);
|
|
41404
41556
|
if (pathParts.includes("..")) {
|
|
41405
41557
|
return {
|
|
41406
41558
|
success: false,
|
|
41407
41559
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
41408
41560
|
};
|
|
41409
41561
|
}
|
|
41410
|
-
const resolvedDir =
|
|
41562
|
+
const resolvedDir = path26.resolve(normalizedDir);
|
|
41411
41563
|
let statResult;
|
|
41412
41564
|
try {
|
|
41413
|
-
statResult =
|
|
41565
|
+
statResult = fs15.statSync(resolvedDir);
|
|
41414
41566
|
} catch {
|
|
41415
41567
|
return {
|
|
41416
41568
|
success: false,
|
|
@@ -41423,17 +41575,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
41423
41575
|
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
41424
41576
|
};
|
|
41425
41577
|
}
|
|
41426
|
-
const resolvedFallback =
|
|
41578
|
+
const resolvedFallback = path26.resolve(fallbackDirectory);
|
|
41427
41579
|
let fallbackExists = false;
|
|
41428
41580
|
try {
|
|
41429
|
-
|
|
41581
|
+
fs15.statSync(resolvedFallback);
|
|
41430
41582
|
fallbackExists = true;
|
|
41431
41583
|
} catch {
|
|
41432
41584
|
fallbackExists = false;
|
|
41433
41585
|
}
|
|
41434
41586
|
if (workingDirectory != null && workingDirectory !== "") {
|
|
41435
41587
|
if (fallbackExists) {
|
|
41436
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
41588
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path26.sep);
|
|
41437
41589
|
if (isSubdirectory) {
|
|
41438
41590
|
return {
|
|
41439
41591
|
success: false,
|
|
@@ -41523,19 +41675,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
41523
41675
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
41524
41676
|
}
|
|
41525
41677
|
function detectGoTest(cwd) {
|
|
41526
|
-
return
|
|
41678
|
+
return fs16.existsSync(path27.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
41527
41679
|
}
|
|
41528
41680
|
function detectJavaMaven(cwd) {
|
|
41529
|
-
return
|
|
41681
|
+
return fs16.existsSync(path27.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
41530
41682
|
}
|
|
41531
41683
|
function detectGradle(cwd) {
|
|
41532
|
-
const hasBuildFile =
|
|
41533
|
-
const hasGradlew =
|
|
41684
|
+
const hasBuildFile = fs16.existsSync(path27.join(cwd, "build.gradle")) || fs16.existsSync(path27.join(cwd, "build.gradle.kts"));
|
|
41685
|
+
const hasGradlew = fs16.existsSync(path27.join(cwd, "gradlew")) || fs16.existsSync(path27.join(cwd, "gradlew.bat"));
|
|
41534
41686
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
41535
41687
|
}
|
|
41536
41688
|
function detectDotnetTest(cwd) {
|
|
41537
41689
|
try {
|
|
41538
|
-
const files =
|
|
41690
|
+
const files = fs16.readdirSync(cwd);
|
|
41539
41691
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
41540
41692
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
41541
41693
|
} catch {
|
|
@@ -41543,32 +41695,32 @@ function detectDotnetTest(cwd) {
|
|
|
41543
41695
|
}
|
|
41544
41696
|
}
|
|
41545
41697
|
function detectCTest(cwd) {
|
|
41546
|
-
const hasSource =
|
|
41547
|
-
const hasBuildCache =
|
|
41698
|
+
const hasSource = fs16.existsSync(path27.join(cwd, "CMakeLists.txt"));
|
|
41699
|
+
const hasBuildCache = fs16.existsSync(path27.join(cwd, "CMakeCache.txt")) || fs16.existsSync(path27.join(cwd, "build", "CMakeCache.txt"));
|
|
41548
41700
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
41549
41701
|
}
|
|
41550
41702
|
function detectSwiftTest(cwd) {
|
|
41551
|
-
return
|
|
41703
|
+
return fs16.existsSync(path27.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
41552
41704
|
}
|
|
41553
41705
|
function detectDartTest(cwd) {
|
|
41554
|
-
return
|
|
41706
|
+
return fs16.existsSync(path27.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
41555
41707
|
}
|
|
41556
41708
|
function detectRSpec(cwd) {
|
|
41557
|
-
const hasRSpecFile =
|
|
41558
|
-
const hasGemfile =
|
|
41559
|
-
const hasSpecDir =
|
|
41709
|
+
const hasRSpecFile = fs16.existsSync(path27.join(cwd, ".rspec"));
|
|
41710
|
+
const hasGemfile = fs16.existsSync(path27.join(cwd, "Gemfile"));
|
|
41711
|
+
const hasSpecDir = fs16.existsSync(path27.join(cwd, "spec"));
|
|
41560
41712
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
41561
41713
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
41562
41714
|
}
|
|
41563
41715
|
function detectMinitest(cwd) {
|
|
41564
|
-
return
|
|
41716
|
+
return fs16.existsSync(path27.join(cwd, "test")) && (fs16.existsSync(path27.join(cwd, "Gemfile")) || fs16.existsSync(path27.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
41565
41717
|
}
|
|
41566
41718
|
async function detectTestFramework(cwd) {
|
|
41567
41719
|
const baseDir = cwd;
|
|
41568
41720
|
try {
|
|
41569
|
-
const packageJsonPath =
|
|
41570
|
-
if (
|
|
41571
|
-
const content =
|
|
41721
|
+
const packageJsonPath = path27.join(baseDir, "package.json");
|
|
41722
|
+
if (fs16.existsSync(packageJsonPath)) {
|
|
41723
|
+
const content = fs16.readFileSync(packageJsonPath, "utf-8");
|
|
41572
41724
|
const pkg = JSON.parse(content);
|
|
41573
41725
|
const _deps = pkg.dependencies || {};
|
|
41574
41726
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -41587,38 +41739,38 @@ async function detectTestFramework(cwd) {
|
|
|
41587
41739
|
return "jest";
|
|
41588
41740
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
41589
41741
|
return "mocha";
|
|
41590
|
-
if (
|
|
41742
|
+
if (fs16.existsSync(path27.join(baseDir, "bun.lockb")) || fs16.existsSync(path27.join(baseDir, "bun.lock"))) {
|
|
41591
41743
|
if (scripts.test?.includes("bun"))
|
|
41592
41744
|
return "bun";
|
|
41593
41745
|
}
|
|
41594
41746
|
}
|
|
41595
41747
|
} catch {}
|
|
41596
41748
|
try {
|
|
41597
|
-
const pyprojectTomlPath =
|
|
41598
|
-
const setupCfgPath =
|
|
41599
|
-
const requirementsTxtPath =
|
|
41600
|
-
if (
|
|
41601
|
-
const content =
|
|
41749
|
+
const pyprojectTomlPath = path27.join(baseDir, "pyproject.toml");
|
|
41750
|
+
const setupCfgPath = path27.join(baseDir, "setup.cfg");
|
|
41751
|
+
const requirementsTxtPath = path27.join(baseDir, "requirements.txt");
|
|
41752
|
+
if (fs16.existsSync(pyprojectTomlPath)) {
|
|
41753
|
+
const content = fs16.readFileSync(pyprojectTomlPath, "utf-8");
|
|
41602
41754
|
if (content.includes("[tool.pytest"))
|
|
41603
41755
|
return "pytest";
|
|
41604
41756
|
if (content.includes("pytest"))
|
|
41605
41757
|
return "pytest";
|
|
41606
41758
|
}
|
|
41607
|
-
if (
|
|
41608
|
-
const content =
|
|
41759
|
+
if (fs16.existsSync(setupCfgPath)) {
|
|
41760
|
+
const content = fs16.readFileSync(setupCfgPath, "utf-8");
|
|
41609
41761
|
if (content.includes("[pytest]"))
|
|
41610
41762
|
return "pytest";
|
|
41611
41763
|
}
|
|
41612
|
-
if (
|
|
41613
|
-
const content =
|
|
41764
|
+
if (fs16.existsSync(requirementsTxtPath)) {
|
|
41765
|
+
const content = fs16.readFileSync(requirementsTxtPath, "utf-8");
|
|
41614
41766
|
if (content.includes("pytest"))
|
|
41615
41767
|
return "pytest";
|
|
41616
41768
|
}
|
|
41617
41769
|
} catch {}
|
|
41618
41770
|
try {
|
|
41619
|
-
const cargoTomlPath =
|
|
41620
|
-
if (
|
|
41621
|
-
const content =
|
|
41771
|
+
const cargoTomlPath = path27.join(baseDir, "Cargo.toml");
|
|
41772
|
+
if (fs16.existsSync(cargoTomlPath)) {
|
|
41773
|
+
const content = fs16.readFileSync(cargoTomlPath, "utf-8");
|
|
41622
41774
|
if (content.includes("[dev-dependencies]")) {
|
|
41623
41775
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
41624
41776
|
return "cargo";
|
|
@@ -41627,10 +41779,10 @@ async function detectTestFramework(cwd) {
|
|
|
41627
41779
|
}
|
|
41628
41780
|
} catch {}
|
|
41629
41781
|
try {
|
|
41630
|
-
const pesterConfigPath =
|
|
41631
|
-
const pesterConfigJsonPath =
|
|
41632
|
-
const pesterPs1Path =
|
|
41633
|
-
if (
|
|
41782
|
+
const pesterConfigPath = path27.join(baseDir, "pester.config.ps1");
|
|
41783
|
+
const pesterConfigJsonPath = path27.join(baseDir, "pester.config.ps1.json");
|
|
41784
|
+
const pesterPs1Path = path27.join(baseDir, "tests.ps1");
|
|
41785
|
+
if (fs16.existsSync(pesterConfigPath) || fs16.existsSync(pesterConfigJsonPath) || fs16.existsSync(pesterPs1Path)) {
|
|
41634
41786
|
return "pester";
|
|
41635
41787
|
}
|
|
41636
41788
|
} catch {}
|
|
@@ -41672,12 +41824,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
41672
41824
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
41673
41825
|
}
|
|
41674
41826
|
function resolveWorkspacePath(file3, workingDir) {
|
|
41675
|
-
return
|
|
41827
|
+
return path27.isAbsolute(file3) ? path27.resolve(file3) : path27.resolve(workingDir, file3);
|
|
41676
41828
|
}
|
|
41677
41829
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
41678
41830
|
if (!preferRelative)
|
|
41679
41831
|
return absolutePath;
|
|
41680
|
-
return
|
|
41832
|
+
return path27.relative(workingDir, absolutePath);
|
|
41681
41833
|
}
|
|
41682
41834
|
function dedupePush(target, value) {
|
|
41683
41835
|
if (!target.includes(value)) {
|
|
@@ -41714,18 +41866,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
41714
41866
|
}
|
|
41715
41867
|
}
|
|
41716
41868
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
41717
|
-
const relativeDir =
|
|
41869
|
+
const relativeDir = path27.dirname(relativePath);
|
|
41718
41870
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
41719
41871
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
41720
|
-
const rootDir =
|
|
41721
|
-
return nestedRelativeDir ? [rootDir,
|
|
41872
|
+
const rootDir = path27.join(workingDir, dirName);
|
|
41873
|
+
return nestedRelativeDir ? [rootDir, path27.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
41722
41874
|
});
|
|
41723
41875
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
41724
41876
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
41725
|
-
directories.push(
|
|
41877
|
+
directories.push(path27.join(workingDir, "src/test/java", path27.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
41726
41878
|
}
|
|
41727
41879
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
41728
|
-
directories.push(
|
|
41880
|
+
directories.push(path27.join(workingDir, "src/test/kotlin", path27.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
41729
41881
|
}
|
|
41730
41882
|
return [...new Set(directories)];
|
|
41731
41883
|
}
|
|
@@ -41753,23 +41905,23 @@ function isLanguageSpecificTestFile(basename4) {
|
|
|
41753
41905
|
}
|
|
41754
41906
|
function isConventionTestFilePath(filePath) {
|
|
41755
41907
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
41756
|
-
const basename4 =
|
|
41908
|
+
const basename4 = path27.basename(filePath);
|
|
41757
41909
|
return hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || isLanguageSpecificTestFile(basename4) || isTestDirectoryPath(normalizedPath);
|
|
41758
41910
|
}
|
|
41759
41911
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
41760
41912
|
const testFiles = [];
|
|
41761
41913
|
for (const file3 of sourceFiles) {
|
|
41762
41914
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
41763
|
-
const relativeFile =
|
|
41764
|
-
const basename4 =
|
|
41765
|
-
const dirname11 =
|
|
41766
|
-
const preferRelativeOutput = !
|
|
41915
|
+
const relativeFile = path27.relative(workingDir, absoluteFile);
|
|
41916
|
+
const basename4 = path27.basename(absoluteFile);
|
|
41917
|
+
const dirname11 = path27.dirname(absoluteFile);
|
|
41918
|
+
const preferRelativeOutput = !path27.isAbsolute(file3);
|
|
41767
41919
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
41768
41920
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
41769
41921
|
continue;
|
|
41770
41922
|
}
|
|
41771
41923
|
const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
|
|
41772
|
-
const ext =
|
|
41924
|
+
const ext = path27.extname(basename4);
|
|
41773
41925
|
const genericTestNames = [
|
|
41774
41926
|
`${nameWithoutExt}.spec${ext}`,
|
|
41775
41927
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -41778,7 +41930,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
41778
41930
|
const colocatedCandidates = [
|
|
41779
41931
|
...genericTestNames,
|
|
41780
41932
|
...languageSpecificTestNames
|
|
41781
|
-
].map((candidateName) =>
|
|
41933
|
+
].map((candidateName) => path27.join(dirname11, candidateName));
|
|
41782
41934
|
const testDirectoryNames = [
|
|
41783
41935
|
basename4,
|
|
41784
41936
|
...genericTestNames,
|
|
@@ -41787,11 +41939,11 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
41787
41939
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
41788
41940
|
const possibleTestFiles = [
|
|
41789
41941
|
...colocatedCandidates,
|
|
41790
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
41791
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
41942
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path27.join(dirname11, dirName, candidateName))),
|
|
41943
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path27.join(candidateDir, candidateName)))
|
|
41792
41944
|
];
|
|
41793
41945
|
for (const testFile of possibleTestFiles) {
|
|
41794
|
-
if (
|
|
41946
|
+
if (fs16.existsSync(testFile)) {
|
|
41795
41947
|
dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
|
|
41796
41948
|
}
|
|
41797
41949
|
}
|
|
@@ -41808,8 +41960,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41808
41960
|
for (const testFile of candidateTestFiles) {
|
|
41809
41961
|
try {
|
|
41810
41962
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
41811
|
-
const content =
|
|
41812
|
-
const testDir =
|
|
41963
|
+
const content = fs16.readFileSync(absoluteTestFile, "utf-8");
|
|
41964
|
+
const testDir = path27.dirname(absoluteTestFile);
|
|
41813
41965
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
41814
41966
|
let match;
|
|
41815
41967
|
match = importRegex.exec(content);
|
|
@@ -41817,8 +41969,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41817
41969
|
const importPath = match[1];
|
|
41818
41970
|
let resolvedImport;
|
|
41819
41971
|
if (importPath.startsWith(".")) {
|
|
41820
|
-
resolvedImport =
|
|
41821
|
-
const existingExt =
|
|
41972
|
+
resolvedImport = path27.resolve(testDir, importPath);
|
|
41973
|
+
const existingExt = path27.extname(resolvedImport);
|
|
41822
41974
|
if (!existingExt) {
|
|
41823
41975
|
for (const extToTry of [
|
|
41824
41976
|
".ts",
|
|
@@ -41829,7 +41981,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41829
41981
|
".cjs"
|
|
41830
41982
|
]) {
|
|
41831
41983
|
const withExt = resolvedImport + extToTry;
|
|
41832
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
41984
|
+
if (absoluteSourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
|
|
41833
41985
|
resolvedImport = withExt;
|
|
41834
41986
|
break;
|
|
41835
41987
|
}
|
|
@@ -41838,12 +41990,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41838
41990
|
} else {
|
|
41839
41991
|
continue;
|
|
41840
41992
|
}
|
|
41841
|
-
const importBasename =
|
|
41842
|
-
const importDir =
|
|
41993
|
+
const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
|
|
41994
|
+
const importDir = path27.dirname(resolvedImport);
|
|
41843
41995
|
for (const sourceFile of absoluteSourceFiles) {
|
|
41844
|
-
const sourceDir =
|
|
41845
|
-
const sourceBasename =
|
|
41846
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
41996
|
+
const sourceDir = path27.dirname(sourceFile);
|
|
41997
|
+
const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
|
|
41998
|
+
const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
|
|
41847
41999
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
41848
42000
|
dedupePush(testFiles, testFile);
|
|
41849
42001
|
break;
|
|
@@ -41856,8 +42008,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41856
42008
|
while (match !== null) {
|
|
41857
42009
|
const importPath = match[1];
|
|
41858
42010
|
if (importPath.startsWith(".")) {
|
|
41859
|
-
let resolvedImport =
|
|
41860
|
-
const existingExt =
|
|
42011
|
+
let resolvedImport = path27.resolve(testDir, importPath);
|
|
42012
|
+
const existingExt = path27.extname(resolvedImport);
|
|
41861
42013
|
if (!existingExt) {
|
|
41862
42014
|
for (const extToTry of [
|
|
41863
42015
|
".ts",
|
|
@@ -41868,18 +42020,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
41868
42020
|
".cjs"
|
|
41869
42021
|
]) {
|
|
41870
42022
|
const withExt = resolvedImport + extToTry;
|
|
41871
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
42023
|
+
if (absoluteSourceFiles.includes(withExt) || fs16.existsSync(withExt)) {
|
|
41872
42024
|
resolvedImport = withExt;
|
|
41873
42025
|
break;
|
|
41874
42026
|
}
|
|
41875
42027
|
}
|
|
41876
42028
|
}
|
|
41877
|
-
const importDir =
|
|
41878
|
-
const importBasename =
|
|
42029
|
+
const importDir = path27.dirname(resolvedImport);
|
|
42030
|
+
const importBasename = path27.basename(resolvedImport, path27.extname(resolvedImport));
|
|
41879
42031
|
for (const sourceFile of absoluteSourceFiles) {
|
|
41880
|
-
const sourceDir =
|
|
41881
|
-
const sourceBasename =
|
|
41882
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
42032
|
+
const sourceDir = path27.dirname(sourceFile);
|
|
42033
|
+
const sourceBasename = path27.basename(sourceFile, path27.extname(sourceFile));
|
|
42034
|
+
const isRelatedDir = importDir === sourceDir || importDir === path27.join(sourceDir, "__tests__") || importDir === path27.join(sourceDir, "tests") || importDir === path27.join(sourceDir, "test") || importDir === path27.join(sourceDir, "spec");
|
|
41883
42035
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
41884
42036
|
dedupePush(testFiles, testFile);
|
|
41885
42037
|
break;
|
|
@@ -41982,8 +42134,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
41982
42134
|
return ["mvn", "test"];
|
|
41983
42135
|
case "gradle": {
|
|
41984
42136
|
const isWindows = process.platform === "win32";
|
|
41985
|
-
const hasGradlewBat =
|
|
41986
|
-
const hasGradlew =
|
|
42137
|
+
const hasGradlewBat = fs16.existsSync(path27.join(baseDir, "gradlew.bat"));
|
|
42138
|
+
const hasGradlew = fs16.existsSync(path27.join(baseDir, "gradlew"));
|
|
41987
42139
|
if (hasGradlewBat && isWindows)
|
|
41988
42140
|
return ["gradlew.bat", "test"];
|
|
41989
42141
|
if (hasGradlew)
|
|
@@ -42000,7 +42152,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
42000
42152
|
"cmake-build-release",
|
|
42001
42153
|
"out"
|
|
42002
42154
|
];
|
|
42003
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
42155
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs16.existsSync(path27.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
42004
42156
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
42005
42157
|
}
|
|
42006
42158
|
case "swift-test":
|
|
@@ -42628,7 +42780,7 @@ var test_runner = createSwarmTool({
|
|
|
42628
42780
|
const sourceFiles = args.files.filter((file3) => {
|
|
42629
42781
|
if (directTestFiles.includes(file3))
|
|
42630
42782
|
return false;
|
|
42631
|
-
const ext =
|
|
42783
|
+
const ext = path27.extname(file3).toLowerCase();
|
|
42632
42784
|
return SOURCE_EXTENSIONS.has(ext);
|
|
42633
42785
|
});
|
|
42634
42786
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -42663,7 +42815,7 @@ var test_runner = createSwarmTool({
|
|
|
42663
42815
|
if (isConventionTestFilePath(f)) {
|
|
42664
42816
|
return false;
|
|
42665
42817
|
}
|
|
42666
|
-
const ext =
|
|
42818
|
+
const ext = path27.extname(f).toLowerCase();
|
|
42667
42819
|
return SOURCE_EXTENSIONS.has(ext);
|
|
42668
42820
|
});
|
|
42669
42821
|
if (sourceFiles.length === 0) {
|
|
@@ -42690,7 +42842,7 @@ var test_runner = createSwarmTool({
|
|
|
42690
42842
|
if (isConventionTestFilePath(f)) {
|
|
42691
42843
|
return false;
|
|
42692
42844
|
}
|
|
42693
|
-
const ext =
|
|
42845
|
+
const ext = path27.extname(f).toLowerCase();
|
|
42694
42846
|
return SOURCE_EXTENSIONS.has(ext);
|
|
42695
42847
|
});
|
|
42696
42848
|
if (sourceFiles.length === 0) {
|
|
@@ -42708,8 +42860,8 @@ var test_runner = createSwarmTool({
|
|
|
42708
42860
|
const impactResult = await analyzeImpact(sourceFiles, workingDir);
|
|
42709
42861
|
if (impactResult.impactedTests.length > 0) {
|
|
42710
42862
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
42711
|
-
const relativePath =
|
|
42712
|
-
return
|
|
42863
|
+
const relativePath = path27.relative(workingDir, absPath);
|
|
42864
|
+
return path27.isAbsolute(relativePath) ? absPath : relativePath;
|
|
42713
42865
|
});
|
|
42714
42866
|
} else {
|
|
42715
42867
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -42802,8 +42954,8 @@ function validateDirectoryPath(dir) {
|
|
|
42802
42954
|
if (dir.includes("..")) {
|
|
42803
42955
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
42804
42956
|
}
|
|
42805
|
-
const normalized =
|
|
42806
|
-
const absolutePath =
|
|
42957
|
+
const normalized = path28.normalize(dir);
|
|
42958
|
+
const absolutePath = path28.isAbsolute(normalized) ? normalized : path28.resolve(normalized);
|
|
42807
42959
|
return absolutePath;
|
|
42808
42960
|
}
|
|
42809
42961
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -42826,9 +42978,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
42826
42978
|
}
|
|
42827
42979
|
function getPackageVersion(dir) {
|
|
42828
42980
|
try {
|
|
42829
|
-
const packagePath =
|
|
42830
|
-
if (
|
|
42831
|
-
const content =
|
|
42981
|
+
const packagePath = path28.join(dir, "package.json");
|
|
42982
|
+
if (fs17.existsSync(packagePath)) {
|
|
42983
|
+
const content = fs17.readFileSync(packagePath, "utf-8");
|
|
42832
42984
|
const pkg = JSON.parse(content);
|
|
42833
42985
|
return pkg.version ?? null;
|
|
42834
42986
|
}
|
|
@@ -42837,9 +42989,9 @@ function getPackageVersion(dir) {
|
|
|
42837
42989
|
}
|
|
42838
42990
|
function getChangelogVersion(dir) {
|
|
42839
42991
|
try {
|
|
42840
|
-
const changelogPath =
|
|
42841
|
-
if (
|
|
42842
|
-
const content =
|
|
42992
|
+
const changelogPath = path28.join(dir, "CHANGELOG.md");
|
|
42993
|
+
if (fs17.existsSync(changelogPath)) {
|
|
42994
|
+
const content = fs17.readFileSync(changelogPath, "utf-8");
|
|
42843
42995
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
42844
42996
|
if (match) {
|
|
42845
42997
|
return match[1];
|
|
@@ -42851,10 +43003,10 @@ function getChangelogVersion(dir) {
|
|
|
42851
43003
|
function getVersionFileVersion(dir) {
|
|
42852
43004
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
42853
43005
|
for (const file3 of possibleFiles) {
|
|
42854
|
-
const filePath =
|
|
42855
|
-
if (
|
|
43006
|
+
const filePath = path28.join(dir, file3);
|
|
43007
|
+
if (fs17.existsSync(filePath)) {
|
|
42856
43008
|
try {
|
|
42857
|
-
const content =
|
|
43009
|
+
const content = fs17.readFileSync(filePath, "utf-8").trim();
|
|
42858
43010
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
42859
43011
|
if (match) {
|
|
42860
43012
|
return match[1];
|
|
@@ -43178,8 +43330,8 @@ async function runEvidenceCheck(dir) {
|
|
|
43178
43330
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
43179
43331
|
const startTime = Date.now();
|
|
43180
43332
|
try {
|
|
43181
|
-
const specPath =
|
|
43182
|
-
if (!
|
|
43333
|
+
const specPath = path28.join(dir, ".swarm", "spec.md");
|
|
43334
|
+
if (!fs17.existsSync(specPath)) {
|
|
43183
43335
|
return {
|
|
43184
43336
|
type: "req_coverage",
|
|
43185
43337
|
status: "skip",
|
|
@@ -43560,7 +43712,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
43560
43712
|
}
|
|
43561
43713
|
|
|
43562
43714
|
// src/commands/reset.ts
|
|
43563
|
-
import * as
|
|
43715
|
+
import * as fs18 from "fs";
|
|
43564
43716
|
|
|
43565
43717
|
// src/background/manager.ts
|
|
43566
43718
|
init_utils();
|
|
@@ -44261,8 +44413,8 @@ async function handleResetCommand(directory, args) {
|
|
|
44261
44413
|
for (const filename of filesToReset) {
|
|
44262
44414
|
try {
|
|
44263
44415
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
44264
|
-
if (
|
|
44265
|
-
|
|
44416
|
+
if (fs18.existsSync(resolvedPath)) {
|
|
44417
|
+
fs18.unlinkSync(resolvedPath);
|
|
44266
44418
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
44267
44419
|
} else {
|
|
44268
44420
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -44279,8 +44431,8 @@ async function handleResetCommand(directory, args) {
|
|
|
44279
44431
|
}
|
|
44280
44432
|
try {
|
|
44281
44433
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
44282
|
-
if (
|
|
44283
|
-
|
|
44434
|
+
if (fs18.existsSync(summariesPath)) {
|
|
44435
|
+
fs18.rmSync(summariesPath, { recursive: true, force: true });
|
|
44284
44436
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
44285
44437
|
} else {
|
|
44286
44438
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -44300,14 +44452,14 @@ async function handleResetCommand(directory, args) {
|
|
|
44300
44452
|
|
|
44301
44453
|
// src/commands/reset-session.ts
|
|
44302
44454
|
init_utils2();
|
|
44303
|
-
import * as
|
|
44304
|
-
import * as
|
|
44455
|
+
import * as fs19 from "fs";
|
|
44456
|
+
import * as path29 from "path";
|
|
44305
44457
|
async function handleResetSessionCommand(directory, _args) {
|
|
44306
44458
|
const results = [];
|
|
44307
44459
|
try {
|
|
44308
44460
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
44309
|
-
if (
|
|
44310
|
-
|
|
44461
|
+
if (fs19.existsSync(statePath)) {
|
|
44462
|
+
fs19.unlinkSync(statePath);
|
|
44311
44463
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
44312
44464
|
} else {
|
|
44313
44465
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -44316,15 +44468,15 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
44316
44468
|
results.push("\u274C Failed to delete state.json");
|
|
44317
44469
|
}
|
|
44318
44470
|
try {
|
|
44319
|
-
const sessionDir =
|
|
44320
|
-
if (
|
|
44321
|
-
const files =
|
|
44471
|
+
const sessionDir = path29.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
44472
|
+
if (fs19.existsSync(sessionDir)) {
|
|
44473
|
+
const files = fs19.readdirSync(sessionDir);
|
|
44322
44474
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
44323
44475
|
let deletedCount = 0;
|
|
44324
44476
|
for (const file3 of otherFiles) {
|
|
44325
|
-
const filePath =
|
|
44326
|
-
if (
|
|
44327
|
-
|
|
44477
|
+
const filePath = path29.join(sessionDir, file3);
|
|
44478
|
+
if (fs19.lstatSync(filePath).isFile()) {
|
|
44479
|
+
fs19.unlinkSync(filePath);
|
|
44328
44480
|
deletedCount++;
|
|
44329
44481
|
}
|
|
44330
44482
|
}
|
|
@@ -44352,7 +44504,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
44352
44504
|
// src/summaries/manager.ts
|
|
44353
44505
|
init_utils2();
|
|
44354
44506
|
init_utils();
|
|
44355
|
-
import * as
|
|
44507
|
+
import * as path30 from "path";
|
|
44356
44508
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
44357
44509
|
function sanitizeSummaryId(id) {
|
|
44358
44510
|
if (!id || id.length === 0) {
|
|
@@ -44376,7 +44528,7 @@ function sanitizeSummaryId(id) {
|
|
|
44376
44528
|
}
|
|
44377
44529
|
async function loadFullOutput(directory, id) {
|
|
44378
44530
|
const sanitizedId = sanitizeSummaryId(id);
|
|
44379
|
-
const relativePath =
|
|
44531
|
+
const relativePath = path30.join("summaries", `${sanitizedId}.json`);
|
|
44380
44532
|
validateSwarmPath(directory, relativePath);
|
|
44381
44533
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
44382
44534
|
if (content === null) {
|
|
@@ -44431,18 +44583,18 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
44431
44583
|
init_plan_schema();
|
|
44432
44584
|
init_utils2();
|
|
44433
44585
|
init_ledger();
|
|
44434
|
-
import * as
|
|
44435
|
-
import * as
|
|
44586
|
+
import * as fs20 from "fs";
|
|
44587
|
+
import * as path31 from "path";
|
|
44436
44588
|
async function handleRollbackCommand(directory, args) {
|
|
44437
44589
|
const phaseArg = args[0];
|
|
44438
44590
|
if (!phaseArg) {
|
|
44439
44591
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
44440
|
-
if (!
|
|
44592
|
+
if (!fs20.existsSync(manifestPath2)) {
|
|
44441
44593
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
44442
44594
|
}
|
|
44443
44595
|
let manifest2;
|
|
44444
44596
|
try {
|
|
44445
|
-
manifest2 = JSON.parse(
|
|
44597
|
+
manifest2 = JSON.parse(fs20.readFileSync(manifestPath2, "utf-8"));
|
|
44446
44598
|
} catch {
|
|
44447
44599
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
44448
44600
|
}
|
|
@@ -44464,12 +44616,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
44464
44616
|
return "Error: Phase number must be a positive integer.";
|
|
44465
44617
|
}
|
|
44466
44618
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
44467
|
-
if (!
|
|
44619
|
+
if (!fs20.existsSync(manifestPath)) {
|
|
44468
44620
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
44469
44621
|
}
|
|
44470
44622
|
let manifest;
|
|
44471
44623
|
try {
|
|
44472
|
-
manifest = JSON.parse(
|
|
44624
|
+
manifest = JSON.parse(fs20.readFileSync(manifestPath, "utf-8"));
|
|
44473
44625
|
} catch {
|
|
44474
44626
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
44475
44627
|
}
|
|
@@ -44479,10 +44631,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
44479
44631
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
44480
44632
|
}
|
|
44481
44633
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
44482
|
-
if (!
|
|
44634
|
+
if (!fs20.existsSync(checkpointDir)) {
|
|
44483
44635
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
44484
44636
|
}
|
|
44485
|
-
const checkpointFiles =
|
|
44637
|
+
const checkpointFiles = fs20.readdirSync(checkpointDir);
|
|
44486
44638
|
if (checkpointFiles.length === 0) {
|
|
44487
44639
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
44488
44640
|
}
|
|
@@ -44497,10 +44649,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
44497
44649
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
44498
44650
|
continue;
|
|
44499
44651
|
}
|
|
44500
|
-
const src =
|
|
44501
|
-
const dest =
|
|
44652
|
+
const src = path31.join(checkpointDir, file3);
|
|
44653
|
+
const dest = path31.join(swarmDir, file3);
|
|
44502
44654
|
try {
|
|
44503
|
-
|
|
44655
|
+
fs20.cpSync(src, dest, { recursive: true, force: true });
|
|
44504
44656
|
successes.push(file3);
|
|
44505
44657
|
} catch (error93) {
|
|
44506
44658
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -44517,14 +44669,14 @@ async function handleRollbackCommand(directory, args) {
|
|
|
44517
44669
|
].join(`
|
|
44518
44670
|
`);
|
|
44519
44671
|
}
|
|
44520
|
-
const existingLedgerPath =
|
|
44521
|
-
if (
|
|
44522
|
-
|
|
44672
|
+
const existingLedgerPath = path31.join(swarmDir, "plan-ledger.jsonl");
|
|
44673
|
+
if (fs20.existsSync(existingLedgerPath)) {
|
|
44674
|
+
fs20.unlinkSync(existingLedgerPath);
|
|
44523
44675
|
}
|
|
44524
44676
|
try {
|
|
44525
|
-
const planJsonPath =
|
|
44526
|
-
if (
|
|
44527
|
-
const planRaw =
|
|
44677
|
+
const planJsonPath = path31.join(swarmDir, "plan.json");
|
|
44678
|
+
if (fs20.existsSync(planJsonPath)) {
|
|
44679
|
+
const planRaw = fs20.readFileSync(planJsonPath, "utf-8");
|
|
44528
44680
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
44529
44681
|
const planId = `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
44530
44682
|
const planHash = computePlanHash(plan);
|
|
@@ -44551,7 +44703,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
44551
44703
|
timestamp: new Date().toISOString()
|
|
44552
44704
|
};
|
|
44553
44705
|
try {
|
|
44554
|
-
|
|
44706
|
+
fs20.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
44555
44707
|
`);
|
|
44556
44708
|
} catch (error93) {
|
|
44557
44709
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -44594,11 +44746,11 @@ async function handleSimulateCommand(directory, args) {
|
|
|
44594
44746
|
];
|
|
44595
44747
|
const report = reportLines.filter(Boolean).join(`
|
|
44596
44748
|
`);
|
|
44597
|
-
const
|
|
44598
|
-
const
|
|
44599
|
-
const reportPath =
|
|
44600
|
-
await
|
|
44601
|
-
await
|
|
44749
|
+
const fs21 = await import("fs/promises");
|
|
44750
|
+
const path32 = await import("path");
|
|
44751
|
+
const reportPath = path32.join(directory, ".swarm", "simulate-report.md");
|
|
44752
|
+
await fs21.mkdir(path32.dirname(reportPath), { recursive: true });
|
|
44753
|
+
await fs21.writeFile(reportPath, report, "utf-8");
|
|
44602
44754
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
44603
44755
|
}
|
|
44604
44756
|
|
|
@@ -45131,19 +45283,20 @@ function resolveCommand(tokens) {
|
|
|
45131
45283
|
}
|
|
45132
45284
|
|
|
45133
45285
|
// src/cli/index.ts
|
|
45134
|
-
var
|
|
45135
|
-
var
|
|
45136
|
-
var
|
|
45137
|
-
var
|
|
45138
|
-
var
|
|
45286
|
+
var { version: version4 } = package_default;
|
|
45287
|
+
var CONFIG_DIR = path32.join(process.env.XDG_CONFIG_HOME || path32.join(os6.homedir(), ".config"), "opencode");
|
|
45288
|
+
var OPENCODE_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode.json");
|
|
45289
|
+
var PLUGIN_CONFIG_PATH = path32.join(CONFIG_DIR, "opencode-swarm.json");
|
|
45290
|
+
var PROMPTS_DIR = path32.join(CONFIG_DIR, "opencode-swarm");
|
|
45291
|
+
var OPENCODE_PLUGIN_CACHE_PATH = path32.join(process.env.XDG_CACHE_HOME || path32.join(os6.homedir(), ".cache"), "opencode", "packages", "opencode-swarm@latest");
|
|
45139
45292
|
function ensureDir(dir) {
|
|
45140
|
-
if (!
|
|
45141
|
-
|
|
45293
|
+
if (!fs21.existsSync(dir)) {
|
|
45294
|
+
fs21.mkdirSync(dir, { recursive: true });
|
|
45142
45295
|
}
|
|
45143
45296
|
}
|
|
45144
45297
|
function loadJson(filepath) {
|
|
45145
45298
|
try {
|
|
45146
|
-
const content =
|
|
45299
|
+
const content = fs21.readFileSync(filepath, "utf-8");
|
|
45147
45300
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
45148
45301
|
return JSON.parse(stripped);
|
|
45149
45302
|
} catch {
|
|
@@ -45151,15 +45304,31 @@ function loadJson(filepath) {
|
|
|
45151
45304
|
}
|
|
45152
45305
|
}
|
|
45153
45306
|
function saveJson(filepath, data) {
|
|
45154
|
-
|
|
45307
|
+
fs21.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
45155
45308
|
`, "utf-8");
|
|
45156
45309
|
}
|
|
45310
|
+
function writeProjectConfigIfMissing(cwd) {
|
|
45311
|
+
try {
|
|
45312
|
+
const opencodeDir = path32.join(cwd, ".opencode");
|
|
45313
|
+
const projectConfigPath = path32.join(opencodeDir, "opencode-swarm.json");
|
|
45314
|
+
if (fs21.existsSync(projectConfigPath)) {
|
|
45315
|
+
return;
|
|
45316
|
+
}
|
|
45317
|
+
ensureDir(opencodeDir);
|
|
45318
|
+
const starterConfig = { agents: {} };
|
|
45319
|
+
saveJson(projectConfigPath, starterConfig);
|
|
45320
|
+
console.log("\u2713 Created project config at:", projectConfigPath);
|
|
45321
|
+
} catch (error93) {
|
|
45322
|
+
console.warn("\u26A0 Could not create project config \u2014 installation will continue:");
|
|
45323
|
+
console.warn(` ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
45324
|
+
}
|
|
45325
|
+
}
|
|
45157
45326
|
async function install() {
|
|
45158
45327
|
console.log(`\uD83D\uDC1D Installing OpenCode Swarm...
|
|
45159
45328
|
`);
|
|
45160
45329
|
ensureDir(CONFIG_DIR);
|
|
45161
45330
|
ensureDir(PROMPTS_DIR);
|
|
45162
|
-
const LEGACY_CONFIG_PATH =
|
|
45331
|
+
const LEGACY_CONFIG_PATH = path32.join(CONFIG_DIR, "config.json");
|
|
45163
45332
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
45164
45333
|
if (!opencodeConfig) {
|
|
45165
45334
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|
|
@@ -45191,15 +45360,15 @@ async function install() {
|
|
|
45191
45360
|
console.log("\u2713 Added opencode-swarm to OpenCode plugins");
|
|
45192
45361
|
console.log("\u2713 Disabled default OpenCode agents (explore, general)");
|
|
45193
45362
|
try {
|
|
45194
|
-
if (
|
|
45195
|
-
|
|
45363
|
+
if (fs21.existsSync(OPENCODE_PLUGIN_CACHE_PATH)) {
|
|
45364
|
+
fs21.rmSync(OPENCODE_PLUGIN_CACHE_PATH, { recursive: true, force: true });
|
|
45196
45365
|
console.log("\u2713 Cleared opencode plugin cache (next start will fetch latest)");
|
|
45197
45366
|
}
|
|
45198
45367
|
} catch {
|
|
45199
45368
|
console.warn("\u26A0 Could not clear opencode plugin cache \u2014 you may need to delete it manually:");
|
|
45200
45369
|
console.warn(` ${OPENCODE_PLUGIN_CACHE_PATH}`);
|
|
45201
45370
|
}
|
|
45202
|
-
if (!
|
|
45371
|
+
if (!fs21.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
45203
45372
|
const defaultConfig = {
|
|
45204
45373
|
agents: {
|
|
45205
45374
|
coder: {
|
|
@@ -45274,6 +45443,7 @@ async function install() {
|
|
|
45274
45443
|
} else {
|
|
45275
45444
|
console.log("\u2713 Plugin config already exists at:", PLUGIN_CONFIG_PATH);
|
|
45276
45445
|
}
|
|
45446
|
+
writeProjectConfigIfMissing(process.cwd());
|
|
45277
45447
|
console.log(`
|
|
45278
45448
|
\uD83D\uDCC1 Configuration files:`);
|
|
45279
45449
|
console.log(` OpenCode config: ${OPENCODE_CONFIG_PATH}`);
|
|
@@ -45302,7 +45472,7 @@ async function uninstall() {
|
|
|
45302
45472
|
`);
|
|
45303
45473
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
45304
45474
|
if (!opencodeConfig) {
|
|
45305
|
-
if (
|
|
45475
|
+
if (fs21.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
45306
45476
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
45307
45477
|
return 1;
|
|
45308
45478
|
} else {
|
|
@@ -45334,13 +45504,13 @@ async function uninstall() {
|
|
|
45334
45504
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
45335
45505
|
if (process.argv.includes("--clean")) {
|
|
45336
45506
|
let cleaned = false;
|
|
45337
|
-
if (
|
|
45338
|
-
|
|
45507
|
+
if (fs21.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
45508
|
+
fs21.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
45339
45509
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
45340
45510
|
cleaned = true;
|
|
45341
45511
|
}
|
|
45342
|
-
if (
|
|
45343
|
-
|
|
45512
|
+
if (fs21.existsSync(PROMPTS_DIR)) {
|
|
45513
|
+
fs21.rmSync(PROMPTS_DIR, { recursive: true });
|
|
45344
45514
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
45345
45515
|
cleaned = true;
|
|
45346
45516
|
}
|
|
@@ -45403,6 +45573,10 @@ Examples:
|
|
|
45403
45573
|
}
|
|
45404
45574
|
async function main() {
|
|
45405
45575
|
const args = process.argv.slice(2);
|
|
45576
|
+
if (args.includes("-v") || args.includes("--version")) {
|
|
45577
|
+
console.log(`opencode-swarm ${version4}`);
|
|
45578
|
+
process.exit(0);
|
|
45579
|
+
}
|
|
45406
45580
|
if (args.includes("-h") || args.includes("--help")) {
|
|
45407
45581
|
printHelp();
|
|
45408
45582
|
process.exit(0);
|