opencode-swarm 6.46.0 → 6.47.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +341 -240
- package/dist/commands/close.d.ts +1 -1
- package/dist/index.js +621 -520
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -16987,13 +16987,13 @@ __export(exports_config_doctor, {
|
|
|
16987
16987
|
import * as crypto3 from "crypto";
|
|
16988
16988
|
import * as fs7 from "fs";
|
|
16989
16989
|
import * as os4 from "os";
|
|
16990
|
-
import * as
|
|
16990
|
+
import * as path16 from "path";
|
|
16991
16991
|
function getUserConfigDir3() {
|
|
16992
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
16992
|
+
return process.env.XDG_CONFIG_HOME || path16.join(os4.homedir(), ".config");
|
|
16993
16993
|
}
|
|
16994
16994
|
function getConfigPaths(directory) {
|
|
16995
|
-
const userConfigPath =
|
|
16996
|
-
const projectConfigPath =
|
|
16995
|
+
const userConfigPath = path16.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
|
|
16996
|
+
const projectConfigPath = path16.join(directory, ".opencode", "opencode-swarm.json");
|
|
16997
16997
|
return { userConfigPath, projectConfigPath };
|
|
16998
16998
|
}
|
|
16999
16999
|
function computeHash(content) {
|
|
@@ -17018,9 +17018,9 @@ function isValidConfigPath(configPath, directory) {
|
|
|
17018
17018
|
const normalizedUser = userConfigPath.replace(/\\/g, "/");
|
|
17019
17019
|
const normalizedProject = projectConfigPath.replace(/\\/g, "/");
|
|
17020
17020
|
try {
|
|
17021
|
-
const resolvedConfig =
|
|
17022
|
-
const resolvedUser =
|
|
17023
|
-
const resolvedProject =
|
|
17021
|
+
const resolvedConfig = path16.resolve(configPath);
|
|
17022
|
+
const resolvedUser = path16.resolve(normalizedUser);
|
|
17023
|
+
const resolvedProject = path16.resolve(normalizedProject);
|
|
17024
17024
|
return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
|
|
17025
17025
|
} catch {
|
|
17026
17026
|
return false;
|
|
@@ -17060,12 +17060,12 @@ function createConfigBackup(directory) {
|
|
|
17060
17060
|
};
|
|
17061
17061
|
}
|
|
17062
17062
|
function writeBackupArtifact(directory, backup) {
|
|
17063
|
-
const swarmDir =
|
|
17063
|
+
const swarmDir = path16.join(directory, ".swarm");
|
|
17064
17064
|
if (!fs7.existsSync(swarmDir)) {
|
|
17065
17065
|
fs7.mkdirSync(swarmDir, { recursive: true });
|
|
17066
17066
|
}
|
|
17067
17067
|
const backupFilename = `config-backup-${backup.createdAt}.json`;
|
|
17068
|
-
const backupPath =
|
|
17068
|
+
const backupPath = path16.join(swarmDir, backupFilename);
|
|
17069
17069
|
const artifact = {
|
|
17070
17070
|
createdAt: backup.createdAt,
|
|
17071
17071
|
configPath: backup.configPath,
|
|
@@ -17095,7 +17095,7 @@ function restoreFromBackup(backupPath, directory) {
|
|
|
17095
17095
|
return null;
|
|
17096
17096
|
}
|
|
17097
17097
|
const targetPath = artifact.configPath;
|
|
17098
|
-
const targetDir =
|
|
17098
|
+
const targetDir = path16.dirname(targetPath);
|
|
17099
17099
|
if (!fs7.existsSync(targetDir)) {
|
|
17100
17100
|
fs7.mkdirSync(targetDir, { recursive: true });
|
|
17101
17101
|
}
|
|
@@ -17126,9 +17126,9 @@ function readConfigFromFile(directory) {
|
|
|
17126
17126
|
return null;
|
|
17127
17127
|
}
|
|
17128
17128
|
}
|
|
17129
|
-
function validateConfigKey(
|
|
17129
|
+
function validateConfigKey(path17, value, _config) {
|
|
17130
17130
|
const findings = [];
|
|
17131
|
-
switch (
|
|
17131
|
+
switch (path17) {
|
|
17132
17132
|
case "agents": {
|
|
17133
17133
|
if (value !== undefined) {
|
|
17134
17134
|
findings.push({
|
|
@@ -17375,27 +17375,27 @@ function validateConfigKey(path16, value, _config) {
|
|
|
17375
17375
|
}
|
|
17376
17376
|
return findings;
|
|
17377
17377
|
}
|
|
17378
|
-
function walkConfigAndValidate(obj,
|
|
17378
|
+
function walkConfigAndValidate(obj, path17, config3, findings) {
|
|
17379
17379
|
if (obj === null || obj === undefined) {
|
|
17380
17380
|
return;
|
|
17381
17381
|
}
|
|
17382
|
-
if (
|
|
17383
|
-
const keyFindings = validateConfigKey(
|
|
17382
|
+
if (path17 && typeof obj === "object" && !Array.isArray(obj)) {
|
|
17383
|
+
const keyFindings = validateConfigKey(path17, obj, config3);
|
|
17384
17384
|
findings.push(...keyFindings);
|
|
17385
17385
|
}
|
|
17386
17386
|
if (typeof obj !== "object") {
|
|
17387
|
-
const keyFindings = validateConfigKey(
|
|
17387
|
+
const keyFindings = validateConfigKey(path17, obj, config3);
|
|
17388
17388
|
findings.push(...keyFindings);
|
|
17389
17389
|
return;
|
|
17390
17390
|
}
|
|
17391
17391
|
if (Array.isArray(obj)) {
|
|
17392
17392
|
obj.forEach((item, index) => {
|
|
17393
|
-
walkConfigAndValidate(item, `${
|
|
17393
|
+
walkConfigAndValidate(item, `${path17}[${index}]`, config3, findings);
|
|
17394
17394
|
});
|
|
17395
17395
|
return;
|
|
17396
17396
|
}
|
|
17397
17397
|
for (const [key, value] of Object.entries(obj)) {
|
|
17398
|
-
const newPath =
|
|
17398
|
+
const newPath = path17 ? `${path17}.${key}` : key;
|
|
17399
17399
|
walkConfigAndValidate(value, newPath, config3, findings);
|
|
17400
17400
|
}
|
|
17401
17401
|
}
|
|
@@ -17515,7 +17515,7 @@ function applySafeAutoFixes(directory, result) {
|
|
|
17515
17515
|
}
|
|
17516
17516
|
}
|
|
17517
17517
|
if (appliedFixes.length > 0) {
|
|
17518
|
-
const configDir =
|
|
17518
|
+
const configDir = path16.dirname(configPath);
|
|
17519
17519
|
if (!fs7.existsSync(configDir)) {
|
|
17520
17520
|
fs7.mkdirSync(configDir, { recursive: true });
|
|
17521
17521
|
}
|
|
@@ -17525,12 +17525,12 @@ function applySafeAutoFixes(directory, result) {
|
|
|
17525
17525
|
return { appliedFixes, updatedConfigPath };
|
|
17526
17526
|
}
|
|
17527
17527
|
function writeDoctorArtifact(directory, result) {
|
|
17528
|
-
const swarmDir =
|
|
17528
|
+
const swarmDir = path16.join(directory, ".swarm");
|
|
17529
17529
|
if (!fs7.existsSync(swarmDir)) {
|
|
17530
17530
|
fs7.mkdirSync(swarmDir, { recursive: true });
|
|
17531
17531
|
}
|
|
17532
17532
|
const artifactFilename = "config-doctor.json";
|
|
17533
|
-
const artifactPath =
|
|
17533
|
+
const artifactPath = path16.join(swarmDir, artifactFilename);
|
|
17534
17534
|
const guiOutput = {
|
|
17535
17535
|
timestamp: result.timestamp,
|
|
17536
17536
|
summary: result.summary,
|
|
@@ -17893,7 +17893,7 @@ var init_evidence_summary_service = __esm(() => {
|
|
|
17893
17893
|
// src/cli/index.ts
|
|
17894
17894
|
import * as fs18 from "fs";
|
|
17895
17895
|
import * as os6 from "os";
|
|
17896
|
-
import * as
|
|
17896
|
+
import * as path28 from "path";
|
|
17897
17897
|
|
|
17898
17898
|
// src/commands/agents.ts
|
|
17899
17899
|
function handleAgentsCommand(agents, guardrails) {
|
|
@@ -32005,7 +32005,9 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
32005
32005
|
}
|
|
32006
32006
|
|
|
32007
32007
|
// src/commands/close.ts
|
|
32008
|
+
import { execFileSync } from "child_process";
|
|
32008
32009
|
import { promises as fs6 } from "fs";
|
|
32010
|
+
import path11 from "path";
|
|
32009
32011
|
init_manager();
|
|
32010
32012
|
|
|
32011
32013
|
// src/hooks/knowledge-store.ts
|
|
@@ -33117,87 +33119,183 @@ var write_retro = createSwarmTool({
|
|
|
33117
33119
|
});
|
|
33118
33120
|
|
|
33119
33121
|
// src/commands/close.ts
|
|
33120
|
-
async function handleCloseCommand(directory,
|
|
33122
|
+
async function handleCloseCommand(directory, args) {
|
|
33121
33123
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
33122
|
-
let
|
|
33124
|
+
let planExists = false;
|
|
33125
|
+
let planData = {
|
|
33126
|
+
title: path11.basename(directory) || "Ad-hoc session",
|
|
33127
|
+
phases: []
|
|
33128
|
+
};
|
|
33123
33129
|
try {
|
|
33124
33130
|
const content = await fs6.readFile(planPath, "utf-8");
|
|
33125
33131
|
planData = JSON.parse(content);
|
|
33132
|
+
planExists = true;
|
|
33126
33133
|
} catch (error93) {
|
|
33127
|
-
|
|
33134
|
+
if (error93?.code !== "ENOENT") {
|
|
33135
|
+
return `\u274C Failed to read plan.json: ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
33136
|
+
}
|
|
33137
|
+
const swarmDirExists = await fs6.access(path11.join(directory, ".swarm")).then(() => true).catch(() => false);
|
|
33138
|
+
if (!swarmDirExists) {
|
|
33139
|
+
return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
|
|
33140
|
+
}
|
|
33128
33141
|
}
|
|
33129
33142
|
const phases = planData.phases ?? [];
|
|
33130
33143
|
const inProgressPhases = phases.filter((p) => p.status === "in_progress");
|
|
33131
|
-
|
|
33132
|
-
if (
|
|
33133
|
-
|
|
33134
|
-
const blockedCount = phases.filter((p) => p.status === "blocked").length;
|
|
33135
|
-
const completeCount = phases.filter((p) => p.status === "complete" || p.status === "completed").length;
|
|
33136
|
-
return `\u2139\uFE0F Swarm already closed. ${completeCount} phases complete, ${closedCount} phases closed, ${blockedCount} phases blocked. No action taken.`;
|
|
33144
|
+
let planAlreadyDone = false;
|
|
33145
|
+
if (planExists) {
|
|
33146
|
+
planAlreadyDone = phases.length > 0 && phases.every((p) => p.status === "complete" || p.status === "completed" || p.status === "blocked" || p.status === "closed");
|
|
33137
33147
|
}
|
|
33138
33148
|
const config3 = KnowledgeConfigSchema.parse({});
|
|
33139
33149
|
const projectName = planData.title ?? "Unknown Project";
|
|
33140
33150
|
const closedPhases = [];
|
|
33141
33151
|
const closedTasks = [];
|
|
33142
33152
|
const warnings = [];
|
|
33143
|
-
|
|
33144
|
-
|
|
33145
|
-
|
|
33146
|
-
|
|
33147
|
-
|
|
33148
|
-
|
|
33149
|
-
|
|
33150
|
-
|
|
33151
|
-
|
|
33152
|
-
|
|
33153
|
-
|
|
33154
|
-
|
|
33155
|
-
|
|
33156
|
-
|
|
33157
|
-
|
|
33158
|
-
|
|
33159
|
-
|
|
33160
|
-
|
|
33153
|
+
if (!planAlreadyDone) {
|
|
33154
|
+
for (const phase of inProgressPhases) {
|
|
33155
|
+
closedPhases.push(phase.id);
|
|
33156
|
+
let retroResult;
|
|
33157
|
+
try {
|
|
33158
|
+
retroResult = await executeWriteRetro({
|
|
33159
|
+
phase: phase.id,
|
|
33160
|
+
summary: "Phase closed via /swarm close",
|
|
33161
|
+
task_count: Math.max(1, (phase.tasks ?? []).length),
|
|
33162
|
+
task_complexity: "simple",
|
|
33163
|
+
total_tool_calls: 0,
|
|
33164
|
+
coder_revisions: 0,
|
|
33165
|
+
reviewer_rejections: 0,
|
|
33166
|
+
test_failures: 0,
|
|
33167
|
+
security_findings: 0,
|
|
33168
|
+
integration_issues: 0
|
|
33169
|
+
}, directory);
|
|
33170
|
+
} catch (retroError) {
|
|
33171
|
+
warnings.push(`Retrospective write threw for phase ${phase.id}: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
33172
|
+
}
|
|
33173
|
+
if (retroResult !== undefined) {
|
|
33174
|
+
try {
|
|
33175
|
+
const parsed = JSON.parse(retroResult);
|
|
33176
|
+
if (parsed.success !== true) {
|
|
33177
|
+
warnings.push(`Retrospective write failed for phase ${phase.id}`);
|
|
33178
|
+
}
|
|
33179
|
+
} catch {}
|
|
33161
33180
|
}
|
|
33162
|
-
|
|
33163
|
-
|
|
33164
|
-
|
|
33165
|
-
|
|
33181
|
+
for (const task of phase.tasks ?? []) {
|
|
33182
|
+
if (task.status !== "completed" && task.status !== "complete") {
|
|
33183
|
+
closedTasks.push(task.id);
|
|
33184
|
+
}
|
|
33166
33185
|
}
|
|
33167
33186
|
}
|
|
33168
33187
|
}
|
|
33188
|
+
const lessonsFilePath = path11.join(directory, ".swarm", "close-lessons.md");
|
|
33189
|
+
let explicitLessons = [];
|
|
33190
|
+
try {
|
|
33191
|
+
const lessonsText = await fs6.readFile(lessonsFilePath, "utf-8");
|
|
33192
|
+
explicitLessons = lessonsText.split(`
|
|
33193
|
+
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
33194
|
+
} catch {}
|
|
33195
|
+
let curationSucceeded = false;
|
|
33169
33196
|
try {
|
|
33170
|
-
await curateAndStoreSwarm(
|
|
33197
|
+
await curateAndStoreSwarm(explicitLessons, projectName, { phase_number: 0 }, directory, config3);
|
|
33198
|
+
curationSucceeded = true;
|
|
33171
33199
|
} catch (error93) {
|
|
33172
33200
|
console.warn("[close-command] curateAndStoreSwarm error:", error93);
|
|
33173
33201
|
}
|
|
33174
|
-
|
|
33175
|
-
|
|
33176
|
-
|
|
33177
|
-
|
|
33178
|
-
|
|
33202
|
+
if (curationSucceeded && explicitLessons.length > 0) {
|
|
33203
|
+
await fs6.unlink(lessonsFilePath).catch(() => {});
|
|
33204
|
+
}
|
|
33205
|
+
if (planExists && !planAlreadyDone) {
|
|
33206
|
+
for (const phase of phases) {
|
|
33207
|
+
if (phase.status !== "complete" && phase.status !== "completed") {
|
|
33208
|
+
phase.status = "closed";
|
|
33209
|
+
if (!closedPhases.includes(phase.id)) {
|
|
33210
|
+
closedPhases.push(phase.id);
|
|
33211
|
+
}
|
|
33179
33212
|
}
|
|
33180
|
-
|
|
33181
|
-
|
|
33182
|
-
|
|
33183
|
-
|
|
33184
|
-
|
|
33185
|
-
|
|
33213
|
+
for (const task of phase.tasks ?? []) {
|
|
33214
|
+
if (task.status !== "completed" && task.status !== "complete") {
|
|
33215
|
+
task.status = "closed";
|
|
33216
|
+
if (!closedTasks.includes(task.id)) {
|
|
33217
|
+
closedTasks.push(task.id);
|
|
33218
|
+
}
|
|
33186
33219
|
}
|
|
33187
33220
|
}
|
|
33188
33221
|
}
|
|
33222
|
+
try {
|
|
33223
|
+
await fs6.writeFile(planPath, JSON.stringify(planData, null, 2), "utf-8");
|
|
33224
|
+
} catch (error93) {
|
|
33225
|
+
console.warn("[close-command] Failed to write plan.json:", error93);
|
|
33226
|
+
}
|
|
33189
33227
|
}
|
|
33190
33228
|
try {
|
|
33191
|
-
await
|
|
33229
|
+
await archiveEvidence(directory, 30, 10);
|
|
33192
33230
|
} catch (error93) {
|
|
33193
|
-
console.warn("[close-command]
|
|
33231
|
+
console.warn("[close-command] archiveEvidence error:", error93);
|
|
33194
33232
|
}
|
|
33233
|
+
const swarmDir = path11.join(directory, ".swarm");
|
|
33234
|
+
let configBackupsRemoved = 0;
|
|
33195
33235
|
try {
|
|
33196
|
-
await
|
|
33236
|
+
const swarmFiles = await fs6.readdir(swarmDir);
|
|
33237
|
+
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
33238
|
+
for (const backup of configBackups) {
|
|
33239
|
+
try {
|
|
33240
|
+
await fs6.unlink(path11.join(swarmDir, backup));
|
|
33241
|
+
configBackupsRemoved++;
|
|
33242
|
+
} catch {}
|
|
33243
|
+
}
|
|
33244
|
+
} catch {}
|
|
33245
|
+
const contextPath = path11.join(directory, ".swarm", "context.md");
|
|
33246
|
+
const contextContent = [
|
|
33247
|
+
"# Context",
|
|
33248
|
+
"",
|
|
33249
|
+
"## Status",
|
|
33250
|
+
`Session closed after: ${projectName}`,
|
|
33251
|
+
`Closed: ${new Date().toISOString()}`,
|
|
33252
|
+
"No active plan. Next session starts fresh.",
|
|
33253
|
+
""
|
|
33254
|
+
].join(`
|
|
33255
|
+
`);
|
|
33256
|
+
try {
|
|
33257
|
+
await fs6.writeFile(contextPath, contextContent, "utf-8");
|
|
33197
33258
|
} catch (error93) {
|
|
33198
|
-
console.warn("[close-command]
|
|
33259
|
+
console.warn("[close-command] Failed to write context.md:", error93);
|
|
33260
|
+
}
|
|
33261
|
+
const pruneBranches = args.includes("--prune-branches");
|
|
33262
|
+
const prunedBranches = [];
|
|
33263
|
+
const pruneErrors = [];
|
|
33264
|
+
if (pruneBranches) {
|
|
33265
|
+
try {
|
|
33266
|
+
const branchOutput = execFileSync("git", ["branch", "-vv"], {
|
|
33267
|
+
cwd: directory,
|
|
33268
|
+
encoding: "utf-8",
|
|
33269
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
33270
|
+
});
|
|
33271
|
+
const goneBranches = branchOutput.split(`
|
|
33272
|
+
`).filter((line) => line.includes(": gone]")).map((line) => line.trim().replace(/^[*+]\s+/, "").split(/\s+/)[0]).filter(Boolean);
|
|
33273
|
+
for (const branch of goneBranches) {
|
|
33274
|
+
try {
|
|
33275
|
+
execFileSync("git", ["branch", "-d", branch], {
|
|
33276
|
+
cwd: directory,
|
|
33277
|
+
encoding: "utf-8",
|
|
33278
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
33279
|
+
});
|
|
33280
|
+
prunedBranches.push(branch);
|
|
33281
|
+
} catch {
|
|
33282
|
+
pruneErrors.push(branch);
|
|
33283
|
+
}
|
|
33284
|
+
}
|
|
33285
|
+
} catch {}
|
|
33199
33286
|
}
|
|
33200
33287
|
const closeSummaryPath = validateSwarmPath(directory, "close-summary.md");
|
|
33288
|
+
const actionsPerformed = [
|
|
33289
|
+
...!planAlreadyDone && inProgressPhases.length > 0 ? ["- Wrote retrospectives for in-progress phases"] : [],
|
|
33290
|
+
"- Archived evidence bundles",
|
|
33291
|
+
"- Reset context.md for next session",
|
|
33292
|
+
...configBackupsRemoved > 0 ? [`- Removed ${configBackupsRemoved} stale config backup file(s)`] : [],
|
|
33293
|
+
...prunedBranches.length > 0 ? [
|
|
33294
|
+
`- Pruned ${prunedBranches.length} stale local git branch(es): ${prunedBranches.join(", ")}`
|
|
33295
|
+
] : [],
|
|
33296
|
+
"- Cleared agent sessions and delegation chains",
|
|
33297
|
+
...planExists && !planAlreadyDone ? ["- Set non-completed phases/tasks to closed status"] : []
|
|
33298
|
+
];
|
|
33201
33299
|
const summaryContent = [
|
|
33202
33300
|
"# Swarm Close Summary",
|
|
33203
33301
|
"",
|
|
@@ -33205,18 +33303,15 @@ async function handleCloseCommand(directory, _args) {
|
|
|
33205
33303
|
`**Closed:** ${new Date().toISOString()}`,
|
|
33206
33304
|
"",
|
|
33207
33305
|
`## Phases Closed: ${closedPhases.length}`,
|
|
33208
|
-
closedPhases.map((id) => `- Phase ${id}`).join(`
|
|
33209
|
-
`),
|
|
33306
|
+
!planExists ? "_No plan \u2014 ad-hoc session_" : closedPhases.length > 0 ? closedPhases.map((id) => `- Phase ${id}`).join(`
|
|
33307
|
+
`) : "_No phases to close_",
|
|
33210
33308
|
"",
|
|
33211
33309
|
`## Tasks Closed: ${closedTasks.length}`,
|
|
33212
33310
|
closedTasks.length > 0 ? closedTasks.map((id) => `- ${id}`).join(`
|
|
33213
33311
|
`) : "_No incomplete tasks_",
|
|
33214
33312
|
"",
|
|
33215
33313
|
"## Actions Performed",
|
|
33216
|
-
|
|
33217
|
-
"- Archived evidence bundles",
|
|
33218
|
-
"- Cleared agent sessions and delegation chains",
|
|
33219
|
-
"- Set non-completed phases/tasks to closed status"
|
|
33314
|
+
...actionsPerformed
|
|
33220
33315
|
].join(`
|
|
33221
33316
|
`);
|
|
33222
33317
|
try {
|
|
@@ -33232,20 +33327,26 @@ async function handleCloseCommand(directory, _args) {
|
|
|
33232
33327
|
await writeCheckpoint(directory).catch(() => {});
|
|
33233
33328
|
swarmState.agentSessions.clear();
|
|
33234
33329
|
swarmState.delegationChains.clear();
|
|
33330
|
+
if (pruneErrors.length > 0) {
|
|
33331
|
+
warnings.push(`Could not prune ${pruneErrors.length} branch(es) (unmerged or checked out): ${pruneErrors.join(", ")}`);
|
|
33332
|
+
}
|
|
33235
33333
|
const warningMsg = warnings.length > 0 ? ` Warnings: ${warnings.join("; ")}.` : "";
|
|
33334
|
+
if (planAlreadyDone) {
|
|
33335
|
+
return `\u2705 Session closed. Plan was already in a terminal state \u2014 cleanup steps applied.${warningMsg}`;
|
|
33336
|
+
}
|
|
33236
33337
|
return `\u2705 Swarm closed successfully. ${closedPhases.length} phase(s) closed, ${closedTasks.length} incomplete task(s) marked closed.${warningMsg}`;
|
|
33237
33338
|
}
|
|
33238
33339
|
|
|
33239
33340
|
// src/commands/config.ts
|
|
33240
33341
|
import * as os3 from "os";
|
|
33241
|
-
import * as
|
|
33342
|
+
import * as path12 from "path";
|
|
33242
33343
|
function getUserConfigDir2() {
|
|
33243
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
33344
|
+
return process.env.XDG_CONFIG_HOME || path12.join(os3.homedir(), ".config");
|
|
33244
33345
|
}
|
|
33245
33346
|
async function handleConfigCommand(directory, _args) {
|
|
33246
33347
|
const config3 = loadPluginConfig(directory);
|
|
33247
|
-
const userConfigPath =
|
|
33248
|
-
const projectConfigPath =
|
|
33348
|
+
const userConfigPath = path12.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
33349
|
+
const projectConfigPath = path12.join(directory, ".opencode", "opencode-swarm.json");
|
|
33249
33350
|
const lines = [
|
|
33250
33351
|
"## Swarm Configuration",
|
|
33251
33352
|
"",
|
|
@@ -33513,13 +33614,13 @@ function formatCurationSummary(summary) {
|
|
|
33513
33614
|
}
|
|
33514
33615
|
|
|
33515
33616
|
// src/commands/dark-matter.ts
|
|
33516
|
-
import
|
|
33617
|
+
import path14 from "path";
|
|
33517
33618
|
|
|
33518
33619
|
// src/tools/co-change-analyzer.ts
|
|
33519
33620
|
import * as child_process2 from "child_process";
|
|
33520
33621
|
import { randomUUID } from "crypto";
|
|
33521
33622
|
import { readdir, readFile as readFile2, stat } from "fs/promises";
|
|
33522
|
-
import * as
|
|
33623
|
+
import * as path13 from "path";
|
|
33523
33624
|
import { promisify } from "util";
|
|
33524
33625
|
function getExecFileAsync() {
|
|
33525
33626
|
return promisify(child_process2.execFile);
|
|
@@ -33621,7 +33722,7 @@ async function scanSourceFiles(dir) {
|
|
|
33621
33722
|
try {
|
|
33622
33723
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
33623
33724
|
for (const entry of entries) {
|
|
33624
|
-
const fullPath =
|
|
33725
|
+
const fullPath = path13.join(dir, entry.name);
|
|
33625
33726
|
if (entry.isDirectory()) {
|
|
33626
33727
|
if (skipDirs.has(entry.name)) {
|
|
33627
33728
|
continue;
|
|
@@ -33629,7 +33730,7 @@ async function scanSourceFiles(dir) {
|
|
|
33629
33730
|
const subFiles = await scanSourceFiles(fullPath);
|
|
33630
33731
|
results.push(...subFiles);
|
|
33631
33732
|
} else if (entry.isFile()) {
|
|
33632
|
-
const ext =
|
|
33733
|
+
const ext = path13.extname(entry.name);
|
|
33633
33734
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
33634
33735
|
results.push(fullPath);
|
|
33635
33736
|
}
|
|
@@ -33651,8 +33752,8 @@ async function getStaticEdges(directory) {
|
|
|
33651
33752
|
continue;
|
|
33652
33753
|
}
|
|
33653
33754
|
try {
|
|
33654
|
-
const sourceDir =
|
|
33655
|
-
const resolvedPath =
|
|
33755
|
+
const sourceDir = path13.dirname(sourceFile);
|
|
33756
|
+
const resolvedPath = path13.resolve(sourceDir, importPath);
|
|
33656
33757
|
const extensions = [
|
|
33657
33758
|
"",
|
|
33658
33759
|
".ts",
|
|
@@ -33677,8 +33778,8 @@ async function getStaticEdges(directory) {
|
|
|
33677
33778
|
if (!targetFile) {
|
|
33678
33779
|
continue;
|
|
33679
33780
|
}
|
|
33680
|
-
const relSource =
|
|
33681
|
-
const relTarget =
|
|
33781
|
+
const relSource = path13.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
33782
|
+
const relTarget = path13.relative(directory, targetFile).replace(/\\/g, "/");
|
|
33682
33783
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
33683
33784
|
edges.add(key);
|
|
33684
33785
|
} catch {}
|
|
@@ -33690,7 +33791,7 @@ async function getStaticEdges(directory) {
|
|
|
33690
33791
|
function isTestImplementationPair(fileA, fileB) {
|
|
33691
33792
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
33692
33793
|
const getBaseName = (filePath) => {
|
|
33693
|
-
const base =
|
|
33794
|
+
const base = path13.basename(filePath);
|
|
33694
33795
|
for (const pattern of testPatterns) {
|
|
33695
33796
|
if (base.endsWith(pattern)) {
|
|
33696
33797
|
return base.slice(0, -pattern.length);
|
|
@@ -33700,16 +33801,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
33700
33801
|
};
|
|
33701
33802
|
const baseA = getBaseName(fileA);
|
|
33702
33803
|
const baseB = getBaseName(fileB);
|
|
33703
|
-
return baseA === baseB && baseA !==
|
|
33804
|
+
return baseA === baseB && baseA !== path13.basename(fileA) && baseA !== path13.basename(fileB);
|
|
33704
33805
|
}
|
|
33705
33806
|
function hasSharedPrefix(fileA, fileB) {
|
|
33706
|
-
const dirA =
|
|
33707
|
-
const dirB =
|
|
33807
|
+
const dirA = path13.dirname(fileA);
|
|
33808
|
+
const dirB = path13.dirname(fileB);
|
|
33708
33809
|
if (dirA !== dirB) {
|
|
33709
33810
|
return false;
|
|
33710
33811
|
}
|
|
33711
|
-
const baseA =
|
|
33712
|
-
const baseB =
|
|
33812
|
+
const baseA = path13.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
33813
|
+
const baseB = path13.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
33713
33814
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
33714
33815
|
return true;
|
|
33715
33816
|
}
|
|
@@ -33763,8 +33864,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
33763
33864
|
const entries = [];
|
|
33764
33865
|
const now = new Date().toISOString();
|
|
33765
33866
|
for (const pair of pairs.slice(0, 10)) {
|
|
33766
|
-
const baseA =
|
|
33767
|
-
const baseB =
|
|
33867
|
+
const baseA = path13.basename(pair.fileA);
|
|
33868
|
+
const baseB = path13.basename(pair.fileB);
|
|
33768
33869
|
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.`;
|
|
33769
33870
|
if (lesson.length > 280) {
|
|
33770
33871
|
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.`;
|
|
@@ -33874,7 +33975,7 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
33874
33975
|
const output = formatDarkMatterOutput(pairs);
|
|
33875
33976
|
if (pairs.length > 0) {
|
|
33876
33977
|
try {
|
|
33877
|
-
const projectName =
|
|
33978
|
+
const projectName = path14.basename(path14.resolve(directory));
|
|
33878
33979
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
33879
33980
|
if (entries.length > 0) {
|
|
33880
33981
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -33896,7 +33997,7 @@ async function handleDarkMatterCommand(directory, args) {
|
|
|
33896
33997
|
// src/services/diagnose-service.ts
|
|
33897
33998
|
import * as child_process3 from "child_process";
|
|
33898
33999
|
import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
|
|
33899
|
-
import
|
|
34000
|
+
import path15 from "path";
|
|
33900
34001
|
import { fileURLToPath } from "url";
|
|
33901
34002
|
init_manager();
|
|
33902
34003
|
init_utils2();
|
|
@@ -34196,7 +34297,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
34196
34297
|
};
|
|
34197
34298
|
}
|
|
34198
34299
|
async function checkConfigParseability(directory) {
|
|
34199
|
-
const configPath =
|
|
34300
|
+
const configPath = path15.join(directory, ".opencode/opencode-swarm.json");
|
|
34200
34301
|
if (!existsSync5(configPath)) {
|
|
34201
34302
|
return {
|
|
34202
34303
|
name: "Config Parseability",
|
|
@@ -34243,15 +34344,15 @@ async function checkGrammarWasmFiles() {
|
|
|
34243
34344
|
"tree-sitter-ini.wasm",
|
|
34244
34345
|
"tree-sitter-regex.wasm"
|
|
34245
34346
|
];
|
|
34246
|
-
const thisDir =
|
|
34347
|
+
const thisDir = path15.dirname(fileURLToPath(import.meta.url));
|
|
34247
34348
|
const isSource = thisDir.replace(/\\/g, "/").endsWith("/src/services");
|
|
34248
|
-
const grammarDir = isSource ?
|
|
34349
|
+
const grammarDir = isSource ? path15.join(thisDir, "..", "lang", "grammars") : path15.join(thisDir, "lang", "grammars");
|
|
34249
34350
|
const missing = [];
|
|
34250
|
-
if (!existsSync5(
|
|
34351
|
+
if (!existsSync5(path15.join(grammarDir, "tree-sitter.wasm"))) {
|
|
34251
34352
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
34252
34353
|
}
|
|
34253
34354
|
for (const file3 of grammarFiles) {
|
|
34254
|
-
if (!existsSync5(
|
|
34355
|
+
if (!existsSync5(path15.join(grammarDir, file3))) {
|
|
34255
34356
|
missing.push(file3);
|
|
34256
34357
|
}
|
|
34257
34358
|
}
|
|
@@ -34269,7 +34370,7 @@ async function checkGrammarWasmFiles() {
|
|
|
34269
34370
|
};
|
|
34270
34371
|
}
|
|
34271
34372
|
async function checkCheckpointManifest(directory) {
|
|
34272
|
-
const manifestPath =
|
|
34373
|
+
const manifestPath = path15.join(directory, ".swarm/checkpoints.json");
|
|
34273
34374
|
if (!existsSync5(manifestPath)) {
|
|
34274
34375
|
return {
|
|
34275
34376
|
name: "Checkpoint Manifest",
|
|
@@ -34321,7 +34422,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
34321
34422
|
}
|
|
34322
34423
|
}
|
|
34323
34424
|
async function checkEventStreamIntegrity(directory) {
|
|
34324
|
-
const eventsPath =
|
|
34425
|
+
const eventsPath = path15.join(directory, ".swarm/events.jsonl");
|
|
34325
34426
|
if (!existsSync5(eventsPath)) {
|
|
34326
34427
|
return {
|
|
34327
34428
|
name: "Event Stream",
|
|
@@ -34362,7 +34463,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
34362
34463
|
}
|
|
34363
34464
|
}
|
|
34364
34465
|
async function checkSteeringDirectives(directory) {
|
|
34365
|
-
const eventsPath =
|
|
34466
|
+
const eventsPath = path15.join(directory, ".swarm/events.jsonl");
|
|
34366
34467
|
if (!existsSync5(eventsPath)) {
|
|
34367
34468
|
return {
|
|
34368
34469
|
name: "Steering Directives",
|
|
@@ -34418,7 +34519,7 @@ async function checkCurator(directory) {
|
|
|
34418
34519
|
detail: "Disabled (enable via curator.enabled)"
|
|
34419
34520
|
};
|
|
34420
34521
|
}
|
|
34421
|
-
const summaryPath =
|
|
34522
|
+
const summaryPath = path15.join(directory, ".swarm/curator-summary.json");
|
|
34422
34523
|
if (!existsSync5(summaryPath)) {
|
|
34423
34524
|
return {
|
|
34424
34525
|
name: "Curator",
|
|
@@ -35315,10 +35416,10 @@ async function handleHistoryCommand(directory, _args) {
|
|
|
35315
35416
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
35316
35417
|
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "fs";
|
|
35317
35418
|
import { mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
35318
|
-
import * as
|
|
35419
|
+
import * as path17 from "path";
|
|
35319
35420
|
async function migrateContextToKnowledge(directory, config3) {
|
|
35320
|
-
const sentinelPath =
|
|
35321
|
-
const contextPath =
|
|
35421
|
+
const sentinelPath = path17.join(directory, ".swarm", ".knowledge-migrated");
|
|
35422
|
+
const contextPath = path17.join(directory, ".swarm", "context.md");
|
|
35322
35423
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
35323
35424
|
if (existsSync7(sentinelPath)) {
|
|
35324
35425
|
return {
|
|
@@ -35514,7 +35615,7 @@ function truncateLesson(text) {
|
|
|
35514
35615
|
return `${text.slice(0, 277)}...`;
|
|
35515
35616
|
}
|
|
35516
35617
|
function inferProjectName(directory) {
|
|
35517
|
-
const packageJsonPath =
|
|
35618
|
+
const packageJsonPath = path17.join(directory, "package.json");
|
|
35518
35619
|
if (existsSync7(packageJsonPath)) {
|
|
35519
35620
|
try {
|
|
35520
35621
|
const pkg = JSON.parse(readFileSync7(packageJsonPath, "utf-8"));
|
|
@@ -35523,7 +35624,7 @@ function inferProjectName(directory) {
|
|
|
35523
35624
|
}
|
|
35524
35625
|
} catch {}
|
|
35525
35626
|
}
|
|
35526
|
-
return
|
|
35627
|
+
return path17.basename(directory);
|
|
35527
35628
|
}
|
|
35528
35629
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
35529
35630
|
const sentinel = {
|
|
@@ -35535,7 +35636,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
35535
35636
|
schema_version: 1,
|
|
35536
35637
|
migration_tool: "knowledge-migrator.ts"
|
|
35537
35638
|
};
|
|
35538
|
-
await mkdir3(
|
|
35639
|
+
await mkdir3(path17.dirname(sentinelPath), { recursive: true });
|
|
35539
35640
|
await writeFile3(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
35540
35641
|
}
|
|
35541
35642
|
|
|
@@ -35772,15 +35873,15 @@ async function handlePlanCommand(directory, args) {
|
|
|
35772
35873
|
init_manager();
|
|
35773
35874
|
init_manager2();
|
|
35774
35875
|
import * as fs13 from "fs";
|
|
35775
|
-
import * as
|
|
35876
|
+
import * as path23 from "path";
|
|
35776
35877
|
|
|
35777
35878
|
// src/tools/lint.ts
|
|
35778
35879
|
import * as fs9 from "fs";
|
|
35779
|
-
import * as
|
|
35880
|
+
import * as path19 from "path";
|
|
35780
35881
|
|
|
35781
35882
|
// src/build/discovery.ts
|
|
35782
35883
|
import * as fs8 from "fs";
|
|
35783
|
-
import * as
|
|
35884
|
+
import * as path18 from "path";
|
|
35784
35885
|
|
|
35785
35886
|
// src/lang/detector.ts
|
|
35786
35887
|
import { access, readdir as readdir2 } from "fs/promises";
|
|
@@ -36877,11 +36978,11 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
36877
36978
|
const regex = simpleGlobToRegex(pattern);
|
|
36878
36979
|
const matches = files.filter((f) => regex.test(f));
|
|
36879
36980
|
if (matches.length > 0) {
|
|
36880
|
-
return
|
|
36981
|
+
return path18.join(dir, matches[0]);
|
|
36881
36982
|
}
|
|
36882
36983
|
} catch {}
|
|
36883
36984
|
} else {
|
|
36884
|
-
const filePath =
|
|
36985
|
+
const filePath = path18.join(workingDir, pattern);
|
|
36885
36986
|
if (fs8.existsSync(filePath)) {
|
|
36886
36987
|
return filePath;
|
|
36887
36988
|
}
|
|
@@ -36890,7 +36991,7 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
36890
36991
|
return null;
|
|
36891
36992
|
}
|
|
36892
36993
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
36893
|
-
const packageJsonPath =
|
|
36994
|
+
const packageJsonPath = path18.join(workingDir, "package.json");
|
|
36894
36995
|
if (!fs8.existsSync(packageJsonPath)) {
|
|
36895
36996
|
return [];
|
|
36896
36997
|
}
|
|
@@ -36931,7 +37032,7 @@ function findAllBuildFiles(workingDir) {
|
|
|
36931
37032
|
const regex = simpleGlobToRegex(pattern);
|
|
36932
37033
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
36933
37034
|
} else {
|
|
36934
|
-
const filePath =
|
|
37035
|
+
const filePath = path18.join(workingDir, pattern);
|
|
36935
37036
|
if (fs8.existsSync(filePath)) {
|
|
36936
37037
|
allBuildFiles.add(filePath);
|
|
36937
37038
|
}
|
|
@@ -36944,7 +37045,7 @@ function findFilesRecursive(dir, regex, results) {
|
|
|
36944
37045
|
try {
|
|
36945
37046
|
const entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
36946
37047
|
for (const entry of entries) {
|
|
36947
|
-
const fullPath =
|
|
37048
|
+
const fullPath = path18.join(dir, entry.name);
|
|
36948
37049
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
36949
37050
|
findFilesRecursive(fullPath, regex, results);
|
|
36950
37051
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -36967,7 +37068,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
|
|
|
36967
37068
|
let foundCommand = false;
|
|
36968
37069
|
for (const cmd of sortedCommands) {
|
|
36969
37070
|
if (cmd.detectFile) {
|
|
36970
|
-
const detectFilePath =
|
|
37071
|
+
const detectFilePath = path18.join(workingDir, cmd.detectFile);
|
|
36971
37072
|
if (!fs8.existsSync(detectFilePath)) {
|
|
36972
37073
|
continue;
|
|
36973
37074
|
}
|
|
@@ -37115,9 +37216,9 @@ function validateArgs(args) {
|
|
|
37115
37216
|
}
|
|
37116
37217
|
function getLinterCommand(linter, mode, projectDir) {
|
|
37117
37218
|
const isWindows = process.platform === "win32";
|
|
37118
|
-
const binDir =
|
|
37119
|
-
const biomeBin = isWindows ?
|
|
37120
|
-
const eslintBin = isWindows ?
|
|
37219
|
+
const binDir = path19.join(projectDir, "node_modules", ".bin");
|
|
37220
|
+
const biomeBin = isWindows ? path19.join(binDir, "biome.EXE") : path19.join(binDir, "biome");
|
|
37221
|
+
const eslintBin = isWindows ? path19.join(binDir, "eslint.cmd") : path19.join(binDir, "eslint");
|
|
37121
37222
|
switch (linter) {
|
|
37122
37223
|
case "biome":
|
|
37123
37224
|
if (mode === "fix") {
|
|
@@ -37133,7 +37234,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
37133
37234
|
}
|
|
37134
37235
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
37135
37236
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
37136
|
-
const gradlew = fs9.existsSync(
|
|
37237
|
+
const gradlew = fs9.existsSync(path19.join(cwd, gradlewName)) ? path19.join(cwd, gradlewName) : null;
|
|
37137
37238
|
switch (linter) {
|
|
37138
37239
|
case "ruff":
|
|
37139
37240
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -37167,10 +37268,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
37167
37268
|
}
|
|
37168
37269
|
}
|
|
37169
37270
|
function detectRuff(cwd) {
|
|
37170
|
-
if (fs9.existsSync(
|
|
37271
|
+
if (fs9.existsSync(path19.join(cwd, "ruff.toml")))
|
|
37171
37272
|
return isCommandAvailable("ruff");
|
|
37172
37273
|
try {
|
|
37173
|
-
const pyproject =
|
|
37274
|
+
const pyproject = path19.join(cwd, "pyproject.toml");
|
|
37174
37275
|
if (fs9.existsSync(pyproject)) {
|
|
37175
37276
|
const content = fs9.readFileSync(pyproject, "utf-8");
|
|
37176
37277
|
if (content.includes("[tool.ruff]"))
|
|
@@ -37180,19 +37281,19 @@ function detectRuff(cwd) {
|
|
|
37180
37281
|
return false;
|
|
37181
37282
|
}
|
|
37182
37283
|
function detectClippy(cwd) {
|
|
37183
|
-
return fs9.existsSync(
|
|
37284
|
+
return fs9.existsSync(path19.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
37184
37285
|
}
|
|
37185
37286
|
function detectGolangciLint(cwd) {
|
|
37186
|
-
return fs9.existsSync(
|
|
37287
|
+
return fs9.existsSync(path19.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
37187
37288
|
}
|
|
37188
37289
|
function detectCheckstyle(cwd) {
|
|
37189
|
-
const hasMaven = fs9.existsSync(
|
|
37190
|
-
const hasGradle = fs9.existsSync(
|
|
37191
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs9.existsSync(
|
|
37290
|
+
const hasMaven = fs9.existsSync(path19.join(cwd, "pom.xml"));
|
|
37291
|
+
const hasGradle = fs9.existsSync(path19.join(cwd, "build.gradle")) || fs9.existsSync(path19.join(cwd, "build.gradle.kts"));
|
|
37292
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs9.existsSync(path19.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
37192
37293
|
return (hasMaven || hasGradle) && hasBinary;
|
|
37193
37294
|
}
|
|
37194
37295
|
function detectKtlint(cwd) {
|
|
37195
|
-
const hasKotlin = fs9.existsSync(
|
|
37296
|
+
const hasKotlin = fs9.existsSync(path19.join(cwd, "build.gradle.kts")) || fs9.existsSync(path19.join(cwd, "build.gradle")) || (() => {
|
|
37196
37297
|
try {
|
|
37197
37298
|
return fs9.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
37198
37299
|
} catch {
|
|
@@ -37211,11 +37312,11 @@ function detectDotnetFormat(cwd) {
|
|
|
37211
37312
|
}
|
|
37212
37313
|
}
|
|
37213
37314
|
function detectCppcheck(cwd) {
|
|
37214
|
-
if (fs9.existsSync(
|
|
37315
|
+
if (fs9.existsSync(path19.join(cwd, "CMakeLists.txt"))) {
|
|
37215
37316
|
return isCommandAvailable("cppcheck");
|
|
37216
37317
|
}
|
|
37217
37318
|
try {
|
|
37218
|
-
const dirsToCheck = [cwd,
|
|
37319
|
+
const dirsToCheck = [cwd, path19.join(cwd, "src")];
|
|
37219
37320
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
37220
37321
|
try {
|
|
37221
37322
|
return fs9.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -37229,13 +37330,13 @@ function detectCppcheck(cwd) {
|
|
|
37229
37330
|
}
|
|
37230
37331
|
}
|
|
37231
37332
|
function detectSwiftlint(cwd) {
|
|
37232
|
-
return fs9.existsSync(
|
|
37333
|
+
return fs9.existsSync(path19.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
37233
37334
|
}
|
|
37234
37335
|
function detectDartAnalyze(cwd) {
|
|
37235
|
-
return fs9.existsSync(
|
|
37336
|
+
return fs9.existsSync(path19.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
37236
37337
|
}
|
|
37237
37338
|
function detectRubocop(cwd) {
|
|
37238
|
-
return (fs9.existsSync(
|
|
37339
|
+
return (fs9.existsSync(path19.join(cwd, "Gemfile")) || fs9.existsSync(path19.join(cwd, "gems.rb")) || fs9.existsSync(path19.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
37239
37340
|
}
|
|
37240
37341
|
function detectAdditionalLinter(cwd) {
|
|
37241
37342
|
if (detectRuff(cwd))
|
|
@@ -37263,10 +37364,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
37263
37364
|
function findBinInAncestors(startDir, binName) {
|
|
37264
37365
|
let dir = startDir;
|
|
37265
37366
|
while (true) {
|
|
37266
|
-
const candidate =
|
|
37367
|
+
const candidate = path19.join(dir, "node_modules", ".bin", binName);
|
|
37267
37368
|
if (fs9.existsSync(candidate))
|
|
37268
37369
|
return candidate;
|
|
37269
|
-
const parent =
|
|
37370
|
+
const parent = path19.dirname(dir);
|
|
37270
37371
|
if (parent === dir)
|
|
37271
37372
|
break;
|
|
37272
37373
|
dir = parent;
|
|
@@ -37275,10 +37376,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
37275
37376
|
}
|
|
37276
37377
|
function findBinInEnvPath(binName) {
|
|
37277
37378
|
const searchPath = process.env.PATH ?? "";
|
|
37278
|
-
for (const dir of searchPath.split(
|
|
37379
|
+
for (const dir of searchPath.split(path19.delimiter)) {
|
|
37279
37380
|
if (!dir)
|
|
37280
37381
|
continue;
|
|
37281
|
-
const candidate =
|
|
37382
|
+
const candidate = path19.join(dir, binName);
|
|
37282
37383
|
if (fs9.existsSync(candidate))
|
|
37283
37384
|
return candidate;
|
|
37284
37385
|
}
|
|
@@ -37291,13 +37392,13 @@ async function detectAvailableLinter(directory) {
|
|
|
37291
37392
|
return null;
|
|
37292
37393
|
const projectDir = directory;
|
|
37293
37394
|
const isWindows = process.platform === "win32";
|
|
37294
|
-
const biomeBin = isWindows ?
|
|
37295
|
-
const eslintBin = isWindows ?
|
|
37395
|
+
const biomeBin = isWindows ? path19.join(projectDir, "node_modules", ".bin", "biome.EXE") : path19.join(projectDir, "node_modules", ".bin", "biome");
|
|
37396
|
+
const eslintBin = isWindows ? path19.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path19.join(projectDir, "node_modules", ".bin", "eslint");
|
|
37296
37397
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
37297
37398
|
if (localResult)
|
|
37298
37399
|
return localResult;
|
|
37299
|
-
const biomeAncestor = findBinInAncestors(
|
|
37300
|
-
const eslintAncestor = findBinInAncestors(
|
|
37400
|
+
const biomeAncestor = findBinInAncestors(path19.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
37401
|
+
const eslintAncestor = findBinInAncestors(path19.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
37301
37402
|
if (biomeAncestor || eslintAncestor) {
|
|
37302
37403
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
37303
37404
|
}
|
|
@@ -37505,7 +37606,7 @@ For Rust: rustup component add clippy`
|
|
|
37505
37606
|
|
|
37506
37607
|
// src/tools/secretscan.ts
|
|
37507
37608
|
import * as fs10 from "fs";
|
|
37508
|
-
import * as
|
|
37609
|
+
import * as path20 from "path";
|
|
37509
37610
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
37510
37611
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
37511
37612
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -37732,7 +37833,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
37732
37833
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
37733
37834
|
}
|
|
37734
37835
|
function loadSecretScanIgnore(scanDir) {
|
|
37735
|
-
const ignorePath =
|
|
37836
|
+
const ignorePath = path20.join(scanDir, ".secretscanignore");
|
|
37736
37837
|
try {
|
|
37737
37838
|
if (!fs10.existsSync(ignorePath))
|
|
37738
37839
|
return [];
|
|
@@ -37755,7 +37856,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
37755
37856
|
if (exactNames.has(entry))
|
|
37756
37857
|
return true;
|
|
37757
37858
|
for (const pattern of globPatterns) {
|
|
37758
|
-
if (
|
|
37859
|
+
if (path20.matchesGlob(relPath, pattern))
|
|
37759
37860
|
return true;
|
|
37760
37861
|
}
|
|
37761
37862
|
return false;
|
|
@@ -37776,7 +37877,7 @@ function validateDirectoryInput(dir) {
|
|
|
37776
37877
|
return null;
|
|
37777
37878
|
}
|
|
37778
37879
|
function isBinaryFile(filePath, buffer) {
|
|
37779
|
-
const ext =
|
|
37880
|
+
const ext = path20.extname(filePath).toLowerCase();
|
|
37780
37881
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
37781
37882
|
return true;
|
|
37782
37883
|
}
|
|
@@ -37913,9 +38014,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
37913
38014
|
return false;
|
|
37914
38015
|
}
|
|
37915
38016
|
function isPathWithinScope(realPath, scanDir) {
|
|
37916
|
-
const resolvedScanDir =
|
|
37917
|
-
const resolvedRealPath =
|
|
37918
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
38017
|
+
const resolvedScanDir = path20.resolve(scanDir);
|
|
38018
|
+
const resolvedRealPath = path20.resolve(realPath);
|
|
38019
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path20.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
37919
38020
|
}
|
|
37920
38021
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
37921
38022
|
skippedDirs: 0,
|
|
@@ -37941,8 +38042,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
37941
38042
|
return a.localeCompare(b);
|
|
37942
38043
|
});
|
|
37943
38044
|
for (const entry of entries) {
|
|
37944
|
-
const fullPath =
|
|
37945
|
-
const relPath =
|
|
38045
|
+
const fullPath = path20.join(dir, entry);
|
|
38046
|
+
const relPath = path20.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
37946
38047
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
37947
38048
|
stats.skippedDirs++;
|
|
37948
38049
|
continue;
|
|
@@ -37977,7 +38078,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
37977
38078
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
37978
38079
|
files.push(...subFiles);
|
|
37979
38080
|
} else if (lstat.isFile()) {
|
|
37980
|
-
const ext =
|
|
38081
|
+
const ext = path20.extname(fullPath).toLowerCase();
|
|
37981
38082
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
37982
38083
|
files.push(fullPath);
|
|
37983
38084
|
} else {
|
|
@@ -38043,7 +38144,7 @@ var secretscan = createSwarmTool({
|
|
|
38043
38144
|
}
|
|
38044
38145
|
}
|
|
38045
38146
|
try {
|
|
38046
|
-
const _scanDirRaw =
|
|
38147
|
+
const _scanDirRaw = path20.resolve(directory);
|
|
38047
38148
|
const scanDir = (() => {
|
|
38048
38149
|
try {
|
|
38049
38150
|
return fs10.realpathSync(_scanDirRaw);
|
|
@@ -38201,11 +38302,11 @@ async function runSecretscan(directory) {
|
|
|
38201
38302
|
|
|
38202
38303
|
// src/tools/test-runner.ts
|
|
38203
38304
|
import * as fs12 from "fs";
|
|
38204
|
-
import * as
|
|
38305
|
+
import * as path22 from "path";
|
|
38205
38306
|
|
|
38206
38307
|
// src/tools/resolve-working-directory.ts
|
|
38207
38308
|
import * as fs11 from "fs";
|
|
38208
|
-
import * as
|
|
38309
|
+
import * as path21 from "path";
|
|
38209
38310
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
38210
38311
|
if (workingDirectory == null || workingDirectory === "") {
|
|
38211
38312
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -38225,15 +38326,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
38225
38326
|
};
|
|
38226
38327
|
}
|
|
38227
38328
|
}
|
|
38228
|
-
const normalizedDir =
|
|
38229
|
-
const pathParts = normalizedDir.split(
|
|
38329
|
+
const normalizedDir = path21.normalize(workingDirectory);
|
|
38330
|
+
const pathParts = normalizedDir.split(path21.sep);
|
|
38230
38331
|
if (pathParts.includes("..")) {
|
|
38231
38332
|
return {
|
|
38232
38333
|
success: false,
|
|
38233
38334
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
38234
38335
|
};
|
|
38235
38336
|
}
|
|
38236
|
-
const resolvedDir =
|
|
38337
|
+
const resolvedDir = path21.resolve(normalizedDir);
|
|
38237
38338
|
try {
|
|
38238
38339
|
const realPath = fs11.realpathSync(resolvedDir);
|
|
38239
38340
|
return { success: true, directory: realPath };
|
|
@@ -38316,14 +38417,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
38316
38417
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
38317
38418
|
}
|
|
38318
38419
|
function detectGoTest(cwd) {
|
|
38319
|
-
return fs12.existsSync(
|
|
38420
|
+
return fs12.existsSync(path22.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
38320
38421
|
}
|
|
38321
38422
|
function detectJavaMaven(cwd) {
|
|
38322
|
-
return fs12.existsSync(
|
|
38423
|
+
return fs12.existsSync(path22.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
38323
38424
|
}
|
|
38324
38425
|
function detectGradle(cwd) {
|
|
38325
|
-
const hasBuildFile = fs12.existsSync(
|
|
38326
|
-
const hasGradlew = fs12.existsSync(
|
|
38426
|
+
const hasBuildFile = fs12.existsSync(path22.join(cwd, "build.gradle")) || fs12.existsSync(path22.join(cwd, "build.gradle.kts"));
|
|
38427
|
+
const hasGradlew = fs12.existsSync(path22.join(cwd, "gradlew")) || fs12.existsSync(path22.join(cwd, "gradlew.bat"));
|
|
38327
38428
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
38328
38429
|
}
|
|
38329
38430
|
function detectDotnetTest(cwd) {
|
|
@@ -38336,30 +38437,30 @@ function detectDotnetTest(cwd) {
|
|
|
38336
38437
|
}
|
|
38337
38438
|
}
|
|
38338
38439
|
function detectCTest(cwd) {
|
|
38339
|
-
const hasSource = fs12.existsSync(
|
|
38340
|
-
const hasBuildCache = fs12.existsSync(
|
|
38440
|
+
const hasSource = fs12.existsSync(path22.join(cwd, "CMakeLists.txt"));
|
|
38441
|
+
const hasBuildCache = fs12.existsSync(path22.join(cwd, "CMakeCache.txt")) || fs12.existsSync(path22.join(cwd, "build", "CMakeCache.txt"));
|
|
38341
38442
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
38342
38443
|
}
|
|
38343
38444
|
function detectSwiftTest(cwd) {
|
|
38344
|
-
return fs12.existsSync(
|
|
38445
|
+
return fs12.existsSync(path22.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
38345
38446
|
}
|
|
38346
38447
|
function detectDartTest(cwd) {
|
|
38347
|
-
return fs12.existsSync(
|
|
38448
|
+
return fs12.existsSync(path22.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
38348
38449
|
}
|
|
38349
38450
|
function detectRSpec(cwd) {
|
|
38350
|
-
const hasRSpecFile = fs12.existsSync(
|
|
38351
|
-
const hasGemfile = fs12.existsSync(
|
|
38352
|
-
const hasSpecDir = fs12.existsSync(
|
|
38451
|
+
const hasRSpecFile = fs12.existsSync(path22.join(cwd, ".rspec"));
|
|
38452
|
+
const hasGemfile = fs12.existsSync(path22.join(cwd, "Gemfile"));
|
|
38453
|
+
const hasSpecDir = fs12.existsSync(path22.join(cwd, "spec"));
|
|
38353
38454
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
38354
38455
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
38355
38456
|
}
|
|
38356
38457
|
function detectMinitest(cwd) {
|
|
38357
|
-
return fs12.existsSync(
|
|
38458
|
+
return fs12.existsSync(path22.join(cwd, "test")) && (fs12.existsSync(path22.join(cwd, "Gemfile")) || fs12.existsSync(path22.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
38358
38459
|
}
|
|
38359
38460
|
async function detectTestFramework(cwd) {
|
|
38360
38461
|
const baseDir = cwd;
|
|
38361
38462
|
try {
|
|
38362
|
-
const packageJsonPath =
|
|
38463
|
+
const packageJsonPath = path22.join(baseDir, "package.json");
|
|
38363
38464
|
if (fs12.existsSync(packageJsonPath)) {
|
|
38364
38465
|
const content = fs12.readFileSync(packageJsonPath, "utf-8");
|
|
38365
38466
|
const pkg = JSON.parse(content);
|
|
@@ -38380,16 +38481,16 @@ async function detectTestFramework(cwd) {
|
|
|
38380
38481
|
return "jest";
|
|
38381
38482
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
38382
38483
|
return "mocha";
|
|
38383
|
-
if (fs12.existsSync(
|
|
38484
|
+
if (fs12.existsSync(path22.join(baseDir, "bun.lockb")) || fs12.existsSync(path22.join(baseDir, "bun.lock"))) {
|
|
38384
38485
|
if (scripts.test?.includes("bun"))
|
|
38385
38486
|
return "bun";
|
|
38386
38487
|
}
|
|
38387
38488
|
}
|
|
38388
38489
|
} catch {}
|
|
38389
38490
|
try {
|
|
38390
|
-
const pyprojectTomlPath =
|
|
38391
|
-
const setupCfgPath =
|
|
38392
|
-
const requirementsTxtPath =
|
|
38491
|
+
const pyprojectTomlPath = path22.join(baseDir, "pyproject.toml");
|
|
38492
|
+
const setupCfgPath = path22.join(baseDir, "setup.cfg");
|
|
38493
|
+
const requirementsTxtPath = path22.join(baseDir, "requirements.txt");
|
|
38393
38494
|
if (fs12.existsSync(pyprojectTomlPath)) {
|
|
38394
38495
|
const content = fs12.readFileSync(pyprojectTomlPath, "utf-8");
|
|
38395
38496
|
if (content.includes("[tool.pytest"))
|
|
@@ -38409,7 +38510,7 @@ async function detectTestFramework(cwd) {
|
|
|
38409
38510
|
}
|
|
38410
38511
|
} catch {}
|
|
38411
38512
|
try {
|
|
38412
|
-
const cargoTomlPath =
|
|
38513
|
+
const cargoTomlPath = path22.join(baseDir, "Cargo.toml");
|
|
38413
38514
|
if (fs12.existsSync(cargoTomlPath)) {
|
|
38414
38515
|
const content = fs12.readFileSync(cargoTomlPath, "utf-8");
|
|
38415
38516
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -38420,9 +38521,9 @@ async function detectTestFramework(cwd) {
|
|
|
38420
38521
|
}
|
|
38421
38522
|
} catch {}
|
|
38422
38523
|
try {
|
|
38423
|
-
const pesterConfigPath =
|
|
38424
|
-
const pesterConfigJsonPath =
|
|
38425
|
-
const pesterPs1Path =
|
|
38524
|
+
const pesterConfigPath = path22.join(baseDir, "pester.config.ps1");
|
|
38525
|
+
const pesterConfigJsonPath = path22.join(baseDir, "pester.config.ps1.json");
|
|
38526
|
+
const pesterPs1Path = path22.join(baseDir, "tests.ps1");
|
|
38426
38527
|
if (fs12.existsSync(pesterConfigPath) || fs12.existsSync(pesterConfigJsonPath) || fs12.existsSync(pesterPs1Path)) {
|
|
38427
38528
|
return "pester";
|
|
38428
38529
|
}
|
|
@@ -38474,8 +38575,8 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
38474
38575
|
const testFiles = [];
|
|
38475
38576
|
for (const file3 of sourceFiles) {
|
|
38476
38577
|
const normalizedPath = file3.replace(/\\/g, "/");
|
|
38477
|
-
const basename4 =
|
|
38478
|
-
const dirname10 =
|
|
38578
|
+
const basename4 = path22.basename(file3);
|
|
38579
|
+
const dirname10 = path22.dirname(file3);
|
|
38479
38580
|
if (hasCompoundTestExtension(basename4) || basename4.includes(".spec.") || basename4.includes(".test.") || normalizedPath.includes("/__tests__/") || normalizedPath.includes("/tests/") || normalizedPath.includes("/test/")) {
|
|
38480
38581
|
if (!testFiles.includes(file3)) {
|
|
38481
38582
|
testFiles.push(file3);
|
|
@@ -38484,13 +38585,13 @@ function getTestFilesFromConvention(sourceFiles) {
|
|
|
38484
38585
|
}
|
|
38485
38586
|
for (const _pattern of TEST_PATTERNS) {
|
|
38486
38587
|
const nameWithoutExt = basename4.replace(/\.[^.]+$/, "");
|
|
38487
|
-
const ext =
|
|
38588
|
+
const ext = path22.extname(basename4);
|
|
38488
38589
|
const possibleTestFiles = [
|
|
38489
|
-
|
|
38490
|
-
|
|
38491
|
-
|
|
38492
|
-
|
|
38493
|
-
|
|
38590
|
+
path22.join(dirname10, `${nameWithoutExt}.spec${ext}`),
|
|
38591
|
+
path22.join(dirname10, `${nameWithoutExt}.test${ext}`),
|
|
38592
|
+
path22.join(dirname10, "__tests__", `${nameWithoutExt}${ext}`),
|
|
38593
|
+
path22.join(dirname10, "tests", `${nameWithoutExt}${ext}`),
|
|
38594
|
+
path22.join(dirname10, "test", `${nameWithoutExt}${ext}`)
|
|
38494
38595
|
];
|
|
38495
38596
|
for (const testFile of possibleTestFiles) {
|
|
38496
38597
|
if (fs12.existsSync(testFile) && !testFiles.includes(testFile)) {
|
|
@@ -38510,7 +38611,7 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38510
38611
|
for (const testFile of candidateTestFiles) {
|
|
38511
38612
|
try {
|
|
38512
38613
|
const content = fs12.readFileSync(testFile, "utf-8");
|
|
38513
|
-
const testDir =
|
|
38614
|
+
const testDir = path22.dirname(testFile);
|
|
38514
38615
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
38515
38616
|
let match;
|
|
38516
38617
|
match = importRegex.exec(content);
|
|
@@ -38518,8 +38619,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38518
38619
|
const importPath = match[1];
|
|
38519
38620
|
let resolvedImport;
|
|
38520
38621
|
if (importPath.startsWith(".")) {
|
|
38521
|
-
resolvedImport =
|
|
38522
|
-
const existingExt =
|
|
38622
|
+
resolvedImport = path22.resolve(testDir, importPath);
|
|
38623
|
+
const existingExt = path22.extname(resolvedImport);
|
|
38523
38624
|
if (!existingExt) {
|
|
38524
38625
|
for (const extToTry of [
|
|
38525
38626
|
".ts",
|
|
@@ -38539,12 +38640,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38539
38640
|
} else {
|
|
38540
38641
|
continue;
|
|
38541
38642
|
}
|
|
38542
|
-
const importBasename =
|
|
38543
|
-
const importDir =
|
|
38643
|
+
const importBasename = path22.basename(resolvedImport, path22.extname(resolvedImport));
|
|
38644
|
+
const importDir = path22.dirname(resolvedImport);
|
|
38544
38645
|
for (const sourceFile of sourceFiles) {
|
|
38545
|
-
const sourceDir =
|
|
38546
|
-
const sourceBasename =
|
|
38547
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
38646
|
+
const sourceDir = path22.dirname(sourceFile);
|
|
38647
|
+
const sourceBasename = path22.basename(sourceFile, path22.extname(sourceFile));
|
|
38648
|
+
const isRelatedDir = importDir === sourceDir || importDir === path22.join(sourceDir, "__tests__") || importDir === path22.join(sourceDir, "tests") || importDir === path22.join(sourceDir, "test");
|
|
38548
38649
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
38549
38650
|
if (!testFiles.includes(testFile)) {
|
|
38550
38651
|
testFiles.push(testFile);
|
|
@@ -38559,8 +38660,8 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38559
38660
|
while (match !== null) {
|
|
38560
38661
|
const importPath = match[1];
|
|
38561
38662
|
if (importPath.startsWith(".")) {
|
|
38562
|
-
let resolvedImport =
|
|
38563
|
-
const existingExt =
|
|
38663
|
+
let resolvedImport = path22.resolve(testDir, importPath);
|
|
38664
|
+
const existingExt = path22.extname(resolvedImport);
|
|
38564
38665
|
if (!existingExt) {
|
|
38565
38666
|
for (const extToTry of [
|
|
38566
38667
|
".ts",
|
|
@@ -38577,12 +38678,12 @@ async function getTestFilesFromGraph(sourceFiles) {
|
|
|
38577
38678
|
}
|
|
38578
38679
|
}
|
|
38579
38680
|
}
|
|
38580
|
-
const importDir =
|
|
38581
|
-
const importBasename =
|
|
38681
|
+
const importDir = path22.dirname(resolvedImport);
|
|
38682
|
+
const importBasename = path22.basename(resolvedImport, path22.extname(resolvedImport));
|
|
38582
38683
|
for (const sourceFile of sourceFiles) {
|
|
38583
|
-
const sourceDir =
|
|
38584
|
-
const sourceBasename =
|
|
38585
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
38684
|
+
const sourceDir = path22.dirname(sourceFile);
|
|
38685
|
+
const sourceBasename = path22.basename(sourceFile, path22.extname(sourceFile));
|
|
38686
|
+
const isRelatedDir = importDir === sourceDir || importDir === path22.join(sourceDir, "__tests__") || importDir === path22.join(sourceDir, "tests") || importDir === path22.join(sourceDir, "test");
|
|
38586
38687
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
38587
38688
|
if (!testFiles.includes(testFile)) {
|
|
38588
38689
|
testFiles.push(testFile);
|
|
@@ -38667,8 +38768,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
38667
38768
|
return ["mvn", "test"];
|
|
38668
38769
|
case "gradle": {
|
|
38669
38770
|
const isWindows = process.platform === "win32";
|
|
38670
|
-
const hasGradlewBat = fs12.existsSync(
|
|
38671
|
-
const hasGradlew = fs12.existsSync(
|
|
38771
|
+
const hasGradlewBat = fs12.existsSync(path22.join(baseDir, "gradlew.bat"));
|
|
38772
|
+
const hasGradlew = fs12.existsSync(path22.join(baseDir, "gradlew"));
|
|
38672
38773
|
if (hasGradlewBat && isWindows)
|
|
38673
38774
|
return ["gradlew.bat", "test"];
|
|
38674
38775
|
if (hasGradlew)
|
|
@@ -38685,7 +38786,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
38685
38786
|
"cmake-build-release",
|
|
38686
38787
|
"out"
|
|
38687
38788
|
];
|
|
38688
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(
|
|
38789
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs12.existsSync(path22.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
38689
38790
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
38690
38791
|
}
|
|
38691
38792
|
case "swift-test":
|
|
@@ -39227,7 +39328,7 @@ var test_runner = createSwarmTool({
|
|
|
39227
39328
|
let effectiveScope = scope;
|
|
39228
39329
|
if (scope === "all") {} else if (scope === "convention") {
|
|
39229
39330
|
const sourceFiles = args.files.filter((f) => {
|
|
39230
|
-
const ext =
|
|
39331
|
+
const ext = path22.extname(f).toLowerCase();
|
|
39231
39332
|
return SOURCE_EXTENSIONS.has(ext);
|
|
39232
39333
|
});
|
|
39233
39334
|
if (sourceFiles.length === 0) {
|
|
@@ -39243,7 +39344,7 @@ var test_runner = createSwarmTool({
|
|
|
39243
39344
|
testFiles = getTestFilesFromConvention(sourceFiles);
|
|
39244
39345
|
} else if (scope === "graph") {
|
|
39245
39346
|
const sourceFiles = args.files.filter((f) => {
|
|
39246
|
-
const ext =
|
|
39347
|
+
const ext = path22.extname(f).toLowerCase();
|
|
39247
39348
|
return SOURCE_EXTENSIONS.has(ext);
|
|
39248
39349
|
});
|
|
39249
39350
|
if (sourceFiles.length === 0) {
|
|
@@ -39314,8 +39415,8 @@ function validateDirectoryPath(dir) {
|
|
|
39314
39415
|
if (dir.includes("..")) {
|
|
39315
39416
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
39316
39417
|
}
|
|
39317
|
-
const normalized =
|
|
39318
|
-
const absolutePath =
|
|
39418
|
+
const normalized = path23.normalize(dir);
|
|
39419
|
+
const absolutePath = path23.isAbsolute(normalized) ? normalized : path23.resolve(normalized);
|
|
39319
39420
|
return absolutePath;
|
|
39320
39421
|
}
|
|
39321
39422
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -39338,7 +39439,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
39338
39439
|
}
|
|
39339
39440
|
function getPackageVersion(dir) {
|
|
39340
39441
|
try {
|
|
39341
|
-
const packagePath =
|
|
39442
|
+
const packagePath = path23.join(dir, "package.json");
|
|
39342
39443
|
if (fs13.existsSync(packagePath)) {
|
|
39343
39444
|
const content = fs13.readFileSync(packagePath, "utf-8");
|
|
39344
39445
|
const pkg = JSON.parse(content);
|
|
@@ -39349,7 +39450,7 @@ function getPackageVersion(dir) {
|
|
|
39349
39450
|
}
|
|
39350
39451
|
function getChangelogVersion(dir) {
|
|
39351
39452
|
try {
|
|
39352
|
-
const changelogPath =
|
|
39453
|
+
const changelogPath = path23.join(dir, "CHANGELOG.md");
|
|
39353
39454
|
if (fs13.existsSync(changelogPath)) {
|
|
39354
39455
|
const content = fs13.readFileSync(changelogPath, "utf-8");
|
|
39355
39456
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -39363,7 +39464,7 @@ function getChangelogVersion(dir) {
|
|
|
39363
39464
|
function getVersionFileVersion(dir) {
|
|
39364
39465
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
39365
39466
|
for (const file3 of possibleFiles) {
|
|
39366
|
-
const filePath =
|
|
39467
|
+
const filePath = path23.join(dir, file3);
|
|
39367
39468
|
if (fs13.existsSync(filePath)) {
|
|
39368
39469
|
try {
|
|
39369
39470
|
const content = fs13.readFileSync(filePath, "utf-8").trim();
|
|
@@ -39861,7 +39962,7 @@ async function handlePreflightCommand(directory, _args) {
|
|
|
39861
39962
|
// src/knowledge/hive-promoter.ts
|
|
39862
39963
|
import * as fs14 from "fs";
|
|
39863
39964
|
import * as os5 from "os";
|
|
39864
|
-
import * as
|
|
39965
|
+
import * as path24 from "path";
|
|
39865
39966
|
var DANGEROUS_PATTERNS = [
|
|
39866
39967
|
[/rm\s+-rf/, "rm\\s+-rf"],
|
|
39867
39968
|
[/:\s*!\s*\|/, ":\\s*!\\s*\\|"],
|
|
@@ -39907,13 +40008,13 @@ function getHiveFilePath() {
|
|
|
39907
40008
|
const home = os5.homedir();
|
|
39908
40009
|
let dataDir;
|
|
39909
40010
|
if (platform === "win32") {
|
|
39910
|
-
dataDir =
|
|
40011
|
+
dataDir = path24.join(process.env.LOCALAPPDATA || path24.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
39911
40012
|
} else if (platform === "darwin") {
|
|
39912
|
-
dataDir =
|
|
40013
|
+
dataDir = path24.join(home, "Library", "Application Support", "opencode-swarm");
|
|
39913
40014
|
} else {
|
|
39914
|
-
dataDir =
|
|
40015
|
+
dataDir = path24.join(process.env.XDG_DATA_HOME || path24.join(home, ".local", "share"), "opencode-swarm");
|
|
39915
40016
|
}
|
|
39916
|
-
return
|
|
40017
|
+
return path24.join(dataDir, "hive-knowledge.jsonl");
|
|
39917
40018
|
}
|
|
39918
40019
|
async function promoteToHive(_directory, lesson, category) {
|
|
39919
40020
|
const trimmed = (lesson ?? "").trim();
|
|
@@ -39925,7 +40026,7 @@ async function promoteToHive(_directory, lesson, category) {
|
|
|
39925
40026
|
throw new Error(`Lesson rejected by validator: ${validation.reason}`);
|
|
39926
40027
|
}
|
|
39927
40028
|
const hivePath = getHiveFilePath();
|
|
39928
|
-
const hiveDir =
|
|
40029
|
+
const hiveDir = path24.dirname(hivePath);
|
|
39929
40030
|
if (!fs14.existsSync(hiveDir)) {
|
|
39930
40031
|
fs14.mkdirSync(hiveDir, { recursive: true });
|
|
39931
40032
|
}
|
|
@@ -39947,7 +40048,7 @@ async function promoteToHive(_directory, lesson, category) {
|
|
|
39947
40048
|
return `Promoted to hive: "${preview}" (confidence: 1.0, source: manual)`;
|
|
39948
40049
|
}
|
|
39949
40050
|
async function promoteFromSwarm(directory, lessonId) {
|
|
39950
|
-
const knowledgePath =
|
|
40051
|
+
const knowledgePath = path24.join(directory, ".swarm", "knowledge.jsonl");
|
|
39951
40052
|
const entries = [];
|
|
39952
40053
|
if (fs14.existsSync(knowledgePath)) {
|
|
39953
40054
|
const content = fs14.readFileSync(knowledgePath, "utf-8");
|
|
@@ -39974,7 +40075,7 @@ async function promoteFromSwarm(directory, lessonId) {
|
|
|
39974
40075
|
throw new Error(`Lesson rejected by validator: ${validation.reason}`);
|
|
39975
40076
|
}
|
|
39976
40077
|
const hivePath = getHiveFilePath();
|
|
39977
|
-
const hiveDir =
|
|
40078
|
+
const hiveDir = path24.dirname(hivePath);
|
|
39978
40079
|
if (!fs14.existsSync(hiveDir)) {
|
|
39979
40080
|
fs14.mkdirSync(hiveDir, { recursive: true });
|
|
39980
40081
|
}
|
|
@@ -40785,7 +40886,7 @@ async function handleResetCommand(directory, args) {
|
|
|
40785
40886
|
// src/commands/reset-session.ts
|
|
40786
40887
|
init_utils2();
|
|
40787
40888
|
import * as fs16 from "fs";
|
|
40788
|
-
import * as
|
|
40889
|
+
import * as path25 from "path";
|
|
40789
40890
|
async function handleResetSessionCommand(directory, _args) {
|
|
40790
40891
|
const results = [];
|
|
40791
40892
|
try {
|
|
@@ -40800,13 +40901,13 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
40800
40901
|
results.push("\u274C Failed to delete state.json");
|
|
40801
40902
|
}
|
|
40802
40903
|
try {
|
|
40803
|
-
const sessionDir =
|
|
40904
|
+
const sessionDir = path25.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
40804
40905
|
if (fs16.existsSync(sessionDir)) {
|
|
40805
40906
|
const files = fs16.readdirSync(sessionDir);
|
|
40806
40907
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
40807
40908
|
let deletedCount = 0;
|
|
40808
40909
|
for (const file3 of otherFiles) {
|
|
40809
|
-
const filePath =
|
|
40910
|
+
const filePath = path25.join(sessionDir, file3);
|
|
40810
40911
|
if (fs16.lstatSync(filePath).isFile()) {
|
|
40811
40912
|
fs16.unlinkSync(filePath);
|
|
40812
40913
|
deletedCount++;
|
|
@@ -40836,7 +40937,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
40836
40937
|
// src/summaries/manager.ts
|
|
40837
40938
|
init_utils2();
|
|
40838
40939
|
init_utils();
|
|
40839
|
-
import * as
|
|
40940
|
+
import * as path26 from "path";
|
|
40840
40941
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
40841
40942
|
function sanitizeSummaryId(id) {
|
|
40842
40943
|
if (!id || id.length === 0) {
|
|
@@ -40860,7 +40961,7 @@ function sanitizeSummaryId(id) {
|
|
|
40860
40961
|
}
|
|
40861
40962
|
async function loadFullOutput(directory, id) {
|
|
40862
40963
|
const sanitizedId = sanitizeSummaryId(id);
|
|
40863
|
-
const relativePath =
|
|
40964
|
+
const relativePath = path26.join("summaries", `${sanitizedId}.json`);
|
|
40864
40965
|
validateSwarmPath(directory, relativePath);
|
|
40865
40966
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
40866
40967
|
if (content === null) {
|
|
@@ -40914,7 +41015,7 @@ ${error93 instanceof Error ? error93.message : String(error93)}`;
|
|
|
40914
41015
|
// src/commands/rollback.ts
|
|
40915
41016
|
init_utils2();
|
|
40916
41017
|
import * as fs17 from "fs";
|
|
40917
|
-
import * as
|
|
41018
|
+
import * as path27 from "path";
|
|
40918
41019
|
async function handleRollbackCommand(directory, args) {
|
|
40919
41020
|
const phaseArg = args[0];
|
|
40920
41021
|
if (!phaseArg) {
|
|
@@ -40972,8 +41073,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
40972
41073
|
const successes = [];
|
|
40973
41074
|
const failures = [];
|
|
40974
41075
|
for (const file3 of checkpointFiles) {
|
|
40975
|
-
const src =
|
|
40976
|
-
const dest =
|
|
41076
|
+
const src = path27.join(checkpointDir, file3);
|
|
41077
|
+
const dest = path27.join(swarmDir, file3);
|
|
40977
41078
|
try {
|
|
40978
41079
|
fs17.cpSync(src, dest, { recursive: true, force: true });
|
|
40979
41080
|
successes.push(file3);
|
|
@@ -41036,9 +41137,9 @@ async function handleSimulateCommand(directory, args) {
|
|
|
41036
41137
|
const report = reportLines.filter(Boolean).join(`
|
|
41037
41138
|
`);
|
|
41038
41139
|
const fs18 = await import("fs/promises");
|
|
41039
|
-
const
|
|
41040
|
-
const reportPath =
|
|
41041
|
-
await fs18.mkdir(
|
|
41140
|
+
const path28 = await import("path");
|
|
41141
|
+
const reportPath = path28.join(directory, ".swarm", "simulate-report.md");
|
|
41142
|
+
await fs18.mkdir(path28.dirname(reportPath), { recursive: true });
|
|
41042
41143
|
await fs18.writeFile(reportPath, report, "utf-8");
|
|
41043
41144
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
41044
41145
|
}
|
|
@@ -41521,10 +41622,10 @@ function resolveCommand(tokens) {
|
|
|
41521
41622
|
}
|
|
41522
41623
|
|
|
41523
41624
|
// src/cli/index.ts
|
|
41524
|
-
var CONFIG_DIR =
|
|
41525
|
-
var OPENCODE_CONFIG_PATH =
|
|
41526
|
-
var PLUGIN_CONFIG_PATH =
|
|
41527
|
-
var PROMPTS_DIR =
|
|
41625
|
+
var CONFIG_DIR = path28.join(process.env.XDG_CONFIG_HOME || path28.join(os6.homedir(), ".config"), "opencode");
|
|
41626
|
+
var OPENCODE_CONFIG_PATH = path28.join(CONFIG_DIR, "opencode.json");
|
|
41627
|
+
var PLUGIN_CONFIG_PATH = path28.join(CONFIG_DIR, "opencode-swarm.json");
|
|
41628
|
+
var PROMPTS_DIR = path28.join(CONFIG_DIR, "opencode-swarm");
|
|
41528
41629
|
function ensureDir(dir) {
|
|
41529
41630
|
if (!fs18.existsSync(dir)) {
|
|
41530
41631
|
fs18.mkdirSync(dir, { recursive: true });
|
|
@@ -41548,7 +41649,7 @@ async function install() {
|
|
|
41548
41649
|
`);
|
|
41549
41650
|
ensureDir(CONFIG_DIR);
|
|
41550
41651
|
ensureDir(PROMPTS_DIR);
|
|
41551
|
-
const LEGACY_CONFIG_PATH =
|
|
41652
|
+
const LEGACY_CONFIG_PATH = path28.join(CONFIG_DIR, "config.json");
|
|
41552
41653
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
41553
41654
|
if (!opencodeConfig) {
|
|
41554
41655
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|