opencode-swarm 7.30.0 → 7.32.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/agents/agent-output-schema.d.ts +38 -0
- package/dist/cli/index.js +448 -489
- package/dist/hooks/knowledge-store.d.ts +12 -0
- package/dist/index.js +16743 -16128
- package/dist/memory/gateway.d.ts +1 -0
- package/dist/memory/index.d.ts +4 -0
- package/dist/memory/injector.d.ts +31 -0
- package/dist/memory/local-jsonl-provider.d.ts +2 -1
- package/dist/memory/prompt-block.d.ts +1 -1
- package/dist/memory/provider.d.ts +13 -0
- package/dist/memory/recall-planner.d.ts +26 -0
- package/dist/memory/role-profiles.d.ts +41 -0
- package/dist/memory/run-log.d.ts +17 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.
|
|
37
|
+
version: "7.32.0",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -35397,6 +35397,9 @@ function resolveSwarmKnowledgePath(directory) {
|
|
|
35397
35397
|
function resolveSwarmRejectedPath(directory) {
|
|
35398
35398
|
return path10.join(directory, ".swarm", "knowledge-rejected.jsonl");
|
|
35399
35399
|
}
|
|
35400
|
+
function resolveSwarmRetractionsPath(directory) {
|
|
35401
|
+
return path10.join(directory, ".swarm", "knowledge-retractions.jsonl");
|
|
35402
|
+
}
|
|
35400
35403
|
function resolveHiveKnowledgePath() {
|
|
35401
35404
|
const platform = process.platform;
|
|
35402
35405
|
const home = process.env.HOME || os3.homedir();
|
|
@@ -35495,6 +35498,12 @@ function normalizeEntry(raw) {
|
|
|
35495
35498
|
async function readRejectedLessons(directory) {
|
|
35496
35499
|
return readKnowledge(resolveSwarmRejectedPath(directory));
|
|
35497
35500
|
}
|
|
35501
|
+
async function readRetractionRecords(directory) {
|
|
35502
|
+
return readKnowledge(resolveSwarmRetractionsPath(directory));
|
|
35503
|
+
}
|
|
35504
|
+
async function appendRetractionRecord(directory, record3) {
|
|
35505
|
+
await appendKnowledge(resolveSwarmRetractionsPath(directory), record3);
|
|
35506
|
+
}
|
|
35498
35507
|
async function appendKnowledge(filePath, entry) {
|
|
35499
35508
|
await mkdir2(path10.dirname(filePath), { recursive: true });
|
|
35500
35509
|
await appendFile2(filePath, `${JSON.stringify(entry)}
|
|
@@ -36259,75 +36268,6 @@ var init_hive_promoter = __esm(() => {
|
|
|
36259
36268
|
init_utils2();
|
|
36260
36269
|
});
|
|
36261
36270
|
|
|
36262
|
-
// src/hooks/knowledge-reader.ts
|
|
36263
|
-
import { existsSync as existsSync8 } from "fs";
|
|
36264
|
-
import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
36265
|
-
import * as path13 from "path";
|
|
36266
|
-
async function updateRetrievalOutcome(directory, phaseInfo, phaseSucceeded) {
|
|
36267
|
-
const shownFile = path13.join(directory, ".swarm", ".knowledge-shown.json");
|
|
36268
|
-
try {
|
|
36269
|
-
if (!existsSync8(shownFile)) {
|
|
36270
|
-
return;
|
|
36271
|
-
}
|
|
36272
|
-
const content = await readFile4(shownFile, "utf-8");
|
|
36273
|
-
const shownData = JSON.parse(content);
|
|
36274
|
-
const shownIds = shownData[phaseInfo];
|
|
36275
|
-
if (!shownIds || shownIds.length === 0) {
|
|
36276
|
-
return;
|
|
36277
|
-
}
|
|
36278
|
-
const swarmPath = resolveSwarmKnowledgePath(directory);
|
|
36279
|
-
const entries = await readKnowledge(swarmPath);
|
|
36280
|
-
let updated = false;
|
|
36281
|
-
const foundInSwarm = new Set;
|
|
36282
|
-
for (const entry of entries) {
|
|
36283
|
-
if (shownIds.includes(entry.id)) {
|
|
36284
|
-
const ro = entry.retrieval_outcomes;
|
|
36285
|
-
if (phaseSucceeded) {
|
|
36286
|
-
ro.succeeded_after_shown_count = (ro.succeeded_after_shown_count ?? 0) + 1;
|
|
36287
|
-
} else {
|
|
36288
|
-
ro.failed_after_shown_count = (ro.failed_after_shown_count ?? 0) + 1;
|
|
36289
|
-
}
|
|
36290
|
-
updated = true;
|
|
36291
|
-
foundInSwarm.add(entry.id);
|
|
36292
|
-
}
|
|
36293
|
-
}
|
|
36294
|
-
if (updated) {
|
|
36295
|
-
await rewriteKnowledge(swarmPath, entries);
|
|
36296
|
-
}
|
|
36297
|
-
const remainingIds = shownIds.filter((id) => !foundInSwarm.has(id));
|
|
36298
|
-
if (remainingIds.length === 0) {
|
|
36299
|
-
delete shownData[phaseInfo];
|
|
36300
|
-
await writeFile5(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
36301
|
-
return;
|
|
36302
|
-
}
|
|
36303
|
-
const hivePath = resolveHiveKnowledgePath();
|
|
36304
|
-
const hiveEntries = await readKnowledge(hivePath);
|
|
36305
|
-
let hiveUpdated = false;
|
|
36306
|
-
for (const entry of hiveEntries) {
|
|
36307
|
-
if (remainingIds.includes(entry.id)) {
|
|
36308
|
-
const ro = entry.retrieval_outcomes;
|
|
36309
|
-
if (phaseSucceeded) {
|
|
36310
|
-
ro.succeeded_after_shown_count = (ro.succeeded_after_shown_count ?? 0) + 1;
|
|
36311
|
-
} else {
|
|
36312
|
-
ro.failed_after_shown_count = (ro.failed_after_shown_count ?? 0) + 1;
|
|
36313
|
-
}
|
|
36314
|
-
hiveUpdated = true;
|
|
36315
|
-
}
|
|
36316
|
-
}
|
|
36317
|
-
if (hiveUpdated) {
|
|
36318
|
-
await rewriteKnowledge(hivePath, hiveEntries);
|
|
36319
|
-
}
|
|
36320
|
-
delete shownData[phaseInfo];
|
|
36321
|
-
await writeFile5(shownFile, JSON.stringify(shownData, null, 2), "utf-8");
|
|
36322
|
-
} catch {
|
|
36323
|
-
warn("[swarm] Knowledge: failed to update retrieval outcomes");
|
|
36324
|
-
}
|
|
36325
|
-
}
|
|
36326
|
-
var init_knowledge_reader = __esm(() => {
|
|
36327
|
-
init_logger();
|
|
36328
|
-
init_knowledge_store();
|
|
36329
|
-
});
|
|
36330
|
-
|
|
36331
36271
|
// src/hooks/knowledge-curator.ts
|
|
36332
36272
|
function pruneSeenRetroSections() {
|
|
36333
36273
|
const cutoff = Date.now() - 86400000;
|
|
@@ -36444,17 +36384,39 @@ function extractRetractionsAndLessons(allLessons) {
|
|
|
36444
36384
|
async function processRetractions(retractions, directory) {
|
|
36445
36385
|
if (retractions.length === 0)
|
|
36446
36386
|
return;
|
|
36447
|
-
const
|
|
36448
|
-
const
|
|
36387
|
+
const swarmEntries = await readKnowledge(resolveSwarmKnowledgePath(directory)) ?? [];
|
|
36388
|
+
const hiveEntries = await readKnowledge(resolveHiveKnowledgePath()) ?? [];
|
|
36389
|
+
const existingRetractions = await readRetractionRecords(directory);
|
|
36390
|
+
const existingSuppressedLessons = new Set(existingRetractions.map((record3) => record3.normalized_lesson).filter((value) => typeof value === "string" && value.length > 0));
|
|
36449
36391
|
for (const retractionText of retractions) {
|
|
36450
36392
|
const normalizedRetraction = normalize2(retractionText);
|
|
36451
|
-
|
|
36393
|
+
const matchedSwarmIds = [];
|
|
36394
|
+
const matchedHiveIds = [];
|
|
36395
|
+
for (const entry of swarmEntries) {
|
|
36452
36396
|
const normalizedLesson = normalize2(entry.lesson);
|
|
36453
36397
|
if (normalizedLesson === normalizedRetraction) {
|
|
36398
|
+
matchedSwarmIds.push(entry.id);
|
|
36454
36399
|
await quarantineEntry(directory, entry.id, `Retracted by architect: ${retractionText}`, "architect");
|
|
36455
36400
|
console.info(`[knowledge-curator] Quarantined entry ${entry.id}: "${entry.lesson}"`);
|
|
36456
36401
|
}
|
|
36457
36402
|
}
|
|
36403
|
+
for (const entry of hiveEntries) {
|
|
36404
|
+
if (normalize2(entry.lesson) === normalizedRetraction) {
|
|
36405
|
+
matchedHiveIds.push(entry.id);
|
|
36406
|
+
}
|
|
36407
|
+
}
|
|
36408
|
+
if (!existingSuppressedLessons.has(normalizedRetraction)) {
|
|
36409
|
+
await appendRetractionRecord(directory, {
|
|
36410
|
+
id: crypto.randomUUID(),
|
|
36411
|
+
retracted_lesson: retractionText,
|
|
36412
|
+
normalized_lesson: normalizedRetraction,
|
|
36413
|
+
recorded_at: new Date().toISOString(),
|
|
36414
|
+
reported_by: "architect",
|
|
36415
|
+
matched_swarm_ids: matchedSwarmIds,
|
|
36416
|
+
matched_hive_ids: matchedHiveIds
|
|
36417
|
+
});
|
|
36418
|
+
existingSuppressedLessons.add(normalizedRetraction);
|
|
36419
|
+
}
|
|
36458
36420
|
}
|
|
36459
36421
|
}
|
|
36460
36422
|
async function curateAndStoreSwarm(lessons, projectName, phaseInfo, directory, config3) {
|
|
@@ -36621,7 +36583,6 @@ function createKnowledgeCuratorHook(directory, config3) {
|
|
|
36621
36583
|
const projectName2 = evidenceData.project_name ?? "unknown";
|
|
36622
36584
|
const phaseNumber2 = typeof evidenceData.phase_number === "number" ? evidenceData.phase_number : 1;
|
|
36623
36585
|
await _internals8.curateAndStoreSwarm(lessons, projectName2, { phase_number: phaseNumber2 }, directory, config3);
|
|
36624
|
-
await updateRetrievalOutcome(directory, `Phase ${phaseNumber2}`, true);
|
|
36625
36586
|
return;
|
|
36626
36587
|
}
|
|
36627
36588
|
const planContent = await readSwarmFileAsync(directory, "plan.md");
|
|
@@ -36644,13 +36605,11 @@ function createKnowledgeCuratorHook(directory, config3) {
|
|
|
36644
36605
|
const phaseMatch = /^Phase:\s*(\d+)/m.exec(planContent);
|
|
36645
36606
|
const phaseNumber = phaseMatch ? parseInt(phaseMatch[1], 10) : 1;
|
|
36646
36607
|
await _internals8.curateAndStoreSwarm(normalLessons, projectName, { phase_number: phaseNumber }, directory, config3);
|
|
36647
|
-
await updateRetrievalOutcome(directory, `Phase ${phaseNumber}`, true);
|
|
36648
36608
|
};
|
|
36649
36609
|
return safeHook(handler);
|
|
36650
36610
|
}
|
|
36651
36611
|
var seenRetroSections, _internals8;
|
|
36652
36612
|
var init_knowledge_curator = __esm(() => {
|
|
36653
|
-
init_knowledge_reader();
|
|
36654
36613
|
init_knowledge_store();
|
|
36655
36614
|
init_knowledge_validator();
|
|
36656
36615
|
init_utils2();
|
|
@@ -36773,9 +36732,9 @@ var init_skill_improver_llm_factory = __esm(() => {
|
|
|
36773
36732
|
});
|
|
36774
36733
|
|
|
36775
36734
|
// src/services/skill-generator.ts
|
|
36776
|
-
import { existsSync as
|
|
36777
|
-
import { mkdir as
|
|
36778
|
-
import * as
|
|
36735
|
+
import { existsSync as existsSync8 } from "fs";
|
|
36736
|
+
import { mkdir as mkdir4, readFile as readFile4, rename as rename3, writeFile as writeFile5 } from "fs/promises";
|
|
36737
|
+
import * as path13 from "path";
|
|
36779
36738
|
function sanitizeSlug(input) {
|
|
36780
36739
|
const lc = input.toLowerCase().trim();
|
|
36781
36740
|
const mapped = lc.replace(/[^a-z0-9-]+/g, "-").replace(/-+/g, "-");
|
|
@@ -36786,10 +36745,10 @@ function isValidSlug(slug) {
|
|
|
36786
36745
|
return SLUG_PATTERN.test(slug);
|
|
36787
36746
|
}
|
|
36788
36747
|
function proposalPath(directory, slug) {
|
|
36789
|
-
return
|
|
36748
|
+
return path13.join(directory, ".swarm", "skills", "proposals", `${slug}.md`);
|
|
36790
36749
|
}
|
|
36791
36750
|
function activePath(directory, slug) {
|
|
36792
|
-
return
|
|
36751
|
+
return path13.join(directory, ".opencode", "skills", "generated", slug, "SKILL.md");
|
|
36793
36752
|
}
|
|
36794
36753
|
function activeRepoRelativePath(slug) {
|
|
36795
36754
|
return `.opencode/skills/generated/${slug}/SKILL.md`;
|
|
@@ -36797,7 +36756,7 @@ function activeRepoRelativePath(slug) {
|
|
|
36797
36756
|
async function selectCandidateEntries(directory, opts) {
|
|
36798
36757
|
const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
36799
36758
|
const hivePath = resolveHiveKnowledgePath();
|
|
36800
|
-
const hive =
|
|
36759
|
+
const hive = existsSync8(hivePath) ? await readKnowledge(hivePath) : [];
|
|
36801
36760
|
const all = [...swarm, ...hive];
|
|
36802
36761
|
return all.filter((e) => {
|
|
36803
36762
|
if (e.status === "archived")
|
|
@@ -36945,9 +36904,9 @@ function escapeMarkdown(s) {
|
|
|
36945
36904
|
return s.replace(/[\r\n]+/g, " ").slice(0, 280);
|
|
36946
36905
|
}
|
|
36947
36906
|
async function atomicWrite(p, content) {
|
|
36948
|
-
await
|
|
36907
|
+
await mkdir4(path13.dirname(p), { recursive: true });
|
|
36949
36908
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
36950
|
-
await
|
|
36909
|
+
await writeFile5(tmp, content, "utf-8");
|
|
36951
36910
|
await rename3(tmp, p);
|
|
36952
36911
|
}
|
|
36953
36912
|
async function generateSkills(req) {
|
|
@@ -36962,7 +36921,7 @@ async function generateSkills(req) {
|
|
|
36962
36921
|
const idSet = new Set(req.sourceKnowledgeIds);
|
|
36963
36922
|
const swarm = await readKnowledge(resolveSwarmKnowledgePath(req.directory));
|
|
36964
36923
|
const hivePath = resolveHiveKnowledgePath();
|
|
36965
|
-
const hive =
|
|
36924
|
+
const hive = existsSync8(hivePath) ? await readKnowledge(hivePath) : [];
|
|
36966
36925
|
pool = [...swarm, ...hive].filter((e) => idSet.has(e.id) && e.status !== "archived");
|
|
36967
36926
|
} else {
|
|
36968
36927
|
pool = candidates;
|
|
@@ -36990,7 +36949,7 @@ async function generateSkills(req) {
|
|
|
36990
36949
|
continue;
|
|
36991
36950
|
}
|
|
36992
36951
|
const targetPath = req.mode === "active" ? activePath(req.directory, cluster.slug) : proposalPath(req.directory, cluster.slug);
|
|
36993
|
-
const repoRel =
|
|
36952
|
+
const repoRel = path13.relative(req.directory, targetPath).replace(/\\/g, "/");
|
|
36994
36953
|
if (!validateSkillPath(repoRel)) {
|
|
36995
36954
|
result.skipped.push({
|
|
36996
36955
|
slug: cluster.slug,
|
|
@@ -36999,8 +36958,8 @@ async function generateSkills(req) {
|
|
|
36999
36958
|
continue;
|
|
37000
36959
|
}
|
|
37001
36960
|
let preserved = false;
|
|
37002
|
-
if (req.mode === "active" &&
|
|
37003
|
-
const existing = await
|
|
36961
|
+
if (req.mode === "active" && existsSync8(targetPath) && !req.force) {
|
|
36962
|
+
const existing = await readFile4(targetPath, "utf-8");
|
|
37004
36963
|
if (!existing.includes("generated by opencode-swarm skill-generator")) {
|
|
37005
36964
|
preserved = true;
|
|
37006
36965
|
result.skipped.push({
|
|
@@ -37044,7 +37003,7 @@ async function stampSourceEntries(directory, slug, ids) {
|
|
|
37044
37003
|
if (touched)
|
|
37045
37004
|
await rewriteKnowledge(swarmPath, swarm);
|
|
37046
37005
|
const hivePath = resolveHiveKnowledgePath();
|
|
37047
|
-
if (!
|
|
37006
|
+
if (!existsSync8(hivePath))
|
|
37048
37007
|
return;
|
|
37049
37008
|
const hive = await readKnowledge(hivePath);
|
|
37050
37009
|
let touchedHive = false;
|
|
@@ -37064,10 +37023,10 @@ async function listSkills(directory) {
|
|
|
37064
37023
|
proposals: [],
|
|
37065
37024
|
active: []
|
|
37066
37025
|
};
|
|
37067
|
-
const proposalsDir =
|
|
37068
|
-
const activeDir =
|
|
37026
|
+
const proposalsDir = path13.join(directory, ".swarm", "skills", "proposals");
|
|
37027
|
+
const activeDir = path13.join(directory, ".opencode", "skills", "generated");
|
|
37069
37028
|
const fs7 = await import("fs/promises");
|
|
37070
|
-
if (
|
|
37029
|
+
if (existsSync8(proposalsDir)) {
|
|
37071
37030
|
const entries = await fs7.readdir(proposalsDir);
|
|
37072
37031
|
for (const f of entries) {
|
|
37073
37032
|
if (!f.endsWith(".md"))
|
|
@@ -37075,17 +37034,17 @@ async function listSkills(directory) {
|
|
|
37075
37034
|
const slug = f.replace(/\.md$/, "");
|
|
37076
37035
|
result.proposals.push({
|
|
37077
37036
|
slug,
|
|
37078
|
-
path:
|
|
37037
|
+
path: path13.join(proposalsDir, f)
|
|
37079
37038
|
});
|
|
37080
37039
|
}
|
|
37081
37040
|
}
|
|
37082
|
-
if (
|
|
37041
|
+
if (existsSync8(activeDir)) {
|
|
37083
37042
|
const entries = await fs7.readdir(activeDir, { withFileTypes: true });
|
|
37084
37043
|
for (const e of entries) {
|
|
37085
37044
|
if (!e.isDirectory())
|
|
37086
37045
|
continue;
|
|
37087
|
-
const skillPath =
|
|
37088
|
-
if (
|
|
37046
|
+
const skillPath = path13.join(activeDir, e.name, "SKILL.md");
|
|
37047
|
+
if (existsSync8(skillPath)) {
|
|
37089
37048
|
result.active.push({
|
|
37090
37049
|
slug: e.name,
|
|
37091
37050
|
path: skillPath
|
|
@@ -37104,9 +37063,9 @@ var init_skill_generator = __esm(() => {
|
|
|
37104
37063
|
});
|
|
37105
37064
|
|
|
37106
37065
|
// src/services/skill-improver-quota.ts
|
|
37107
|
-
import { existsSync as
|
|
37108
|
-
import { mkdir as
|
|
37109
|
-
import * as
|
|
37066
|
+
import { existsSync as existsSync9 } from "fs";
|
|
37067
|
+
import { mkdir as mkdir5, readFile as readFile5, rename as rename4, writeFile as writeFile6 } from "fs/promises";
|
|
37068
|
+
import * as path14 from "path";
|
|
37110
37069
|
async function acquireLock(dir) {
|
|
37111
37070
|
const acquire = import_proper_lockfile5.default.lock(dir, LOCK_RETRY_OPTS);
|
|
37112
37071
|
let timer;
|
|
@@ -37124,7 +37083,7 @@ async function acquireLock(dir) {
|
|
|
37124
37083
|
}
|
|
37125
37084
|
}
|
|
37126
37085
|
function resolveQuotaPath(directory) {
|
|
37127
|
-
return
|
|
37086
|
+
return path14.join(directory, ".swarm", "skill-improver-quota.json");
|
|
37128
37087
|
}
|
|
37129
37088
|
function todayKey(window, now = new Date) {
|
|
37130
37089
|
if (window === "utc") {
|
|
@@ -37136,10 +37095,10 @@ function todayKey(window, now = new Date) {
|
|
|
37136
37095
|
return `${yr}-${m}-${d}`;
|
|
37137
37096
|
}
|
|
37138
37097
|
async function readState(filePath) {
|
|
37139
|
-
if (!
|
|
37098
|
+
if (!existsSync9(filePath))
|
|
37140
37099
|
return null;
|
|
37141
37100
|
try {
|
|
37142
|
-
const raw = await
|
|
37101
|
+
const raw = await readFile5(filePath, "utf-8");
|
|
37143
37102
|
const parsed = JSON.parse(raw);
|
|
37144
37103
|
if (typeof parsed.date !== "string" || typeof parsed.calls_used !== "number" || typeof parsed.max_calls !== "number" || parsed.window !== "utc" && parsed.window !== "local") {
|
|
37145
37104
|
return null;
|
|
@@ -37150,9 +37109,9 @@ async function readState(filePath) {
|
|
|
37150
37109
|
}
|
|
37151
37110
|
}
|
|
37152
37111
|
async function writeState(filePath, state) {
|
|
37153
|
-
await
|
|
37112
|
+
await mkdir5(path14.dirname(filePath), { recursive: true });
|
|
37154
37113
|
const tmp = `${filePath}.tmp-${process.pid}`;
|
|
37155
|
-
await
|
|
37114
|
+
await writeFile6(tmp, JSON.stringify(state, null, 2), "utf-8");
|
|
37156
37115
|
await rename4(tmp, filePath);
|
|
37157
37116
|
}
|
|
37158
37117
|
async function getQuotaState(directory, opts) {
|
|
@@ -37173,10 +37132,10 @@ async function getQuotaState(directory, opts) {
|
|
|
37173
37132
|
}
|
|
37174
37133
|
async function reserveQuota(directory, opts) {
|
|
37175
37134
|
const filePath = resolveQuotaPath(directory);
|
|
37176
|
-
await
|
|
37135
|
+
await mkdir5(path14.dirname(filePath), { recursive: true });
|
|
37177
37136
|
let release = null;
|
|
37178
37137
|
try {
|
|
37179
|
-
release = await acquireLock(
|
|
37138
|
+
release = await acquireLock(path14.dirname(filePath));
|
|
37180
37139
|
const state = await getQuotaState(directory, opts);
|
|
37181
37140
|
if (state.calls_used + opts.nCalls > opts.maxCalls) {
|
|
37182
37141
|
return {
|
|
@@ -37203,10 +37162,10 @@ async function reserveQuota(directory, opts) {
|
|
|
37203
37162
|
}
|
|
37204
37163
|
async function releaseQuota(directory, opts) {
|
|
37205
37164
|
const filePath = resolveQuotaPath(directory);
|
|
37206
|
-
await
|
|
37165
|
+
await mkdir5(path14.dirname(filePath), { recursive: true });
|
|
37207
37166
|
let release = null;
|
|
37208
37167
|
try {
|
|
37209
|
-
release = await acquireLock(
|
|
37168
|
+
release = await acquireLock(path14.dirname(filePath));
|
|
37210
37169
|
const state = await getQuotaState(directory, opts);
|
|
37211
37170
|
const next = {
|
|
37212
37171
|
...state,
|
|
@@ -37238,22 +37197,22 @@ var init_skill_improver_quota = __esm(() => {
|
|
|
37238
37197
|
});
|
|
37239
37198
|
|
|
37240
37199
|
// src/services/skill-improver.ts
|
|
37241
|
-
import { existsSync as
|
|
37242
|
-
import { mkdir as
|
|
37243
|
-
import * as
|
|
37200
|
+
import { existsSync as existsSync10 } from "fs";
|
|
37201
|
+
import { mkdir as mkdir6, rename as rename5, writeFile as writeFile7 } from "fs/promises";
|
|
37202
|
+
import * as path15 from "path";
|
|
37244
37203
|
function timestampSlug(d) {
|
|
37245
37204
|
return d.toISOString().replace(/[:.]/g, "-");
|
|
37246
37205
|
}
|
|
37247
37206
|
async function atomicWrite2(p, content) {
|
|
37248
|
-
await
|
|
37207
|
+
await mkdir6(path15.dirname(p), { recursive: true });
|
|
37249
37208
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
37250
|
-
await
|
|
37209
|
+
await writeFile7(tmp, content, "utf-8");
|
|
37251
37210
|
await rename5(tmp, p);
|
|
37252
37211
|
}
|
|
37253
37212
|
async function gatherInventory(directory) {
|
|
37254
37213
|
const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
37255
37214
|
const hivePath = resolveHiveKnowledgePath();
|
|
37256
|
-
const hive =
|
|
37215
|
+
const hive = existsSync10(hivePath) ? await readKnowledge(hivePath) : [];
|
|
37257
37216
|
const archived = [...swarm, ...hive].filter((e) => e.status === "archived").length;
|
|
37258
37217
|
const skills = await listSkills(directory);
|
|
37259
37218
|
const matureCandidates = swarm.concat(hive).filter((e) => e.status !== "archived" && e.confidence >= 0.85 && !e.generated_skill_slug && (e.confirmed_by ?? []).length >= 2);
|
|
@@ -37526,8 +37485,8 @@ async function runSkillImprover(req) {
|
|
|
37526
37485
|
}
|
|
37527
37486
|
throw err;
|
|
37528
37487
|
}
|
|
37529
|
-
const proposalDir =
|
|
37530
|
-
const proposalFile =
|
|
37488
|
+
const proposalDir = path15.join(req.directory, ".swarm", "skill-improver", "proposals");
|
|
37489
|
+
const proposalFile = path15.join(proposalDir, `${timestampSlug(now)}.md`);
|
|
37531
37490
|
const finalBody = source === "llm" ? buildLLMProposalFrame({
|
|
37532
37491
|
body,
|
|
37533
37492
|
targets,
|
|
@@ -37923,7 +37882,7 @@ var init_write_retro = __esm(() => {
|
|
|
37923
37882
|
|
|
37924
37883
|
// src/commands/close.ts
|
|
37925
37884
|
import { promises as fs7 } from "fs";
|
|
37926
|
-
import
|
|
37885
|
+
import path16 from "path";
|
|
37927
37886
|
async function runAbortableSkillReview(req, timeoutMs) {
|
|
37928
37887
|
const controller = new AbortController;
|
|
37929
37888
|
let timeout;
|
|
@@ -37979,10 +37938,10 @@ function guaranteeAllPlansComplete(planData) {
|
|
|
37979
37938
|
}
|
|
37980
37939
|
async function handleCloseCommand(directory, args, options = {}) {
|
|
37981
37940
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
37982
|
-
const swarmDir =
|
|
37941
|
+
const swarmDir = path16.join(directory, ".swarm");
|
|
37983
37942
|
let planExists = false;
|
|
37984
37943
|
let planData = {
|
|
37985
|
-
title:
|
|
37944
|
+
title: path16.basename(directory) || "Ad-hoc session",
|
|
37986
37945
|
phases: []
|
|
37987
37946
|
};
|
|
37988
37947
|
try {
|
|
@@ -38091,7 +38050,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38091
38050
|
warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
38092
38051
|
}
|
|
38093
38052
|
}
|
|
38094
|
-
const lessonsFilePath =
|
|
38053
|
+
const lessonsFilePath = path16.join(swarmDir, "close-lessons.md");
|
|
38095
38054
|
let explicitLessons = [];
|
|
38096
38055
|
try {
|
|
38097
38056
|
const lessonsText = await fs7.readFile(lessonsFilePath, "utf-8");
|
|
@@ -38100,11 +38059,11 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38100
38059
|
} catch {}
|
|
38101
38060
|
const retroLessons = [];
|
|
38102
38061
|
try {
|
|
38103
|
-
const evidenceDir =
|
|
38062
|
+
const evidenceDir = path16.join(swarmDir, "evidence");
|
|
38104
38063
|
const evidenceEntries = await fs7.readdir(evidenceDir);
|
|
38105
38064
|
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
38106
38065
|
for (const retroDir of retroDirs) {
|
|
38107
|
-
const evidencePath =
|
|
38066
|
+
const evidencePath = path16.join(evidenceDir, retroDir, "evidence.json");
|
|
38108
38067
|
try {
|
|
38109
38068
|
const content = await fs7.readFile(evidencePath, "utf-8");
|
|
38110
38069
|
const parsed = JSON.parse(content);
|
|
@@ -38229,7 +38188,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38229
38188
|
}
|
|
38230
38189
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
38231
38190
|
const suffix = Math.random().toString(36).slice(2, 8);
|
|
38232
|
-
const archiveDir =
|
|
38191
|
+
const archiveDir = path16.join(swarmDir, "archive", `swarm-${timestamp}-${suffix}`);
|
|
38233
38192
|
let archiveResult = "";
|
|
38234
38193
|
let archivedFileCount = 0;
|
|
38235
38194
|
const archivedActiveStateFiles = new Set;
|
|
@@ -38237,8 +38196,8 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38237
38196
|
try {
|
|
38238
38197
|
await fs7.mkdir(archiveDir, { recursive: true });
|
|
38239
38198
|
for (const artifact of ARCHIVE_ARTIFACTS) {
|
|
38240
|
-
const srcPath =
|
|
38241
|
-
const destPath =
|
|
38199
|
+
const srcPath = path16.join(swarmDir, artifact);
|
|
38200
|
+
const destPath = path16.join(archiveDir, artifact);
|
|
38242
38201
|
try {
|
|
38243
38202
|
await fs7.copyFile(srcPath, destPath);
|
|
38244
38203
|
archivedFileCount++;
|
|
@@ -38248,22 +38207,22 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38248
38207
|
} catch {}
|
|
38249
38208
|
}
|
|
38250
38209
|
for (const dirName of ACTIVE_STATE_DIRS_TO_CLEAN) {
|
|
38251
|
-
const srcDir =
|
|
38252
|
-
const destDir =
|
|
38210
|
+
const srcDir = path16.join(swarmDir, dirName);
|
|
38211
|
+
const destDir = path16.join(archiveDir, dirName);
|
|
38253
38212
|
try {
|
|
38254
38213
|
const entries = await fs7.readdir(srcDir);
|
|
38255
38214
|
if (entries.length > 0) {
|
|
38256
38215
|
await fs7.mkdir(destDir, { recursive: true });
|
|
38257
38216
|
for (const entry of entries) {
|
|
38258
|
-
const srcEntry =
|
|
38259
|
-
const destEntry =
|
|
38217
|
+
const srcEntry = path16.join(srcDir, entry);
|
|
38218
|
+
const destEntry = path16.join(destDir, entry);
|
|
38260
38219
|
try {
|
|
38261
38220
|
const stat2 = await fs7.stat(srcEntry);
|
|
38262
38221
|
if (stat2.isDirectory()) {
|
|
38263
38222
|
await fs7.mkdir(destEntry, { recursive: true });
|
|
38264
38223
|
const subEntries = await fs7.readdir(srcEntry);
|
|
38265
38224
|
for (const sub of subEntries) {
|
|
38266
|
-
await fs7.copyFile(
|
|
38225
|
+
await fs7.copyFile(path16.join(srcEntry, sub), path16.join(destEntry, sub)).catch(() => {});
|
|
38267
38226
|
}
|
|
38268
38227
|
} else {
|
|
38269
38228
|
await fs7.copyFile(srcEntry, destEntry);
|
|
@@ -38295,7 +38254,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38295
38254
|
warnings.push(`Preserved ${artifact} because it was not successfully archived.`);
|
|
38296
38255
|
continue;
|
|
38297
38256
|
}
|
|
38298
|
-
const filePath =
|
|
38257
|
+
const filePath = path16.join(swarmDir, artifact);
|
|
38299
38258
|
try {
|
|
38300
38259
|
await fs7.unlink(filePath);
|
|
38301
38260
|
cleanedFiles.push(artifact);
|
|
@@ -38308,7 +38267,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38308
38267
|
if (!archivedActiveStateDirs.has(dirName)) {
|
|
38309
38268
|
continue;
|
|
38310
38269
|
}
|
|
38311
|
-
const dirPath =
|
|
38270
|
+
const dirPath = path16.join(swarmDir, dirName);
|
|
38312
38271
|
try {
|
|
38313
38272
|
await fs7.rm(dirPath, { recursive: true, force: true });
|
|
38314
38273
|
cleanedFiles.push(`${dirName}/`);
|
|
@@ -38319,23 +38278,23 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38319
38278
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
38320
38279
|
for (const backup of configBackups) {
|
|
38321
38280
|
try {
|
|
38322
|
-
await fs7.unlink(
|
|
38281
|
+
await fs7.unlink(path16.join(swarmDir, backup));
|
|
38323
38282
|
configBackupsRemoved++;
|
|
38324
38283
|
} catch {}
|
|
38325
38284
|
}
|
|
38326
38285
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
38327
38286
|
for (const sibling of ledgerSiblings) {
|
|
38328
38287
|
try {
|
|
38329
|
-
await fs7.unlink(
|
|
38288
|
+
await fs7.unlink(path16.join(swarmDir, sibling));
|
|
38330
38289
|
} catch {}
|
|
38331
38290
|
}
|
|
38332
38291
|
} catch {}
|
|
38333
38292
|
let swarmPlanFilesRemoved = 0;
|
|
38334
38293
|
const candidates = [
|
|
38335
|
-
|
|
38336
|
-
|
|
38337
|
-
|
|
38338
|
-
|
|
38294
|
+
path16.join(directory, ".swarm", "SWARM_PLAN.json"),
|
|
38295
|
+
path16.join(directory, ".swarm", "SWARM_PLAN.md"),
|
|
38296
|
+
path16.join(directory, "SWARM_PLAN.json"),
|
|
38297
|
+
path16.join(directory, "SWARM_PLAN.md")
|
|
38339
38298
|
];
|
|
38340
38299
|
for (const candidate of candidates) {
|
|
38341
38300
|
try {
|
|
@@ -38343,12 +38302,12 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
38343
38302
|
swarmPlanFilesRemoved++;
|
|
38344
38303
|
} catch (err) {
|
|
38345
38304
|
if (err?.code !== "ENOENT") {
|
|
38346
|
-
warnings.push(`Failed to remove ${
|
|
38305
|
+
warnings.push(`Failed to remove ${path16.basename(candidate)}: ${err instanceof Error ? err.message : String(err)}`);
|
|
38347
38306
|
}
|
|
38348
38307
|
}
|
|
38349
38308
|
}
|
|
38350
38309
|
clearAllScopes(directory);
|
|
38351
|
-
const contextPath =
|
|
38310
|
+
const contextPath = path16.join(swarmDir, "context.md");
|
|
38352
38311
|
const contextContent = [
|
|
38353
38312
|
"# Context",
|
|
38354
38313
|
"",
|
|
@@ -38567,14 +38526,14 @@ var init_close = __esm(() => {
|
|
|
38567
38526
|
|
|
38568
38527
|
// src/commands/config.ts
|
|
38569
38528
|
import * as os4 from "os";
|
|
38570
|
-
import * as
|
|
38529
|
+
import * as path17 from "path";
|
|
38571
38530
|
function getUserConfigDir2() {
|
|
38572
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
38531
|
+
return process.env.XDG_CONFIG_HOME || path17.join(os4.homedir(), ".config");
|
|
38573
38532
|
}
|
|
38574
38533
|
async function handleConfigCommand(directory, _args) {
|
|
38575
38534
|
const config3 = loadPluginConfig(directory);
|
|
38576
|
-
const userConfigPath =
|
|
38577
|
-
const projectConfigPath =
|
|
38535
|
+
const userConfigPath = path17.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
38536
|
+
const projectConfigPath = path17.join(directory, ".opencode", "opencode-swarm.json");
|
|
38578
38537
|
const lines = [
|
|
38579
38538
|
"## Swarm Configuration",
|
|
38580
38539
|
"",
|
|
@@ -38700,8 +38659,8 @@ var init_curate = __esm(() => {
|
|
|
38700
38659
|
// src/tools/co-change-analyzer.ts
|
|
38701
38660
|
import * as child_process3 from "child_process";
|
|
38702
38661
|
import { randomUUID } from "crypto";
|
|
38703
|
-
import { readdir, readFile as
|
|
38704
|
-
import * as
|
|
38662
|
+
import { readdir, readFile as readFile6, stat as stat2 } from "fs/promises";
|
|
38663
|
+
import * as path18 from "path";
|
|
38705
38664
|
import { promisify } from "util";
|
|
38706
38665
|
function getExecFileAsync() {
|
|
38707
38666
|
return promisify(child_process3.execFile);
|
|
@@ -38803,7 +38762,7 @@ async function scanSourceFiles(dir) {
|
|
|
38803
38762
|
try {
|
|
38804
38763
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
38805
38764
|
for (const entry of entries) {
|
|
38806
|
-
const fullPath =
|
|
38765
|
+
const fullPath = path18.join(dir, entry.name);
|
|
38807
38766
|
if (entry.isDirectory()) {
|
|
38808
38767
|
if (skipDirs.has(entry.name)) {
|
|
38809
38768
|
continue;
|
|
@@ -38811,7 +38770,7 @@ async function scanSourceFiles(dir) {
|
|
|
38811
38770
|
const subFiles = await scanSourceFiles(fullPath);
|
|
38812
38771
|
results.push(...subFiles);
|
|
38813
38772
|
} else if (entry.isFile()) {
|
|
38814
|
-
const ext =
|
|
38773
|
+
const ext = path18.extname(entry.name);
|
|
38815
38774
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
38816
38775
|
results.push(fullPath);
|
|
38817
38776
|
}
|
|
@@ -38825,7 +38784,7 @@ async function getStaticEdges(directory) {
|
|
|
38825
38784
|
const sourceFiles = await scanSourceFiles(directory);
|
|
38826
38785
|
for (const sourceFile of sourceFiles) {
|
|
38827
38786
|
try {
|
|
38828
|
-
const content = await
|
|
38787
|
+
const content = await readFile6(sourceFile, "utf-8");
|
|
38829
38788
|
const importRegex = /(?:import|require)\s*(?:\(?\s*['"`]|.*?from\s+['"`])([^'"`]+)['"`]/g;
|
|
38830
38789
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
38831
38790
|
const importPath = match[1].trim();
|
|
@@ -38833,8 +38792,8 @@ async function getStaticEdges(directory) {
|
|
|
38833
38792
|
continue;
|
|
38834
38793
|
}
|
|
38835
38794
|
try {
|
|
38836
|
-
const sourceDir =
|
|
38837
|
-
const resolvedPath =
|
|
38795
|
+
const sourceDir = path18.dirname(sourceFile);
|
|
38796
|
+
const resolvedPath = path18.resolve(sourceDir, importPath);
|
|
38838
38797
|
const extensions = [
|
|
38839
38798
|
"",
|
|
38840
38799
|
".ts",
|
|
@@ -38859,8 +38818,8 @@ async function getStaticEdges(directory) {
|
|
|
38859
38818
|
if (!targetFile) {
|
|
38860
38819
|
continue;
|
|
38861
38820
|
}
|
|
38862
|
-
const relSource =
|
|
38863
|
-
const relTarget =
|
|
38821
|
+
const relSource = path18.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
38822
|
+
const relTarget = path18.relative(directory, targetFile).replace(/\\/g, "/");
|
|
38864
38823
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
38865
38824
|
edges.add(key);
|
|
38866
38825
|
} catch {}
|
|
@@ -38872,7 +38831,7 @@ async function getStaticEdges(directory) {
|
|
|
38872
38831
|
function isTestImplementationPair(fileA, fileB) {
|
|
38873
38832
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
38874
38833
|
const getBaseName = (filePath) => {
|
|
38875
|
-
const base =
|
|
38834
|
+
const base = path18.basename(filePath);
|
|
38876
38835
|
for (const pattern of testPatterns) {
|
|
38877
38836
|
if (base.endsWith(pattern)) {
|
|
38878
38837
|
return base.slice(0, -pattern.length);
|
|
@@ -38882,16 +38841,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
38882
38841
|
};
|
|
38883
38842
|
const baseA = getBaseName(fileA);
|
|
38884
38843
|
const baseB = getBaseName(fileB);
|
|
38885
|
-
return baseA === baseB && baseA !==
|
|
38844
|
+
return baseA === baseB && baseA !== path18.basename(fileA) && baseA !== path18.basename(fileB);
|
|
38886
38845
|
}
|
|
38887
38846
|
function hasSharedPrefix(fileA, fileB) {
|
|
38888
|
-
const dirA =
|
|
38889
|
-
const dirB =
|
|
38847
|
+
const dirA = path18.dirname(fileA);
|
|
38848
|
+
const dirB = path18.dirname(fileB);
|
|
38890
38849
|
if (dirA !== dirB) {
|
|
38891
38850
|
return false;
|
|
38892
38851
|
}
|
|
38893
|
-
const baseA =
|
|
38894
|
-
const baseB =
|
|
38852
|
+
const baseA = path18.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
38853
|
+
const baseB = path18.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
38895
38854
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
38896
38855
|
return true;
|
|
38897
38856
|
}
|
|
@@ -38945,8 +38904,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
38945
38904
|
const entries = [];
|
|
38946
38905
|
const now = new Date().toISOString();
|
|
38947
38906
|
for (const pair of pairs.slice(0, 10)) {
|
|
38948
|
-
const baseA =
|
|
38949
|
-
const baseB =
|
|
38907
|
+
const baseA = path18.basename(pair.fileA);
|
|
38908
|
+
const baseB = path18.basename(pair.fileB);
|
|
38950
38909
|
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.`;
|
|
38951
38910
|
if (lesson.length > 280) {
|
|
38952
38911
|
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.`;
|
|
@@ -39048,7 +39007,7 @@ var init_co_change_analyzer = __esm(() => {
|
|
|
39048
39007
|
});
|
|
39049
39008
|
|
|
39050
39009
|
// src/commands/dark-matter.ts
|
|
39051
|
-
import
|
|
39010
|
+
import path19 from "path";
|
|
39052
39011
|
async function handleDarkMatterCommand(directory, args) {
|
|
39053
39012
|
const options = {};
|
|
39054
39013
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -39080,7 +39039,7 @@ Ensure this is a git repository with commit history.`;
|
|
|
39080
39039
|
const output = formatDarkMatterOutput(pairs);
|
|
39081
39040
|
if (pairs.length > 0) {
|
|
39082
39041
|
try {
|
|
39083
|
-
const projectName =
|
|
39042
|
+
const projectName = path19.basename(path19.resolve(directory));
|
|
39084
39043
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
39085
39044
|
if (entries.length > 0) {
|
|
39086
39045
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -39217,67 +39176,67 @@ var init_deep_dive = __esm(() => {
|
|
|
39217
39176
|
|
|
39218
39177
|
// src/config/cache-paths.ts
|
|
39219
39178
|
import * as os5 from "os";
|
|
39220
|
-
import * as
|
|
39179
|
+
import * as path20 from "path";
|
|
39221
39180
|
function getPluginConfigDir() {
|
|
39222
|
-
return
|
|
39181
|
+
return path20.join(process.env.XDG_CONFIG_HOME || path20.join(os5.homedir(), ".config"), "opencode");
|
|
39223
39182
|
}
|
|
39224
39183
|
function getPluginCachePaths() {
|
|
39225
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
39184
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path20.join(os5.homedir(), ".cache");
|
|
39226
39185
|
const configDir = getPluginConfigDir();
|
|
39227
39186
|
const paths = [
|
|
39228
|
-
|
|
39229
|
-
|
|
39230
|
-
|
|
39187
|
+
path20.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
|
|
39188
|
+
path20.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
|
|
39189
|
+
path20.join(configDir, "node_modules", "opencode-swarm")
|
|
39231
39190
|
];
|
|
39232
39191
|
if (process.platform === "darwin") {
|
|
39233
|
-
const libCaches =
|
|
39234
|
-
paths.push(
|
|
39192
|
+
const libCaches = path20.join(os5.homedir(), "Library", "Caches");
|
|
39193
|
+
paths.push(path20.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path20.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
|
|
39235
39194
|
}
|
|
39236
39195
|
if (process.platform === "win32") {
|
|
39237
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
39238
|
-
const appData = process.env.APPDATA ||
|
|
39239
|
-
paths.push(
|
|
39196
|
+
const localAppData = process.env.LOCALAPPDATA || path20.join(os5.homedir(), "AppData", "Local");
|
|
39197
|
+
const appData = process.env.APPDATA || path20.join(os5.homedir(), "AppData", "Roaming");
|
|
39198
|
+
paths.push(path20.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path20.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path20.join(appData, "opencode", "node_modules", "opencode-swarm"));
|
|
39240
39199
|
}
|
|
39241
39200
|
return paths;
|
|
39242
39201
|
}
|
|
39243
39202
|
function getPluginLockFilePaths() {
|
|
39244
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
39203
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path20.join(os5.homedir(), ".cache");
|
|
39245
39204
|
const configDir = getPluginConfigDir();
|
|
39246
39205
|
const paths = [
|
|
39247
|
-
|
|
39248
|
-
|
|
39249
|
-
|
|
39206
|
+
path20.join(cacheBase, "opencode", "bun.lock"),
|
|
39207
|
+
path20.join(cacheBase, "opencode", "bun.lockb"),
|
|
39208
|
+
path20.join(configDir, "package-lock.json")
|
|
39250
39209
|
];
|
|
39251
39210
|
if (process.platform === "darwin") {
|
|
39252
|
-
const libCaches =
|
|
39253
|
-
paths.push(
|
|
39211
|
+
const libCaches = path20.join(os5.homedir(), "Library", "Caches");
|
|
39212
|
+
paths.push(path20.join(libCaches, "opencode", "bun.lock"), path20.join(libCaches, "opencode", "bun.lockb"));
|
|
39254
39213
|
}
|
|
39255
39214
|
if (process.platform === "win32") {
|
|
39256
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
39257
|
-
paths.push(
|
|
39215
|
+
const localAppData = process.env.LOCALAPPDATA || path20.join(os5.homedir(), "AppData", "Local");
|
|
39216
|
+
paths.push(path20.join(localAppData, "opencode", "bun.lock"), path20.join(localAppData, "opencode", "bun.lockb"));
|
|
39258
39217
|
}
|
|
39259
39218
|
return paths;
|
|
39260
39219
|
}
|
|
39261
39220
|
var init_cache_paths = () => {};
|
|
39262
39221
|
|
|
39263
39222
|
// src/services/version-check.ts
|
|
39264
|
-
import { existsSync as
|
|
39223
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
39265
39224
|
import { homedir as homedir5 } from "os";
|
|
39266
|
-
import { join as
|
|
39225
|
+
import { join as join19 } from "path";
|
|
39267
39226
|
function cacheDir() {
|
|
39268
39227
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
39269
|
-
const base = xdg && xdg.length > 0 ? xdg :
|
|
39270
|
-
return
|
|
39228
|
+
const base = xdg && xdg.length > 0 ? xdg : join19(homedir5(), ".cache");
|
|
39229
|
+
return join19(base, "opencode-swarm");
|
|
39271
39230
|
}
|
|
39272
39231
|
function cacheFile() {
|
|
39273
|
-
return
|
|
39232
|
+
return join19(cacheDir(), "version-check.json");
|
|
39274
39233
|
}
|
|
39275
39234
|
function readVersionCache() {
|
|
39276
39235
|
try {
|
|
39277
|
-
const
|
|
39278
|
-
if (!
|
|
39236
|
+
const path21 = cacheFile();
|
|
39237
|
+
if (!existsSync11(path21))
|
|
39279
39238
|
return null;
|
|
39280
|
-
const raw = readFileSync6(
|
|
39239
|
+
const raw = readFileSync6(path21, "utf-8");
|
|
39281
39240
|
const parsed = JSON.parse(raw);
|
|
39282
39241
|
if (typeof parsed?.checkedAt !== "number")
|
|
39283
39242
|
return null;
|
|
@@ -39316,8 +39275,8 @@ var init_version_check = __esm(() => {
|
|
|
39316
39275
|
|
|
39317
39276
|
// src/services/diagnose-service.ts
|
|
39318
39277
|
import * as child_process4 from "child_process";
|
|
39319
|
-
import { existsSync as
|
|
39320
|
-
import
|
|
39278
|
+
import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync6 } from "fs";
|
|
39279
|
+
import path21 from "path";
|
|
39321
39280
|
import { fileURLToPath } from "url";
|
|
39322
39281
|
function validateTaskDag(plan) {
|
|
39323
39282
|
const allTaskIds = new Set;
|
|
@@ -39550,7 +39509,7 @@ async function checkConfigBackups(directory) {
|
|
|
39550
39509
|
}
|
|
39551
39510
|
async function checkGitRepository(directory) {
|
|
39552
39511
|
try {
|
|
39553
|
-
if (!
|
|
39512
|
+
if (!existsSync12(directory) || !statSync6(directory).isDirectory()) {
|
|
39554
39513
|
return {
|
|
39555
39514
|
name: "Git Repository",
|
|
39556
39515
|
status: "\u274C",
|
|
@@ -39614,8 +39573,8 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
39614
39573
|
};
|
|
39615
39574
|
}
|
|
39616
39575
|
async function checkConfigParseability(directory) {
|
|
39617
|
-
const configPath =
|
|
39618
|
-
if (!
|
|
39576
|
+
const configPath = path21.join(directory, ".opencode/opencode-swarm.json");
|
|
39577
|
+
if (!existsSync12(configPath)) {
|
|
39619
39578
|
return {
|
|
39620
39579
|
name: "Config Parseability",
|
|
39621
39580
|
status: "\u2705",
|
|
@@ -39643,7 +39602,7 @@ function resolveGrammarDir(thisDir) {
|
|
|
39643
39602
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
39644
39603
|
const isSource = normalized.endsWith("/src/services");
|
|
39645
39604
|
const isCliBundle = normalized.endsWith("/cli");
|
|
39646
|
-
return isSource || isCliBundle ?
|
|
39605
|
+
return isSource || isCliBundle ? path21.join(thisDir, "..", "lang", "grammars") : path21.join(thisDir, "lang", "grammars");
|
|
39647
39606
|
}
|
|
39648
39607
|
async function checkGrammarWasmFiles() {
|
|
39649
39608
|
const grammarFiles = [
|
|
@@ -39667,14 +39626,14 @@ async function checkGrammarWasmFiles() {
|
|
|
39667
39626
|
"tree-sitter-ini.wasm",
|
|
39668
39627
|
"tree-sitter-regex.wasm"
|
|
39669
39628
|
];
|
|
39670
|
-
const thisDir =
|
|
39629
|
+
const thisDir = path21.dirname(fileURLToPath(import.meta.url));
|
|
39671
39630
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
39672
39631
|
const missing = [];
|
|
39673
|
-
if (!
|
|
39632
|
+
if (!existsSync12(path21.join(grammarDir, "tree-sitter.wasm"))) {
|
|
39674
39633
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
39675
39634
|
}
|
|
39676
39635
|
for (const file3 of grammarFiles) {
|
|
39677
|
-
if (!
|
|
39636
|
+
if (!existsSync12(path21.join(grammarDir, file3))) {
|
|
39678
39637
|
missing.push(file3);
|
|
39679
39638
|
}
|
|
39680
39639
|
}
|
|
@@ -39692,8 +39651,8 @@ async function checkGrammarWasmFiles() {
|
|
|
39692
39651
|
};
|
|
39693
39652
|
}
|
|
39694
39653
|
async function checkCheckpointManifest(directory) {
|
|
39695
|
-
const manifestPath =
|
|
39696
|
-
if (!
|
|
39654
|
+
const manifestPath = path21.join(directory, ".swarm/checkpoints.json");
|
|
39655
|
+
if (!existsSync12(manifestPath)) {
|
|
39697
39656
|
return {
|
|
39698
39657
|
name: "Checkpoint Manifest",
|
|
39699
39658
|
status: "\u2705",
|
|
@@ -39744,8 +39703,8 @@ async function checkCheckpointManifest(directory) {
|
|
|
39744
39703
|
}
|
|
39745
39704
|
}
|
|
39746
39705
|
async function checkEventStreamIntegrity(directory) {
|
|
39747
|
-
const eventsPath =
|
|
39748
|
-
if (!
|
|
39706
|
+
const eventsPath = path21.join(directory, ".swarm/events.jsonl");
|
|
39707
|
+
if (!existsSync12(eventsPath)) {
|
|
39749
39708
|
return {
|
|
39750
39709
|
name: "Event Stream",
|
|
39751
39710
|
status: "\u2705",
|
|
@@ -39785,8 +39744,8 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
39785
39744
|
}
|
|
39786
39745
|
}
|
|
39787
39746
|
async function checkSteeringDirectives(directory) {
|
|
39788
|
-
const eventsPath =
|
|
39789
|
-
if (!
|
|
39747
|
+
const eventsPath = path21.join(directory, ".swarm/events.jsonl");
|
|
39748
|
+
if (!existsSync12(eventsPath)) {
|
|
39790
39749
|
return {
|
|
39791
39750
|
name: "Steering Directives",
|
|
39792
39751
|
status: "\u2705",
|
|
@@ -39841,8 +39800,8 @@ async function checkCurator(directory) {
|
|
|
39841
39800
|
detail: "Disabled (enable via curator.enabled)"
|
|
39842
39801
|
};
|
|
39843
39802
|
}
|
|
39844
|
-
const summaryPath =
|
|
39845
|
-
if (!
|
|
39803
|
+
const summaryPath = path21.join(directory, ".swarm/curator-summary.json");
|
|
39804
|
+
if (!existsSync12(summaryPath)) {
|
|
39846
39805
|
return {
|
|
39847
39806
|
name: "Curator",
|
|
39848
39807
|
status: "\u2705",
|
|
@@ -40007,8 +39966,8 @@ async function getDiagnoseData(directory) {
|
|
|
40007
39966
|
checks5.push(await checkSteeringDirectives(directory));
|
|
40008
39967
|
checks5.push(await checkCurator(directory));
|
|
40009
39968
|
try {
|
|
40010
|
-
const evidenceDir =
|
|
40011
|
-
const snapshotFiles =
|
|
39969
|
+
const evidenceDir = path21.join(directory, ".swarm", "evidence");
|
|
39970
|
+
const snapshotFiles = existsSync12(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
40012
39971
|
if (snapshotFiles.length > 0) {
|
|
40013
39972
|
const latest = snapshotFiles.sort().pop();
|
|
40014
39973
|
checks5.push({
|
|
@@ -40041,11 +40000,11 @@ async function getDiagnoseData(directory) {
|
|
|
40041
40000
|
const cacheRows = [];
|
|
40042
40001
|
for (const cachePath of cachePaths) {
|
|
40043
40002
|
try {
|
|
40044
|
-
if (!
|
|
40003
|
+
if (!existsSync12(cachePath)) {
|
|
40045
40004
|
cacheRows.push(`\u2B1C ${cachePath} \u2014 absent`);
|
|
40046
40005
|
continue;
|
|
40047
40006
|
}
|
|
40048
|
-
const pkgJsonPath =
|
|
40007
|
+
const pkgJsonPath = path21.join(cachePath, "package.json");
|
|
40049
40008
|
try {
|
|
40050
40009
|
const raw = readFileSync7(pkgJsonPath, "utf-8");
|
|
40051
40010
|
const parsed = JSON.parse(raw);
|
|
@@ -40135,13 +40094,13 @@ __export(exports_config_doctor, {
|
|
|
40135
40094
|
import * as crypto3 from "crypto";
|
|
40136
40095
|
import * as fs8 from "fs";
|
|
40137
40096
|
import * as os6 from "os";
|
|
40138
|
-
import * as
|
|
40097
|
+
import * as path22 from "path";
|
|
40139
40098
|
function getUserConfigDir3() {
|
|
40140
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
40099
|
+
return process.env.XDG_CONFIG_HOME || path22.join(os6.homedir(), ".config");
|
|
40141
40100
|
}
|
|
40142
40101
|
function getConfigPaths(directory) {
|
|
40143
|
-
const userConfigPath =
|
|
40144
|
-
const projectConfigPath =
|
|
40102
|
+
const userConfigPath = path22.join(getUserConfigDir3(), "opencode", "opencode-swarm.json");
|
|
40103
|
+
const projectConfigPath = path22.join(directory, ".opencode", "opencode-swarm.json");
|
|
40145
40104
|
return { userConfigPath, projectConfigPath };
|
|
40146
40105
|
}
|
|
40147
40106
|
function computeHash(content) {
|
|
@@ -40166,9 +40125,9 @@ function isValidConfigPath(configPath, directory) {
|
|
|
40166
40125
|
const normalizedUser = userConfigPath.replace(/\\/g, "/");
|
|
40167
40126
|
const normalizedProject = projectConfigPath.replace(/\\/g, "/");
|
|
40168
40127
|
try {
|
|
40169
|
-
const resolvedConfig =
|
|
40170
|
-
const resolvedUser =
|
|
40171
|
-
const resolvedProject =
|
|
40128
|
+
const resolvedConfig = path22.resolve(configPath);
|
|
40129
|
+
const resolvedUser = path22.resolve(normalizedUser);
|
|
40130
|
+
const resolvedProject = path22.resolve(normalizedProject);
|
|
40172
40131
|
return resolvedConfig === resolvedUser || resolvedConfig === resolvedProject;
|
|
40173
40132
|
} catch {
|
|
40174
40133
|
return false;
|
|
@@ -40208,12 +40167,12 @@ function createConfigBackup(directory) {
|
|
|
40208
40167
|
};
|
|
40209
40168
|
}
|
|
40210
40169
|
function writeBackupArtifact(directory, backup) {
|
|
40211
|
-
const swarmDir =
|
|
40170
|
+
const swarmDir = path22.join(directory, ".swarm");
|
|
40212
40171
|
if (!fs8.existsSync(swarmDir)) {
|
|
40213
40172
|
fs8.mkdirSync(swarmDir, { recursive: true });
|
|
40214
40173
|
}
|
|
40215
40174
|
const backupFilename = `config-backup-${backup.createdAt}.json`;
|
|
40216
|
-
const backupPath =
|
|
40175
|
+
const backupPath = path22.join(swarmDir, backupFilename);
|
|
40217
40176
|
const artifact = {
|
|
40218
40177
|
createdAt: backup.createdAt,
|
|
40219
40178
|
configPath: backup.configPath,
|
|
@@ -40243,7 +40202,7 @@ function restoreFromBackup(backupPath, directory) {
|
|
|
40243
40202
|
return null;
|
|
40244
40203
|
}
|
|
40245
40204
|
const targetPath = artifact.configPath;
|
|
40246
|
-
const targetDir =
|
|
40205
|
+
const targetDir = path22.dirname(targetPath);
|
|
40247
40206
|
if (!fs8.existsSync(targetDir)) {
|
|
40248
40207
|
fs8.mkdirSync(targetDir, { recursive: true });
|
|
40249
40208
|
}
|
|
@@ -40274,9 +40233,9 @@ function readConfigFromFile(directory) {
|
|
|
40274
40233
|
return null;
|
|
40275
40234
|
}
|
|
40276
40235
|
}
|
|
40277
|
-
function validateConfigKey(
|
|
40236
|
+
function validateConfigKey(path23, value, _config) {
|
|
40278
40237
|
const findings = [];
|
|
40279
|
-
switch (
|
|
40238
|
+
switch (path23) {
|
|
40280
40239
|
case "agents": {
|
|
40281
40240
|
if (value !== undefined) {
|
|
40282
40241
|
findings.push({
|
|
@@ -40513,27 +40472,27 @@ function validateConfigKey(path24, value, _config) {
|
|
|
40513
40472
|
}
|
|
40514
40473
|
return findings;
|
|
40515
40474
|
}
|
|
40516
|
-
function walkConfigAndValidate(obj,
|
|
40475
|
+
function walkConfigAndValidate(obj, path23, config3, findings) {
|
|
40517
40476
|
if (obj === null || obj === undefined) {
|
|
40518
40477
|
return;
|
|
40519
40478
|
}
|
|
40520
|
-
if (
|
|
40521
|
-
const keyFindings = validateConfigKey(
|
|
40479
|
+
if (path23 && typeof obj === "object" && !Array.isArray(obj)) {
|
|
40480
|
+
const keyFindings = validateConfigKey(path23, obj, config3);
|
|
40522
40481
|
findings.push(...keyFindings);
|
|
40523
40482
|
}
|
|
40524
40483
|
if (typeof obj !== "object") {
|
|
40525
|
-
const keyFindings = validateConfigKey(
|
|
40484
|
+
const keyFindings = validateConfigKey(path23, obj, config3);
|
|
40526
40485
|
findings.push(...keyFindings);
|
|
40527
40486
|
return;
|
|
40528
40487
|
}
|
|
40529
40488
|
if (Array.isArray(obj)) {
|
|
40530
40489
|
obj.forEach((item, index) => {
|
|
40531
|
-
walkConfigAndValidate(item, `${
|
|
40490
|
+
walkConfigAndValidate(item, `${path23}[${index}]`, config3, findings);
|
|
40532
40491
|
});
|
|
40533
40492
|
return;
|
|
40534
40493
|
}
|
|
40535
40494
|
for (const [key, value] of Object.entries(obj)) {
|
|
40536
|
-
const newPath =
|
|
40495
|
+
const newPath = path23 ? `${path23}.${key}` : key;
|
|
40537
40496
|
walkConfigAndValidate(value, newPath, config3, findings);
|
|
40538
40497
|
}
|
|
40539
40498
|
}
|
|
@@ -40653,7 +40612,7 @@ function applySafeAutoFixes(directory, result) {
|
|
|
40653
40612
|
}
|
|
40654
40613
|
}
|
|
40655
40614
|
if (appliedFixes.length > 0) {
|
|
40656
|
-
const configDir =
|
|
40615
|
+
const configDir = path22.dirname(configPath);
|
|
40657
40616
|
if (!fs8.existsSync(configDir)) {
|
|
40658
40617
|
fs8.mkdirSync(configDir, { recursive: true });
|
|
40659
40618
|
}
|
|
@@ -40663,12 +40622,12 @@ function applySafeAutoFixes(directory, result) {
|
|
|
40663
40622
|
return { appliedFixes, updatedConfigPath };
|
|
40664
40623
|
}
|
|
40665
40624
|
function writeDoctorArtifact(directory, result) {
|
|
40666
|
-
const swarmDir =
|
|
40625
|
+
const swarmDir = path22.join(directory, ".swarm");
|
|
40667
40626
|
if (!fs8.existsSync(swarmDir)) {
|
|
40668
40627
|
fs8.mkdirSync(swarmDir, { recursive: true });
|
|
40669
40628
|
}
|
|
40670
40629
|
const artifactFilename = "config-doctor.json";
|
|
40671
|
-
const artifactPath =
|
|
40630
|
+
const artifactPath = path22.join(swarmDir, artifactFilename);
|
|
40672
40631
|
const guiOutput = {
|
|
40673
40632
|
timestamp: result.timestamp,
|
|
40674
40633
|
summary: result.summary,
|
|
@@ -40764,17 +40723,17 @@ function detectStraySwarmDirs(projectRoot) {
|
|
|
40764
40723
|
if (!entry.isDirectory())
|
|
40765
40724
|
continue;
|
|
40766
40725
|
const name = entry.name;
|
|
40767
|
-
const fullPath =
|
|
40726
|
+
const fullPath = path22.join(dir, name);
|
|
40768
40727
|
if (SKIP_DIRS.has(name))
|
|
40769
40728
|
continue;
|
|
40770
|
-
const gitPath =
|
|
40729
|
+
const gitPath = path22.join(fullPath, ".git");
|
|
40771
40730
|
try {
|
|
40772
40731
|
const gitStat = fs8.statSync(gitPath);
|
|
40773
40732
|
if (gitStat.isFile() || gitStat.isDirectory())
|
|
40774
40733
|
continue;
|
|
40775
40734
|
} catch {}
|
|
40776
40735
|
if (name === ".swarm") {
|
|
40777
|
-
const parentDir =
|
|
40736
|
+
const parentDir = path22.dirname(fullPath);
|
|
40778
40737
|
if (parentDir === projectRoot)
|
|
40779
40738
|
continue;
|
|
40780
40739
|
let contents = [];
|
|
@@ -40784,7 +40743,7 @@ function detectStraySwarmDirs(projectRoot) {
|
|
|
40784
40743
|
contents = ["<unreadable>"];
|
|
40785
40744
|
}
|
|
40786
40745
|
findings.push({
|
|
40787
|
-
path:
|
|
40746
|
+
path: path22.relative(projectRoot, fullPath).replace(/\\/g, "/"),
|
|
40788
40747
|
absolutePath: fullPath,
|
|
40789
40748
|
contents: contents.slice(0, MAX_CONTENTS_ENTRIES),
|
|
40790
40749
|
totalEntries: contents.length
|
|
@@ -40802,21 +40761,21 @@ function removeStraySwarmDir(projectRoot, strayPath) {
|
|
|
40802
40761
|
let canonicalStray;
|
|
40803
40762
|
try {
|
|
40804
40763
|
canonicalRoot = fs8.realpathSync(projectRoot);
|
|
40805
|
-
canonicalStray = fs8.realpathSync(
|
|
40764
|
+
canonicalStray = fs8.realpathSync(path22.isAbsolute(strayPath) ? strayPath : path22.resolve(projectRoot, strayPath));
|
|
40806
40765
|
} catch (err) {
|
|
40807
40766
|
return {
|
|
40808
40767
|
success: false,
|
|
40809
40768
|
message: `Failed to resolve paths: ${err instanceof Error ? err.message : String(err)}`
|
|
40810
40769
|
};
|
|
40811
40770
|
}
|
|
40812
|
-
const rootSwarm =
|
|
40771
|
+
const rootSwarm = path22.join(canonicalRoot, ".swarm");
|
|
40813
40772
|
if (canonicalStray === rootSwarm || canonicalStray === canonicalRoot) {
|
|
40814
40773
|
return {
|
|
40815
40774
|
success: false,
|
|
40816
40775
|
message: "Refusing to remove root .swarm/ directory"
|
|
40817
40776
|
};
|
|
40818
40777
|
}
|
|
40819
|
-
if (!canonicalStray.startsWith(canonicalRoot +
|
|
40778
|
+
if (!canonicalStray.startsWith(canonicalRoot + path22.sep)) {
|
|
40820
40779
|
return {
|
|
40821
40780
|
success: false,
|
|
40822
40781
|
message: "Path is outside project root \u2014 refusing to remove"
|
|
@@ -41905,7 +41864,7 @@ var init_profiles = __esm(() => {
|
|
|
41905
41864
|
|
|
41906
41865
|
// src/lang/detector.ts
|
|
41907
41866
|
import { access as access3, readdir as readdir2 } from "fs/promises";
|
|
41908
|
-
import { extname as extname2, join as
|
|
41867
|
+
import { extname as extname2, join as join21 } from "path";
|
|
41909
41868
|
async function detectProjectLanguages(projectDir) {
|
|
41910
41869
|
const detected = new Set;
|
|
41911
41870
|
async function scanDir(dir) {
|
|
@@ -41921,7 +41880,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
41921
41880
|
if (detectFile.includes("*") || detectFile.includes("?"))
|
|
41922
41881
|
continue;
|
|
41923
41882
|
try {
|
|
41924
|
-
await access3(
|
|
41883
|
+
await access3(join21(dir, detectFile));
|
|
41925
41884
|
detected.add(profile.id);
|
|
41926
41885
|
break;
|
|
41927
41886
|
} catch {}
|
|
@@ -41942,7 +41901,7 @@ async function detectProjectLanguages(projectDir) {
|
|
|
41942
41901
|
const topEntries = await readdir2(projectDir, { withFileTypes: true });
|
|
41943
41902
|
for (const entry of topEntries) {
|
|
41944
41903
|
if (entry.isDirectory() && !entry.name.startsWith(".") && entry.name !== "node_modules") {
|
|
41945
|
-
await scanDir(
|
|
41904
|
+
await scanDir(join21(projectDir, entry.name));
|
|
41946
41905
|
}
|
|
41947
41906
|
}
|
|
41948
41907
|
} catch {}
|
|
@@ -41961,7 +41920,7 @@ var init_detector = __esm(() => {
|
|
|
41961
41920
|
|
|
41962
41921
|
// src/build/discovery.ts
|
|
41963
41922
|
import * as fs9 from "fs";
|
|
41964
|
-
import * as
|
|
41923
|
+
import * as path23 from "path";
|
|
41965
41924
|
function isCommandAvailable(command) {
|
|
41966
41925
|
if (toolchainCache.has(command)) {
|
|
41967
41926
|
return toolchainCache.get(command);
|
|
@@ -41996,11 +41955,11 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
41996
41955
|
const regex = simpleGlobToRegex(pattern);
|
|
41997
41956
|
const matches = files.filter((f) => regex.test(f));
|
|
41998
41957
|
if (matches.length > 0) {
|
|
41999
|
-
return
|
|
41958
|
+
return path23.join(dir, matches[0]);
|
|
42000
41959
|
}
|
|
42001
41960
|
} catch {}
|
|
42002
41961
|
} else {
|
|
42003
|
-
const filePath =
|
|
41962
|
+
const filePath = path23.join(workingDir, pattern);
|
|
42004
41963
|
if (fs9.existsSync(filePath)) {
|
|
42005
41964
|
return filePath;
|
|
42006
41965
|
}
|
|
@@ -42009,7 +41968,7 @@ function findBuildFiles(workingDir, patterns) {
|
|
|
42009
41968
|
return null;
|
|
42010
41969
|
}
|
|
42011
41970
|
function getRepoDefinedScripts(workingDir, scripts) {
|
|
42012
|
-
const packageJsonPath =
|
|
41971
|
+
const packageJsonPath = path23.join(workingDir, "package.json");
|
|
42013
41972
|
if (!fs9.existsSync(packageJsonPath)) {
|
|
42014
41973
|
return [];
|
|
42015
41974
|
}
|
|
@@ -42050,7 +42009,7 @@ function findAllBuildFiles(workingDir) {
|
|
|
42050
42009
|
const regex = simpleGlobToRegex(pattern);
|
|
42051
42010
|
findFilesRecursive(workingDir, regex, allBuildFiles);
|
|
42052
42011
|
} else {
|
|
42053
|
-
const filePath =
|
|
42012
|
+
const filePath = path23.join(workingDir, pattern);
|
|
42054
42013
|
if (fs9.existsSync(filePath)) {
|
|
42055
42014
|
allBuildFiles.add(filePath);
|
|
42056
42015
|
}
|
|
@@ -42063,7 +42022,7 @@ function findFilesRecursive(dir, regex, results) {
|
|
|
42063
42022
|
try {
|
|
42064
42023
|
const entries = fs9.readdirSync(dir, { withFileTypes: true });
|
|
42065
42024
|
for (const entry of entries) {
|
|
42066
|
-
const fullPath =
|
|
42025
|
+
const fullPath = path23.join(dir, entry.name);
|
|
42067
42026
|
if (entry.isDirectory() && !["node_modules", ".git", "dist", "build", "target"].includes(entry.name)) {
|
|
42068
42027
|
findFilesRecursive(fullPath, regex, results);
|
|
42069
42028
|
} else if (entry.isFile() && regex.test(entry.name)) {
|
|
@@ -42086,7 +42045,7 @@ async function discoverBuildCommandsFromProfiles(workingDir) {
|
|
|
42086
42045
|
let foundCommand = false;
|
|
42087
42046
|
for (const cmd of sortedCommands) {
|
|
42088
42047
|
if (cmd.detectFile) {
|
|
42089
|
-
const detectFilePath =
|
|
42048
|
+
const detectFilePath = path23.join(workingDir, cmd.detectFile);
|
|
42090
42049
|
if (!fs9.existsSync(detectFilePath)) {
|
|
42091
42050
|
continue;
|
|
42092
42051
|
}
|
|
@@ -42327,7 +42286,7 @@ var init_discovery = __esm(() => {
|
|
|
42327
42286
|
|
|
42328
42287
|
// src/services/tool-doctor.ts
|
|
42329
42288
|
import * as fs10 from "fs";
|
|
42330
|
-
import * as
|
|
42289
|
+
import * as path24 from "path";
|
|
42331
42290
|
function extractRegisteredToolKeys(indexPath) {
|
|
42332
42291
|
const registeredKeys = new Set;
|
|
42333
42292
|
try {
|
|
@@ -42382,8 +42341,8 @@ function checkBinaryReadiness() {
|
|
|
42382
42341
|
}
|
|
42383
42342
|
function runToolDoctor(_directory, pluginRoot) {
|
|
42384
42343
|
const findings = [];
|
|
42385
|
-
const resolvedPluginRoot = pluginRoot ??
|
|
42386
|
-
const indexPath =
|
|
42344
|
+
const resolvedPluginRoot = pluginRoot ?? path24.resolve(import.meta.dir, "..", "..");
|
|
42345
|
+
const indexPath = path24.join(resolvedPluginRoot, "src", "index.ts");
|
|
42387
42346
|
if (!fs10.existsSync(indexPath)) {
|
|
42388
42347
|
return {
|
|
42389
42348
|
findings: [
|
|
@@ -43129,12 +43088,12 @@ var init_export = __esm(() => {
|
|
|
43129
43088
|
|
|
43130
43089
|
// src/full-auto/state.ts
|
|
43131
43090
|
import * as fs11 from "fs";
|
|
43132
|
-
import * as
|
|
43091
|
+
import * as path25 from "path";
|
|
43133
43092
|
function nowISO() {
|
|
43134
43093
|
return new Date().toISOString();
|
|
43135
43094
|
}
|
|
43136
43095
|
function ensureSwarmDir(directory) {
|
|
43137
|
-
const swarmDir =
|
|
43096
|
+
const swarmDir = path25.resolve(directory, ".swarm");
|
|
43138
43097
|
if (!fs11.existsSync(swarmDir)) {
|
|
43139
43098
|
fs11.mkdirSync(swarmDir, { recursive: true });
|
|
43140
43099
|
}
|
|
@@ -43835,7 +43794,7 @@ var init_handoff_service = __esm(() => {
|
|
|
43835
43794
|
|
|
43836
43795
|
// src/session/snapshot-writer.ts
|
|
43837
43796
|
import { closeSync as closeSync3, fsyncSync as fsyncSync2, mkdirSync as mkdirSync10, openSync as openSync3, renameSync as renameSync6 } from "fs";
|
|
43838
|
-
import * as
|
|
43797
|
+
import * as path26 from "path";
|
|
43839
43798
|
function serializeAgentSession(s) {
|
|
43840
43799
|
const gateLog = {};
|
|
43841
43800
|
const rawGateLog = s.gateLog ?? new Map;
|
|
@@ -43932,7 +43891,7 @@ async function writeSnapshot(directory, state) {
|
|
|
43932
43891
|
}
|
|
43933
43892
|
const content = JSON.stringify(snapshot, null, 2);
|
|
43934
43893
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
43935
|
-
const dir =
|
|
43894
|
+
const dir = path26.dirname(resolvedPath);
|
|
43936
43895
|
mkdirSync10(dir, { recursive: true });
|
|
43937
43896
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
43938
43897
|
await bunWrite(tempPath, content);
|
|
@@ -44389,9 +44348,9 @@ var init_issue = __esm(() => {
|
|
|
44389
44348
|
|
|
44390
44349
|
// src/hooks/knowledge-migrator.ts
|
|
44391
44350
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
44392
|
-
import { existsSync as
|
|
44393
|
-
import { mkdir as
|
|
44394
|
-
import * as
|
|
44351
|
+
import { existsSync as existsSync17, readFileSync as readFileSync12 } from "fs";
|
|
44352
|
+
import { mkdir as mkdir7, readFile as readFile7, writeFile as writeFile8 } from "fs/promises";
|
|
44353
|
+
import * as path27 from "path";
|
|
44395
44354
|
async function migrateKnowledgeToExternal(_directory, _config) {
|
|
44396
44355
|
return {
|
|
44397
44356
|
migrated: false,
|
|
@@ -44402,10 +44361,10 @@ async function migrateKnowledgeToExternal(_directory, _config) {
|
|
|
44402
44361
|
};
|
|
44403
44362
|
}
|
|
44404
44363
|
async function migrateContextToKnowledge(directory, config3) {
|
|
44405
|
-
const sentinelPath =
|
|
44406
|
-
const contextPath =
|
|
44364
|
+
const sentinelPath = path27.join(directory, ".swarm", ".knowledge-migrated");
|
|
44365
|
+
const contextPath = path27.join(directory, ".swarm", "context.md");
|
|
44407
44366
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
44408
|
-
if (
|
|
44367
|
+
if (existsSync17(sentinelPath)) {
|
|
44409
44368
|
return {
|
|
44410
44369
|
migrated: false,
|
|
44411
44370
|
entriesMigrated: 0,
|
|
@@ -44414,7 +44373,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
44414
44373
|
skippedReason: "sentinel-exists"
|
|
44415
44374
|
};
|
|
44416
44375
|
}
|
|
44417
|
-
if (!
|
|
44376
|
+
if (!existsSync17(contextPath)) {
|
|
44418
44377
|
return {
|
|
44419
44378
|
migrated: false,
|
|
44420
44379
|
entriesMigrated: 0,
|
|
@@ -44423,7 +44382,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
44423
44382
|
skippedReason: "no-context-file"
|
|
44424
44383
|
};
|
|
44425
44384
|
}
|
|
44426
|
-
const contextContent = await
|
|
44385
|
+
const contextContent = await readFile7(contextPath, "utf-8");
|
|
44427
44386
|
if (contextContent.trim().length === 0) {
|
|
44428
44387
|
return {
|
|
44429
44388
|
migrated: false,
|
|
@@ -44599,8 +44558,8 @@ function truncateLesson(text) {
|
|
|
44599
44558
|
return `${text.slice(0, 277)}...`;
|
|
44600
44559
|
}
|
|
44601
44560
|
function inferProjectName(directory) {
|
|
44602
|
-
const packageJsonPath =
|
|
44603
|
-
if (
|
|
44561
|
+
const packageJsonPath = path27.join(directory, "package.json");
|
|
44562
|
+
if (existsSync17(packageJsonPath)) {
|
|
44604
44563
|
try {
|
|
44605
44564
|
const pkg = JSON.parse(readFileSync12(packageJsonPath, "utf-8"));
|
|
44606
44565
|
if (pkg.name && typeof pkg.name === "string") {
|
|
@@ -44608,7 +44567,7 @@ function inferProjectName(directory) {
|
|
|
44608
44567
|
}
|
|
44609
44568
|
} catch {}
|
|
44610
44569
|
}
|
|
44611
|
-
return
|
|
44570
|
+
return path27.basename(directory);
|
|
44612
44571
|
}
|
|
44613
44572
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
44614
44573
|
const sentinel = {
|
|
@@ -44620,8 +44579,8 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
44620
44579
|
schema_version: 1,
|
|
44621
44580
|
migration_tool: "knowledge-migrator.ts"
|
|
44622
44581
|
};
|
|
44623
|
-
await
|
|
44624
|
-
await
|
|
44582
|
+
await mkdir7(path27.dirname(sentinelPath), { recursive: true });
|
|
44583
|
+
await writeFile8(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
44625
44584
|
}
|
|
44626
44585
|
var _internals16;
|
|
44627
44586
|
var init_knowledge_migrator = __esm(() => {
|
|
@@ -44642,7 +44601,7 @@ var init_knowledge_migrator = __esm(() => {
|
|
|
44642
44601
|
});
|
|
44643
44602
|
|
|
44644
44603
|
// src/commands/knowledge.ts
|
|
44645
|
-
import { join as
|
|
44604
|
+
import { join as join25 } from "path";
|
|
44646
44605
|
function resolveEntryByPrefix(entries, inputId) {
|
|
44647
44606
|
const exact = entries.find((e) => e.id === inputId);
|
|
44648
44607
|
if (exact)
|
|
@@ -44693,7 +44652,7 @@ async function handleKnowledgeRestoreCommand(directory, args) {
|
|
|
44693
44652
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
44694
44653
|
}
|
|
44695
44654
|
try {
|
|
44696
|
-
const quarantinePath =
|
|
44655
|
+
const quarantinePath = join25(directory, ".swarm", "knowledge-quarantined.jsonl");
|
|
44697
44656
|
const entries = await readKnowledge(quarantinePath);
|
|
44698
44657
|
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
44699
44658
|
if ("error" in resolved) {
|
|
@@ -45148,7 +45107,7 @@ var init_path_security = () => {};
|
|
|
45148
45107
|
|
|
45149
45108
|
// src/tools/lint.ts
|
|
45150
45109
|
import * as fs12 from "fs";
|
|
45151
|
-
import * as
|
|
45110
|
+
import * as path28 from "path";
|
|
45152
45111
|
function validateArgs(args) {
|
|
45153
45112
|
if (typeof args !== "object" || args === null)
|
|
45154
45113
|
return false;
|
|
@@ -45159,9 +45118,9 @@ function validateArgs(args) {
|
|
|
45159
45118
|
}
|
|
45160
45119
|
function getLinterCommand(linter, mode, projectDir) {
|
|
45161
45120
|
const isWindows = process.platform === "win32";
|
|
45162
|
-
const binDir =
|
|
45163
|
-
const biomeBin = isWindows ?
|
|
45164
|
-
const eslintBin = isWindows ?
|
|
45121
|
+
const binDir = path28.join(projectDir, "node_modules", ".bin");
|
|
45122
|
+
const biomeBin = isWindows ? path28.join(binDir, "biome.EXE") : path28.join(binDir, "biome");
|
|
45123
|
+
const eslintBin = isWindows ? path28.join(binDir, "eslint.cmd") : path28.join(binDir, "eslint");
|
|
45165
45124
|
switch (linter) {
|
|
45166
45125
|
case "biome":
|
|
45167
45126
|
if (mode === "fix") {
|
|
@@ -45177,7 +45136,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
45177
45136
|
}
|
|
45178
45137
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
45179
45138
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
45180
|
-
const gradlew = fs12.existsSync(
|
|
45139
|
+
const gradlew = fs12.existsSync(path28.join(cwd, gradlewName)) ? path28.join(cwd, gradlewName) : null;
|
|
45181
45140
|
switch (linter) {
|
|
45182
45141
|
case "ruff":
|
|
45183
45142
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -45211,10 +45170,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
45211
45170
|
}
|
|
45212
45171
|
}
|
|
45213
45172
|
function detectRuff(cwd) {
|
|
45214
|
-
if (fs12.existsSync(
|
|
45173
|
+
if (fs12.existsSync(path28.join(cwd, "ruff.toml")))
|
|
45215
45174
|
return isCommandAvailable("ruff");
|
|
45216
45175
|
try {
|
|
45217
|
-
const pyproject =
|
|
45176
|
+
const pyproject = path28.join(cwd, "pyproject.toml");
|
|
45218
45177
|
if (fs12.existsSync(pyproject)) {
|
|
45219
45178
|
const content = fs12.readFileSync(pyproject, "utf-8");
|
|
45220
45179
|
if (content.includes("[tool.ruff]"))
|
|
@@ -45224,19 +45183,19 @@ function detectRuff(cwd) {
|
|
|
45224
45183
|
return false;
|
|
45225
45184
|
}
|
|
45226
45185
|
function detectClippy(cwd) {
|
|
45227
|
-
return fs12.existsSync(
|
|
45186
|
+
return fs12.existsSync(path28.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
45228
45187
|
}
|
|
45229
45188
|
function detectGolangciLint(cwd) {
|
|
45230
|
-
return fs12.existsSync(
|
|
45189
|
+
return fs12.existsSync(path28.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
45231
45190
|
}
|
|
45232
45191
|
function detectCheckstyle(cwd) {
|
|
45233
|
-
const hasMaven = fs12.existsSync(
|
|
45234
|
-
const hasGradle = fs12.existsSync(
|
|
45235
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(
|
|
45192
|
+
const hasMaven = fs12.existsSync(path28.join(cwd, "pom.xml"));
|
|
45193
|
+
const hasGradle = fs12.existsSync(path28.join(cwd, "build.gradle")) || fs12.existsSync(path28.join(cwd, "build.gradle.kts"));
|
|
45194
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path28.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
45236
45195
|
return (hasMaven || hasGradle) && hasBinary;
|
|
45237
45196
|
}
|
|
45238
45197
|
function detectKtlint(cwd) {
|
|
45239
|
-
const hasKotlin = fs12.existsSync(
|
|
45198
|
+
const hasKotlin = fs12.existsSync(path28.join(cwd, "build.gradle.kts")) || fs12.existsSync(path28.join(cwd, "build.gradle")) || (() => {
|
|
45240
45199
|
try {
|
|
45241
45200
|
return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
45242
45201
|
} catch {
|
|
@@ -45255,11 +45214,11 @@ function detectDotnetFormat(cwd) {
|
|
|
45255
45214
|
}
|
|
45256
45215
|
}
|
|
45257
45216
|
function detectCppcheck(cwd) {
|
|
45258
|
-
if (fs12.existsSync(
|
|
45217
|
+
if (fs12.existsSync(path28.join(cwd, "CMakeLists.txt"))) {
|
|
45259
45218
|
return isCommandAvailable("cppcheck");
|
|
45260
45219
|
}
|
|
45261
45220
|
try {
|
|
45262
|
-
const dirsToCheck = [cwd,
|
|
45221
|
+
const dirsToCheck = [cwd, path28.join(cwd, "src")];
|
|
45263
45222
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
45264
45223
|
try {
|
|
45265
45224
|
return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -45273,13 +45232,13 @@ function detectCppcheck(cwd) {
|
|
|
45273
45232
|
}
|
|
45274
45233
|
}
|
|
45275
45234
|
function detectSwiftlint(cwd) {
|
|
45276
|
-
return fs12.existsSync(
|
|
45235
|
+
return fs12.existsSync(path28.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
45277
45236
|
}
|
|
45278
45237
|
function detectDartAnalyze(cwd) {
|
|
45279
|
-
return fs12.existsSync(
|
|
45238
|
+
return fs12.existsSync(path28.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
45280
45239
|
}
|
|
45281
45240
|
function detectRubocop(cwd) {
|
|
45282
|
-
return (fs12.existsSync(
|
|
45241
|
+
return (fs12.existsSync(path28.join(cwd, "Gemfile")) || fs12.existsSync(path28.join(cwd, "gems.rb")) || fs12.existsSync(path28.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
45283
45242
|
}
|
|
45284
45243
|
function detectAdditionalLinter(cwd) {
|
|
45285
45244
|
if (detectRuff(cwd))
|
|
@@ -45307,10 +45266,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
45307
45266
|
function findBinInAncestors(startDir, binName) {
|
|
45308
45267
|
let dir = startDir;
|
|
45309
45268
|
while (true) {
|
|
45310
|
-
const candidate =
|
|
45269
|
+
const candidate = path28.join(dir, "node_modules", ".bin", binName);
|
|
45311
45270
|
if (fs12.existsSync(candidate))
|
|
45312
45271
|
return candidate;
|
|
45313
|
-
const parent =
|
|
45272
|
+
const parent = path28.dirname(dir);
|
|
45314
45273
|
if (parent === dir)
|
|
45315
45274
|
break;
|
|
45316
45275
|
dir = parent;
|
|
@@ -45319,10 +45278,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
45319
45278
|
}
|
|
45320
45279
|
function findBinInEnvPath(binName) {
|
|
45321
45280
|
const searchPath = process.env.PATH ?? "";
|
|
45322
|
-
for (const dir of searchPath.split(
|
|
45281
|
+
for (const dir of searchPath.split(path28.delimiter)) {
|
|
45323
45282
|
if (!dir)
|
|
45324
45283
|
continue;
|
|
45325
|
-
const candidate =
|
|
45284
|
+
const candidate = path28.join(dir, binName);
|
|
45326
45285
|
if (fs12.existsSync(candidate))
|
|
45327
45286
|
return candidate;
|
|
45328
45287
|
}
|
|
@@ -45335,13 +45294,13 @@ async function detectAvailableLinter(directory) {
|
|
|
45335
45294
|
return null;
|
|
45336
45295
|
const projectDir = directory;
|
|
45337
45296
|
const isWindows = process.platform === "win32";
|
|
45338
|
-
const biomeBin = isWindows ?
|
|
45339
|
-
const eslintBin = isWindows ?
|
|
45297
|
+
const biomeBin = isWindows ? path28.join(projectDir, "node_modules", ".bin", "biome.EXE") : path28.join(projectDir, "node_modules", ".bin", "biome");
|
|
45298
|
+
const eslintBin = isWindows ? path28.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path28.join(projectDir, "node_modules", ".bin", "eslint");
|
|
45340
45299
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
45341
45300
|
if (localResult)
|
|
45342
45301
|
return localResult;
|
|
45343
|
-
const biomeAncestor = findBinInAncestors(
|
|
45344
|
-
const eslintAncestor = findBinInAncestors(
|
|
45302
|
+
const biomeAncestor = findBinInAncestors(path28.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
45303
|
+
const eslintAncestor = findBinInAncestors(path28.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
45345
45304
|
if (biomeAncestor || eslintAncestor) {
|
|
45346
45305
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
45347
45306
|
}
|
|
@@ -45564,7 +45523,7 @@ For Rust: rustup component add clippy`
|
|
|
45564
45523
|
|
|
45565
45524
|
// src/tools/secretscan.ts
|
|
45566
45525
|
import * as fs13 from "fs";
|
|
45567
|
-
import * as
|
|
45526
|
+
import * as path29 from "path";
|
|
45568
45527
|
function calculateShannonEntropy(str) {
|
|
45569
45528
|
if (str.length === 0)
|
|
45570
45529
|
return 0;
|
|
@@ -45612,7 +45571,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
45612
45571
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
45613
45572
|
}
|
|
45614
45573
|
function loadSecretScanIgnore(scanDir) {
|
|
45615
|
-
const ignorePath =
|
|
45574
|
+
const ignorePath = path29.join(scanDir, ".secretscanignore");
|
|
45616
45575
|
try {
|
|
45617
45576
|
if (!fs13.existsSync(ignorePath))
|
|
45618
45577
|
return [];
|
|
@@ -45635,7 +45594,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
45635
45594
|
if (exactNames.has(entry))
|
|
45636
45595
|
return true;
|
|
45637
45596
|
for (const pattern of globPatterns) {
|
|
45638
|
-
if (
|
|
45597
|
+
if (path29.matchesGlob(relPath, pattern))
|
|
45639
45598
|
return true;
|
|
45640
45599
|
}
|
|
45641
45600
|
return false;
|
|
@@ -45656,7 +45615,7 @@ function validateDirectoryInput(dir) {
|
|
|
45656
45615
|
return null;
|
|
45657
45616
|
}
|
|
45658
45617
|
function isBinaryFile(filePath, buffer) {
|
|
45659
|
-
const ext =
|
|
45618
|
+
const ext = path29.extname(filePath).toLowerCase();
|
|
45660
45619
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
45661
45620
|
return true;
|
|
45662
45621
|
}
|
|
@@ -45792,9 +45751,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
45792
45751
|
return false;
|
|
45793
45752
|
}
|
|
45794
45753
|
function isPathWithinScope(realPath, scanDir) {
|
|
45795
|
-
const resolvedScanDir =
|
|
45796
|
-
const resolvedRealPath =
|
|
45797
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
45754
|
+
const resolvedScanDir = path29.resolve(scanDir);
|
|
45755
|
+
const resolvedRealPath = path29.resolve(realPath);
|
|
45756
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path29.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
45798
45757
|
}
|
|
45799
45758
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
45800
45759
|
skippedDirs: 0,
|
|
@@ -45820,8 +45779,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
45820
45779
|
return a.localeCompare(b);
|
|
45821
45780
|
});
|
|
45822
45781
|
for (const entry of entries) {
|
|
45823
|
-
const fullPath =
|
|
45824
|
-
const relPath =
|
|
45782
|
+
const fullPath = path29.join(dir, entry);
|
|
45783
|
+
const relPath = path29.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
45825
45784
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
45826
45785
|
stats.skippedDirs++;
|
|
45827
45786
|
continue;
|
|
@@ -45856,7 +45815,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
45856
45815
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
45857
45816
|
files.push(...subFiles);
|
|
45858
45817
|
} else if (lstat.isFile()) {
|
|
45859
|
-
const ext =
|
|
45818
|
+
const ext = path29.extname(fullPath).toLowerCase();
|
|
45860
45819
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
45861
45820
|
files.push(fullPath);
|
|
45862
45821
|
} else {
|
|
@@ -46116,7 +46075,7 @@ var init_secretscan = __esm(() => {
|
|
|
46116
46075
|
}
|
|
46117
46076
|
}
|
|
46118
46077
|
try {
|
|
46119
|
-
const _scanDirRaw =
|
|
46078
|
+
const _scanDirRaw = path29.resolve(directory);
|
|
46120
46079
|
const scanDir = (() => {
|
|
46121
46080
|
try {
|
|
46122
46081
|
return fs13.realpathSync(_scanDirRaw);
|
|
@@ -46263,7 +46222,7 @@ var init_secretscan = __esm(() => {
|
|
|
46263
46222
|
|
|
46264
46223
|
// src/lang/default-backend.ts
|
|
46265
46224
|
import * as fs14 from "fs";
|
|
46266
|
-
import * as
|
|
46225
|
+
import * as path30 from "path";
|
|
46267
46226
|
function detectFileExists(dir, pattern) {
|
|
46268
46227
|
if (pattern.includes("*") || pattern.includes("?")) {
|
|
46269
46228
|
try {
|
|
@@ -46275,7 +46234,7 @@ function detectFileExists(dir, pattern) {
|
|
|
46275
46234
|
}
|
|
46276
46235
|
}
|
|
46277
46236
|
try {
|
|
46278
|
-
fs14.accessSync(
|
|
46237
|
+
fs14.accessSync(path30.join(dir, pattern));
|
|
46279
46238
|
return true;
|
|
46280
46239
|
} catch {
|
|
46281
46240
|
return false;
|
|
@@ -46403,8 +46362,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
46403
46362
|
return ["mvn", "test"];
|
|
46404
46363
|
case "gradle": {
|
|
46405
46364
|
const isWindows = process.platform === "win32";
|
|
46406
|
-
const hasGradlewBat = fs14.existsSync(
|
|
46407
|
-
const hasGradlew = fs14.existsSync(
|
|
46365
|
+
const hasGradlewBat = fs14.existsSync(path30.join(dir, "gradlew.bat"));
|
|
46366
|
+
const hasGradlew = fs14.existsSync(path30.join(dir, "gradlew"));
|
|
46408
46367
|
if (hasGradlewBat && isWindows)
|
|
46409
46368
|
return ["gradlew.bat", "test"];
|
|
46410
46369
|
if (hasGradlew)
|
|
@@ -46421,7 +46380,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
46421
46380
|
"cmake-build-release",
|
|
46422
46381
|
"out"
|
|
46423
46382
|
];
|
|
46424
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs14.existsSync(
|
|
46383
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs14.existsSync(path30.join(dir, d, "CMakeCache.txt"))) ?? "build";
|
|
46425
46384
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
46426
46385
|
}
|
|
46427
46386
|
case "swift-test":
|
|
@@ -46708,17 +46667,17 @@ async function defaultSelectBuildCommand(profile, dir) {
|
|
|
46708
46667
|
return null;
|
|
46709
46668
|
}
|
|
46710
46669
|
async function defaultTestFilesFor(profile, sourceFile, dir) {
|
|
46711
|
-
const ext =
|
|
46670
|
+
const ext = path30.extname(sourceFile);
|
|
46712
46671
|
if (!profile.extensions.includes(ext))
|
|
46713
46672
|
return [];
|
|
46714
|
-
const base =
|
|
46715
|
-
const rel =
|
|
46716
|
-
const relDir =
|
|
46673
|
+
const base = path30.basename(sourceFile, ext);
|
|
46674
|
+
const rel = path30.relative(dir, sourceFile);
|
|
46675
|
+
const relDir = path30.dirname(rel);
|
|
46717
46676
|
const stripSrc = relDir.replace(/^src(\/|\\)/, "");
|
|
46718
46677
|
const candidates = new Set;
|
|
46719
46678
|
for (const tDir of ["tests", "test", "__tests__", "spec"]) {
|
|
46720
46679
|
for (const suffix of ["", "_test", ".test", "_spec", ".spec"]) {
|
|
46721
|
-
candidates.add(
|
|
46680
|
+
candidates.add(path30.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
|
|
46722
46681
|
}
|
|
46723
46682
|
}
|
|
46724
46683
|
const existing = [];
|
|
@@ -46759,7 +46718,7 @@ var init_default_backend = __esm(() => {
|
|
|
46759
46718
|
|
|
46760
46719
|
// src/lang/backends/go.ts
|
|
46761
46720
|
import * as fs15 from "fs";
|
|
46762
|
-
import * as
|
|
46721
|
+
import * as path31 from "path";
|
|
46763
46722
|
function extractImports(_sourceFile, source) {
|
|
46764
46723
|
const out = new Set;
|
|
46765
46724
|
IMPORT_REGEX_SINGLE.lastIndex = 0;
|
|
@@ -46785,7 +46744,7 @@ function extractImports(_sourceFile, source) {
|
|
|
46785
46744
|
async function selectFramework(dir) {
|
|
46786
46745
|
let content;
|
|
46787
46746
|
try {
|
|
46788
|
-
content = fs15.readFileSync(
|
|
46747
|
+
content = fs15.readFileSync(path31.join(dir, "go.mod"), "utf-8");
|
|
46789
46748
|
} catch {
|
|
46790
46749
|
return null;
|
|
46791
46750
|
}
|
|
@@ -46806,16 +46765,16 @@ async function selectFramework(dir) {
|
|
|
46806
46765
|
async function selectEntryPoints(dir) {
|
|
46807
46766
|
const points = [];
|
|
46808
46767
|
try {
|
|
46809
|
-
fs15.accessSync(
|
|
46768
|
+
fs15.accessSync(path31.join(dir, "main.go"));
|
|
46810
46769
|
points.push("main.go");
|
|
46811
46770
|
} catch {}
|
|
46812
46771
|
try {
|
|
46813
|
-
const cmdDir =
|
|
46772
|
+
const cmdDir = path31.join(dir, "cmd");
|
|
46814
46773
|
const subdirs = fs15.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
46815
46774
|
for (const sub of subdirs) {
|
|
46816
|
-
const main =
|
|
46775
|
+
const main = path31.join("cmd", sub.name, "main.go");
|
|
46817
46776
|
try {
|
|
46818
|
-
fs15.accessSync(
|
|
46777
|
+
fs15.accessSync(path31.join(dir, main));
|
|
46819
46778
|
points.push(main);
|
|
46820
46779
|
} catch {}
|
|
46821
46780
|
}
|
|
@@ -46846,7 +46805,7 @@ var init_go = __esm(() => {
|
|
|
46846
46805
|
|
|
46847
46806
|
// src/lang/backends/python.ts
|
|
46848
46807
|
import * as fs16 from "fs";
|
|
46849
|
-
import * as
|
|
46808
|
+
import * as path32 from "path";
|
|
46850
46809
|
function parseImportTargets(rawTargets) {
|
|
46851
46810
|
const cleaned = rawTargets.replace(/[()]/g, "").split(`
|
|
46852
46811
|
`).map((line) => line.replace(/#.*$/, "").replace(/\\\s*$/, "")).join(" ");
|
|
@@ -46906,7 +46865,7 @@ async function selectFramework2(dir) {
|
|
|
46906
46865
|
];
|
|
46907
46866
|
for (const candidate of ["pyproject.toml", "requirements.txt", "setup.py"]) {
|
|
46908
46867
|
try {
|
|
46909
|
-
const content = fs16.readFileSync(
|
|
46868
|
+
const content = fs16.readFileSync(path32.join(dir, candidate), "utf-8");
|
|
46910
46869
|
const lower = content.toLowerCase();
|
|
46911
46870
|
for (const [pkg, name] of candidates) {
|
|
46912
46871
|
if (lower.includes(pkg)) {
|
|
@@ -46920,7 +46879,7 @@ async function selectFramework2(dir) {
|
|
|
46920
46879
|
async function selectEntryPoints2(dir) {
|
|
46921
46880
|
const points = new Set;
|
|
46922
46881
|
try {
|
|
46923
|
-
const content = fs16.readFileSync(
|
|
46882
|
+
const content = fs16.readFileSync(path32.join(dir, "pyproject.toml"), "utf-8");
|
|
46924
46883
|
const scriptsBlock = content.match(/\[project\.scripts\][\s\S]*?(?=\n\[|$)/);
|
|
46925
46884
|
if (scriptsBlock) {
|
|
46926
46885
|
for (const line of scriptsBlock[0].split(`
|
|
@@ -46935,7 +46894,7 @@ async function selectEntryPoints2(dir) {
|
|
|
46935
46894
|
} catch {}
|
|
46936
46895
|
for (const name of ["manage.py", "main.py", "app.py", "__main__.py"]) {
|
|
46937
46896
|
try {
|
|
46938
|
-
fs16.accessSync(
|
|
46897
|
+
fs16.accessSync(path32.join(dir, name));
|
|
46939
46898
|
points.add(name);
|
|
46940
46899
|
} catch {}
|
|
46941
46900
|
}
|
|
@@ -46964,7 +46923,7 @@ var init_python = __esm(() => {
|
|
|
46964
46923
|
|
|
46965
46924
|
// src/test-impact/analyzer.ts
|
|
46966
46925
|
import fs17 from "fs";
|
|
46967
|
-
import
|
|
46926
|
+
import path33 from "path";
|
|
46968
46927
|
function normalizePath(p) {
|
|
46969
46928
|
return p.replace(/\\/g, "/");
|
|
46970
46929
|
}
|
|
@@ -46985,8 +46944,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
46985
46944
|
if (!importPath.startsWith(".")) {
|
|
46986
46945
|
return null;
|
|
46987
46946
|
}
|
|
46988
|
-
const resolved =
|
|
46989
|
-
if (
|
|
46947
|
+
const resolved = path33.resolve(fromDir, importPath);
|
|
46948
|
+
if (path33.extname(resolved)) {
|
|
46990
46949
|
if (fs17.existsSync(resolved) && fs17.statSync(resolved).isFile()) {
|
|
46991
46950
|
return normalizePath(resolved);
|
|
46992
46951
|
}
|
|
@@ -47006,20 +46965,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
47006
46965
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
47007
46966
|
let baseDir = fromDir;
|
|
47008
46967
|
for (let i = 1;i < leadingDots; i++) {
|
|
47009
|
-
baseDir =
|
|
46968
|
+
baseDir = path33.dirname(baseDir);
|
|
47010
46969
|
}
|
|
47011
46970
|
const rest = module.slice(leadingDots);
|
|
47012
46971
|
if (rest.length === 0) {
|
|
47013
|
-
const initPath =
|
|
46972
|
+
const initPath = path33.join(baseDir, "__init__.py");
|
|
47014
46973
|
if (fs17.existsSync(initPath) && fs17.statSync(initPath).isFile()) {
|
|
47015
46974
|
return normalizePath(initPath);
|
|
47016
46975
|
}
|
|
47017
46976
|
return null;
|
|
47018
46977
|
}
|
|
47019
|
-
const subpath = rest.replace(/\./g,
|
|
46978
|
+
const subpath = rest.replace(/\./g, path33.sep);
|
|
47020
46979
|
const candidates = [
|
|
47021
|
-
`${
|
|
47022
|
-
|
|
46980
|
+
`${path33.join(baseDir, subpath)}.py`,
|
|
46981
|
+
path33.join(baseDir, subpath, "__init__.py")
|
|
47023
46982
|
];
|
|
47024
46983
|
for (const c of candidates) {
|
|
47025
46984
|
if (fs17.existsSync(c) && fs17.statSync(c).isFile())
|
|
@@ -47028,7 +46987,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
47028
46987
|
return null;
|
|
47029
46988
|
}
|
|
47030
46989
|
function findGoModule(fromDir) {
|
|
47031
|
-
const resolved =
|
|
46990
|
+
const resolved = path33.resolve(fromDir);
|
|
47032
46991
|
let cur = resolved;
|
|
47033
46992
|
const walked = [];
|
|
47034
46993
|
for (let i = 0;i < 16; i++) {
|
|
@@ -47040,7 +46999,7 @@ function findGoModule(fromDir) {
|
|
|
47040
46999
|
}
|
|
47041
47000
|
walked.push(cur);
|
|
47042
47001
|
try {
|
|
47043
|
-
const goMod =
|
|
47002
|
+
const goMod = path33.join(cur, "go.mod");
|
|
47044
47003
|
const content = fs17.readFileSync(goMod, "utf-8");
|
|
47045
47004
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
47046
47005
|
if (moduleMatch) {
|
|
@@ -47051,10 +47010,10 @@ function findGoModule(fromDir) {
|
|
|
47051
47010
|
}
|
|
47052
47011
|
} catch {}
|
|
47053
47012
|
try {
|
|
47054
|
-
fs17.accessSync(
|
|
47013
|
+
fs17.accessSync(path33.join(cur, ".git"));
|
|
47055
47014
|
break;
|
|
47056
47015
|
} catch {}
|
|
47057
|
-
const parent =
|
|
47016
|
+
const parent = path33.dirname(cur);
|
|
47058
47017
|
if (parent === cur)
|
|
47059
47018
|
break;
|
|
47060
47019
|
cur = parent;
|
|
@@ -47066,12 +47025,12 @@ function findGoModule(fromDir) {
|
|
|
47066
47025
|
function resolveGoImport(fromDir, importPath) {
|
|
47067
47026
|
let dir = null;
|
|
47068
47027
|
if (importPath.startsWith(".")) {
|
|
47069
|
-
dir =
|
|
47028
|
+
dir = path33.resolve(fromDir, importPath);
|
|
47070
47029
|
} else {
|
|
47071
47030
|
const mod = findGoModule(fromDir);
|
|
47072
47031
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
47073
47032
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
47074
|
-
dir =
|
|
47033
|
+
dir = path33.join(mod.moduleRoot, subpath);
|
|
47075
47034
|
}
|
|
47076
47035
|
}
|
|
47077
47036
|
if (dir === null)
|
|
@@ -47079,7 +47038,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
47079
47038
|
if (!fs17.existsSync(dir) || !fs17.statSync(dir).isDirectory())
|
|
47080
47039
|
return [];
|
|
47081
47040
|
try {
|
|
47082
|
-
return fs17.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(
|
|
47041
|
+
return fs17.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(path33.join(dir, f)));
|
|
47083
47042
|
} catch {
|
|
47084
47043
|
return [];
|
|
47085
47044
|
}
|
|
@@ -47118,15 +47077,15 @@ function findTestFilesSync(cwd) {
|
|
|
47118
47077
|
for (const entry of entries) {
|
|
47119
47078
|
if (entry.isDirectory()) {
|
|
47120
47079
|
if (!skipDirs.has(entry.name)) {
|
|
47121
|
-
walk(
|
|
47080
|
+
walk(path33.join(dir, entry.name), visitedInodes);
|
|
47122
47081
|
}
|
|
47123
47082
|
} else if (entry.isFile()) {
|
|
47124
47083
|
const name = entry.name;
|
|
47125
47084
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
47126
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
47085
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path33.sep}tests${path33.sep}`) && name.endsWith(".py");
|
|
47127
47086
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
47128
47087
|
if (isTsTest || isPyTest || isGoTest) {
|
|
47129
|
-
testFiles.push(normalizePath(
|
|
47088
|
+
testFiles.push(normalizePath(path33.join(dir, entry.name)));
|
|
47130
47089
|
}
|
|
47131
47090
|
}
|
|
47132
47091
|
}
|
|
@@ -47151,8 +47110,8 @@ function extractImports3(content) {
|
|
|
47151
47110
|
];
|
|
47152
47111
|
}
|
|
47153
47112
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
47154
|
-
const ext =
|
|
47155
|
-
const testDir =
|
|
47113
|
+
const ext = path33.extname(testFile).toLowerCase();
|
|
47114
|
+
const testDir = path33.dirname(testFile);
|
|
47156
47115
|
function addEdge(source) {
|
|
47157
47116
|
if (!impactMap[source])
|
|
47158
47117
|
impactMap[source] = [];
|
|
@@ -47211,7 +47170,7 @@ async function buildImpactMap(cwd) {
|
|
|
47211
47170
|
return impactMap;
|
|
47212
47171
|
}
|
|
47213
47172
|
async function loadImpactMap(cwd, options) {
|
|
47214
|
-
const cachePath =
|
|
47173
|
+
const cachePath = path33.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
47215
47174
|
if (fs17.existsSync(cachePath)) {
|
|
47216
47175
|
try {
|
|
47217
47176
|
const content = fs17.readFileSync(cachePath, "utf-8");
|
|
@@ -47244,12 +47203,12 @@ async function loadImpactMap(cwd, options) {
|
|
|
47244
47203
|
return _internals22.buildImpactMap(cwd);
|
|
47245
47204
|
}
|
|
47246
47205
|
async function saveImpactMap(cwd, impactMap) {
|
|
47247
|
-
if (!
|
|
47206
|
+
if (!path33.isAbsolute(cwd)) {
|
|
47248
47207
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
47249
47208
|
}
|
|
47250
47209
|
_internals22.validateProjectRoot(cwd);
|
|
47251
|
-
const cacheDir2 =
|
|
47252
|
-
const cachePath =
|
|
47210
|
+
const cacheDir2 = path33.join(cwd, ".swarm", "cache");
|
|
47211
|
+
const cachePath = path33.join(cacheDir2, "impact-map.json");
|
|
47253
47212
|
if (!fs17.existsSync(cacheDir2)) {
|
|
47254
47213
|
fs17.mkdirSync(cacheDir2, { recursive: true });
|
|
47255
47214
|
}
|
|
@@ -47281,7 +47240,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
47281
47240
|
budgetExceeded = true;
|
|
47282
47241
|
break;
|
|
47283
47242
|
}
|
|
47284
|
-
const normalizedChanged = normalizePath(
|
|
47243
|
+
const normalizedChanged = normalizePath(path33.resolve(changedFile));
|
|
47285
47244
|
const tests = impactMap[normalizedChanged];
|
|
47286
47245
|
if (tests && tests.length > 0) {
|
|
47287
47246
|
for (const test of tests) {
|
|
@@ -47574,15 +47533,15 @@ var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
|
|
|
47574
47533
|
|
|
47575
47534
|
// src/test-impact/history-store.ts
|
|
47576
47535
|
import fs18 from "fs";
|
|
47577
|
-
import
|
|
47536
|
+
import path34 from "path";
|
|
47578
47537
|
function getHistoryPath(workingDir) {
|
|
47579
47538
|
if (!workingDir) {
|
|
47580
47539
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
47581
47540
|
}
|
|
47582
|
-
if (!
|
|
47541
|
+
if (!path34.isAbsolute(workingDir)) {
|
|
47583
47542
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
47584
47543
|
}
|
|
47585
|
-
return
|
|
47544
|
+
return path34.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
47586
47545
|
}
|
|
47587
47546
|
function sanitizeErrorMessage(errorMessage) {
|
|
47588
47547
|
if (errorMessage === undefined) {
|
|
@@ -47669,7 +47628,7 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
47669
47628
|
}
|
|
47670
47629
|
}
|
|
47671
47630
|
const historyPath = getHistoryPath(workingDir);
|
|
47672
|
-
const historyDir =
|
|
47631
|
+
const historyDir = path34.dirname(historyPath);
|
|
47673
47632
|
_internals23.validateProjectRoot(workingDir);
|
|
47674
47633
|
if (!fs18.existsSync(historyDir)) {
|
|
47675
47634
|
fs18.mkdirSync(historyDir, { recursive: true });
|
|
@@ -47765,7 +47724,7 @@ var init_history_store = __esm(() => {
|
|
|
47765
47724
|
|
|
47766
47725
|
// src/tools/resolve-working-directory.ts
|
|
47767
47726
|
import * as fs19 from "fs";
|
|
47768
|
-
import * as
|
|
47727
|
+
import * as path35 from "path";
|
|
47769
47728
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
47770
47729
|
if (workingDirectory == null || workingDirectory === "") {
|
|
47771
47730
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -47785,15 +47744,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
47785
47744
|
};
|
|
47786
47745
|
}
|
|
47787
47746
|
}
|
|
47788
|
-
const normalizedDir =
|
|
47789
|
-
const pathParts = normalizedDir.split(
|
|
47747
|
+
const normalizedDir = path35.normalize(workingDirectory);
|
|
47748
|
+
const pathParts = normalizedDir.split(path35.sep);
|
|
47790
47749
|
if (pathParts.includes("..")) {
|
|
47791
47750
|
return {
|
|
47792
47751
|
success: false,
|
|
47793
47752
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
47794
47753
|
};
|
|
47795
47754
|
}
|
|
47796
|
-
const resolvedDir =
|
|
47755
|
+
const resolvedDir = path35.resolve(normalizedDir);
|
|
47797
47756
|
let statResult;
|
|
47798
47757
|
try {
|
|
47799
47758
|
statResult = fs19.statSync(resolvedDir);
|
|
@@ -47809,7 +47768,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
47809
47768
|
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
47810
47769
|
};
|
|
47811
47770
|
}
|
|
47812
|
-
const resolvedFallback =
|
|
47771
|
+
const resolvedFallback = path35.resolve(fallbackDirectory);
|
|
47813
47772
|
let fallbackExists = false;
|
|
47814
47773
|
try {
|
|
47815
47774
|
fs19.statSync(resolvedFallback);
|
|
@@ -47819,7 +47778,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
47819
47778
|
}
|
|
47820
47779
|
if (workingDirectory != null && workingDirectory !== "") {
|
|
47821
47780
|
if (fallbackExists) {
|
|
47822
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
47781
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path35.sep);
|
|
47823
47782
|
if (isSubdirectory) {
|
|
47824
47783
|
return {
|
|
47825
47784
|
success: false,
|
|
@@ -47874,10 +47833,10 @@ var init_registry_backend = __esm(() => {
|
|
|
47874
47833
|
|
|
47875
47834
|
// src/lang/backends/typescript.ts
|
|
47876
47835
|
import * as fs20 from "fs";
|
|
47877
|
-
import * as
|
|
47836
|
+
import * as path36 from "path";
|
|
47878
47837
|
function readPackageJsonRaw(dir) {
|
|
47879
47838
|
try {
|
|
47880
|
-
const content = fs20.readFileSync(
|
|
47839
|
+
const content = fs20.readFileSync(path36.join(dir, "package.json"), "utf-8");
|
|
47881
47840
|
return JSON.parse(content);
|
|
47882
47841
|
} catch {
|
|
47883
47842
|
return null;
|
|
@@ -48097,7 +48056,7 @@ __export(exports_dispatch, {
|
|
|
48097
48056
|
_internals: () => _internals25
|
|
48098
48057
|
});
|
|
48099
48058
|
import * as fs21 from "fs";
|
|
48100
|
-
import * as
|
|
48059
|
+
import * as path37 from "path";
|
|
48101
48060
|
function safeReaddirSet(dir) {
|
|
48102
48061
|
try {
|
|
48103
48062
|
return new Set(fs21.readdirSync(dir));
|
|
@@ -48114,14 +48073,14 @@ function manifestHash(dir) {
|
|
|
48114
48073
|
if (!entries.has(name))
|
|
48115
48074
|
continue;
|
|
48116
48075
|
try {
|
|
48117
|
-
const stat3 = fs21.statSync(
|
|
48076
|
+
const stat3 = fs21.statSync(path37.join(dir, name));
|
|
48118
48077
|
parts.push(`${name}:${stat3.size}:${stat3.mtimeMs}:${stat3.ino}`);
|
|
48119
48078
|
} catch {}
|
|
48120
48079
|
}
|
|
48121
48080
|
return parts.join("|");
|
|
48122
48081
|
}
|
|
48123
48082
|
function findManifestRoot(start) {
|
|
48124
|
-
const resolved =
|
|
48083
|
+
const resolved = path37.resolve(start);
|
|
48125
48084
|
const cached3 = manifestRootCache.get(resolved);
|
|
48126
48085
|
if (cached3 !== undefined)
|
|
48127
48086
|
return cached3;
|
|
@@ -48140,7 +48099,7 @@ function findManifestRoot(start) {
|
|
|
48140
48099
|
return cur;
|
|
48141
48100
|
}
|
|
48142
48101
|
}
|
|
48143
|
-
const parent =
|
|
48102
|
+
const parent = path37.dirname(cur);
|
|
48144
48103
|
if (parent === cur)
|
|
48145
48104
|
break;
|
|
48146
48105
|
cur = parent;
|
|
@@ -48250,13 +48209,13 @@ var init_dispatch = __esm(() => {
|
|
|
48250
48209
|
|
|
48251
48210
|
// src/tools/test-runner.ts
|
|
48252
48211
|
import * as fs22 from "fs";
|
|
48253
|
-
import * as
|
|
48212
|
+
import * as path38 from "path";
|
|
48254
48213
|
async function estimateFanOut(sourceFiles, cwd) {
|
|
48255
48214
|
try {
|
|
48256
48215
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
48257
48216
|
const uniqueTestFiles = new Set;
|
|
48258
48217
|
for (const sourceFile of sourceFiles) {
|
|
48259
|
-
const resolvedPath =
|
|
48218
|
+
const resolvedPath = path38.resolve(cwd, sourceFile);
|
|
48260
48219
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
48261
48220
|
const testFiles = impactMap[normalizedPath];
|
|
48262
48221
|
if (testFiles) {
|
|
@@ -48334,14 +48293,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
48334
48293
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
48335
48294
|
}
|
|
48336
48295
|
function detectGoTest(cwd) {
|
|
48337
|
-
return fs22.existsSync(
|
|
48296
|
+
return fs22.existsSync(path38.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
48338
48297
|
}
|
|
48339
48298
|
function detectJavaMaven(cwd) {
|
|
48340
|
-
return fs22.existsSync(
|
|
48299
|
+
return fs22.existsSync(path38.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
48341
48300
|
}
|
|
48342
48301
|
function detectGradle(cwd) {
|
|
48343
|
-
const hasBuildFile = fs22.existsSync(
|
|
48344
|
-
const hasGradlew = fs22.existsSync(
|
|
48302
|
+
const hasBuildFile = fs22.existsSync(path38.join(cwd, "build.gradle")) || fs22.existsSync(path38.join(cwd, "build.gradle.kts"));
|
|
48303
|
+
const hasGradlew = fs22.existsSync(path38.join(cwd, "gradlew")) || fs22.existsSync(path38.join(cwd, "gradlew.bat"));
|
|
48345
48304
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
48346
48305
|
}
|
|
48347
48306
|
function detectDotnetTest(cwd) {
|
|
@@ -48354,25 +48313,25 @@ function detectDotnetTest(cwd) {
|
|
|
48354
48313
|
}
|
|
48355
48314
|
}
|
|
48356
48315
|
function detectCTest(cwd) {
|
|
48357
|
-
const hasSource = fs22.existsSync(
|
|
48358
|
-
const hasBuildCache = fs22.existsSync(
|
|
48316
|
+
const hasSource = fs22.existsSync(path38.join(cwd, "CMakeLists.txt"));
|
|
48317
|
+
const hasBuildCache = fs22.existsSync(path38.join(cwd, "CMakeCache.txt")) || fs22.existsSync(path38.join(cwd, "build", "CMakeCache.txt"));
|
|
48359
48318
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
48360
48319
|
}
|
|
48361
48320
|
function detectSwiftTest(cwd) {
|
|
48362
|
-
return fs22.existsSync(
|
|
48321
|
+
return fs22.existsSync(path38.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
48363
48322
|
}
|
|
48364
48323
|
function detectDartTest(cwd) {
|
|
48365
|
-
return fs22.existsSync(
|
|
48324
|
+
return fs22.existsSync(path38.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
48366
48325
|
}
|
|
48367
48326
|
function detectRSpec(cwd) {
|
|
48368
|
-
const hasRSpecFile = fs22.existsSync(
|
|
48369
|
-
const hasGemfile = fs22.existsSync(
|
|
48370
|
-
const hasSpecDir = fs22.existsSync(
|
|
48327
|
+
const hasRSpecFile = fs22.existsSync(path38.join(cwd, ".rspec"));
|
|
48328
|
+
const hasGemfile = fs22.existsSync(path38.join(cwd, "Gemfile"));
|
|
48329
|
+
const hasSpecDir = fs22.existsSync(path38.join(cwd, "spec"));
|
|
48371
48330
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
48372
48331
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
48373
48332
|
}
|
|
48374
48333
|
function detectMinitest(cwd) {
|
|
48375
|
-
return fs22.existsSync(
|
|
48334
|
+
return fs22.existsSync(path38.join(cwd, "test")) && (fs22.existsSync(path38.join(cwd, "Gemfile")) || fs22.existsSync(path38.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
48376
48335
|
}
|
|
48377
48336
|
async function detectTestFrameworkViaDispatch(cwd) {
|
|
48378
48337
|
try {
|
|
@@ -48434,7 +48393,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
48434
48393
|
async function detectTestFramework(cwd) {
|
|
48435
48394
|
const baseDir = cwd;
|
|
48436
48395
|
try {
|
|
48437
|
-
const packageJsonPath =
|
|
48396
|
+
const packageJsonPath = path38.join(baseDir, "package.json");
|
|
48438
48397
|
if (fs22.existsSync(packageJsonPath)) {
|
|
48439
48398
|
const content = fs22.readFileSync(packageJsonPath, "utf-8");
|
|
48440
48399
|
const pkg = JSON.parse(content);
|
|
@@ -48455,16 +48414,16 @@ async function detectTestFramework(cwd) {
|
|
|
48455
48414
|
return "jest";
|
|
48456
48415
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
48457
48416
|
return "mocha";
|
|
48458
|
-
if (fs22.existsSync(
|
|
48417
|
+
if (fs22.existsSync(path38.join(baseDir, "bun.lockb")) || fs22.existsSync(path38.join(baseDir, "bun.lock"))) {
|
|
48459
48418
|
if (scripts.test?.includes("bun"))
|
|
48460
48419
|
return "bun";
|
|
48461
48420
|
}
|
|
48462
48421
|
}
|
|
48463
48422
|
} catch {}
|
|
48464
48423
|
try {
|
|
48465
|
-
const pyprojectTomlPath =
|
|
48466
|
-
const setupCfgPath =
|
|
48467
|
-
const requirementsTxtPath =
|
|
48424
|
+
const pyprojectTomlPath = path38.join(baseDir, "pyproject.toml");
|
|
48425
|
+
const setupCfgPath = path38.join(baseDir, "setup.cfg");
|
|
48426
|
+
const requirementsTxtPath = path38.join(baseDir, "requirements.txt");
|
|
48468
48427
|
if (fs22.existsSync(pyprojectTomlPath)) {
|
|
48469
48428
|
const content = fs22.readFileSync(pyprojectTomlPath, "utf-8");
|
|
48470
48429
|
if (content.includes("[tool.pytest"))
|
|
@@ -48484,7 +48443,7 @@ async function detectTestFramework(cwd) {
|
|
|
48484
48443
|
}
|
|
48485
48444
|
} catch {}
|
|
48486
48445
|
try {
|
|
48487
|
-
const cargoTomlPath =
|
|
48446
|
+
const cargoTomlPath = path38.join(baseDir, "Cargo.toml");
|
|
48488
48447
|
if (fs22.existsSync(cargoTomlPath)) {
|
|
48489
48448
|
const content = fs22.readFileSync(cargoTomlPath, "utf-8");
|
|
48490
48449
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -48495,9 +48454,9 @@ async function detectTestFramework(cwd) {
|
|
|
48495
48454
|
}
|
|
48496
48455
|
} catch {}
|
|
48497
48456
|
try {
|
|
48498
|
-
const pesterConfigPath =
|
|
48499
|
-
const pesterConfigJsonPath =
|
|
48500
|
-
const pesterPs1Path =
|
|
48457
|
+
const pesterConfigPath = path38.join(baseDir, "pester.config.ps1");
|
|
48458
|
+
const pesterConfigJsonPath = path38.join(baseDir, "pester.config.ps1.json");
|
|
48459
|
+
const pesterPs1Path = path38.join(baseDir, "tests.ps1");
|
|
48501
48460
|
if (fs22.existsSync(pesterConfigPath) || fs22.existsSync(pesterConfigJsonPath) || fs22.existsSync(pesterPs1Path)) {
|
|
48502
48461
|
return "pester";
|
|
48503
48462
|
}
|
|
@@ -48526,12 +48485,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
48526
48485
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
48527
48486
|
}
|
|
48528
48487
|
function resolveWorkspacePath(file3, workingDir) {
|
|
48529
|
-
return
|
|
48488
|
+
return path38.isAbsolute(file3) ? path38.resolve(file3) : path38.resolve(workingDir, file3);
|
|
48530
48489
|
}
|
|
48531
48490
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
48532
48491
|
if (!preferRelative)
|
|
48533
48492
|
return absolutePath;
|
|
48534
|
-
return
|
|
48493
|
+
return path38.relative(workingDir, absolutePath);
|
|
48535
48494
|
}
|
|
48536
48495
|
function dedupePush(target, value) {
|
|
48537
48496
|
if (!target.includes(value)) {
|
|
@@ -48568,18 +48527,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
48568
48527
|
}
|
|
48569
48528
|
}
|
|
48570
48529
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
48571
|
-
const relativeDir =
|
|
48530
|
+
const relativeDir = path38.dirname(relativePath);
|
|
48572
48531
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
48573
48532
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
48574
|
-
const rootDir =
|
|
48575
|
-
return nestedRelativeDir ? [rootDir,
|
|
48533
|
+
const rootDir = path38.join(workingDir, dirName);
|
|
48534
|
+
return nestedRelativeDir ? [rootDir, path38.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
48576
48535
|
});
|
|
48577
48536
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
48578
48537
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
48579
|
-
directories.push(
|
|
48538
|
+
directories.push(path38.join(workingDir, "src/test/java", path38.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
48580
48539
|
}
|
|
48581
48540
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
48582
|
-
directories.push(
|
|
48541
|
+
directories.push(path38.join(workingDir, "src/test/kotlin", path38.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
48583
48542
|
}
|
|
48584
48543
|
return [...new Set(directories)];
|
|
48585
48544
|
}
|
|
@@ -48607,23 +48566,23 @@ function isLanguageSpecificTestFile(basename6) {
|
|
|
48607
48566
|
}
|
|
48608
48567
|
function isConventionTestFilePath(filePath) {
|
|
48609
48568
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
48610
|
-
const basename6 =
|
|
48569
|
+
const basename6 = path38.basename(filePath);
|
|
48611
48570
|
return hasCompoundTestExtension(basename6) || basename6.includes(".spec.") || basename6.includes(".test.") || isLanguageSpecificTestFile(basename6) || isTestDirectoryPath(normalizedPath);
|
|
48612
48571
|
}
|
|
48613
48572
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
48614
48573
|
const testFiles = [];
|
|
48615
48574
|
for (const file3 of sourceFiles) {
|
|
48616
48575
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
48617
|
-
const relativeFile =
|
|
48618
|
-
const basename6 =
|
|
48619
|
-
const
|
|
48620
|
-
const preferRelativeOutput = !
|
|
48576
|
+
const relativeFile = path38.relative(workingDir, absoluteFile);
|
|
48577
|
+
const basename6 = path38.basename(absoluteFile);
|
|
48578
|
+
const dirname17 = path38.dirname(absoluteFile);
|
|
48579
|
+
const preferRelativeOutput = !path38.isAbsolute(file3);
|
|
48621
48580
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
48622
48581
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
48623
48582
|
continue;
|
|
48624
48583
|
}
|
|
48625
48584
|
const nameWithoutExt = basename6.replace(/\.[^.]+$/, "");
|
|
48626
|
-
const ext =
|
|
48585
|
+
const ext = path38.extname(basename6);
|
|
48627
48586
|
const genericTestNames = [
|
|
48628
48587
|
`${nameWithoutExt}.spec${ext}`,
|
|
48629
48588
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -48632,7 +48591,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
48632
48591
|
const colocatedCandidates = [
|
|
48633
48592
|
...genericTestNames,
|
|
48634
48593
|
...languageSpecificTestNames
|
|
48635
|
-
].map((candidateName) =>
|
|
48594
|
+
].map((candidateName) => path38.join(dirname17, candidateName));
|
|
48636
48595
|
const testDirectoryNames = [
|
|
48637
48596
|
basename6,
|
|
48638
48597
|
...genericTestNames,
|
|
@@ -48641,8 +48600,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
48641
48600
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
48642
48601
|
const possibleTestFiles = [
|
|
48643
48602
|
...colocatedCandidates,
|
|
48644
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
48645
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
48603
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path38.join(dirname17, dirName, candidateName))),
|
|
48604
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path38.join(candidateDir, candidateName)))
|
|
48646
48605
|
];
|
|
48647
48606
|
for (const testFile of possibleTestFiles) {
|
|
48648
48607
|
if (fs22.existsSync(testFile)) {
|
|
@@ -48663,7 +48622,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
48663
48622
|
try {
|
|
48664
48623
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
48665
48624
|
const content = fs22.readFileSync(absoluteTestFile, "utf-8");
|
|
48666
|
-
const testDir =
|
|
48625
|
+
const testDir = path38.dirname(absoluteTestFile);
|
|
48667
48626
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
48668
48627
|
let match;
|
|
48669
48628
|
match = importRegex.exec(content);
|
|
@@ -48671,8 +48630,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
48671
48630
|
const importPath = match[1];
|
|
48672
48631
|
let resolvedImport;
|
|
48673
48632
|
if (importPath.startsWith(".")) {
|
|
48674
|
-
resolvedImport =
|
|
48675
|
-
const existingExt =
|
|
48633
|
+
resolvedImport = path38.resolve(testDir, importPath);
|
|
48634
|
+
const existingExt = path38.extname(resolvedImport);
|
|
48676
48635
|
if (!existingExt) {
|
|
48677
48636
|
for (const extToTry of [
|
|
48678
48637
|
".ts",
|
|
@@ -48692,12 +48651,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
48692
48651
|
} else {
|
|
48693
48652
|
continue;
|
|
48694
48653
|
}
|
|
48695
|
-
const importBasename =
|
|
48696
|
-
const importDir =
|
|
48654
|
+
const importBasename = path38.basename(resolvedImport, path38.extname(resolvedImport));
|
|
48655
|
+
const importDir = path38.dirname(resolvedImport);
|
|
48697
48656
|
for (const sourceFile of absoluteSourceFiles) {
|
|
48698
|
-
const sourceDir =
|
|
48699
|
-
const sourceBasename =
|
|
48700
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
48657
|
+
const sourceDir = path38.dirname(sourceFile);
|
|
48658
|
+
const sourceBasename = path38.basename(sourceFile, path38.extname(sourceFile));
|
|
48659
|
+
const isRelatedDir = importDir === sourceDir || importDir === path38.join(sourceDir, "__tests__") || importDir === path38.join(sourceDir, "tests") || importDir === path38.join(sourceDir, "test") || importDir === path38.join(sourceDir, "spec");
|
|
48701
48660
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
48702
48661
|
dedupePush(testFiles, testFile);
|
|
48703
48662
|
break;
|
|
@@ -48710,8 +48669,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
48710
48669
|
while (match !== null) {
|
|
48711
48670
|
const importPath = match[1];
|
|
48712
48671
|
if (importPath.startsWith(".")) {
|
|
48713
|
-
let resolvedImport =
|
|
48714
|
-
const existingExt =
|
|
48672
|
+
let resolvedImport = path38.resolve(testDir, importPath);
|
|
48673
|
+
const existingExt = path38.extname(resolvedImport);
|
|
48715
48674
|
if (!existingExt) {
|
|
48716
48675
|
for (const extToTry of [
|
|
48717
48676
|
".ts",
|
|
@@ -48728,12 +48687,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
48728
48687
|
}
|
|
48729
48688
|
}
|
|
48730
48689
|
}
|
|
48731
|
-
const importDir =
|
|
48732
|
-
const importBasename =
|
|
48690
|
+
const importDir = path38.dirname(resolvedImport);
|
|
48691
|
+
const importBasename = path38.basename(resolvedImport, path38.extname(resolvedImport));
|
|
48733
48692
|
for (const sourceFile of absoluteSourceFiles) {
|
|
48734
|
-
const sourceDir =
|
|
48735
|
-
const sourceBasename =
|
|
48736
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
48693
|
+
const sourceDir = path38.dirname(sourceFile);
|
|
48694
|
+
const sourceBasename = path38.basename(sourceFile, path38.extname(sourceFile));
|
|
48695
|
+
const isRelatedDir = importDir === sourceDir || importDir === path38.join(sourceDir, "__tests__") || importDir === path38.join(sourceDir, "tests") || importDir === path38.join(sourceDir, "test") || importDir === path38.join(sourceDir, "spec");
|
|
48737
48696
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
48738
48697
|
dedupePush(testFiles, testFile);
|
|
48739
48698
|
break;
|
|
@@ -48843,8 +48802,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
|
48843
48802
|
return ["mvn", "test"];
|
|
48844
48803
|
case "gradle": {
|
|
48845
48804
|
const isWindows = process.platform === "win32";
|
|
48846
|
-
const hasGradlewBat = fs22.existsSync(
|
|
48847
|
-
const hasGradlew = fs22.existsSync(
|
|
48805
|
+
const hasGradlewBat = fs22.existsSync(path38.join(baseDir, "gradlew.bat"));
|
|
48806
|
+
const hasGradlew = fs22.existsSync(path38.join(baseDir, "gradlew"));
|
|
48848
48807
|
if (hasGradlewBat && isWindows)
|
|
48849
48808
|
return ["gradlew.bat", "test"];
|
|
48850
48809
|
if (hasGradlew)
|
|
@@ -48861,7 +48820,7 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir) {
|
|
|
48861
48820
|
"cmake-build-release",
|
|
48862
48821
|
"out"
|
|
48863
48822
|
];
|
|
48864
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs22.existsSync(
|
|
48823
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs22.existsSync(path38.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
48865
48824
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
48866
48825
|
}
|
|
48867
48826
|
case "swift-test":
|
|
@@ -49293,11 +49252,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
49293
49252
|
};
|
|
49294
49253
|
}
|
|
49295
49254
|
const startTime = Date.now();
|
|
49296
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
49255
|
+
const vitestJsonOutputPath = framework === "vitest" ? path38.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
49297
49256
|
try {
|
|
49298
49257
|
if (vitestJsonOutputPath) {
|
|
49299
49258
|
try {
|
|
49300
|
-
fs22.mkdirSync(
|
|
49259
|
+
fs22.mkdirSync(path38.dirname(vitestJsonOutputPath), { recursive: true });
|
|
49301
49260
|
if (fs22.existsSync(vitestJsonOutputPath)) {
|
|
49302
49261
|
fs22.unlinkSync(vitestJsonOutputPath);
|
|
49303
49262
|
}
|
|
@@ -49413,10 +49372,10 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
49413
49372
|
}
|
|
49414
49373
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
49415
49374
|
const normalized = testFile.replace(/\\/g, "/");
|
|
49416
|
-
if (!
|
|
49375
|
+
if (!path38.isAbsolute(testFile))
|
|
49417
49376
|
return normalized;
|
|
49418
|
-
const relative9 =
|
|
49419
|
-
if (relative9.startsWith("..") ||
|
|
49377
|
+
const relative9 = path38.relative(workingDir, testFile);
|
|
49378
|
+
if (relative9.startsWith("..") || path38.isAbsolute(relative9)) {
|
|
49420
49379
|
return normalized;
|
|
49421
49380
|
}
|
|
49422
49381
|
return relative9.replace(/\\/g, "/");
|
|
@@ -49754,7 +49713,7 @@ var init_test_runner = __esm(() => {
|
|
|
49754
49713
|
const sourceFiles = args.files.filter((file3) => {
|
|
49755
49714
|
if (directTestFiles.includes(file3))
|
|
49756
49715
|
return false;
|
|
49757
|
-
const ext =
|
|
49716
|
+
const ext = path38.extname(file3).toLowerCase();
|
|
49758
49717
|
return SOURCE_EXTENSIONS.has(ext);
|
|
49759
49718
|
});
|
|
49760
49719
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -49800,7 +49759,7 @@ var init_test_runner = __esm(() => {
|
|
|
49800
49759
|
if (isConventionTestFilePath(f)) {
|
|
49801
49760
|
return false;
|
|
49802
49761
|
}
|
|
49803
|
-
const ext =
|
|
49762
|
+
const ext = path38.extname(f).toLowerCase();
|
|
49804
49763
|
return SOURCE_EXTENSIONS.has(ext);
|
|
49805
49764
|
});
|
|
49806
49765
|
if (sourceFiles.length === 0) {
|
|
@@ -49850,7 +49809,7 @@ var init_test_runner = __esm(() => {
|
|
|
49850
49809
|
if (isConventionTestFilePath(f)) {
|
|
49851
49810
|
return false;
|
|
49852
49811
|
}
|
|
49853
|
-
const ext =
|
|
49812
|
+
const ext = path38.extname(f).toLowerCase();
|
|
49854
49813
|
return SOURCE_EXTENSIONS.has(ext);
|
|
49855
49814
|
});
|
|
49856
49815
|
if (sourceFiles.length === 0) {
|
|
@@ -49902,8 +49861,8 @@ var init_test_runner = __esm(() => {
|
|
|
49902
49861
|
}
|
|
49903
49862
|
if (impactResult.impactedTests.length > 0) {
|
|
49904
49863
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
49905
|
-
const relativePath =
|
|
49906
|
-
return
|
|
49864
|
+
const relativePath = path38.relative(workingDir, absPath);
|
|
49865
|
+
return path38.isAbsolute(relativePath) ? absPath : relativePath;
|
|
49907
49866
|
});
|
|
49908
49867
|
} else {
|
|
49909
49868
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -49979,7 +49938,7 @@ var init_test_runner = __esm(() => {
|
|
|
49979
49938
|
|
|
49980
49939
|
// src/services/preflight-service.ts
|
|
49981
49940
|
import * as fs23 from "fs";
|
|
49982
|
-
import * as
|
|
49941
|
+
import * as path39 from "path";
|
|
49983
49942
|
function validateDirectoryPath(dir) {
|
|
49984
49943
|
if (!dir || typeof dir !== "string") {
|
|
49985
49944
|
throw new Error("Directory path is required");
|
|
@@ -49987,8 +49946,8 @@ function validateDirectoryPath(dir) {
|
|
|
49987
49946
|
if (dir.includes("..")) {
|
|
49988
49947
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
49989
49948
|
}
|
|
49990
|
-
const normalized =
|
|
49991
|
-
const absolutePath =
|
|
49949
|
+
const normalized = path39.normalize(dir);
|
|
49950
|
+
const absolutePath = path39.isAbsolute(normalized) ? normalized : path39.resolve(normalized);
|
|
49992
49951
|
return absolutePath;
|
|
49993
49952
|
}
|
|
49994
49953
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -50011,7 +49970,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
50011
49970
|
}
|
|
50012
49971
|
function getPackageVersion(dir) {
|
|
50013
49972
|
try {
|
|
50014
|
-
const packagePath =
|
|
49973
|
+
const packagePath = path39.join(dir, "package.json");
|
|
50015
49974
|
if (fs23.existsSync(packagePath)) {
|
|
50016
49975
|
const content = fs23.readFileSync(packagePath, "utf-8");
|
|
50017
49976
|
const pkg = JSON.parse(content);
|
|
@@ -50022,7 +49981,7 @@ function getPackageVersion(dir) {
|
|
|
50022
49981
|
}
|
|
50023
49982
|
function getChangelogVersion(dir) {
|
|
50024
49983
|
try {
|
|
50025
|
-
const changelogPath =
|
|
49984
|
+
const changelogPath = path39.join(dir, "CHANGELOG.md");
|
|
50026
49985
|
if (fs23.existsSync(changelogPath)) {
|
|
50027
49986
|
const content = fs23.readFileSync(changelogPath, "utf-8");
|
|
50028
49987
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -50036,7 +49995,7 @@ function getChangelogVersion(dir) {
|
|
|
50036
49995
|
function getVersionFileVersion(dir) {
|
|
50037
49996
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
50038
49997
|
for (const file3 of possibleFiles) {
|
|
50039
|
-
const filePath =
|
|
49998
|
+
const filePath = path39.join(dir, file3);
|
|
50040
49999
|
if (fs23.existsSync(filePath)) {
|
|
50041
50000
|
try {
|
|
50042
50001
|
const content = fs23.readFileSync(filePath, "utf-8").trim();
|
|
@@ -50363,7 +50322,7 @@ async function runEvidenceCheck(dir) {
|
|
|
50363
50322
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
50364
50323
|
const startTime = Date.now();
|
|
50365
50324
|
try {
|
|
50366
|
-
const specPath =
|
|
50325
|
+
const specPath = path39.join(dir, ".swarm", "spec.md");
|
|
50367
50326
|
if (!fs23.existsSync(specPath)) {
|
|
50368
50327
|
return {
|
|
50369
50328
|
type: "req_coverage",
|
|
@@ -51480,7 +51439,7 @@ var init_manager3 = __esm(() => {
|
|
|
51480
51439
|
|
|
51481
51440
|
// src/commands/reset.ts
|
|
51482
51441
|
import * as fs24 from "fs";
|
|
51483
|
-
import * as
|
|
51442
|
+
import * as path40 from "path";
|
|
51484
51443
|
async function handleResetCommand(directory, args) {
|
|
51485
51444
|
const hasConfirm = args.includes("--confirm");
|
|
51486
51445
|
if (!hasConfirm) {
|
|
@@ -51520,7 +51479,7 @@ async function handleResetCommand(directory, args) {
|
|
|
51520
51479
|
}
|
|
51521
51480
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
51522
51481
|
try {
|
|
51523
|
-
const rootPath =
|
|
51482
|
+
const rootPath = path40.join(directory, filename);
|
|
51524
51483
|
if (fs24.existsSync(rootPath)) {
|
|
51525
51484
|
fs24.unlinkSync(rootPath);
|
|
51526
51485
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -51560,7 +51519,7 @@ var init_reset = __esm(() => {
|
|
|
51560
51519
|
|
|
51561
51520
|
// src/commands/reset-session.ts
|
|
51562
51521
|
import * as fs25 from "fs";
|
|
51563
|
-
import * as
|
|
51522
|
+
import * as path41 from "path";
|
|
51564
51523
|
async function handleResetSessionCommand(directory, _args) {
|
|
51565
51524
|
const results = [];
|
|
51566
51525
|
try {
|
|
@@ -51575,13 +51534,13 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
51575
51534
|
results.push("\u274C Failed to delete state.json");
|
|
51576
51535
|
}
|
|
51577
51536
|
try {
|
|
51578
|
-
const sessionDir =
|
|
51537
|
+
const sessionDir = path41.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
51579
51538
|
if (fs25.existsSync(sessionDir)) {
|
|
51580
51539
|
const files = fs25.readdirSync(sessionDir);
|
|
51581
51540
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
51582
51541
|
let deletedCount = 0;
|
|
51583
51542
|
for (const file3 of otherFiles) {
|
|
51584
|
-
const filePath =
|
|
51543
|
+
const filePath = path41.join(sessionDir, file3);
|
|
51585
51544
|
if (fs25.lstatSync(filePath).isFile()) {
|
|
51586
51545
|
fs25.unlinkSync(filePath);
|
|
51587
51546
|
deletedCount++;
|
|
@@ -51613,7 +51572,7 @@ var init_reset_session = __esm(() => {
|
|
|
51613
51572
|
});
|
|
51614
51573
|
|
|
51615
51574
|
// src/summaries/manager.ts
|
|
51616
|
-
import * as
|
|
51575
|
+
import * as path42 from "path";
|
|
51617
51576
|
function sanitizeSummaryId(id) {
|
|
51618
51577
|
if (!id || id.length === 0) {
|
|
51619
51578
|
throw new Error("Invalid summary ID: empty string");
|
|
@@ -51636,7 +51595,7 @@ function sanitizeSummaryId(id) {
|
|
|
51636
51595
|
}
|
|
51637
51596
|
async function loadFullOutput(directory, id) {
|
|
51638
51597
|
const sanitizedId = sanitizeSummaryId(id);
|
|
51639
|
-
const relativePath =
|
|
51598
|
+
const relativePath = path42.join("summaries", `${sanitizedId}.json`);
|
|
51640
51599
|
validateSwarmPath(directory, relativePath);
|
|
51641
51600
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
51642
51601
|
if (content === null) {
|
|
@@ -51699,7 +51658,7 @@ var init_retrieve = __esm(() => {
|
|
|
51699
51658
|
|
|
51700
51659
|
// src/commands/rollback.ts
|
|
51701
51660
|
import * as fs26 from "fs";
|
|
51702
|
-
import * as
|
|
51661
|
+
import * as path43 from "path";
|
|
51703
51662
|
async function handleRollbackCommand(directory, args) {
|
|
51704
51663
|
const phaseArg = args[0];
|
|
51705
51664
|
if (!phaseArg) {
|
|
@@ -51764,8 +51723,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
51764
51723
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
51765
51724
|
continue;
|
|
51766
51725
|
}
|
|
51767
|
-
const src =
|
|
51768
|
-
const dest =
|
|
51726
|
+
const src = path43.join(checkpointDir, file3);
|
|
51727
|
+
const dest = path43.join(swarmDir, file3);
|
|
51769
51728
|
try {
|
|
51770
51729
|
fs26.cpSync(src, dest, { recursive: true, force: true });
|
|
51771
51730
|
successes.push(file3);
|
|
@@ -51784,12 +51743,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
51784
51743
|
].join(`
|
|
51785
51744
|
`);
|
|
51786
51745
|
}
|
|
51787
|
-
const existingLedgerPath =
|
|
51746
|
+
const existingLedgerPath = path43.join(swarmDir, "plan-ledger.jsonl");
|
|
51788
51747
|
if (fs26.existsSync(existingLedgerPath)) {
|
|
51789
51748
|
fs26.unlinkSync(existingLedgerPath);
|
|
51790
51749
|
}
|
|
51791
51750
|
try {
|
|
51792
|
-
const planJsonPath =
|
|
51751
|
+
const planJsonPath = path43.join(swarmDir, "plan.json");
|
|
51793
51752
|
if (fs26.existsSync(planJsonPath)) {
|
|
51794
51753
|
const planRaw = fs26.readFileSync(planJsonPath, "utf-8");
|
|
51795
51754
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -51880,9 +51839,9 @@ Ensure this is a git repository with commit history.`;
|
|
|
51880
51839
|
`);
|
|
51881
51840
|
try {
|
|
51882
51841
|
const fs27 = await import("fs/promises");
|
|
51883
|
-
const
|
|
51884
|
-
const reportPath =
|
|
51885
|
-
await fs27.mkdir(
|
|
51842
|
+
const path44 = await import("path");
|
|
51843
|
+
const reportPath = path44.join(directory, ".swarm", "simulate-report.md");
|
|
51844
|
+
await fs27.mkdir(path44.dirname(reportPath), { recursive: true });
|
|
51886
51845
|
await fs27.writeFile(reportPath, report, "utf-8");
|
|
51887
51846
|
} catch (err) {
|
|
51888
51847
|
const writeErr = err instanceof Error ? err.message : String(err);
|
|
@@ -51906,12 +51865,12 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
51906
51865
|
|
|
51907
51866
|
// src/turbo/lean/state.ts
|
|
51908
51867
|
import * as fs27 from "fs";
|
|
51909
|
-
import * as
|
|
51868
|
+
import * as path44 from "path";
|
|
51910
51869
|
function nowISO2() {
|
|
51911
51870
|
return new Date().toISOString();
|
|
51912
51871
|
}
|
|
51913
51872
|
function ensureSwarmDir2(directory) {
|
|
51914
|
-
const swarmDir =
|
|
51873
|
+
const swarmDir = path44.resolve(directory, ".swarm");
|
|
51915
51874
|
if (!fs27.existsSync(swarmDir)) {
|
|
51916
51875
|
fs27.mkdirSync(swarmDir, { recursive: true });
|
|
51917
51876
|
}
|
|
@@ -51955,7 +51914,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
51955
51914
|
}
|
|
51956
51915
|
function readPersisted2(directory) {
|
|
51957
51916
|
try {
|
|
51958
|
-
const filePath =
|
|
51917
|
+
const filePath = path44.join(directory, ".swarm", STATE_FILE2);
|
|
51959
51918
|
if (!fs27.existsSync(filePath)) {
|
|
51960
51919
|
const seed = emptyPersisted2();
|
|
51961
51920
|
try {
|
|
@@ -51991,7 +51950,7 @@ function writePersisted2(directory, persisted) {
|
|
|
51991
51950
|
let payload;
|
|
51992
51951
|
try {
|
|
51993
51952
|
ensureSwarmDir2(directory);
|
|
51994
|
-
filePath =
|
|
51953
|
+
filePath = path44.join(directory, ".swarm", STATE_FILE2);
|
|
51995
51954
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
51996
51955
|
persisted.updatedAt = nowISO2();
|
|
51997
51956
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -52118,10 +52077,10 @@ var init_context_budget_service = __esm(() => {
|
|
|
52118
52077
|
|
|
52119
52078
|
// src/services/status-service.ts
|
|
52120
52079
|
import * as fsSync2 from "fs";
|
|
52121
|
-
import * as
|
|
52080
|
+
import * as path45 from "path";
|
|
52122
52081
|
function readSpecStalenessSnapshot(directory) {
|
|
52123
52082
|
try {
|
|
52124
|
-
const p =
|
|
52083
|
+
const p = path45.join(directory, ".swarm", "spec-staleness.json");
|
|
52125
52084
|
if (!fsSync2.existsSync(p))
|
|
52126
52085
|
return { stale: false };
|
|
52127
52086
|
const raw = fsSync2.readFileSync(p, "utf-8");
|
|
@@ -52647,7 +52606,7 @@ var init_write_retro2 = __esm(() => {
|
|
|
52647
52606
|
|
|
52648
52607
|
// src/commands/command-dispatch.ts
|
|
52649
52608
|
import fs28 from "fs";
|
|
52650
|
-
import
|
|
52609
|
+
import path46 from "path";
|
|
52651
52610
|
function normalizeSwarmCommandInput(command, argumentText) {
|
|
52652
52611
|
if (command !== "swarm" && !command.startsWith("swarm-")) {
|
|
52653
52612
|
return { isSwarmCommand: false, tokens: [] };
|
|
@@ -52683,9 +52642,9 @@ ${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
|
|
|
52683
52642
|
`);
|
|
52684
52643
|
}
|
|
52685
52644
|
function maybeMarkFirstRun(directory) {
|
|
52686
|
-
const sentinelPath =
|
|
52645
|
+
const sentinelPath = path46.join(directory, ".swarm", ".first-run-complete");
|
|
52687
52646
|
try {
|
|
52688
|
-
const swarmDir =
|
|
52647
|
+
const swarmDir = path46.join(directory, ".swarm");
|
|
52689
52648
|
fs28.mkdirSync(swarmDir, { recursive: true });
|
|
52690
52649
|
fs28.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
|
|
52691
52650
|
`, { flag: "wx" });
|
|
@@ -53367,24 +53326,24 @@ function validateAliases() {
|
|
|
53367
53326
|
}
|
|
53368
53327
|
aliasTargets.get(target).push(name);
|
|
53369
53328
|
const visited = new Set;
|
|
53370
|
-
const
|
|
53329
|
+
const path47 = [];
|
|
53371
53330
|
let current = target;
|
|
53372
53331
|
while (current) {
|
|
53373
53332
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
53374
53333
|
if (!currentEntry)
|
|
53375
53334
|
break;
|
|
53376
53335
|
if (visited.has(current)) {
|
|
53377
|
-
const cycleStart =
|
|
53336
|
+
const cycleStart = path47.indexOf(current);
|
|
53378
53337
|
const fullChain = [
|
|
53379
53338
|
name,
|
|
53380
|
-
...
|
|
53339
|
+
...path47.slice(0, cycleStart > 0 ? cycleStart : path47.length),
|
|
53381
53340
|
current
|
|
53382
53341
|
].join(" \u2192 ");
|
|
53383
53342
|
errors5.push(`Circular alias detected: ${fullChain}`);
|
|
53384
53343
|
break;
|
|
53385
53344
|
}
|
|
53386
53345
|
visited.add(current);
|
|
53387
|
-
|
|
53346
|
+
path47.push(current);
|
|
53388
53347
|
current = currentEntry.aliasOf || "";
|
|
53389
53348
|
}
|
|
53390
53349
|
}
|
|
@@ -53895,53 +53854,53 @@ init_cache_paths();
|
|
|
53895
53854
|
init_constants();
|
|
53896
53855
|
import * as fs29 from "fs";
|
|
53897
53856
|
import * as os7 from "os";
|
|
53898
|
-
import * as
|
|
53857
|
+
import * as path47 from "path";
|
|
53899
53858
|
var { version: version4 } = package_default;
|
|
53900
53859
|
var CONFIG_DIR = getPluginConfigDir();
|
|
53901
|
-
var OPENCODE_CONFIG_PATH =
|
|
53902
|
-
var PLUGIN_CONFIG_PATH =
|
|
53903
|
-
var PROMPTS_DIR =
|
|
53860
|
+
var OPENCODE_CONFIG_PATH = path47.join(CONFIG_DIR, "opencode.json");
|
|
53861
|
+
var PLUGIN_CONFIG_PATH = path47.join(CONFIG_DIR, "opencode-swarm.json");
|
|
53862
|
+
var PROMPTS_DIR = path47.join(CONFIG_DIR, "opencode-swarm");
|
|
53904
53863
|
var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
53905
53864
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
53906
53865
|
function isSafeCachePath(p) {
|
|
53907
|
-
const resolved =
|
|
53908
|
-
const home =
|
|
53866
|
+
const resolved = path47.resolve(p);
|
|
53867
|
+
const home = path47.resolve(os7.homedir());
|
|
53909
53868
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
53910
53869
|
return false;
|
|
53911
53870
|
}
|
|
53912
|
-
const segments = resolved.split(
|
|
53871
|
+
const segments = resolved.split(path47.sep).filter((s) => s.length > 0);
|
|
53913
53872
|
if (segments.length < 4) {
|
|
53914
53873
|
return false;
|
|
53915
53874
|
}
|
|
53916
|
-
const leaf =
|
|
53875
|
+
const leaf = path47.basename(resolved);
|
|
53917
53876
|
if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
|
|
53918
53877
|
return false;
|
|
53919
53878
|
}
|
|
53920
|
-
const parent =
|
|
53879
|
+
const parent = path47.basename(path47.dirname(resolved));
|
|
53921
53880
|
if (parent !== "packages" && parent !== "node_modules") {
|
|
53922
53881
|
return false;
|
|
53923
53882
|
}
|
|
53924
|
-
const grandparent =
|
|
53883
|
+
const grandparent = path47.basename(path47.dirname(path47.dirname(resolved)));
|
|
53925
53884
|
if (grandparent !== "opencode") {
|
|
53926
53885
|
return false;
|
|
53927
53886
|
}
|
|
53928
53887
|
return true;
|
|
53929
53888
|
}
|
|
53930
53889
|
function isSafeLockFilePath(p) {
|
|
53931
|
-
const resolved =
|
|
53932
|
-
const home =
|
|
53890
|
+
const resolved = path47.resolve(p);
|
|
53891
|
+
const home = path47.resolve(os7.homedir());
|
|
53933
53892
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
53934
53893
|
return false;
|
|
53935
53894
|
}
|
|
53936
|
-
const segments = resolved.split(
|
|
53895
|
+
const segments = resolved.split(path47.sep).filter((s) => s.length > 0);
|
|
53937
53896
|
if (segments.length < 4) {
|
|
53938
53897
|
return false;
|
|
53939
53898
|
}
|
|
53940
|
-
const leaf =
|
|
53899
|
+
const leaf = path47.basename(resolved);
|
|
53941
53900
|
if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
|
|
53942
53901
|
return false;
|
|
53943
53902
|
}
|
|
53944
|
-
const parent =
|
|
53903
|
+
const parent = path47.basename(path47.dirname(resolved));
|
|
53945
53904
|
if (parent !== "opencode") {
|
|
53946
53905
|
return false;
|
|
53947
53906
|
}
|
|
@@ -53967,8 +53926,8 @@ function saveJson(filepath, data) {
|
|
|
53967
53926
|
}
|
|
53968
53927
|
function writeProjectConfigIfMissing(cwd) {
|
|
53969
53928
|
try {
|
|
53970
|
-
const opencodeDir =
|
|
53971
|
-
const projectConfigPath =
|
|
53929
|
+
const opencodeDir = path47.join(cwd, ".opencode");
|
|
53930
|
+
const projectConfigPath = path47.join(opencodeDir, "opencode-swarm.json");
|
|
53972
53931
|
if (fs29.existsSync(projectConfigPath)) {
|
|
53973
53932
|
return;
|
|
53974
53933
|
}
|
|
@@ -53985,7 +53944,7 @@ async function install() {
|
|
|
53985
53944
|
`);
|
|
53986
53945
|
ensureDir(CONFIG_DIR);
|
|
53987
53946
|
ensureDir(PROMPTS_DIR);
|
|
53988
|
-
const LEGACY_CONFIG_PATH =
|
|
53947
|
+
const LEGACY_CONFIG_PATH = path47.join(CONFIG_DIR, "config.json");
|
|
53989
53948
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
53990
53949
|
if (!opencodeConfig) {
|
|
53991
53950
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|