opencode-swarm 7.109.2 → 7.109.3
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/.opencode/skills/ci-failure-batching/SKILL.md +39 -0
- package/.opencode/skills/gate-attribution/SKILL.md +31 -0
- package/.opencode/skills/merge-queue-readiness/SKILL.md +37 -0
- package/.opencode/skills/skill-edit-validation/SKILL.md +29 -0
- package/.opencode/skills/worktree-retry-cleanup/SKILL.md +24 -0
- package/dist/cli/{curator-6p9tpprq.js → curator-9q3m25va.js} +6 -6
- package/dist/cli/{curator-llm-factory-wqbm9mwr.js → curator-llm-factory-78dyv010.js} +6 -6
- package/dist/cli/{guardrail-explain-ynge4ww3.js → guardrail-explain-csnawe0d.js} +7 -7
- package/dist/cli/{hive-promoter-qh2rh8x2.js → hive-promoter-xnx734y3.js} +6 -6
- package/dist/cli/{index-3qwaydq1.js → index-3nd7bz90.js} +7 -7
- package/dist/cli/{index-fz1jgbvw.js → index-41fgssqr.js} +22 -2
- package/dist/cli/{index-wg0665ft.js → index-8f10r7ay.js} +2 -2
- package/dist/cli/{index-9qxntjtx.js → index-b15qbvph.js} +190 -41
- package/dist/cli/{index-5gnp8fyw.js → index-mtzjbaaa.js} +3 -3
- package/dist/cli/{index-8a8b5wjf.js → index-r9dbs4zr.js} +1 -1
- package/dist/cli/{index-cqbqynzp.js → index-xyz8epk6.js} +643 -548
- package/dist/cli/{index-mmny81g1.js → index-y5z2qdvk.js} +1 -1
- package/dist/cli/index.js +6 -6
- package/dist/cli/{knowledge-escalator-6v7sjprx.js → knowledge-escalator-9ksrgq7h.js} +3 -3
- package/dist/cli/{knowledge-events-6n3x3he2.js → knowledge-events-ymysgtrr.js} +1 -1
- package/dist/cli/{knowledge-store-exkw6yb1.js → knowledge-store-562fefjy.js} +1 -1
- package/dist/cli/{knowledge-validator-exymfcb9.js → knowledge-validator-b9nvmzjc.js} +4 -2
- package/dist/cli/{skill-generator-mx9br4ty.js → skill-generator-mjfqvnn0.js} +15 -5
- package/dist/config/bundled-skills.d.ts +1 -1
- package/dist/hooks/knowledge-types.d.ts +6 -0
- package/dist/hooks/knowledge-validator.d.ts +5 -0
- package/dist/hooks/skill-invalidator.d.ts +48 -0
- package/dist/index.js +215 -214
- package/dist/services/skill-generator.d.ts +47 -2
- package/dist/tools/knowledge-remove.d.ts +3 -8
- package/package.json +6 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
import {
|
|
3
3
|
readRecentEscalations
|
|
4
|
-
} from "./index-
|
|
4
|
+
} from "./index-mtzjbaaa.js";
|
|
5
5
|
import {
|
|
6
6
|
getGlobalEventBus
|
|
7
7
|
} from "./index-c8s9a3zh.js";
|
|
@@ -102,6 +102,8 @@ import {
|
|
|
102
102
|
appendSkillChangelog,
|
|
103
103
|
autoApplyProposals,
|
|
104
104
|
evaluateSkillChange,
|
|
105
|
+
findSkillsBySourceKnowledgeId,
|
|
106
|
+
findStaleSkillsBySourceKnowledgeId,
|
|
105
107
|
generateSkills,
|
|
106
108
|
listSkills,
|
|
107
109
|
parseDraftFrontmatter,
|
|
@@ -109,14 +111,15 @@ import {
|
|
|
109
111
|
retireOrMarkStale,
|
|
110
112
|
retireSkill,
|
|
111
113
|
selectCandidateEntries
|
|
112
|
-
} from "./index-
|
|
114
|
+
} from "./index-b15qbvph.js";
|
|
113
115
|
import {
|
|
114
116
|
effectiveRetrievalOutcomes,
|
|
115
117
|
readKnowledgeCounterRollups,
|
|
116
118
|
readKnowledgeEvents,
|
|
119
|
+
recordHiveKnowledgeEvent,
|
|
117
120
|
recordKnowledgeEvent,
|
|
118
121
|
resolveKnowledgeEventsPath
|
|
119
|
-
} from "./index-
|
|
122
|
+
} from "./index-y5z2qdvk.js";
|
|
120
123
|
import {
|
|
121
124
|
appendUnactionable,
|
|
122
125
|
quarantineEntry,
|
|
@@ -126,7 +129,7 @@ import {
|
|
|
126
129
|
validateActionability,
|
|
127
130
|
validateActionableFields,
|
|
128
131
|
validateLesson
|
|
129
|
-
} from "./index-
|
|
132
|
+
} from "./index-41fgssqr.js";
|
|
130
133
|
import {
|
|
131
134
|
appendKnowledge,
|
|
132
135
|
appendRejectedLesson,
|
|
@@ -148,7 +151,7 @@ import {
|
|
|
148
151
|
rewriteKnowledge,
|
|
149
152
|
transactFile,
|
|
150
153
|
transactKnowledge
|
|
151
|
-
} from "./index-
|
|
154
|
+
} from "./index-8f10r7ay.js";
|
|
152
155
|
import {
|
|
153
156
|
isLinked,
|
|
154
157
|
readLinkPointer,
|
|
@@ -211,7 +214,7 @@ import {
|
|
|
211
214
|
|
|
212
215
|
// src/state.ts
|
|
213
216
|
import * as fs30 from "fs/promises";
|
|
214
|
-
import * as
|
|
217
|
+
import * as path66 from "path";
|
|
215
218
|
|
|
216
219
|
// src/db/qa-gate-profile.ts
|
|
217
220
|
import { createHash } from "crypto";
|
|
@@ -4958,7 +4961,12 @@ var BUNDLED_PROJECT_SKILLS = [
|
|
|
4958
4961
|
"writing-tests",
|
|
4959
4962
|
"running-tests",
|
|
4960
4963
|
"engineering-conventions",
|
|
4961
|
-
"commit-pr"
|
|
4964
|
+
"commit-pr",
|
|
4965
|
+
"worktree-retry-cleanup",
|
|
4966
|
+
"skill-edit-validation",
|
|
4967
|
+
"merge-queue-readiness",
|
|
4968
|
+
"gate-attribution",
|
|
4969
|
+
"ci-failure-batching"
|
|
4962
4970
|
];
|
|
4963
4971
|
var MAX_SKILL_FILES = 64;
|
|
4964
4972
|
var MAX_SKILL_BYTES = 512000;
|
|
@@ -6484,7 +6492,7 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
6484
6492
|
import * as child_process2 from "child_process";
|
|
6485
6493
|
import * as fsSync from "fs";
|
|
6486
6494
|
import { promises as fs9 } from "fs";
|
|
6487
|
-
import
|
|
6495
|
+
import path28 from "path";
|
|
6488
6496
|
|
|
6489
6497
|
// src/hooks/curator-postmortem.ts
|
|
6490
6498
|
import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync4 } from "fs";
|
|
@@ -7203,11 +7211,11 @@ var _internals7 = {
|
|
|
7203
7211
|
return KnowledgeConfigSchema2.parse({});
|
|
7204
7212
|
},
|
|
7205
7213
|
applyCuratorKnowledgeUpdates: async (directory, recommendations, knowledgeConfig) => {
|
|
7206
|
-
const { applyCuratorKnowledgeUpdates } = await import("./curator-
|
|
7214
|
+
const { applyCuratorKnowledgeUpdates } = await import("./curator-9q3m25va.js");
|
|
7207
7215
|
return applyCuratorKnowledgeUpdates(directory, recommendations, knowledgeConfig);
|
|
7208
7216
|
},
|
|
7209
7217
|
checkHivePromotions: async (entries, knowledgeConfig) => {
|
|
7210
|
-
const { checkHivePromotions } = await import("./hive-promoter-
|
|
7218
|
+
const { checkHivePromotions } = await import("./hive-promoter-xnx734y3.js");
|
|
7211
7219
|
return checkHivePromotions(entries, knowledgeConfig);
|
|
7212
7220
|
},
|
|
7213
7221
|
applyProposalTriage: async (directory, triage) => {
|
|
@@ -7216,7 +7224,7 @@ var _internals7 = {
|
|
|
7216
7224
|
activateProposal,
|
|
7217
7225
|
listSkills: listSkills2,
|
|
7218
7226
|
sanitizeSlug
|
|
7219
|
-
} = await import("./skill-generator-
|
|
7227
|
+
} = await import("./skill-generator-mjfqvnn0.js");
|
|
7220
7228
|
const result = {
|
|
7221
7229
|
approved: [],
|
|
7222
7230
|
rejected: [],
|
|
@@ -7233,7 +7241,8 @@ var _internals7 = {
|
|
|
7233
7241
|
if (item.action === "apply") {
|
|
7234
7242
|
const activation = await activateProposal(directory, slug, false, {
|
|
7235
7243
|
evaluate: true,
|
|
7236
|
-
operation: "post_mortem_queue_triage"
|
|
7244
|
+
operation: "post_mortem_queue_triage",
|
|
7245
|
+
confirmUnevaluated: true
|
|
7237
7246
|
});
|
|
7238
7247
|
if (activation.activated) {
|
|
7239
7248
|
result.approved.push(slug);
|
|
@@ -7264,12 +7273,12 @@ var _internals7 = {
|
|
|
7264
7273
|
};
|
|
7265
7274
|
|
|
7266
7275
|
// src/hooks/hive-promoter.ts
|
|
7267
|
-
import
|
|
7276
|
+
import path17 from "path";
|
|
7268
7277
|
|
|
7269
7278
|
// src/hooks/curator.ts
|
|
7270
7279
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
7271
7280
|
import * as fs5 from "fs";
|
|
7272
|
-
import * as
|
|
7281
|
+
import * as path16 from "path";
|
|
7273
7282
|
|
|
7274
7283
|
// src/services/learning-metrics.ts
|
|
7275
7284
|
var SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
|
|
@@ -8087,10 +8096,69 @@ var _internals8 = {
|
|
|
8087
8096
|
// src/hooks/curator.ts
|
|
8088
8097
|
init_logger();
|
|
8089
8098
|
|
|
8099
|
+
// src/hooks/skill-invalidator.ts
|
|
8100
|
+
import * as path14 from "path";
|
|
8101
|
+
init_logger();
|
|
8102
|
+
async function writeArchiveTombstoneAndInvalidateSkills(ctx) {
|
|
8103
|
+
const label = ctx.sourceLabel ?? "skill-invalidator";
|
|
8104
|
+
if (!ctx.skipTombstone) {
|
|
8105
|
+
const tombstone = {
|
|
8106
|
+
type: "archived",
|
|
8107
|
+
entry_id: ctx.entryId,
|
|
8108
|
+
tier: ctx.tier,
|
|
8109
|
+
actor: ctx.actor,
|
|
8110
|
+
reason: ctx.reason,
|
|
8111
|
+
mode: ctx.mode,
|
|
8112
|
+
evidence: ctx.evidence,
|
|
8113
|
+
previous_status: ctx.previousStatus
|
|
8114
|
+
};
|
|
8115
|
+
if (ctx.tier === "hive") {
|
|
8116
|
+
await recordHiveKnowledgeEvent(tombstone);
|
|
8117
|
+
} else {
|
|
8118
|
+
await recordKnowledgeEvent(ctx.directory, tombstone);
|
|
8119
|
+
}
|
|
8120
|
+
}
|
|
8121
|
+
const allArchivedIds = ctx.precomputedArchivedIds ? new Set(ctx.precomputedArchivedIds) : await getArchivedKnowledgeIds(ctx.directory);
|
|
8122
|
+
allArchivedIds.add(ctx.entryId);
|
|
8123
|
+
queueMicrotask(async () => {
|
|
8124
|
+
try {
|
|
8125
|
+
const affectedSkillDirs = await findSkillsBySourceKnowledgeId(ctx.directory, ctx.entryId);
|
|
8126
|
+
const staleSkillDirs = await findStaleSkillsBySourceKnowledgeId(ctx.directory, allArchivedIds);
|
|
8127
|
+
const allSkillDirs = new Set([...affectedSkillDirs, ...staleSkillDirs]);
|
|
8128
|
+
if (allSkillDirs.size === 0)
|
|
8129
|
+
return;
|
|
8130
|
+
const slugSet = new Set;
|
|
8131
|
+
let retiredCount = 0;
|
|
8132
|
+
let staleCount = 0;
|
|
8133
|
+
for (const skillDir of allSkillDirs) {
|
|
8134
|
+
const slug = path14.basename(skillDir);
|
|
8135
|
+
if (slugSet.has(slug))
|
|
8136
|
+
continue;
|
|
8137
|
+
slugSet.add(slug);
|
|
8138
|
+
const result = await retireOrMarkStale(ctx.directory, skillDir, allArchivedIds);
|
|
8139
|
+
if (result.action === "retire")
|
|
8140
|
+
retiredCount++;
|
|
8141
|
+
else
|
|
8142
|
+
staleCount++;
|
|
8143
|
+
}
|
|
8144
|
+
const batchEvent = {
|
|
8145
|
+
type: "skill-stale-batch",
|
|
8146
|
+
skillIds: Array.from(slugSet),
|
|
8147
|
+
archivedIds: Array.from(allArchivedIds),
|
|
8148
|
+
retiredCount,
|
|
8149
|
+
staleCount
|
|
8150
|
+
};
|
|
8151
|
+
await recordKnowledgeEvent(ctx.directory, batchEvent);
|
|
8152
|
+
} catch (err) {
|
|
8153
|
+
warn(`[${label}] post-archive skill invalidation failed for entry '${ctx.entryId}': ${err instanceof Error ? err.message : String(err)}`);
|
|
8154
|
+
}
|
|
8155
|
+
});
|
|
8156
|
+
}
|
|
8157
|
+
|
|
8090
8158
|
// src/hooks/skill-usage-log.ts
|
|
8091
8159
|
import * as crypto2 from "crypto";
|
|
8092
8160
|
import * as fs4 from "fs";
|
|
8093
|
-
import * as
|
|
8161
|
+
import * as path15 from "path";
|
|
8094
8162
|
function resolveLogPath(directory) {
|
|
8095
8163
|
return validateSwarmPath(directory, "skill-usage.jsonl");
|
|
8096
8164
|
}
|
|
@@ -8189,7 +8257,7 @@ function appendFeedbackAppliedMarker(directory, processedEntryIds) {
|
|
|
8189
8257
|
if (processedEntryIds.length === 0)
|
|
8190
8258
|
return;
|
|
8191
8259
|
const resolved = resolveLogPath(directory);
|
|
8192
|
-
const dir =
|
|
8260
|
+
const dir = path15.dirname(resolved);
|
|
8193
8261
|
if (!_internals9.existsSync(dir)) {
|
|
8194
8262
|
_internals9.mkdirSync(dir, { recursive: true });
|
|
8195
8263
|
}
|
|
@@ -8234,7 +8302,7 @@ function appendSkillUsageEntry(directory, entry) {
|
|
|
8234
8302
|
throw new Error("sessionID is required and must be a non-empty string");
|
|
8235
8303
|
}
|
|
8236
8304
|
const resolved = validateSwarmPath(directory, "skill-usage.jsonl");
|
|
8237
|
-
const dir =
|
|
8305
|
+
const dir = path15.dirname(resolved);
|
|
8238
8306
|
if (!_internals9.existsSync(dir)) {
|
|
8239
8307
|
_internals9.mkdirSync(dir, { recursive: true });
|
|
8240
8308
|
}
|
|
@@ -8410,8 +8478,8 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
8410
8478
|
}
|
|
8411
8479
|
if (entries.length === 0) {
|
|
8412
8480
|
if (preservedMarkers.length > 0) {
|
|
8413
|
-
const dir2 =
|
|
8414
|
-
const tmpPath2 =
|
|
8481
|
+
const dir2 = path15.dirname(resolved);
|
|
8482
|
+
const tmpPath2 = path15.join(dir2, `skill-usage-${Date.now()}.tmp`);
|
|
8415
8483
|
const content2 = preservedMarkers.join(`
|
|
8416
8484
|
`).concat(preservedMarkers.length > 0 ? `
|
|
8417
8485
|
` : "");
|
|
@@ -8453,8 +8521,8 @@ function pruneSkillUsageLog(directory, maxEntriesPerSkill = 500) {
|
|
|
8453
8521
|
if (pruned === 0) {
|
|
8454
8522
|
return { pruned: 0, remaining: entries.length };
|
|
8455
8523
|
}
|
|
8456
|
-
const dir =
|
|
8457
|
-
const tmpPath =
|
|
8524
|
+
const dir = path15.dirname(resolved);
|
|
8525
|
+
const tmpPath = path15.join(dir, `skill-usage-${Date.now()}.tmp`);
|
|
8458
8526
|
const entryLines = surviving.map((e) => JSON.stringify(e));
|
|
8459
8527
|
const allLines = [...entryLines, ...preservedMarkers];
|
|
8460
8528
|
const content = allLines.join(`
|
|
@@ -8483,9 +8551,9 @@ async function resolveSourceKnowledgeIds(directory, skillPath) {
|
|
|
8483
8551
|
if (/\.\.[/\\]/.test(cleanPath)) {
|
|
8484
8552
|
return [];
|
|
8485
8553
|
}
|
|
8486
|
-
const absolute =
|
|
8487
|
-
const baseDir =
|
|
8488
|
-
const isContained = process.platform === "win32" ? absolute.toLowerCase().startsWith((baseDir +
|
|
8554
|
+
const absolute = path15.normalize(path15.isAbsolute(cleanPath) ? cleanPath : path15.resolve(directory, cleanPath));
|
|
8555
|
+
const baseDir = path15.normalize(path15.resolve(directory));
|
|
8556
|
+
const isContained = process.platform === "win32" ? absolute.toLowerCase().startsWith((baseDir + path15.sep).toLowerCase()) : absolute.startsWith(baseDir + path15.sep);
|
|
8489
8557
|
if (!isContained) {
|
|
8490
8558
|
return [];
|
|
8491
8559
|
}
|
|
@@ -8679,7 +8747,7 @@ async function autoRetireSkills(directory, _curatorKnowledgePath, excludeSlugs)
|
|
|
8679
8747
|
}
|
|
8680
8748
|
}
|
|
8681
8749
|
if (archivedSourceMatched) {
|
|
8682
|
-
const result = await _internals10.retireOrMarkStale(directory,
|
|
8750
|
+
const result = await _internals10.retireOrMarkStale(directory, path16.dirname(active.path), allArchivedIds);
|
|
8683
8751
|
if (result.action === "retire") {
|
|
8684
8752
|
observations.push(`Skill '${active.slug}' auto-retired: all source knowledge entries archived`);
|
|
8685
8753
|
warn(`[curator] ${observations[observations.length - 1]}`);
|
|
@@ -8876,11 +8944,11 @@ function arrayOfStrings(v) {
|
|
|
8876
8944
|
}
|
|
8877
8945
|
function readLatestPostMortemDigest(directory) {
|
|
8878
8946
|
try {
|
|
8879
|
-
const swarmDir =
|
|
8947
|
+
const swarmDir = path16.join(directory, ".swarm");
|
|
8880
8948
|
if (!fs5.existsSync(swarmDir))
|
|
8881
8949
|
return null;
|
|
8882
8950
|
const candidates = fs5.readdirSync(swarmDir).filter((name) => /^post-mortem-[^/\\]+\.md$/.test(name)).map((name) => {
|
|
8883
|
-
const filePath =
|
|
8951
|
+
const filePath = path16.join(swarmDir, name);
|
|
8884
8952
|
return { name, filePath, mtimeMs: fs5.statSync(filePath).mtimeMs };
|
|
8885
8953
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
8886
8954
|
const latest = candidates[0];
|
|
@@ -8923,7 +8991,7 @@ async function readCuratorSummary(directory) {
|
|
|
8923
8991
|
}
|
|
8924
8992
|
async function writeCuratorSummary(directory, summary) {
|
|
8925
8993
|
const resolvedPath = validateSwarmPath(directory, "curator-summary.json");
|
|
8926
|
-
fs5.mkdirSync(
|
|
8994
|
+
fs5.mkdirSync(path16.dirname(resolvedPath), { recursive: true });
|
|
8927
8995
|
await bunWrite(resolvedPath, JSON.stringify(summary, null, 2));
|
|
8928
8996
|
}
|
|
8929
8997
|
function normalizeAgentName(name) {
|
|
@@ -9363,15 +9431,15 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
|
|
|
9363
9431
|
await _internals10.writeCuratorSummary(directory, updatedSummary);
|
|
9364
9432
|
if (knowledgeApplicationFindings.length > 0) {
|
|
9365
9433
|
try {
|
|
9366
|
-
const evidenceDir =
|
|
9434
|
+
const evidenceDir = path16.join(directory, ".swarm", "evidence", String(phase));
|
|
9367
9435
|
fs5.mkdirSync(evidenceDir, { recursive: true });
|
|
9368
|
-
const findingsPath =
|
|
9436
|
+
const findingsPath = path16.join(evidenceDir, "curator-findings.json");
|
|
9369
9437
|
await bunWrite(findingsPath, JSON.stringify({ findings: knowledgeApplicationFindings }, null, 2));
|
|
9370
9438
|
} catch (err) {
|
|
9371
9439
|
warn(`[curator] failed to persist application findings: ${err instanceof Error ? err.message : String(err)}`);
|
|
9372
9440
|
}
|
|
9373
9441
|
}
|
|
9374
|
-
const eventsPath =
|
|
9442
|
+
const eventsPath = path16.join(directory, ".swarm", "events.jsonl");
|
|
9375
9443
|
for (const obs of complianceObservations) {
|
|
9376
9444
|
await appendKnowledge(eventsPath, {
|
|
9377
9445
|
type: "curator_compliance",
|
|
@@ -9384,7 +9452,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
|
|
|
9384
9452
|
}
|
|
9385
9453
|
if (config.skill_generation_enabled === true && skillCandidates.length > 0) {
|
|
9386
9454
|
try {
|
|
9387
|
-
const skillModule = await import("./skill-generator-
|
|
9455
|
+
const skillModule = await import("./skill-generator-mjfqvnn0.js");
|
|
9388
9456
|
for (const cand of skillCandidates) {
|
|
9389
9457
|
if (cand.confidence < (config.min_skill_confidence ?? DEFAULT_SKILL_MIN_CONFIDENCE)) {
|
|
9390
9458
|
continue;
|
|
@@ -9552,10 +9620,12 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
|
|
|
9552
9620
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
9553
9621
|
const appliedIds = new Set;
|
|
9554
9622
|
const foundIds = new Set;
|
|
9623
|
+
const archivedPrevStatus = new Map;
|
|
9555
9624
|
const contradictedEntries = [];
|
|
9556
9625
|
await transactKnowledge(knowledgePath, (entries) => {
|
|
9557
9626
|
appliedIds.clear();
|
|
9558
9627
|
foundIds.clear();
|
|
9628
|
+
archivedPrevStatus.clear();
|
|
9559
9629
|
contradictedEntries.length = 0;
|
|
9560
9630
|
let txApplied = 0;
|
|
9561
9631
|
let modified = false;
|
|
@@ -9581,6 +9651,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
|
|
|
9581
9651
|
return entry;
|
|
9582
9652
|
}
|
|
9583
9653
|
appliedIds.add(entry.id);
|
|
9654
|
+
archivedPrevStatus.set(entry.id, entry.status);
|
|
9584
9655
|
txApplied++;
|
|
9585
9656
|
modified = true;
|
|
9586
9657
|
return {
|
|
@@ -9654,7 +9725,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
|
|
|
9654
9725
|
} catch {}
|
|
9655
9726
|
}
|
|
9656
9727
|
if (contradictedEntries.length > 0 && knowledgeConfig.contradiction_threshold_action === "quarantine") {
|
|
9657
|
-
const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-
|
|
9728
|
+
const { maybeQuarantineOnContradiction } = await import("./knowledge-escalator-9ksrgq7h.js");
|
|
9658
9729
|
for (const { id } of contradictedEntries) {
|
|
9659
9730
|
try {
|
|
9660
9731
|
await maybeQuarantineOnContradiction(directory, id, knowledgeConfig.contradiction_quarantine_threshold, knowledgeConfig.contradiction_quarantine_window_days);
|
|
@@ -9669,6 +9740,25 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
|
|
|
9669
9740
|
skipped++;
|
|
9670
9741
|
}
|
|
9671
9742
|
}
|
|
9743
|
+
const archivedRecs = validRecommendations.filter((r) => r.action === "archive" && r.entry_id && appliedIds.has(r.entry_id));
|
|
9744
|
+
const precomputedArchivedIds = archivedRecs.length > 0 ? await getArchivedKnowledgeIds(directory) : undefined;
|
|
9745
|
+
for (const rec of archivedRecs) {
|
|
9746
|
+
try {
|
|
9747
|
+
await writeArchiveTombstoneAndInvalidateSkills({
|
|
9748
|
+
directory,
|
|
9749
|
+
entryId: rec.entry_id,
|
|
9750
|
+
tier: "swarm",
|
|
9751
|
+
actor: "curator",
|
|
9752
|
+
reason: rec.reason ?? "curator archive recommendation",
|
|
9753
|
+
mode: "archive",
|
|
9754
|
+
previousStatus: archivedPrevStatus.get(rec.entry_id),
|
|
9755
|
+
sourceLabel: "curator",
|
|
9756
|
+
precomputedArchivedIds
|
|
9757
|
+
});
|
|
9758
|
+
} catch (err) {
|
|
9759
|
+
warn(`[curator] archive invalidation for entry '${rec.entry_id}' failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
9760
|
+
}
|
|
9761
|
+
}
|
|
9672
9762
|
const currentEntries = await readKnowledge(knowledgePath);
|
|
9673
9763
|
const currentLessons = currentEntries.map((e) => e.lesson);
|
|
9674
9764
|
for (const rec of validRecommendations) {
|
|
@@ -9718,7 +9808,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
|
|
|
9718
9808
|
created_at: now,
|
|
9719
9809
|
updated_at: now,
|
|
9720
9810
|
auto_generated: true,
|
|
9721
|
-
project_name:
|
|
9811
|
+
project_name: path16.basename(directory)
|
|
9722
9812
|
};
|
|
9723
9813
|
if (!validateActionability(newEntry).actionable) {
|
|
9724
9814
|
try {
|
|
@@ -9964,7 +10054,7 @@ async function promoteToHive(directory, lesson, category) {
|
|
|
9964
10054
|
schema_version: 1,
|
|
9965
10055
|
created_at: new Date().toISOString(),
|
|
9966
10056
|
updated_at: new Date().toISOString(),
|
|
9967
|
-
source_project:
|
|
10057
|
+
source_project: path17.basename(directory) || "unknown",
|
|
9968
10058
|
encounter_score: 1
|
|
9969
10059
|
};
|
|
9970
10060
|
await appendKnowledge(resolveHiveKnowledgePath(), newHiveEntry);
|
|
@@ -10018,7 +10108,7 @@ async function promoteFromSwarm(directory, lessonId) {
|
|
|
10018
10108
|
import { createHash as createHash4 } from "crypto";
|
|
10019
10109
|
import { existsSync as existsSync13 } from "fs";
|
|
10020
10110
|
import { appendFile as appendFile2, mkdir as mkdir6, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
10021
|
-
import * as
|
|
10111
|
+
import * as path22 from "path";
|
|
10022
10112
|
|
|
10023
10113
|
// src/services/synonym-map.ts
|
|
10024
10114
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
@@ -10030,7 +10120,7 @@ import {
|
|
|
10030
10120
|
unlink,
|
|
10031
10121
|
writeFile as writeFile6
|
|
10032
10122
|
} from "fs/promises";
|
|
10033
|
-
import * as
|
|
10123
|
+
import * as path18 from "path";
|
|
10034
10124
|
var SYNONYM_MAP_FILENAME = "synonym-map.json";
|
|
10035
10125
|
var MAX_TOKEN_LENGTH = 64;
|
|
10036
10126
|
var DEFAULT_MAX_PAIRS = 500;
|
|
@@ -10185,7 +10275,7 @@ async function readSynonymMap(directory, maxPairs = DEFAULT_MAX_PAIRS) {
|
|
|
10185
10275
|
}
|
|
10186
10276
|
}
|
|
10187
10277
|
async function writeSynonymMapAtomic(filePath, map) {
|
|
10188
|
-
await mkdir5(
|
|
10278
|
+
await mkdir5(path18.dirname(filePath), { recursive: true });
|
|
10189
10279
|
const tmp = `${filePath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
10190
10280
|
try {
|
|
10191
10281
|
await writeFile6(tmp, JSON.stringify(map, null, 2), "utf-8");
|
|
@@ -10198,7 +10288,7 @@ async function writeSynonymMapAtomic(filePath, map) {
|
|
|
10198
10288
|
}
|
|
10199
10289
|
async function rebuildSynonymMap(directory, entries, maxPairs = DEFAULT_MAX_PAIRS) {
|
|
10200
10290
|
const filePath = resolveSynonymMapPath(directory);
|
|
10201
|
-
const dir =
|
|
10291
|
+
const dir = path18.dirname(filePath);
|
|
10202
10292
|
await mkdir5(dir, { recursive: true });
|
|
10203
10293
|
let release = null;
|
|
10204
10294
|
try {
|
|
@@ -10258,17 +10348,17 @@ function reinforceSwarmKnowledgeEntry(entry, confirmation) {
|
|
|
10258
10348
|
// src/hooks/micro-reflector.ts
|
|
10259
10349
|
import { existsSync as existsSync12 } from "fs";
|
|
10260
10350
|
import { readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
|
|
10261
|
-
import * as
|
|
10351
|
+
import * as path21 from "path";
|
|
10262
10352
|
init_logger();
|
|
10263
10353
|
|
|
10264
10354
|
// src/hooks/skill-propagation-gate.ts
|
|
10265
10355
|
import * as fs7 from "fs";
|
|
10266
|
-
import * as
|
|
10356
|
+
import * as path20 from "path";
|
|
10267
10357
|
init_logger();
|
|
10268
10358
|
|
|
10269
10359
|
// src/hooks/skill-scoring.ts
|
|
10270
10360
|
import * as fs6 from "fs";
|
|
10271
|
-
import * as
|
|
10361
|
+
import * as path19 from "path";
|
|
10272
10362
|
var FREQUENCY_CAP = 10;
|
|
10273
10363
|
var FREQUENCY_WEIGHT = 0.3;
|
|
10274
10364
|
var COMPLIANCE_WEIGHT = 0.3;
|
|
@@ -10296,10 +10386,10 @@ var _internals11 = {
|
|
|
10296
10386
|
computeTriggerMatchBoost: null
|
|
10297
10387
|
};
|
|
10298
10388
|
function extractSkillName(skillPath) {
|
|
10299
|
-
const base =
|
|
10389
|
+
const base = path19.basename(skillPath, path19.extname(skillPath));
|
|
10300
10390
|
if (base !== "SKILL")
|
|
10301
10391
|
return base;
|
|
10302
|
-
const parent =
|
|
10392
|
+
const parent = path19.basename(path19.dirname(skillPath));
|
|
10303
10393
|
return parent;
|
|
10304
10394
|
}
|
|
10305
10395
|
function stripQuotes(value) {
|
|
@@ -10457,12 +10547,12 @@ function readSkillMetadata(skillPath, directory) {
|
|
|
10457
10547
|
const normalizedPath = skillPath.replace(/^file:/, "").replace(/\\/g, "/");
|
|
10458
10548
|
const fallback = parseSkillFrontmatter("", normalizedPath);
|
|
10459
10549
|
try {
|
|
10460
|
-
if (
|
|
10550
|
+
if (path19.isAbsolute(normalizedPath) || normalizedPath.split("/").includes("..")) {
|
|
10461
10551
|
return fallback;
|
|
10462
10552
|
}
|
|
10463
|
-
const root =
|
|
10464
|
-
const absolutePath =
|
|
10465
|
-
if (absolutePath !== root && !absolutePath.startsWith(root +
|
|
10553
|
+
const root = path19.resolve(directory);
|
|
10554
|
+
const absolutePath = path19.resolve(directory, normalizedPath);
|
|
10555
|
+
if (absolutePath !== root && !absolutePath.startsWith(root + path19.sep)) {
|
|
10466
10556
|
return fallback;
|
|
10467
10557
|
}
|
|
10468
10558
|
const content = readFilePrefix(absolutePath);
|
|
@@ -10600,7 +10690,7 @@ function getSkillStats(skillPath, directory) {
|
|
|
10600
10690
|
};
|
|
10601
10691
|
}
|
|
10602
10692
|
function formatSkillIndexWithContext(skills, directory) {
|
|
10603
|
-
const usageLogPath =
|
|
10693
|
+
const usageLogPath = path19.join(directory, ".swarm", "skill-usage.jsonl");
|
|
10604
10694
|
let hasHistory = false;
|
|
10605
10695
|
try {
|
|
10606
10696
|
const stat4 = fs6.statSync(usageLogPath);
|
|
@@ -10734,7 +10824,7 @@ function parseYamlValue(value) {
|
|
|
10734
10824
|
return trimmed;
|
|
10735
10825
|
}
|
|
10736
10826
|
function loadRoutingSkills(directory, targetAgent) {
|
|
10737
|
-
const routingPath =
|
|
10827
|
+
const routingPath = path20.join(directory, ".opencode", "skill-routing.yaml");
|
|
10738
10828
|
if (!_internals12.existsSync(routingPath))
|
|
10739
10829
|
return [];
|
|
10740
10830
|
try {
|
|
@@ -10794,7 +10884,7 @@ var _internals12 = {
|
|
|
10794
10884
|
function discoverAvailableSkills(directory) {
|
|
10795
10885
|
const results = [];
|
|
10796
10886
|
for (const root of SKILL_SEARCH_ROOTS) {
|
|
10797
|
-
const rootPath =
|
|
10887
|
+
const rootPath = path20.join(directory, root);
|
|
10798
10888
|
if (!_internals12.existsSync(rootPath))
|
|
10799
10889
|
continue;
|
|
10800
10890
|
let entries;
|
|
@@ -10806,13 +10896,13 @@ function discoverAvailableSkills(directory) {
|
|
|
10806
10896
|
for (const entry of entries) {
|
|
10807
10897
|
if (entry.startsWith("."))
|
|
10808
10898
|
continue;
|
|
10809
|
-
const skillDir =
|
|
10810
|
-
if (_internals12.existsSync(
|
|
10899
|
+
const skillDir = path20.join(rootPath, entry);
|
|
10900
|
+
if (_internals12.existsSync(path20.join(skillDir, "retired.marker")) || _internals12.existsSync(path20.join(skillDir, "stale.marker")))
|
|
10811
10901
|
continue;
|
|
10812
|
-
const skillFile =
|
|
10902
|
+
const skillFile = path20.join(skillDir, "SKILL.md");
|
|
10813
10903
|
try {
|
|
10814
10904
|
if (_internals12.statSync(skillDir).isDirectory() && _internals12.existsSync(skillFile)) {
|
|
10815
|
-
results.push(
|
|
10905
|
+
results.push(path20.join(root, entry, "SKILL.md").replace(/\\/g, "/"));
|
|
10816
10906
|
}
|
|
10817
10907
|
} catch (err) {
|
|
10818
10908
|
warn(`[skill-propagation-gate] failed to stat skill directory ${entry}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -10881,9 +10971,9 @@ function extractSkillsFieldFromPrompt(prompt) {
|
|
|
10881
10971
|
return "";
|
|
10882
10972
|
}
|
|
10883
10973
|
function writeWarnEvent(directory, record) {
|
|
10884
|
-
const filePath =
|
|
10974
|
+
const filePath = path20.join(directory, ".swarm", "events.jsonl");
|
|
10885
10975
|
try {
|
|
10886
|
-
const dir =
|
|
10976
|
+
const dir = path20.dirname(filePath);
|
|
10887
10977
|
if (!_internals12.existsSync(dir)) {
|
|
10888
10978
|
_internals12.mkdirSync(dir, { recursive: true });
|
|
10889
10979
|
}
|
|
@@ -11012,8 +11102,8 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
11012
11102
|
if (routingPaths.length > 0) {
|
|
11013
11103
|
const existingPaths = new Set(scored.map((s) => s.skillPath));
|
|
11014
11104
|
for (const routingPath of routingPaths) {
|
|
11015
|
-
const routedSkillDir =
|
|
11016
|
-
if (_internals12.existsSync(
|
|
11105
|
+
const routedSkillDir = path20.dirname(path20.join(directory, routingPath));
|
|
11106
|
+
if (_internals12.existsSync(path20.join(routedSkillDir, "retired.marker")) || _internals12.existsSync(path20.join(routedSkillDir, "stale.marker")))
|
|
11017
11107
|
continue;
|
|
11018
11108
|
if (!existingPaths.has(routingPath)) {
|
|
11019
11109
|
scored.push({
|
|
@@ -11032,8 +11122,8 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
11032
11122
|
let skillsForIndex = availableSkills;
|
|
11033
11123
|
if (scoringSkipped) {
|
|
11034
11124
|
skillsForIndex = [...availableSkills].sort((a, b) => {
|
|
11035
|
-
const nameA =
|
|
11036
|
-
const nameB =
|
|
11125
|
+
const nameA = path20.basename(path20.dirname(a));
|
|
11126
|
+
const nameB = path20.basename(path20.dirname(b));
|
|
11037
11127
|
return nameA.localeCompare(nameB);
|
|
11038
11128
|
});
|
|
11039
11129
|
} else if (typeof scored !== "undefined" && scored.length > 0) {
|
|
@@ -11041,7 +11131,7 @@ async function skillPropagationGateBefore(directory, input, config) {
|
|
|
11041
11131
|
}
|
|
11042
11132
|
const formattedIndex = _internals12.formatSkillIndexWithContext(skillsForIndex, directory);
|
|
11043
11133
|
if (formattedIndex.length > 0) {
|
|
11044
|
-
const contextPath =
|
|
11134
|
+
const contextPath = path20.join(directory, ".swarm", "context.md");
|
|
11045
11135
|
let existingContent = "";
|
|
11046
11136
|
if (_internals12.existsSync(contextPath)) {
|
|
11047
11137
|
existingContent = _internals12.readFileSync(contextPath, "utf-8");
|
|
@@ -11063,7 +11153,7 @@ ${newSection}`;
|
|
|
11063
11153
|
updatedContent = existingContent + newSection;
|
|
11064
11154
|
}
|
|
11065
11155
|
}
|
|
11066
|
-
const swarmDir =
|
|
11156
|
+
const swarmDir = path20.dirname(contextPath);
|
|
11067
11157
|
if (!_internals12.existsSync(swarmDir)) {
|
|
11068
11158
|
_internals12.mkdirSync(swarmDir, { recursive: true });
|
|
11069
11159
|
}
|
|
@@ -11289,7 +11379,7 @@ function resolveInsightCandidatesPath(directory) {
|
|
|
11289
11379
|
}
|
|
11290
11380
|
async function readTaskTrajectory(directory, taskId) {
|
|
11291
11381
|
try {
|
|
11292
|
-
const rel =
|
|
11382
|
+
const rel = path21.join("evidence", sanitizeTaskId(taskId), "trajectory.jsonl");
|
|
11293
11383
|
const filePath = validateSwarmPath(directory, rel);
|
|
11294
11384
|
if (!existsSync12(filePath))
|
|
11295
11385
|
return [];
|
|
@@ -11719,8 +11809,8 @@ RETRY: your last output was missing ${result.missing.join("; ")}; produce valid
|
|
|
11719
11809
|
}
|
|
11720
11810
|
async function appendCuratorSkippedEvent(directory, record) {
|
|
11721
11811
|
try {
|
|
11722
|
-
const filePath =
|
|
11723
|
-
await mkdir6(
|
|
11812
|
+
const filePath = path22.join(directory, ".swarm", "events.jsonl");
|
|
11813
|
+
await mkdir6(path22.dirname(filePath), { recursive: true });
|
|
11724
11814
|
await appendFile2(filePath, `${JSON.stringify({
|
|
11725
11815
|
timestamp: new Date().toISOString(),
|
|
11726
11816
|
event: "curator_skipped",
|
|
@@ -12287,7 +12377,7 @@ var _internals14 = {
|
|
|
12287
12377
|
|
|
12288
12378
|
// src/services/session-reflection.ts
|
|
12289
12379
|
import { promises as fs8 } from "fs";
|
|
12290
|
-
import * as
|
|
12380
|
+
import * as path23 from "path";
|
|
12291
12381
|
|
|
12292
12382
|
// src/hooks/abort-utils.ts
|
|
12293
12383
|
function isAbortError(err) {
|
|
@@ -12448,11 +12538,11 @@ async function gatherRetroLessonsAndTaxonomy(directory) {
|
|
|
12448
12538
|
const lessons = [];
|
|
12449
12539
|
const taxonomy = {};
|
|
12450
12540
|
try {
|
|
12451
|
-
const evidenceDir =
|
|
12541
|
+
const evidenceDir = path23.join(directory, ".swarm", "evidence");
|
|
12452
12542
|
const entries = await fs8.readdir(evidenceDir);
|
|
12453
12543
|
const retroDirs = entries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
12454
12544
|
for (const retroDir of retroDirs) {
|
|
12455
|
-
const evidencePath =
|
|
12545
|
+
const evidencePath = path23.join(evidenceDir, retroDir, "evidence.json");
|
|
12456
12546
|
try {
|
|
12457
12547
|
const content = await fs8.readFile(evidencePath, "utf-8");
|
|
12458
12548
|
const parsed = JSON.parse(content);
|
|
@@ -12481,12 +12571,12 @@ async function gatherRetroLessonsAndTaxonomy(directory) {
|
|
|
12481
12571
|
async function gatherGateFailures(directory) {
|
|
12482
12572
|
const failures = new Map;
|
|
12483
12573
|
try {
|
|
12484
|
-
const evidenceDir =
|
|
12574
|
+
const evidenceDir = path23.join(directory, ".swarm", "evidence");
|
|
12485
12575
|
const entries = await fs8.readdir(evidenceDir);
|
|
12486
12576
|
for (const entry of entries) {
|
|
12487
12577
|
if (entry.startsWith("retro-"))
|
|
12488
12578
|
continue;
|
|
12489
|
-
const evidencePath =
|
|
12579
|
+
const evidencePath = path23.join(evidenceDir, entry, "evidence.json");
|
|
12490
12580
|
try {
|
|
12491
12581
|
const content = await fs8.readFile(evidencePath, "utf-8");
|
|
12492
12582
|
const parsed = JSON.parse(content);
|
|
@@ -12687,12 +12777,12 @@ async function writeSessionReflection(directory, result) {
|
|
|
12687
12777
|
// src/services/skill-improver.ts
|
|
12688
12778
|
import { existsSync as existsSync15 } from "fs";
|
|
12689
12779
|
import { mkdir as mkdir8, readFile as readFile9, rename as rename6, writeFile as writeFile10 } from "fs/promises";
|
|
12690
|
-
import * as
|
|
12780
|
+
import * as path25 from "path";
|
|
12691
12781
|
init_logger();
|
|
12692
12782
|
|
|
12693
12783
|
// src/services/trajectory-cluster.ts
|
|
12694
12784
|
import { mkdir as mkdir7, writeFile as writeFile9 } from "fs/promises";
|
|
12695
|
-
import * as
|
|
12785
|
+
import * as path24 from "path";
|
|
12696
12786
|
init_logger();
|
|
12697
12787
|
var MACRO_TRAJECTORY_WINDOW = 200;
|
|
12698
12788
|
var MOTIF_MIN_TASKS = 2;
|
|
@@ -12824,11 +12914,11 @@ async function writeMotifProposals(directory, opts = {}) {
|
|
|
12824
12914
|
if (motifs.length === 0)
|
|
12825
12915
|
return result;
|
|
12826
12916
|
const max = opts.maxProposals ?? 10;
|
|
12827
|
-
const proposalsDir = validateSwarmPath(directory,
|
|
12917
|
+
const proposalsDir = validateSwarmPath(directory, path24.join("skills", "proposals"));
|
|
12828
12918
|
await mkdir7(proposalsDir, { recursive: true });
|
|
12829
12919
|
for (const motif of motifs.slice(0, max)) {
|
|
12830
12920
|
const slug = `motif-${slugify(motif.signature)}`;
|
|
12831
|
-
const filePath =
|
|
12921
|
+
const filePath = path24.join(proposalsDir, `${slug}.md`);
|
|
12832
12922
|
await writeFile9(filePath, buildMotifProposal(motif), "utf-8");
|
|
12833
12923
|
result.proposalsWritten.push(filePath);
|
|
12834
12924
|
}
|
|
@@ -12969,11 +13059,11 @@ async function writeSuccessMotifProposals(directory, opts = {}) {
|
|
|
12969
13059
|
if (motifs.length === 0)
|
|
12970
13060
|
return result;
|
|
12971
13061
|
const max = opts.maxProposals ?? 10;
|
|
12972
|
-
const proposalsDir = validateSwarmPath(directory,
|
|
13062
|
+
const proposalsDir = validateSwarmPath(directory, path24.join("skills", "proposals"));
|
|
12973
13063
|
await mkdir7(proposalsDir, { recursive: true });
|
|
12974
13064
|
for (const motif of motifs.slice(0, max)) {
|
|
12975
13065
|
const slug = workflowSlug(motif.signature);
|
|
12976
|
-
const filePath =
|
|
13066
|
+
const filePath = path24.join(proposalsDir, `${slug}.md`);
|
|
12977
13067
|
await writeFile9(filePath, buildWorkflowProposal(motif), "utf-8");
|
|
12978
13068
|
result.proposalsWritten.push(filePath);
|
|
12979
13069
|
}
|
|
@@ -13096,7 +13186,7 @@ function timestampSlug(d) {
|
|
|
13096
13186
|
return d.toISOString().replace(/[:.]/g, "-");
|
|
13097
13187
|
}
|
|
13098
13188
|
async function atomicWrite(p, content) {
|
|
13099
|
-
await mkdir8(
|
|
13189
|
+
await mkdir8(path25.dirname(p), { recursive: true });
|
|
13100
13190
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
13101
13191
|
await writeFile10(tmp, content, "utf-8");
|
|
13102
13192
|
await rename6(tmp, p);
|
|
@@ -13499,8 +13589,8 @@ async function runSkillImprover(req) {
|
|
|
13499
13589
|
}
|
|
13500
13590
|
throw err;
|
|
13501
13591
|
}
|
|
13502
|
-
const proposalDir =
|
|
13503
|
-
const proposalFile =
|
|
13592
|
+
const proposalDir = path25.join(req.directory, ".swarm", "skill-improver", "proposals");
|
|
13593
|
+
const proposalFile = path25.join(proposalDir, `${timestampSlug(now)}.md`);
|
|
13504
13594
|
const finalBody = source === "llm" ? buildLLMProposalFrame({
|
|
13505
13595
|
body,
|
|
13506
13596
|
targets,
|
|
@@ -13570,13 +13660,13 @@ var _internals15 = {
|
|
|
13570
13660
|
|
|
13571
13661
|
// src/session/session-start-store.ts
|
|
13572
13662
|
import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "fs";
|
|
13573
|
-
import * as
|
|
13663
|
+
import * as path26 from "path";
|
|
13574
13664
|
var SESSION_START_FILE = "session-start.jsonl";
|
|
13575
13665
|
function recordSessionStart(directory, startMs) {
|
|
13576
13666
|
try {
|
|
13577
|
-
const swarmDir =
|
|
13578
|
-
const sessionDir =
|
|
13579
|
-
const filePath =
|
|
13667
|
+
const swarmDir = path26.join(directory, ".swarm");
|
|
13668
|
+
const sessionDir = path26.join(swarmDir, "session");
|
|
13669
|
+
const filePath = path26.join(sessionDir, SESSION_START_FILE);
|
|
13580
13670
|
const line = JSON.stringify({ startMs, ts: Date.now() });
|
|
13581
13671
|
mkdirSync9(sessionDir, { recursive: true });
|
|
13582
13672
|
writeFileSync4(filePath, `${line}
|
|
@@ -13585,7 +13675,7 @@ function recordSessionStart(directory, startMs) {
|
|
|
13585
13675
|
}
|
|
13586
13676
|
function readEarliestSessionStart(directory) {
|
|
13587
13677
|
try {
|
|
13588
|
-
const filePath =
|
|
13678
|
+
const filePath = path26.join(directory, ".swarm", "session", SESSION_START_FILE);
|
|
13589
13679
|
if (!existsSync16(filePath))
|
|
13590
13680
|
return null;
|
|
13591
13681
|
const content = readFileSync8(filePath, "utf-8");
|
|
@@ -13612,7 +13702,7 @@ function readEarliestSessionStart(directory) {
|
|
|
13612
13702
|
|
|
13613
13703
|
// src/tools/write-retro.ts
|
|
13614
13704
|
import { existsSync as existsSync17 } from "fs";
|
|
13615
|
-
import
|
|
13705
|
+
import path27 from "path";
|
|
13616
13706
|
async function executeWriteRetro(args, directory) {
|
|
13617
13707
|
if (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])(:|$)/i.test(directory)) {
|
|
13618
13708
|
return JSON.stringify({
|
|
@@ -13620,7 +13710,7 @@ async function executeWriteRetro(args, directory) {
|
|
|
13620
13710
|
message: "Invalid directory: reserved device name"
|
|
13621
13711
|
}, null, 2);
|
|
13622
13712
|
}
|
|
13623
|
-
if (!existsSync17(
|
|
13713
|
+
if (!existsSync17(path27.join(directory, ".swarm"))) {
|
|
13624
13714
|
return JSON.stringify({
|
|
13625
13715
|
success: false,
|
|
13626
13716
|
message: `Cannot write evidence in "${directory}" \u2014 no .swarm/ folder was found. Run write_retro from an initialized project root.`
|
|
@@ -14036,8 +14126,8 @@ async function copyDirRecursiveWithFailures(src, dest) {
|
|
|
14036
14126
|
const entries = await fs9.readdir(src);
|
|
14037
14127
|
await fs9.mkdir(dest, { recursive: true });
|
|
14038
14128
|
for (const entry of entries) {
|
|
14039
|
-
const srcEntry =
|
|
14040
|
-
const destEntry =
|
|
14129
|
+
const srcEntry = path28.join(src, entry);
|
|
14130
|
+
const destEntry = path28.join(dest, entry);
|
|
14041
14131
|
try {
|
|
14042
14132
|
const stat4 = await fs9.stat(srcEntry);
|
|
14043
14133
|
if (stat4.isDirectory()) {
|
|
@@ -14222,18 +14312,18 @@ async function runFinalizeStage(ctx) {
|
|
|
14222
14312
|
ctx.warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
14223
14313
|
}
|
|
14224
14314
|
}
|
|
14225
|
-
const lessonsFilePath =
|
|
14315
|
+
const lessonsFilePath = path28.join(ctx.swarmDir, "close-lessons.md");
|
|
14226
14316
|
try {
|
|
14227
14317
|
const lessonsText = await fs9.readFile(lessonsFilePath, "utf-8");
|
|
14228
14318
|
ctx.explicitLessons = lessonsText.split(`
|
|
14229
14319
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
14230
14320
|
} catch {}
|
|
14231
14321
|
try {
|
|
14232
|
-
const evidenceDir =
|
|
14322
|
+
const evidenceDir = path28.join(ctx.swarmDir, "evidence");
|
|
14233
14323
|
const evidenceEntries = await fs9.readdir(evidenceDir);
|
|
14234
14324
|
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
14235
14325
|
for (const retroDir of retroDirs) {
|
|
14236
|
-
const evidencePath =
|
|
14326
|
+
const evidencePath = path28.join(evidenceDir, retroDir, "evidence.json");
|
|
14237
14327
|
try {
|
|
14238
14328
|
const content = await fs9.readFile(evidencePath, "utf-8");
|
|
14239
14329
|
const parsed = JSON.parse(content);
|
|
@@ -14417,7 +14507,7 @@ async function copySqliteSafe(srcPath, destPath, laneEnv) {
|
|
|
14417
14507
|
let checkpointVerified = false;
|
|
14418
14508
|
try {
|
|
14419
14509
|
const result = _internals17.spawnSync("sqlite3", [srcPath, "PRAGMA wal_checkpoint(TRUNCATE);"], {
|
|
14420
|
-
cwd:
|
|
14510
|
+
cwd: path28.dirname(srcPath),
|
|
14421
14511
|
encoding: "utf-8",
|
|
14422
14512
|
stdio: ["ignore", "pipe", "pipe"],
|
|
14423
14513
|
timeout: 1e4,
|
|
@@ -14486,7 +14576,7 @@ async function copySqliteSafe(srcPath, destPath, laneEnv) {
|
|
|
14486
14576
|
async function runArchiveStage(ctx) {
|
|
14487
14577
|
ctx.timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
14488
14578
|
ctx.archiveSuffix = Math.random().toString(36).slice(2, 8);
|
|
14489
|
-
ctx.archiveDir =
|
|
14579
|
+
ctx.archiveDir = path28.join(ctx.swarmDir, "archive", `swarm-${ctx.timestamp}-${ctx.archiveSuffix}`);
|
|
14490
14580
|
try {
|
|
14491
14581
|
await fs9.mkdir(ctx.archiveDir, { recursive: true });
|
|
14492
14582
|
const WAL_SIDECAR_FILES = new Set(["swarm.db-shm", "swarm.db-wal"]);
|
|
@@ -14501,8 +14591,8 @@ async function runArchiveStage(ctx) {
|
|
|
14501
14591
|
if (linkedKnowledgeShared && KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact)) {
|
|
14502
14592
|
continue;
|
|
14503
14593
|
}
|
|
14504
|
-
const srcPath =
|
|
14505
|
-
const destPath =
|
|
14594
|
+
const srcPath = path28.join(ctx.swarmDir, artifact);
|
|
14595
|
+
const destPath = path28.join(ctx.archiveDir, artifact);
|
|
14506
14596
|
if (artifact === "swarm.db") {
|
|
14507
14597
|
const result = await copySqliteSafe(srcPath, destPath, undefined);
|
|
14508
14598
|
if (result.skipped) {} else if (result.success) {
|
|
@@ -14535,8 +14625,8 @@ async function runArchiveStage(ctx) {
|
|
|
14535
14625
|
}
|
|
14536
14626
|
const dynamicArchiveArtifacts = (await fs9.readdir(ctx.swarmDir).catch(() => [])).filter((name) => /^post-mortem-[^/\\]+\.md$/.test(name) || /^drift-report-phase-\d+\.json$/.test(name));
|
|
14537
14627
|
for (const artifact of dynamicArchiveArtifacts) {
|
|
14538
|
-
const srcPath =
|
|
14539
|
-
const destPath =
|
|
14628
|
+
const srcPath = path28.join(ctx.swarmDir, artifact);
|
|
14629
|
+
const destPath = path28.join(ctx.archiveDir, artifact);
|
|
14540
14630
|
try {
|
|
14541
14631
|
await fs9.copyFile(srcPath, destPath);
|
|
14542
14632
|
ctx.archivedFileCount++;
|
|
@@ -14551,8 +14641,8 @@ async function runArchiveStage(ctx) {
|
|
|
14551
14641
|
}
|
|
14552
14642
|
}
|
|
14553
14643
|
for (const dirName of ACTIVE_STATE_DIRS_TO_CLEAN) {
|
|
14554
|
-
const srcDir =
|
|
14555
|
-
const destDir =
|
|
14644
|
+
const srcDir = path28.join(ctx.swarmDir, dirName);
|
|
14645
|
+
const destDir = path28.join(ctx.archiveDir, dirName);
|
|
14556
14646
|
try {
|
|
14557
14647
|
const result = await copyDirRecursiveWithFailures(srcDir, destDir);
|
|
14558
14648
|
ctx.archivedFileCount += result.copied;
|
|
@@ -14629,7 +14719,7 @@ async function runCleanStage(ctx) {
|
|
|
14629
14719
|
ctx.warnings.push(reason ? `Preserved ${artifact} because it was not successfully archived: ${reason}.` : `Preserved ${artifact} because it was not successfully archived.`);
|
|
14630
14720
|
continue;
|
|
14631
14721
|
}
|
|
14632
|
-
const filePath =
|
|
14722
|
+
const filePath = path28.join(ctx.swarmDir, artifact);
|
|
14633
14723
|
try {
|
|
14634
14724
|
await fs9.unlink(filePath);
|
|
14635
14725
|
cleanedFiles.push(artifact);
|
|
@@ -14649,7 +14739,7 @@ async function runCleanStage(ctx) {
|
|
|
14649
14739
|
continue;
|
|
14650
14740
|
}
|
|
14651
14741
|
try {
|
|
14652
|
-
await fs9.unlink(
|
|
14742
|
+
await fs9.unlink(path28.join(ctx.swarmDir, artifact));
|
|
14653
14743
|
cleanedFiles.push(artifact);
|
|
14654
14744
|
} catch (err) {
|
|
14655
14745
|
const errno = err?.code;
|
|
@@ -14663,7 +14753,7 @@ async function runCleanStage(ctx) {
|
|
|
14663
14753
|
if (!ctx.archivedActiveStateDirs.has(dirName)) {
|
|
14664
14754
|
continue;
|
|
14665
14755
|
}
|
|
14666
|
-
const dirPath =
|
|
14756
|
+
const dirPath = path28.join(ctx.swarmDir, dirName);
|
|
14667
14757
|
try {
|
|
14668
14758
|
await fs9.rm(dirPath, { recursive: true, force: true });
|
|
14669
14759
|
cleanedFiles.push(`${dirName}/`);
|
|
@@ -14674,7 +14764,7 @@ async function runCleanStage(ctx) {
|
|
|
14674
14764
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
14675
14765
|
for (const backup of configBackups) {
|
|
14676
14766
|
try {
|
|
14677
|
-
await fs9.unlink(
|
|
14767
|
+
await fs9.unlink(path28.join(ctx.swarmDir, backup));
|
|
14678
14768
|
configBackupsRemoved++;
|
|
14679
14769
|
} catch (err) {
|
|
14680
14770
|
const errno = err?.code;
|
|
@@ -14687,7 +14777,7 @@ async function runCleanStage(ctx) {
|
|
|
14687
14777
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
14688
14778
|
for (const sibling of ledgerSiblings) {
|
|
14689
14779
|
try {
|
|
14690
|
-
await fs9.unlink(
|
|
14780
|
+
await fs9.unlink(path28.join(ctx.swarmDir, sibling));
|
|
14691
14781
|
} catch (err) {
|
|
14692
14782
|
const errno = err?.code;
|
|
14693
14783
|
if (errno === "ENOENT") {} else {
|
|
@@ -14705,12 +14795,12 @@ async function runCleanStage(ctx) {
|
|
|
14705
14795
|
}
|
|
14706
14796
|
let swarmPlanFilesRemoved = 0;
|
|
14707
14797
|
const candidates = [
|
|
14708
|
-
|
|
14709
|
-
|
|
14710
|
-
|
|
14711
|
-
|
|
14712
|
-
|
|
14713
|
-
|
|
14798
|
+
path28.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.json"),
|
|
14799
|
+
path28.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.md"),
|
|
14800
|
+
path28.join(ctx.directory, ".swarm", "SWARM_PLAN.json"),
|
|
14801
|
+
path28.join(ctx.directory, ".swarm", "SWARM_PLAN.md"),
|
|
14802
|
+
path28.join(ctx.directory, "SWARM_PLAN.json"),
|
|
14803
|
+
path28.join(ctx.directory, "SWARM_PLAN.md")
|
|
14714
14804
|
];
|
|
14715
14805
|
for (const candidate of candidates) {
|
|
14716
14806
|
try {
|
|
@@ -14728,7 +14818,7 @@ async function runCleanStage(ctx) {
|
|
|
14728
14818
|
const tmpFiles = swarmFiles.filter((f) => f.startsWith(".tmp."));
|
|
14729
14819
|
for (const tmp of tmpFiles) {
|
|
14730
14820
|
try {
|
|
14731
|
-
await fs9.unlink(
|
|
14821
|
+
await fs9.unlink(path28.join(ctx.swarmDir, tmp));
|
|
14732
14822
|
tmpFilesRemoved++;
|
|
14733
14823
|
} catch (err) {
|
|
14734
14824
|
const errno = err?.code;
|
|
@@ -14750,7 +14840,7 @@ async function runCleanStage(ctx) {
|
|
|
14750
14840
|
}
|
|
14751
14841
|
for (const terminalFile of TERMINAL_STATE_FILES) {
|
|
14752
14842
|
try {
|
|
14753
|
-
await fs9.unlink(
|
|
14843
|
+
await fs9.unlink(path28.join(ctx.swarmDir, terminalFile));
|
|
14754
14844
|
if (!cleanedFiles.includes(terminalFile)) {
|
|
14755
14845
|
cleanedFiles.push(terminalFile);
|
|
14756
14846
|
}
|
|
@@ -14763,7 +14853,7 @@ async function runCleanStage(ctx) {
|
|
|
14763
14853
|
}
|
|
14764
14854
|
}
|
|
14765
14855
|
clearAllScopes(ctx.directory);
|
|
14766
|
-
const contextPath =
|
|
14856
|
+
const contextPath = path28.join(ctx.swarmDir, "context.md");
|
|
14767
14857
|
const contextContent = [
|
|
14768
14858
|
"# Context",
|
|
14769
14859
|
"",
|
|
@@ -14775,7 +14865,7 @@ async function runCleanStage(ctx) {
|
|
|
14775
14865
|
""
|
|
14776
14866
|
].join(`
|
|
14777
14867
|
`);
|
|
14778
|
-
const contextTempPath =
|
|
14868
|
+
const contextTempPath = path28.join(path28.dirname(contextPath), `${path28.basename(contextPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
14779
14869
|
try {
|
|
14780
14870
|
await fs9.writeFile(contextTempPath, contextContent, "utf-8");
|
|
14781
14871
|
fsSync.renameSync(contextTempPath, contextPath);
|
|
@@ -14839,7 +14929,7 @@ async function runAlignStage(ctx) {
|
|
|
14839
14929
|
return { gitAlignResult, prunedBranches };
|
|
14840
14930
|
}
|
|
14841
14931
|
async function handleCloseCommand(directory, args, options = {}) {
|
|
14842
|
-
const swarmDir =
|
|
14932
|
+
const swarmDir = path28.join(directory, ".swarm");
|
|
14843
14933
|
try {
|
|
14844
14934
|
const stat4 = fsSync.lstatSync(swarmDir);
|
|
14845
14935
|
if (stat4.isSymbolicLink()) {
|
|
@@ -14853,7 +14943,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
14853
14943
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
14854
14944
|
let planExists = false;
|
|
14855
14945
|
let planData = {
|
|
14856
|
-
title:
|
|
14946
|
+
title: path28.basename(directory) || "Ad-hoc session",
|
|
14857
14947
|
phases: []
|
|
14858
14948
|
};
|
|
14859
14949
|
try {
|
|
@@ -14878,7 +14968,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
14878
14968
|
}
|
|
14879
14969
|
try {
|
|
14880
14970
|
if (!planExists) {
|
|
14881
|
-
const archiveDir =
|
|
14971
|
+
const archiveDir = path28.join(swarmDir, "archive");
|
|
14882
14972
|
try {
|
|
14883
14973
|
const archiveEntries = await fs9.readdir(archiveDir);
|
|
14884
14974
|
const hasArchiveBundle = archiveEntries.some((entry) => entry.startsWith("swarm-"));
|
|
@@ -14886,7 +14976,7 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
14886
14976
|
const hasActiveState = [
|
|
14887
14977
|
...ACTIVE_STATE_TO_CLEAN,
|
|
14888
14978
|
...ACTIVE_STATE_DIRS_TO_CLEAN
|
|
14889
|
-
].some((entry) => fsSync.existsSync(
|
|
14979
|
+
].some((entry) => fsSync.existsSync(path28.join(swarmDir, entry)));
|
|
14890
14980
|
if (!hasActiveState) {
|
|
14891
14981
|
return `\u2705 Already finalized \u2014 nothing to do.
|
|
14892
14982
|
|
|
@@ -15014,7 +15104,7 @@ This project was already finalized in a previous /swarm close run. The plan has
|
|
|
15014
15104
|
...ctx.warnings.length > 0 ? ["## Warnings", ...ctx.warnings.map((w) => `- ${w}`), ""] : []
|
|
15015
15105
|
].join(`
|
|
15016
15106
|
`);
|
|
15017
|
-
const closeSummaryTempPath =
|
|
15107
|
+
const closeSummaryTempPath = path28.join(path28.dirname(closeSummaryPath), `${path28.basename(closeSummaryPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
15018
15108
|
try {
|
|
15019
15109
|
await fs9.writeFile(closeSummaryTempPath, summaryContent, "utf-8");
|
|
15020
15110
|
fsSync.renameSync(closeSummaryTempPath, closeSummaryPath);
|
|
@@ -15365,14 +15455,14 @@ function buildStatusMessage(session, plan) {
|
|
|
15365
15455
|
|
|
15366
15456
|
// src/commands/config.ts
|
|
15367
15457
|
import * as os5 from "os";
|
|
15368
|
-
import * as
|
|
15458
|
+
import * as path29 from "path";
|
|
15369
15459
|
function getUserConfigDir2() {
|
|
15370
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
15460
|
+
return process.env.XDG_CONFIG_HOME || path29.join(os5.homedir(), ".config");
|
|
15371
15461
|
}
|
|
15372
15462
|
async function handleConfigCommand(directory, _args) {
|
|
15373
15463
|
const config = loadPluginConfig(directory);
|
|
15374
|
-
const userConfigPath =
|
|
15375
|
-
const projectConfigPath =
|
|
15464
|
+
const userConfigPath = path29.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
15465
|
+
const projectConfigPath = path29.join(directory, ".opencode", "opencode-swarm.json");
|
|
15376
15466
|
const lines = [
|
|
15377
15467
|
"## Swarm Configuration",
|
|
15378
15468
|
"",
|
|
@@ -15392,7 +15482,7 @@ async function handleConfigCommand(directory, _args) {
|
|
|
15392
15482
|
// src/services/skill-consolidation.ts
|
|
15393
15483
|
import { existsSync as existsSync19 } from "fs";
|
|
15394
15484
|
import { mkdir as mkdir9, readFile as readFile10, rename as rename7, writeFile as writeFile11 } from "fs/promises";
|
|
15395
|
-
import * as
|
|
15485
|
+
import * as path30 from "path";
|
|
15396
15486
|
|
|
15397
15487
|
// src/utils/timeout.ts
|
|
15398
15488
|
async function withTimeout(promise, ms, timeoutError) {
|
|
@@ -15417,7 +15507,7 @@ var DEFAULT_CONSOLIDATION_MAX_CALLS_PER_RUN = 1;
|
|
|
15417
15507
|
var CONSOLIDATION_RUN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
15418
15508
|
var runningByDirectory = new Map;
|
|
15419
15509
|
function consolidationStatePath(directory) {
|
|
15420
|
-
return
|
|
15510
|
+
return path30.join(directory, ".swarm", "skill-improver", "consolidation-state.json");
|
|
15421
15511
|
}
|
|
15422
15512
|
async function readState2(directory) {
|
|
15423
15513
|
const filePath = consolidationStatePath(directory);
|
|
@@ -15433,7 +15523,7 @@ async function readState2(directory) {
|
|
|
15433
15523
|
}
|
|
15434
15524
|
}
|
|
15435
15525
|
async function atomicWrite2(filePath, content) {
|
|
15436
|
-
await mkdir9(
|
|
15526
|
+
await mkdir9(path30.dirname(filePath), { recursive: true });
|
|
15437
15527
|
const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
15438
15528
|
await writeFile11(tmp, content, "utf-8");
|
|
15439
15529
|
await rename7(tmp, filePath);
|
|
@@ -15513,7 +15603,7 @@ async function runSkillConsolidationInner(req) {
|
|
|
15513
15603
|
};
|
|
15514
15604
|
}
|
|
15515
15605
|
async function runSkillConsolidation(req) {
|
|
15516
|
-
const key =
|
|
15606
|
+
const key = path30.resolve(req.directory);
|
|
15517
15607
|
const existing = runningByDirectory.get(key);
|
|
15518
15608
|
if (existing) {
|
|
15519
15609
|
return {
|
|
@@ -15715,7 +15805,7 @@ async function handleCouncilCommand(_directory, args) {
|
|
|
15715
15805
|
// src/commands/coupling.ts
|
|
15716
15806
|
import { randomBytes } from "crypto";
|
|
15717
15807
|
import * as fs10 from "fs";
|
|
15718
|
-
import * as
|
|
15808
|
+
import * as path32 from "path";
|
|
15719
15809
|
|
|
15720
15810
|
// src/turbo/epic/cochange-source.ts
|
|
15721
15811
|
import * as child_process4 from "child_process";
|
|
@@ -15725,7 +15815,7 @@ import { promisify as promisify2 } from "util";
|
|
|
15725
15815
|
import * as child_process3 from "child_process";
|
|
15726
15816
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
15727
15817
|
import { readdir as readdir2, readFile as readFile11, stat as stat4 } from "fs/promises";
|
|
15728
|
-
import * as
|
|
15818
|
+
import * as path31 from "path";
|
|
15729
15819
|
import { promisify } from "util";
|
|
15730
15820
|
function getExecFileAsync() {
|
|
15731
15821
|
return promisify(child_process3.execFile);
|
|
@@ -15829,7 +15919,7 @@ async function scanSourceFiles(dir) {
|
|
|
15829
15919
|
try {
|
|
15830
15920
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
15831
15921
|
for (const entry of entries) {
|
|
15832
|
-
const fullPath =
|
|
15922
|
+
const fullPath = path31.join(dir, entry.name);
|
|
15833
15923
|
if (entry.isDirectory()) {
|
|
15834
15924
|
if (skipDirs.has(entry.name)) {
|
|
15835
15925
|
continue;
|
|
@@ -15837,7 +15927,7 @@ async function scanSourceFiles(dir) {
|
|
|
15837
15927
|
const subFiles = await scanSourceFiles(fullPath);
|
|
15838
15928
|
results.push(...subFiles);
|
|
15839
15929
|
} else if (entry.isFile()) {
|
|
15840
|
-
const ext =
|
|
15930
|
+
const ext = path31.extname(entry.name);
|
|
15841
15931
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
15842
15932
|
results.push(fullPath);
|
|
15843
15933
|
}
|
|
@@ -15859,8 +15949,8 @@ async function getStaticEdges(directory) {
|
|
|
15859
15949
|
continue;
|
|
15860
15950
|
}
|
|
15861
15951
|
try {
|
|
15862
|
-
const sourceDir =
|
|
15863
|
-
const resolvedPath =
|
|
15952
|
+
const sourceDir = path31.dirname(sourceFile);
|
|
15953
|
+
const resolvedPath = path31.resolve(sourceDir, importPath);
|
|
15864
15954
|
const extensions = [
|
|
15865
15955
|
"",
|
|
15866
15956
|
".ts",
|
|
@@ -15885,8 +15975,8 @@ async function getStaticEdges(directory) {
|
|
|
15885
15975
|
if (!targetFile) {
|
|
15886
15976
|
continue;
|
|
15887
15977
|
}
|
|
15888
|
-
const relSource =
|
|
15889
|
-
const relTarget =
|
|
15978
|
+
const relSource = path31.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
15979
|
+
const relTarget = path31.relative(directory, targetFile).replace(/\\/g, "/");
|
|
15890
15980
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
15891
15981
|
edges.add(key);
|
|
15892
15982
|
} catch {}
|
|
@@ -15898,7 +15988,7 @@ async function getStaticEdges(directory) {
|
|
|
15898
15988
|
function isTestImplementationPair(fileA, fileB) {
|
|
15899
15989
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
15900
15990
|
const getBaseName = (filePath) => {
|
|
15901
|
-
const base =
|
|
15991
|
+
const base = path31.basename(filePath);
|
|
15902
15992
|
for (const pattern of testPatterns) {
|
|
15903
15993
|
if (base.endsWith(pattern)) {
|
|
15904
15994
|
return base.slice(0, -pattern.length);
|
|
@@ -15908,16 +15998,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
15908
15998
|
};
|
|
15909
15999
|
const baseA = getBaseName(fileA);
|
|
15910
16000
|
const baseB = getBaseName(fileB);
|
|
15911
|
-
return baseA === baseB && baseA !==
|
|
16001
|
+
return baseA === baseB && baseA !== path31.basename(fileA) && baseA !== path31.basename(fileB);
|
|
15912
16002
|
}
|
|
15913
16003
|
function hasSharedPrefix(fileA, fileB) {
|
|
15914
|
-
const dirA =
|
|
15915
|
-
const dirB =
|
|
16004
|
+
const dirA = path31.dirname(fileA);
|
|
16005
|
+
const dirB = path31.dirname(fileB);
|
|
15916
16006
|
if (dirA !== dirB) {
|
|
15917
16007
|
return false;
|
|
15918
16008
|
}
|
|
15919
|
-
const baseA =
|
|
15920
|
-
const baseB =
|
|
16009
|
+
const baseA = path31.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
16010
|
+
const baseB = path31.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
15921
16011
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
15922
16012
|
return true;
|
|
15923
16013
|
}
|
|
@@ -15972,8 +16062,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
15972
16062
|
const entries = [];
|
|
15973
16063
|
const now = new Date().toISOString();
|
|
15974
16064
|
for (const pair of pairs.slice(0, 10)) {
|
|
15975
|
-
const baseA =
|
|
15976
|
-
const baseB =
|
|
16065
|
+
const baseA = path31.basename(pair.fileA);
|
|
16066
|
+
const baseB = path31.basename(pair.fileB);
|
|
15977
16067
|
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.`;
|
|
15978
16068
|
if (lesson.length > 280) {
|
|
15979
16069
|
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.`;
|
|
@@ -16399,9 +16489,9 @@ function parseArgs3(args) {
|
|
|
16399
16489
|
return parsed;
|
|
16400
16490
|
}
|
|
16401
16491
|
function persistReportJson(directory, report) {
|
|
16402
|
-
const epicDir =
|
|
16492
|
+
const epicDir = path32.join(directory, ".swarm", "epic");
|
|
16403
16493
|
fs10.mkdirSync(epicDir, { recursive: true });
|
|
16404
|
-
const filePath =
|
|
16494
|
+
const filePath = path32.join(epicDir, "coupling-report.json");
|
|
16405
16495
|
const tmpPath = `${filePath}.tmp.${randomBytes(8).toString("hex")}`;
|
|
16406
16496
|
fs10.writeFileSync(tmpPath, `${JSON.stringify(report, null, 2)}
|
|
16407
16497
|
`, "utf-8");
|
|
@@ -16460,7 +16550,7 @@ Usage: /swarm coupling [--phase <n>] [--threshold <-1..1>] [--min-co-changes <n>
|
|
|
16460
16550
|
persistStatus = {
|
|
16461
16551
|
requested: true,
|
|
16462
16552
|
written: true,
|
|
16463
|
-
path:
|
|
16553
|
+
path: path32.relative(directory, writtenAt).replace(/\\/g, "/")
|
|
16464
16554
|
};
|
|
16465
16555
|
} catch (err) {
|
|
16466
16556
|
persistStatus = {
|
|
@@ -16499,8 +16589,8 @@ var _internals21 = {
|
|
|
16499
16589
|
loadCuratorDeps: async () => {
|
|
16500
16590
|
const [{ CuratorConfigSchema }, curator, { createCuratorLLMDelegate: createCuratorLLMDelegate2 }] = await Promise.all([
|
|
16501
16591
|
import("./schema-x17zmd03.js"),
|
|
16502
|
-
import("./curator-
|
|
16503
|
-
import("./curator-llm-factory-
|
|
16592
|
+
import("./curator-9q3m25va.js"),
|
|
16593
|
+
import("./curator-llm-factory-78dyv010.js")
|
|
16504
16594
|
]);
|
|
16505
16595
|
return { CuratorConfigSchema, curator, createCuratorLLMDelegate: createCuratorLLMDelegate2 };
|
|
16506
16596
|
}
|
|
@@ -16592,7 +16682,7 @@ function formatCurationSummary(summary) {
|
|
|
16592
16682
|
}
|
|
16593
16683
|
|
|
16594
16684
|
// src/commands/dark-matter.ts
|
|
16595
|
-
import
|
|
16685
|
+
import path33 from "path";
|
|
16596
16686
|
async function handleDarkMatterCommand(directory, args) {
|
|
16597
16687
|
const options = {};
|
|
16598
16688
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -16624,7 +16714,7 @@ Ensure this is a git repository with commit history.`;
|
|
|
16624
16714
|
const output = formatDarkMatterOutput(pairs);
|
|
16625
16715
|
if (pairs.length > 0) {
|
|
16626
16716
|
try {
|
|
16627
|
-
const projectName =
|
|
16717
|
+
const projectName = path33.basename(path33.resolve(directory));
|
|
16628
16718
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
16629
16719
|
if (entries.length > 0) {
|
|
16630
16720
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -16991,12 +17081,12 @@ ${USAGE5}`;
|
|
|
16991
17081
|
// src/services/diagnose-service.ts
|
|
16992
17082
|
import * as child_process5 from "child_process";
|
|
16993
17083
|
import { existsSync as existsSync22, readdirSync as readdirSync4, readFileSync as readFileSync10, statSync as statSync6 } from "fs";
|
|
16994
|
-
import * as
|
|
17084
|
+
import * as path35 from "path";
|
|
16995
17085
|
import { fileURLToPath } from "url";
|
|
16996
17086
|
// package.json
|
|
16997
17087
|
var package_default = {
|
|
16998
17088
|
name: "opencode-swarm",
|
|
16999
|
-
version: "7.109.
|
|
17089
|
+
version: "7.109.3",
|
|
17000
17090
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
17001
17091
|
main: "dist/index.js",
|
|
17002
17092
|
types: "dist/index.d.ts",
|
|
@@ -17063,6 +17153,11 @@ var package_default = {
|
|
|
17063
17153
|
".opencode/skills/running-tests",
|
|
17064
17154
|
".opencode/skills/engineering-conventions",
|
|
17065
17155
|
".opencode/skills/commit-pr",
|
|
17156
|
+
".opencode/skills/worktree-retry-cleanup",
|
|
17157
|
+
".opencode/skills/skill-edit-validation",
|
|
17158
|
+
".opencode/skills/merge-queue-readiness",
|
|
17159
|
+
".opencode/skills/gate-attribution",
|
|
17160
|
+
".opencode/skills/ci-failure-batching",
|
|
17066
17161
|
"tests/fixtures/memory-recall",
|
|
17067
17162
|
"README.md",
|
|
17068
17163
|
"LICENSE"
|
|
@@ -17105,44 +17200,44 @@ var package_default = {
|
|
|
17105
17200
|
|
|
17106
17201
|
// src/config/cache-paths.ts
|
|
17107
17202
|
import * as os6 from "os";
|
|
17108
|
-
import * as
|
|
17203
|
+
import * as path34 from "path";
|
|
17109
17204
|
function getPluginConfigDir() {
|
|
17110
|
-
return
|
|
17205
|
+
return path34.join(process.env.XDG_CONFIG_HOME || path34.join(os6.homedir(), ".config"), "opencode");
|
|
17111
17206
|
}
|
|
17112
17207
|
function getPluginCachePaths() {
|
|
17113
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
17208
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path34.join(os6.homedir(), ".cache");
|
|
17114
17209
|
const configDir = getPluginConfigDir();
|
|
17115
17210
|
const paths = [
|
|
17116
|
-
|
|
17117
|
-
|
|
17118
|
-
|
|
17211
|
+
path34.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
|
|
17212
|
+
path34.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
|
|
17213
|
+
path34.join(configDir, "node_modules", "opencode-swarm")
|
|
17119
17214
|
];
|
|
17120
17215
|
if (process.platform === "darwin") {
|
|
17121
|
-
const libCaches =
|
|
17122
|
-
paths.push(
|
|
17216
|
+
const libCaches = path34.join(os6.homedir(), "Library", "Caches");
|
|
17217
|
+
paths.push(path34.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path34.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
|
|
17123
17218
|
}
|
|
17124
17219
|
if (process.platform === "win32") {
|
|
17125
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
17126
|
-
const appData = process.env.APPDATA ||
|
|
17127
|
-
paths.push(
|
|
17220
|
+
const localAppData = process.env.LOCALAPPDATA || path34.join(os6.homedir(), "AppData", "Local");
|
|
17221
|
+
const appData = process.env.APPDATA || path34.join(os6.homedir(), "AppData", "Roaming");
|
|
17222
|
+
paths.push(path34.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path34.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path34.join(appData, "opencode", "node_modules", "opencode-swarm"));
|
|
17128
17223
|
}
|
|
17129
17224
|
return paths;
|
|
17130
17225
|
}
|
|
17131
17226
|
function getPluginLockFilePaths() {
|
|
17132
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
17227
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path34.join(os6.homedir(), ".cache");
|
|
17133
17228
|
const configDir = getPluginConfigDir();
|
|
17134
17229
|
const paths = [
|
|
17135
|
-
|
|
17136
|
-
|
|
17137
|
-
|
|
17230
|
+
path34.join(cacheBase, "opencode", "bun.lock"),
|
|
17231
|
+
path34.join(cacheBase, "opencode", "bun.lockb"),
|
|
17232
|
+
path34.join(configDir, "package-lock.json")
|
|
17138
17233
|
];
|
|
17139
17234
|
if (process.platform === "darwin") {
|
|
17140
|
-
const libCaches =
|
|
17141
|
-
paths.push(
|
|
17235
|
+
const libCaches = path34.join(os6.homedir(), "Library", "Caches");
|
|
17236
|
+
paths.push(path34.join(libCaches, "opencode", "bun.lock"), path34.join(libCaches, "opencode", "bun.lockb"));
|
|
17142
17237
|
}
|
|
17143
17238
|
if (process.platform === "win32") {
|
|
17144
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
17145
|
-
paths.push(
|
|
17239
|
+
const localAppData = process.env.LOCALAPPDATA || path34.join(os6.homedir(), "AppData", "Local");
|
|
17240
|
+
paths.push(path34.join(localAppData, "opencode", "bun.lock"), path34.join(localAppData, "opencode", "bun.lockb"));
|
|
17146
17241
|
}
|
|
17147
17242
|
return paths;
|
|
17148
17243
|
}
|
|
@@ -17172,10 +17267,10 @@ function cacheFile() {
|
|
|
17172
17267
|
}
|
|
17173
17268
|
function readVersionCache() {
|
|
17174
17269
|
try {
|
|
17175
|
-
const
|
|
17176
|
-
if (!existsSync20(
|
|
17270
|
+
const path35 = cacheFile();
|
|
17271
|
+
if (!existsSync20(path35))
|
|
17177
17272
|
return null;
|
|
17178
|
-
const raw = readFileSync9(
|
|
17273
|
+
const raw = readFileSync9(path35, "utf-8");
|
|
17179
17274
|
const parsed = JSON.parse(raw);
|
|
17180
17275
|
if (typeof parsed?.checkedAt !== "number")
|
|
17181
17276
|
return null;
|
|
@@ -17430,7 +17525,7 @@ var REQUIRED_CACHE_GRAMMAR_ASSETS = [
|
|
|
17430
17525
|
"tree-sitter-typescript.wasm"
|
|
17431
17526
|
];
|
|
17432
17527
|
function resolveCachePackageRoot(cachePath) {
|
|
17433
|
-
const nestedPackageRoot =
|
|
17528
|
+
const nestedPackageRoot = path35.join(cachePath, "node_modules", "opencode-swarm");
|
|
17434
17529
|
return existsSync22(nestedPackageRoot) ? nestedPackageRoot : cachePath;
|
|
17435
17530
|
}
|
|
17436
17531
|
var _internals22 = {
|
|
@@ -17746,7 +17841,7 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
17746
17841
|
};
|
|
17747
17842
|
}
|
|
17748
17843
|
async function checkConfigParseability(directory) {
|
|
17749
|
-
const configPath =
|
|
17844
|
+
const configPath = path35.join(directory, ".opencode/opencode-swarm.json");
|
|
17750
17845
|
if (!existsSync22(configPath)) {
|
|
17751
17846
|
return {
|
|
17752
17847
|
name: "Config Parseability",
|
|
@@ -17775,7 +17870,7 @@ function resolveGrammarDir(thisDir) {
|
|
|
17775
17870
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
17776
17871
|
const isSource = normalized.endsWith("/src/services");
|
|
17777
17872
|
const isCliBundle = normalized.endsWith("/cli");
|
|
17778
|
-
return isSource || isCliBundle ?
|
|
17873
|
+
return isSource || isCliBundle ? path35.join(thisDir, "..", "lang", "grammars") : path35.join(thisDir, "lang", "grammars");
|
|
17779
17874
|
}
|
|
17780
17875
|
async function checkGrammarWasmFiles() {
|
|
17781
17876
|
const grammarFiles = [
|
|
@@ -17799,14 +17894,14 @@ async function checkGrammarWasmFiles() {
|
|
|
17799
17894
|
"tree-sitter-ini.wasm",
|
|
17800
17895
|
"tree-sitter-regex.wasm"
|
|
17801
17896
|
];
|
|
17802
|
-
const thisDir =
|
|
17897
|
+
const thisDir = path35.dirname(fileURLToPath(import.meta.url));
|
|
17803
17898
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
17804
17899
|
const missing = [];
|
|
17805
|
-
if (!existsSync22(
|
|
17900
|
+
if (!existsSync22(path35.join(grammarDir, "tree-sitter.wasm"))) {
|
|
17806
17901
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
17807
17902
|
}
|
|
17808
17903
|
for (const file of grammarFiles) {
|
|
17809
|
-
if (!existsSync22(
|
|
17904
|
+
if (!existsSync22(path35.join(grammarDir, file))) {
|
|
17810
17905
|
missing.push(file);
|
|
17811
17906
|
}
|
|
17812
17907
|
}
|
|
@@ -17824,7 +17919,7 @@ async function checkGrammarWasmFiles() {
|
|
|
17824
17919
|
};
|
|
17825
17920
|
}
|
|
17826
17921
|
async function checkCheckpointManifest(directory) {
|
|
17827
|
-
const manifestPath =
|
|
17922
|
+
const manifestPath = path35.join(directory, ".swarm/checkpoints.json");
|
|
17828
17923
|
if (!existsSync22(manifestPath)) {
|
|
17829
17924
|
return {
|
|
17830
17925
|
name: "Checkpoint Manifest",
|
|
@@ -17876,7 +17971,7 @@ async function checkCheckpointManifest(directory) {
|
|
|
17876
17971
|
}
|
|
17877
17972
|
}
|
|
17878
17973
|
async function checkEventStreamIntegrity(directory) {
|
|
17879
|
-
const eventsPath =
|
|
17974
|
+
const eventsPath = path35.join(directory, ".swarm/events.jsonl");
|
|
17880
17975
|
if (!existsSync22(eventsPath)) {
|
|
17881
17976
|
return {
|
|
17882
17977
|
name: "Event Stream",
|
|
@@ -17917,7 +18012,7 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
17917
18012
|
}
|
|
17918
18013
|
}
|
|
17919
18014
|
async function checkSteeringDirectives(directory) {
|
|
17920
|
-
const eventsPath =
|
|
18015
|
+
const eventsPath = path35.join(directory, ".swarm/events.jsonl");
|
|
17921
18016
|
if (!existsSync22(eventsPath)) {
|
|
17922
18017
|
return {
|
|
17923
18018
|
name: "Steering Directives",
|
|
@@ -17973,7 +18068,7 @@ async function checkCurator(directory) {
|
|
|
17973
18068
|
detail: "Disabled (enable via curator.enabled)"
|
|
17974
18069
|
};
|
|
17975
18070
|
}
|
|
17976
|
-
const summaryPath =
|
|
18071
|
+
const summaryPath = path35.join(directory, ".swarm/curator-summary.json");
|
|
17977
18072
|
if (!existsSync22(summaryPath)) {
|
|
17978
18073
|
return {
|
|
17979
18074
|
name: "Curator",
|
|
@@ -18175,7 +18270,7 @@ async function getDiagnoseData(directory) {
|
|
|
18175
18270
|
checks.push(await checkCurator(directory));
|
|
18176
18271
|
checks.push(await checkKnowledgeHealth(directory));
|
|
18177
18272
|
try {
|
|
18178
|
-
const evidenceDir =
|
|
18273
|
+
const evidenceDir = path35.join(directory, ".swarm", "evidence");
|
|
18179
18274
|
const snapshotFiles = existsSync22(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
18180
18275
|
if (snapshotFiles.length > 0) {
|
|
18181
18276
|
const latest = snapshotFiles.sort().pop();
|
|
@@ -18215,8 +18310,8 @@ async function getDiagnoseData(directory) {
|
|
|
18215
18310
|
}
|
|
18216
18311
|
const packageRoot = resolveCachePackageRoot(cachePath);
|
|
18217
18312
|
const cacheLabel = packageRoot === cachePath ? cachePath : `${cachePath} -> ${packageRoot}`;
|
|
18218
|
-
const missingGrammarAssets = REQUIRED_CACHE_GRAMMAR_ASSETS.filter((file) => !existsSync22(
|
|
18219
|
-
const pkgJsonPath =
|
|
18313
|
+
const missingGrammarAssets = REQUIRED_CACHE_GRAMMAR_ASSETS.filter((file) => !existsSync22(path35.join(packageRoot, "dist", "lang", "grammars", file)));
|
|
18314
|
+
const pkgJsonPath = path35.join(packageRoot, "package.json");
|
|
18220
18315
|
try {
|
|
18221
18316
|
const raw = readFileSync10(pkgJsonPath, "utf-8");
|
|
18222
18317
|
const parsed = JSON.parse(raw);
|
|
@@ -18592,9 +18687,9 @@ function decideEpicActivation(tasks, cochangePairs, commitsObserved, options) {
|
|
|
18592
18687
|
// src/turbo/epic/calibration.ts
|
|
18593
18688
|
init_logger();
|
|
18594
18689
|
import * as fs11 from "fs";
|
|
18595
|
-
import * as
|
|
18690
|
+
import * as path36 from "path";
|
|
18596
18691
|
var STATE_FILE = "calibration.json";
|
|
18597
|
-
var STATE_REL_DIR =
|
|
18692
|
+
var STATE_REL_DIR = path36.join(".swarm", "epic");
|
|
18598
18693
|
function nowISO() {
|
|
18599
18694
|
return new Date().toISOString();
|
|
18600
18695
|
}
|
|
@@ -18616,7 +18711,7 @@ function markUnreadable(directory, reason) {
|
|
|
18616
18711
|
error(`[epic/calibration] state file unreadable for ${directory}: ${reason} \u2014 failing closed`);
|
|
18617
18712
|
}
|
|
18618
18713
|
function repairCalibrationUnreadable(directory) {
|
|
18619
|
-
const filePath =
|
|
18714
|
+
const filePath = path36.join(directory, STATE_REL_DIR, STATE_FILE);
|
|
18620
18715
|
if (!fs11.existsSync(filePath)) {
|
|
18621
18716
|
stateUnreadableMap.delete(directory);
|
|
18622
18717
|
return;
|
|
@@ -18648,7 +18743,7 @@ function isValidCalibrationShape(candidate) {
|
|
|
18648
18743
|
return true;
|
|
18649
18744
|
}
|
|
18650
18745
|
function ensureSwarmEpicDir(directory) {
|
|
18651
|
-
const dir =
|
|
18746
|
+
const dir = path36.resolve(directory, STATE_REL_DIR);
|
|
18652
18747
|
if (!fs11.existsSync(dir)) {
|
|
18653
18748
|
fs11.mkdirSync(dir, { recursive: true });
|
|
18654
18749
|
}
|
|
@@ -18660,7 +18755,7 @@ function loadCalibrationState(directory) {
|
|
|
18660
18755
|
if (stateUnreadableMap.get(directory))
|
|
18661
18756
|
return null;
|
|
18662
18757
|
}
|
|
18663
|
-
const filePath =
|
|
18758
|
+
const filePath = path36.join(directory, STATE_REL_DIR, STATE_FILE);
|
|
18664
18759
|
try {
|
|
18665
18760
|
if (!fs11.existsSync(filePath)) {
|
|
18666
18761
|
const seed = emptyCalibrationState();
|
|
@@ -18687,12 +18782,12 @@ function loadCalibrationState(directory) {
|
|
|
18687
18782
|
// src/turbo/epic/divergence-recorder.ts
|
|
18688
18783
|
init_logger();
|
|
18689
18784
|
import * as fs12 from "fs";
|
|
18690
|
-
import * as
|
|
18691
|
-
var EVIDENCE_REL_DIR =
|
|
18785
|
+
import * as path37 from "path";
|
|
18786
|
+
var EVIDENCE_REL_DIR = path37.join(".swarm", "epic");
|
|
18692
18787
|
var EVIDENCE_FILE = "divergence.jsonl";
|
|
18693
18788
|
var MAX_TAIL_BYTES2 = 16 * 1024 * 1024;
|
|
18694
18789
|
function readDivergenceHistory(directory, options) {
|
|
18695
|
-
const filePath =
|
|
18790
|
+
const filePath = path37.join(directory, EVIDENCE_REL_DIR, EVIDENCE_FILE);
|
|
18696
18791
|
if (!fs12.existsSync(filePath)) {
|
|
18697
18792
|
return [];
|
|
18698
18793
|
}
|
|
@@ -18741,11 +18836,11 @@ function readDivergenceHistory(directory, options) {
|
|
|
18741
18836
|
|
|
18742
18837
|
// src/turbo/epic/promotion-evidence.ts
|
|
18743
18838
|
import * as fs13 from "fs";
|
|
18744
|
-
import * as
|
|
18745
|
-
var EVIDENCE_REL_DIR2 =
|
|
18839
|
+
import * as path38 from "path";
|
|
18840
|
+
var EVIDENCE_REL_DIR2 = path38.join(".swarm", "evidence");
|
|
18746
18841
|
var EVIDENCE_FILE2 = "epic-promotions.jsonl";
|
|
18747
18842
|
function readPromotionEvidence(directory) {
|
|
18748
|
-
const filePath =
|
|
18843
|
+
const filePath = path38.join(directory, EVIDENCE_REL_DIR2, EVIDENCE_FILE2);
|
|
18749
18844
|
if (!fs13.existsSync(filePath)) {
|
|
18750
18845
|
return [];
|
|
18751
18846
|
}
|
|
@@ -19319,7 +19414,7 @@ async function handleExportCommand(directory, _args) {
|
|
|
19319
19414
|
// src/full-auto/state.ts
|
|
19320
19415
|
var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
|
|
19321
19416
|
import * as fs14 from "fs";
|
|
19322
|
-
import * as
|
|
19417
|
+
import * as path39 from "path";
|
|
19323
19418
|
init_logger();
|
|
19324
19419
|
var lockfile3 = import_proper_lockfile3.default;
|
|
19325
19420
|
var STATE_FILE2 = "full-auto-state.json";
|
|
@@ -19327,7 +19422,7 @@ function nowISO2() {
|
|
|
19327
19422
|
return new Date().toISOString();
|
|
19328
19423
|
}
|
|
19329
19424
|
function ensureSwarmDir(directory) {
|
|
19330
|
-
const swarmDir =
|
|
19425
|
+
const swarmDir = path39.resolve(directory, ".swarm");
|
|
19331
19426
|
if (!fs14.existsSync(swarmDir)) {
|
|
19332
19427
|
fs14.mkdirSync(swarmDir, { recursive: true });
|
|
19333
19428
|
}
|
|
@@ -20139,7 +20234,7 @@ var _internals25 = {
|
|
|
20139
20234
|
|
|
20140
20235
|
// src/session/snapshot-writer.ts
|
|
20141
20236
|
import { closeSync as closeSync5, fsyncSync as fsyncSync2, mkdirSync as mkdirSync16, openSync as openSync5, renameSync as renameSync8 } from "fs";
|
|
20142
|
-
import * as
|
|
20237
|
+
import * as path40 from "path";
|
|
20143
20238
|
var _writeInFlight = Promise.resolve();
|
|
20144
20239
|
function serializeAgentSession(s) {
|
|
20145
20240
|
const gateLog = {};
|
|
@@ -20252,7 +20347,7 @@ async function writeSnapshot(directory, state) {
|
|
|
20252
20347
|
}
|
|
20253
20348
|
const content = JSON.stringify(snapshot, null, 2);
|
|
20254
20349
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
20255
|
-
const dir =
|
|
20350
|
+
const dir = path40.dirname(resolvedPath);
|
|
20256
20351
|
mkdirSync16(dir, { recursive: true });
|
|
20257
20352
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
20258
20353
|
await bunWrite(tempPath, content);
|
|
@@ -20780,10 +20875,10 @@ import { randomUUID as randomUUID7 } from "crypto";
|
|
|
20780
20875
|
import { existsSync as existsSync27, readFileSync as readFileSync15 } from "fs";
|
|
20781
20876
|
import { mkdir as mkdir10, readFile as readFile13, writeFile as writeFile12 } from "fs/promises";
|
|
20782
20877
|
import * as os7 from "os";
|
|
20783
|
-
import * as
|
|
20878
|
+
import * as path41 from "path";
|
|
20784
20879
|
async function migrateKnowledgeToExternal(_directory, _config) {
|
|
20785
|
-
const externalSentinelPath =
|
|
20786
|
-
const contextPath =
|
|
20880
|
+
const externalSentinelPath = path41.join(_directory, ".swarm", ".knowledge-external-migrated");
|
|
20881
|
+
const contextPath = path41.join(_directory, ".swarm", "context.md");
|
|
20787
20882
|
if (_internals28.existsSync(externalSentinelPath)) {
|
|
20788
20883
|
return {
|
|
20789
20884
|
migrated: false,
|
|
@@ -20848,8 +20943,8 @@ var _internals28 = {
|
|
|
20848
20943
|
writeFile: writeFile12
|
|
20849
20944
|
};
|
|
20850
20945
|
async function migrateContextToKnowledge(directory, config) {
|
|
20851
|
-
const sentinelPath =
|
|
20852
|
-
const contextPath =
|
|
20946
|
+
const sentinelPath = path41.join(directory, ".swarm", ".knowledge-migrated");
|
|
20947
|
+
const contextPath = path41.join(directory, ".swarm", "context.md");
|
|
20853
20948
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
20854
20949
|
if (existsSync27(sentinelPath)) {
|
|
20855
20950
|
return {
|
|
@@ -20951,7 +21046,7 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
20951
21046
|
async function migrateHiveKnowledgeLegacy(config) {
|
|
20952
21047
|
const legacyHivePath = _internals28.resolveLegacyHiveKnowledgePath();
|
|
20953
21048
|
const canonicalHivePath = resolveHiveKnowledgePath();
|
|
20954
|
-
const sentinelPath =
|
|
21049
|
+
const sentinelPath = path41.join(path41.dirname(canonicalHivePath), ".hive-knowledge-migrated");
|
|
20955
21050
|
if (existsSync27(sentinelPath)) {
|
|
20956
21051
|
return {
|
|
20957
21052
|
migrated: false,
|
|
@@ -21162,7 +21257,7 @@ function truncateLesson2(text) {
|
|
|
21162
21257
|
return `${text.slice(0, 277)}...`;
|
|
21163
21258
|
}
|
|
21164
21259
|
function inferProjectName(directory) {
|
|
21165
|
-
const packageJsonPath =
|
|
21260
|
+
const packageJsonPath = path41.join(directory, "package.json");
|
|
21166
21261
|
if (existsSync27(packageJsonPath)) {
|
|
21167
21262
|
try {
|
|
21168
21263
|
const pkg = JSON.parse(readFileSync15(packageJsonPath, "utf-8"));
|
|
@@ -21171,7 +21266,7 @@ function inferProjectName(directory) {
|
|
|
21171
21266
|
}
|
|
21172
21267
|
} catch {}
|
|
21173
21268
|
}
|
|
21174
|
-
return
|
|
21269
|
+
return path41.basename(directory);
|
|
21175
21270
|
}
|
|
21176
21271
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
21177
21272
|
const sentinel = {
|
|
@@ -21183,7 +21278,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
21183
21278
|
schema_version: 1,
|
|
21184
21279
|
migration_tool: "knowledge-migrator.ts"
|
|
21185
21280
|
};
|
|
21186
|
-
await _internals28.mkdir(
|
|
21281
|
+
await _internals28.mkdir(path41.dirname(sentinelPath), { recursive: true });
|
|
21187
21282
|
await _internals28.writeFile(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
21188
21283
|
}
|
|
21189
21284
|
function resolveLegacyHiveKnowledgePath() {
|
|
@@ -21191,13 +21286,13 @@ function resolveLegacyHiveKnowledgePath() {
|
|
|
21191
21286
|
const home = process.env.HOME || os7.homedir();
|
|
21192
21287
|
let dataDir;
|
|
21193
21288
|
if (platform === "win32") {
|
|
21194
|
-
dataDir =
|
|
21289
|
+
dataDir = path41.join(process.env.LOCALAPPDATA || path41.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
21195
21290
|
} else if (platform === "darwin") {
|
|
21196
|
-
dataDir =
|
|
21291
|
+
dataDir = path41.join(home, "Library", "Application Support", "opencode-swarm");
|
|
21197
21292
|
} else {
|
|
21198
|
-
dataDir =
|
|
21293
|
+
dataDir = path41.join(process.env.XDG_DATA_HOME || path41.join(home, ".local", "share"), "opencode-swarm");
|
|
21199
21294
|
}
|
|
21200
|
-
return
|
|
21295
|
+
return path41.join(dataDir, "hive-knowledge.jsonl");
|
|
21201
21296
|
}
|
|
21202
21297
|
|
|
21203
21298
|
// src/commands/knowledge.ts
|
|
@@ -21628,14 +21723,14 @@ var _internals29 = {
|
|
|
21628
21723
|
|
|
21629
21724
|
// src/commands/link.ts
|
|
21630
21725
|
import { existsSync as existsSync28 } from "fs";
|
|
21631
|
-
import * as
|
|
21726
|
+
import * as path43 from "path";
|
|
21632
21727
|
|
|
21633
21728
|
// src/knowledge/identity.ts
|
|
21634
21729
|
import * as child_process7 from "child_process";
|
|
21635
21730
|
import { createHash as createHash5 } from "crypto";
|
|
21636
|
-
import * as
|
|
21731
|
+
import * as path42 from "path";
|
|
21637
21732
|
function deriveProjectHash(directory) {
|
|
21638
|
-
const absolutePath =
|
|
21733
|
+
const absolutePath = path42.resolve(directory);
|
|
21639
21734
|
let hashInput;
|
|
21640
21735
|
try {
|
|
21641
21736
|
const remoteUrl = child_process7.execSync("git remote get-url origin", {
|
|
@@ -21655,8 +21750,8 @@ function deriveProjectHash(directory) {
|
|
|
21655
21750
|
// src/commands/link.ts
|
|
21656
21751
|
var DEDUP_THRESHOLD = 0.6;
|
|
21657
21752
|
async function mergeLocalKnowledgeIntoLink(localSwarmDir, linkDir) {
|
|
21658
|
-
const localPath =
|
|
21659
|
-
const sharedPath =
|
|
21753
|
+
const localPath = path43.join(localSwarmDir, "knowledge.jsonl");
|
|
21754
|
+
const sharedPath = path43.join(linkDir, "knowledge.jsonl");
|
|
21660
21755
|
if (!existsSync28(localPath))
|
|
21661
21756
|
return { merged: 0, skipped: 0 };
|
|
21662
21757
|
let merged = 0;
|
|
@@ -21754,7 +21849,7 @@ ${formatStatus(directory)}`;
|
|
|
21754
21849
|
const linkDir = resolveLinkDir(linkId);
|
|
21755
21850
|
let merge;
|
|
21756
21851
|
try {
|
|
21757
|
-
merge = await mergeLocalKnowledgeIntoLink(
|
|
21852
|
+
merge = await mergeLocalKnowledgeIntoLink(path43.join(directory, ".swarm"), linkDir);
|
|
21758
21853
|
} catch (error2) {
|
|
21759
21854
|
return `\u274C Failed to merge local knowledge into the link store: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
21760
21855
|
}
|
|
@@ -21951,12 +22046,12 @@ ${USAGE7}`;
|
|
|
21951
22046
|
|
|
21952
22047
|
// src/commands/memory.ts
|
|
21953
22048
|
import { existsSync as existsSync29 } from "fs";
|
|
21954
|
-
import * as
|
|
22049
|
+
import * as path46 from "path";
|
|
21955
22050
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
21956
22051
|
// src/memory/evaluation.ts
|
|
21957
22052
|
import * as fs15 from "fs/promises";
|
|
21958
22053
|
import * as os8 from "os";
|
|
21959
|
-
import * as
|
|
22054
|
+
import * as path44 from "path";
|
|
21960
22055
|
var DEFAULT_PROVIDERS = [
|
|
21961
22056
|
"local-jsonl",
|
|
21962
22057
|
"sqlite"
|
|
@@ -21968,7 +22063,7 @@ var DEFAULT_MODES = [
|
|
|
21968
22063
|
];
|
|
21969
22064
|
var DEFAULT_TIMESTAMP = "2026-05-26T12:00:00.000Z";
|
|
21970
22065
|
async function evaluateMemoryRecallFixtures(options) {
|
|
21971
|
-
const fixtureDirectory =
|
|
22066
|
+
const fixtureDirectory = path44.resolve(options.fixtureDirectory);
|
|
21972
22067
|
const providers = options.providers ?? DEFAULT_PROVIDERS;
|
|
21973
22068
|
const modes = options.modes ?? DEFAULT_MODES;
|
|
21974
22069
|
const generatedAt = new Date().toISOString();
|
|
@@ -21977,7 +22072,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
21977
22072
|
for (const fixture of fixtures) {
|
|
21978
22073
|
const materialized = materializeFixture(fixture);
|
|
21979
22074
|
for (const providerName of providers) {
|
|
21980
|
-
const tempRoot = await fs15.realpath(await fs15.mkdtemp(
|
|
22075
|
+
const tempRoot = await fs15.realpath(await fs15.mkdtemp(path44.join(os8.tmpdir(), "swarm-memory-eval-")));
|
|
21981
22076
|
const provider = createEvaluationProvider(providerName, tempRoot);
|
|
21982
22077
|
try {
|
|
21983
22078
|
await provider.initialize?.();
|
|
@@ -22034,7 +22129,7 @@ async function loadRecallEvaluationFixtures(fixtureDirectory) {
|
|
|
22034
22129
|
const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
22035
22130
|
const fixtures = [];
|
|
22036
22131
|
for (const file of files) {
|
|
22037
|
-
const raw = await fs15.readFile(
|
|
22132
|
+
const raw = await fs15.readFile(path44.join(fixtureDirectory, file), "utf-8");
|
|
22038
22133
|
fixtures.push(validateFixture(JSON.parse(raw), file));
|
|
22039
22134
|
}
|
|
22040
22135
|
return fixtures;
|
|
@@ -22311,8 +22406,8 @@ var CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
|
22311
22406
|
}).passthrough();
|
|
22312
22407
|
// src/memory/consolidation-log.ts
|
|
22313
22408
|
import { appendFile as appendFile3, mkdir as mkdir11, readFile as readFile15 } from "fs/promises";
|
|
22314
|
-
import * as
|
|
22315
|
-
var LOG_RELATIVE_PATH =
|
|
22409
|
+
import * as path45 from "path";
|
|
22410
|
+
var LOG_RELATIVE_PATH = path45.join("memory", "consolidation-log.jsonl");
|
|
22316
22411
|
async function readConsolidationLog(directory) {
|
|
22317
22412
|
const filePath = validateSwarmPath(directory, LOG_RELATIVE_PATH);
|
|
22318
22413
|
let raw;
|
|
@@ -22335,7 +22430,7 @@ async function readConsolidationLog(directory) {
|
|
|
22335
22430
|
}
|
|
22336
22431
|
|
|
22337
22432
|
// src/commands/memory.ts
|
|
22338
|
-
var PACKAGE_ROOT =
|
|
22433
|
+
var PACKAGE_ROOT = path46.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
|
|
22339
22434
|
async function handleMemoryCommand(_directory, _args) {
|
|
22340
22435
|
return [
|
|
22341
22436
|
"## Swarm Memory",
|
|
@@ -22692,7 +22787,7 @@ function resolveCommandMemoryConfig(directory) {
|
|
|
22692
22787
|
}
|
|
22693
22788
|
function parseEvaluateArgs(directory, args) {
|
|
22694
22789
|
let json = false;
|
|
22695
|
-
let fixtureDirectory =
|
|
22790
|
+
let fixtureDirectory = path46.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
|
|
22696
22791
|
for (let i = 0;i < args.length; i++) {
|
|
22697
22792
|
const arg = args[i];
|
|
22698
22793
|
if (arg === "--json") {
|
|
@@ -22706,10 +22801,10 @@ function parseEvaluateArgs(directory, args) {
|
|
|
22706
22801
|
error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
|
|
22707
22802
|
};
|
|
22708
22803
|
}
|
|
22709
|
-
const resolvedFixtures =
|
|
22710
|
-
const canonical =
|
|
22711
|
-
const allowedRootA =
|
|
22712
|
-
const allowedRootB =
|
|
22804
|
+
const resolvedFixtures = path46.resolve(directory, next);
|
|
22805
|
+
const canonical = path46.normalize(resolvedFixtures) + path46.sep;
|
|
22806
|
+
const allowedRootA = path46.normalize(directory) + path46.sep;
|
|
22807
|
+
const allowedRootB = path46.normalize(path46.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path46.sep;
|
|
22713
22808
|
if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
|
|
22714
22809
|
return {
|
|
22715
22810
|
error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
|
|
@@ -22748,15 +22843,15 @@ function parseMaintenanceArgs(args, options) {
|
|
|
22748
22843
|
return { limit, confirm };
|
|
22749
22844
|
}
|
|
22750
22845
|
function resolvePackageRootFromModule(modulePath) {
|
|
22751
|
-
const moduleDir =
|
|
22752
|
-
const leaf =
|
|
22846
|
+
const moduleDir = path46.dirname(modulePath);
|
|
22847
|
+
const leaf = path46.basename(moduleDir);
|
|
22753
22848
|
if (leaf === "commands" || leaf === "cli") {
|
|
22754
|
-
return
|
|
22849
|
+
return path46.resolve(moduleDir, "..", "..");
|
|
22755
22850
|
}
|
|
22756
22851
|
if (leaf === "dist") {
|
|
22757
|
-
return
|
|
22852
|
+
return path46.resolve(moduleDir, "..");
|
|
22758
22853
|
}
|
|
22759
|
-
return
|
|
22854
|
+
return path46.resolve(moduleDir, "..");
|
|
22760
22855
|
}
|
|
22761
22856
|
function formatMigrationResult(label, report) {
|
|
22762
22857
|
if (!report) {
|
|
@@ -23491,11 +23586,11 @@ var _internals35 = {
|
|
|
23491
23586
|
|
|
23492
23587
|
// src/services/preflight-service.ts
|
|
23493
23588
|
import * as fs22 from "fs";
|
|
23494
|
-
import * as
|
|
23589
|
+
import * as path53 from "path";
|
|
23495
23590
|
|
|
23496
23591
|
// src/tools/lint.ts
|
|
23497
23592
|
import * as fs16 from "fs";
|
|
23498
|
-
import * as
|
|
23593
|
+
import * as path47 from "path";
|
|
23499
23594
|
|
|
23500
23595
|
// src/utils/path-security.ts
|
|
23501
23596
|
function containsPathTraversal(str) {
|
|
@@ -23551,9 +23646,9 @@ function validateArgs(args) {
|
|
|
23551
23646
|
}
|
|
23552
23647
|
function getLinterCommand(linter, mode, projectDir) {
|
|
23553
23648
|
const isWindows = process.platform === "win32";
|
|
23554
|
-
const binDir =
|
|
23555
|
-
const biomeBin = isWindows ?
|
|
23556
|
-
const eslintBin = isWindows ?
|
|
23649
|
+
const binDir = path47.join(projectDir, "node_modules", ".bin");
|
|
23650
|
+
const biomeBin = isWindows ? path47.join(binDir, "biome.EXE") : path47.join(binDir, "biome");
|
|
23651
|
+
const eslintBin = isWindows ? path47.join(binDir, "eslint.cmd") : path47.join(binDir, "eslint");
|
|
23557
23652
|
switch (linter) {
|
|
23558
23653
|
case "biome":
|
|
23559
23654
|
if (mode === "fix") {
|
|
@@ -23569,7 +23664,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
23569
23664
|
}
|
|
23570
23665
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
23571
23666
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
23572
|
-
const gradlew = fs16.existsSync(
|
|
23667
|
+
const gradlew = fs16.existsSync(path47.join(cwd, gradlewName)) ? path47.join(cwd, gradlewName) : null;
|
|
23573
23668
|
switch (linter) {
|
|
23574
23669
|
case "ruff":
|
|
23575
23670
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -23611,10 +23706,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
23611
23706
|
}
|
|
23612
23707
|
}
|
|
23613
23708
|
function detectRuff(cwd) {
|
|
23614
|
-
if (fs16.existsSync(
|
|
23709
|
+
if (fs16.existsSync(path47.join(cwd, "ruff.toml")))
|
|
23615
23710
|
return isCommandAvailable("ruff");
|
|
23616
23711
|
try {
|
|
23617
|
-
const pyproject =
|
|
23712
|
+
const pyproject = path47.join(cwd, "pyproject.toml");
|
|
23618
23713
|
if (fs16.existsSync(pyproject)) {
|
|
23619
23714
|
const content = fs16.readFileSync(pyproject, "utf-8");
|
|
23620
23715
|
if (content.includes("[tool.ruff]"))
|
|
@@ -23624,10 +23719,10 @@ function detectRuff(cwd) {
|
|
|
23624
23719
|
return false;
|
|
23625
23720
|
}
|
|
23626
23721
|
function detectClippy(cwd) {
|
|
23627
|
-
return fs16.existsSync(
|
|
23722
|
+
return fs16.existsSync(path47.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
23628
23723
|
}
|
|
23629
23724
|
function detectGolangciLint(cwd) {
|
|
23630
|
-
return fs16.existsSync(
|
|
23725
|
+
return fs16.existsSync(path47.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
23631
23726
|
}
|
|
23632
23727
|
function readTextFileSafe(filePath) {
|
|
23633
23728
|
try {
|
|
@@ -23638,18 +23733,18 @@ function readTextFileSafe(filePath) {
|
|
|
23638
23733
|
}
|
|
23639
23734
|
function phpVendorBin(_cwd, name) {
|
|
23640
23735
|
const fileName = process.platform === "win32" ? `${name}.bat` : name;
|
|
23641
|
-
return
|
|
23736
|
+
return path47.join("vendor", "bin", fileName);
|
|
23642
23737
|
}
|
|
23643
23738
|
function phpVendorBinExists(cwd, name) {
|
|
23644
|
-
const local =
|
|
23645
|
-
const localWin =
|
|
23739
|
+
const local = path47.join(cwd, "vendor", "bin", name);
|
|
23740
|
+
const localWin = path47.join(cwd, "vendor", "bin", `${name}.bat`);
|
|
23646
23741
|
return fs16.existsSync(local) || fs16.existsSync(localWin);
|
|
23647
23742
|
}
|
|
23648
23743
|
function detectCheckstyle(cwd) {
|
|
23649
|
-
const hasMaven = fs16.existsSync(
|
|
23650
|
-
const gradleFiles = ["build.gradle", "build.gradle.kts"].map((file) =>
|
|
23651
|
-
const hasGradleCheckstyleSignal = fs16.existsSync(
|
|
23652
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradleCheckstyleSignal && (fs16.existsSync(
|
|
23744
|
+
const hasMaven = fs16.existsSync(path47.join(cwd, "pom.xml"));
|
|
23745
|
+
const gradleFiles = ["build.gradle", "build.gradle.kts"].map((file) => path47.join(cwd, file)).filter((file) => fs16.existsSync(file));
|
|
23746
|
+
const hasGradleCheckstyleSignal = fs16.existsSync(path47.join(cwd, "checkstyle.xml")) || fs16.existsSync(path47.join(cwd, "config", "checkstyle", "checkstyle.xml")) || gradleFiles.some((file) => /\bcheckstyle\b/i.test(readTextFileSafe(file)));
|
|
23747
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradleCheckstyleSignal && (fs16.existsSync(path47.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
23653
23748
|
return (hasMaven || hasGradleCheckstyleSignal) && hasBinary;
|
|
23654
23749
|
}
|
|
23655
23750
|
function hasRootKotlinFile(cwd) {
|
|
@@ -23660,24 +23755,24 @@ function hasRootKotlinFile(cwd) {
|
|
|
23660
23755
|
}
|
|
23661
23756
|
}
|
|
23662
23757
|
function buildGradleHasKotlinSignal(cwd) {
|
|
23663
|
-
const content = readTextFileSafe(
|
|
23758
|
+
const content = readTextFileSafe(path47.join(cwd, "build.gradle"));
|
|
23664
23759
|
return /\b(kotlin|org\.jetbrains\.kotlin|ktlint)\b/i.test(content);
|
|
23665
23760
|
}
|
|
23666
23761
|
function detectKtlint(cwd) {
|
|
23667
|
-
const hasKotlin = fs16.existsSync(
|
|
23762
|
+
const hasKotlin = fs16.existsSync(path47.join(cwd, "build.gradle.kts")) || fs16.existsSync(path47.join(cwd, "build.gradle")) && buildGradleHasKotlinSignal(cwd) || hasRootKotlinFile(cwd);
|
|
23668
23763
|
return hasKotlin && isCommandAvailable("ktlint");
|
|
23669
23764
|
}
|
|
23670
23765
|
function detectPhpLinter(cwd) {
|
|
23671
|
-
if ((fs16.existsSync(
|
|
23766
|
+
if ((fs16.existsSync(path47.join(cwd, "phpstan.neon")) || fs16.existsSync(path47.join(cwd, "phpstan.neon.dist"))) && phpVendorBinExists(cwd, "phpstan")) {
|
|
23672
23767
|
return "phpstan";
|
|
23673
23768
|
}
|
|
23674
|
-
if (fs16.existsSync(
|
|
23769
|
+
if (fs16.existsSync(path47.join(cwd, "pint.json")) && phpVendorBinExists(cwd, "pint")) {
|
|
23675
23770
|
return "pint";
|
|
23676
23771
|
}
|
|
23677
|
-
if (fs16.existsSync(
|
|
23772
|
+
if (fs16.existsSync(path47.join(cwd, ".php-cs-fixer.php")) && phpVendorBinExists(cwd, "php-cs-fixer")) {
|
|
23678
23773
|
return "php-cs-fixer";
|
|
23679
23774
|
}
|
|
23680
|
-
if (fs16.existsSync(
|
|
23775
|
+
if (fs16.existsSync(path47.join(cwd, "phpcs.xml")) && phpVendorBinExists(cwd, "phpcs")) {
|
|
23681
23776
|
return "phpcs";
|
|
23682
23777
|
}
|
|
23683
23778
|
return null;
|
|
@@ -23692,11 +23787,11 @@ function detectDotnetFormat(cwd) {
|
|
|
23692
23787
|
}
|
|
23693
23788
|
}
|
|
23694
23789
|
function detectCppcheck(cwd) {
|
|
23695
|
-
if (fs16.existsSync(
|
|
23790
|
+
if (fs16.existsSync(path47.join(cwd, "CMakeLists.txt"))) {
|
|
23696
23791
|
return isCommandAvailable("cppcheck");
|
|
23697
23792
|
}
|
|
23698
23793
|
try {
|
|
23699
|
-
const dirsToCheck = [cwd,
|
|
23794
|
+
const dirsToCheck = [cwd, path47.join(cwd, "src")];
|
|
23700
23795
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
23701
23796
|
try {
|
|
23702
23797
|
return fs16.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -23710,13 +23805,13 @@ function detectCppcheck(cwd) {
|
|
|
23710
23805
|
}
|
|
23711
23806
|
}
|
|
23712
23807
|
function detectSwiftlint(cwd) {
|
|
23713
|
-
return fs16.existsSync(
|
|
23808
|
+
return fs16.existsSync(path47.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
23714
23809
|
}
|
|
23715
23810
|
function detectDartAnalyze(cwd) {
|
|
23716
|
-
return fs16.existsSync(
|
|
23811
|
+
return fs16.existsSync(path47.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
23717
23812
|
}
|
|
23718
23813
|
function detectRubocop(cwd) {
|
|
23719
|
-
return (fs16.existsSync(
|
|
23814
|
+
return (fs16.existsSync(path47.join(cwd, "Gemfile")) || fs16.existsSync(path47.join(cwd, "gems.rb")) || fs16.existsSync(path47.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
23720
23815
|
}
|
|
23721
23816
|
function detectAdditionalLinter(cwd) {
|
|
23722
23817
|
if (detectRuff(cwd))
|
|
@@ -23747,10 +23842,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
23747
23842
|
function findBinInAncestors(startDir, binName) {
|
|
23748
23843
|
let dir = startDir;
|
|
23749
23844
|
while (true) {
|
|
23750
|
-
const candidate =
|
|
23845
|
+
const candidate = path47.join(dir, "node_modules", ".bin", binName);
|
|
23751
23846
|
if (fs16.existsSync(candidate))
|
|
23752
23847
|
return candidate;
|
|
23753
|
-
const parent =
|
|
23848
|
+
const parent = path47.dirname(dir);
|
|
23754
23849
|
if (parent === dir)
|
|
23755
23850
|
break;
|
|
23756
23851
|
dir = parent;
|
|
@@ -23759,10 +23854,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
23759
23854
|
}
|
|
23760
23855
|
function findBinInEnvPath(binName) {
|
|
23761
23856
|
const searchPath = process.env.PATH ?? "";
|
|
23762
|
-
for (const dir of searchPath.split(
|
|
23857
|
+
for (const dir of searchPath.split(path47.delimiter)) {
|
|
23763
23858
|
if (!dir)
|
|
23764
23859
|
continue;
|
|
23765
|
-
const candidate =
|
|
23860
|
+
const candidate = path47.join(dir, binName);
|
|
23766
23861
|
if (fs16.existsSync(candidate))
|
|
23767
23862
|
return candidate;
|
|
23768
23863
|
}
|
|
@@ -23775,13 +23870,13 @@ async function detectAvailableLinter(directory) {
|
|
|
23775
23870
|
return null;
|
|
23776
23871
|
const projectDir = directory;
|
|
23777
23872
|
const isWindows = process.platform === "win32";
|
|
23778
|
-
const biomeBin = isWindows ?
|
|
23779
|
-
const eslintBin = isWindows ?
|
|
23873
|
+
const biomeBin = isWindows ? path47.join(projectDir, "node_modules", ".bin", "biome.EXE") : path47.join(projectDir, "node_modules", ".bin", "biome");
|
|
23874
|
+
const eslintBin = isWindows ? path47.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path47.join(projectDir, "node_modules", ".bin", "eslint");
|
|
23780
23875
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
23781
23876
|
if (localResult)
|
|
23782
23877
|
return localResult;
|
|
23783
|
-
const biomeAncestor = findBinInAncestors(
|
|
23784
|
-
const eslintAncestor = findBinInAncestors(
|
|
23878
|
+
const biomeAncestor = findBinInAncestors(path47.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
23879
|
+
const eslintAncestor = findBinInAncestors(path47.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
23785
23880
|
if (biomeAncestor || eslintAncestor) {
|
|
23786
23881
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
23787
23882
|
}
|
|
@@ -23995,7 +24090,7 @@ var _internals36 = {
|
|
|
23995
24090
|
|
|
23996
24091
|
// src/tools/secretscan.ts
|
|
23997
24092
|
import * as fs17 from "fs";
|
|
23998
|
-
import * as
|
|
24093
|
+
import * as path48 from "path";
|
|
23999
24094
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
24000
24095
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
24001
24096
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -24222,7 +24317,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
24222
24317
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
24223
24318
|
}
|
|
24224
24319
|
function loadSecretScanIgnore(scanDir) {
|
|
24225
|
-
const ignorePath =
|
|
24320
|
+
const ignorePath = path48.join(scanDir, ".secretscanignore");
|
|
24226
24321
|
try {
|
|
24227
24322
|
if (!fs17.existsSync(ignorePath))
|
|
24228
24323
|
return [];
|
|
@@ -24245,7 +24340,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
24245
24340
|
if (exactNames.has(entry))
|
|
24246
24341
|
return true;
|
|
24247
24342
|
for (const pattern of globPatterns) {
|
|
24248
|
-
if (
|
|
24343
|
+
if (path48.matchesGlob(relPath, pattern))
|
|
24249
24344
|
return true;
|
|
24250
24345
|
}
|
|
24251
24346
|
return false;
|
|
@@ -24266,7 +24361,7 @@ function validateDirectoryInput(dir) {
|
|
|
24266
24361
|
return null;
|
|
24267
24362
|
}
|
|
24268
24363
|
function isBinaryFile(filePath, buffer) {
|
|
24269
|
-
const ext =
|
|
24364
|
+
const ext = path48.extname(filePath).toLowerCase();
|
|
24270
24365
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
24271
24366
|
return true;
|
|
24272
24367
|
}
|
|
@@ -24403,9 +24498,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
24403
24498
|
return false;
|
|
24404
24499
|
}
|
|
24405
24500
|
function isPathWithinScope(realPath, scanDir) {
|
|
24406
|
-
const resolvedScanDir =
|
|
24407
|
-
const resolvedRealPath =
|
|
24408
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
24501
|
+
const resolvedScanDir = path48.resolve(scanDir);
|
|
24502
|
+
const resolvedRealPath = path48.resolve(realPath);
|
|
24503
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path48.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
24409
24504
|
}
|
|
24410
24505
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
24411
24506
|
skippedDirs: 0,
|
|
@@ -24431,8 +24526,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
24431
24526
|
return a.localeCompare(b);
|
|
24432
24527
|
});
|
|
24433
24528
|
for (const entry of entries) {
|
|
24434
|
-
const fullPath =
|
|
24435
|
-
const relPath =
|
|
24529
|
+
const fullPath = path48.join(dir, entry);
|
|
24530
|
+
const relPath = path48.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
24436
24531
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
24437
24532
|
stats.skippedDirs++;
|
|
24438
24533
|
continue;
|
|
@@ -24467,7 +24562,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
24467
24562
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
24468
24563
|
files.push(...subFiles);
|
|
24469
24564
|
} else if (lstat2.isFile()) {
|
|
24470
|
-
const ext =
|
|
24565
|
+
const ext = path48.extname(fullPath).toLowerCase();
|
|
24471
24566
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
24472
24567
|
files.push(fullPath);
|
|
24473
24568
|
} else {
|
|
@@ -24533,7 +24628,7 @@ var secretscan = createSwarmTool({
|
|
|
24533
24628
|
}
|
|
24534
24629
|
}
|
|
24535
24630
|
try {
|
|
24536
|
-
const _scanDirRaw =
|
|
24631
|
+
const _scanDirRaw = path48.resolve(directory);
|
|
24537
24632
|
const scanDir = (() => {
|
|
24538
24633
|
try {
|
|
24539
24634
|
return fs17.realpathSync(_scanDirRaw);
|
|
@@ -24699,12 +24794,12 @@ async function runSecretscanOnFiles(files, directory) {
|
|
|
24699
24794
|
skippedFiles++;
|
|
24700
24795
|
continue;
|
|
24701
24796
|
}
|
|
24702
|
-
const resolvedPath =
|
|
24797
|
+
const resolvedPath = path48.isAbsolute(file) ? path48.resolve(file) : path48.resolve(directory, file);
|
|
24703
24798
|
if (!isPathWithinScope(resolvedPath, directory)) {
|
|
24704
24799
|
skippedFiles++;
|
|
24705
24800
|
continue;
|
|
24706
24801
|
}
|
|
24707
|
-
const ext =
|
|
24802
|
+
const ext = path48.extname(resolvedPath).toLowerCase();
|
|
24708
24803
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
24709
24804
|
skippedFiles++;
|
|
24710
24805
|
continue;
|
|
@@ -24755,11 +24850,11 @@ var _internals37 = {
|
|
|
24755
24850
|
|
|
24756
24851
|
// src/tools/test-runner.ts
|
|
24757
24852
|
import * as fs21 from "fs";
|
|
24758
|
-
import * as
|
|
24853
|
+
import * as path52 from "path";
|
|
24759
24854
|
|
|
24760
24855
|
// src/test-impact/analyzer.ts
|
|
24761
24856
|
import fs18 from "fs";
|
|
24762
|
-
import
|
|
24857
|
+
import path49 from "path";
|
|
24763
24858
|
var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
24764
24859
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
24765
24860
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -24800,8 +24895,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
24800
24895
|
if (!importPath.startsWith(".")) {
|
|
24801
24896
|
return null;
|
|
24802
24897
|
}
|
|
24803
|
-
const resolved =
|
|
24804
|
-
if (
|
|
24898
|
+
const resolved = path49.resolve(fromDir, importPath);
|
|
24899
|
+
if (path49.extname(resolved)) {
|
|
24805
24900
|
if (fs18.existsSync(resolved) && fs18.statSync(resolved).isFile()) {
|
|
24806
24901
|
return normalizePath2(resolved);
|
|
24807
24902
|
}
|
|
@@ -24821,20 +24916,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
24821
24916
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
24822
24917
|
let baseDir = fromDir;
|
|
24823
24918
|
for (let i = 1;i < leadingDots; i++) {
|
|
24824
|
-
baseDir =
|
|
24919
|
+
baseDir = path49.dirname(baseDir);
|
|
24825
24920
|
}
|
|
24826
24921
|
const rest = module.slice(leadingDots);
|
|
24827
24922
|
if (rest.length === 0) {
|
|
24828
|
-
const initPath =
|
|
24923
|
+
const initPath = path49.join(baseDir, "__init__.py");
|
|
24829
24924
|
if (fs18.existsSync(initPath) && fs18.statSync(initPath).isFile()) {
|
|
24830
24925
|
return normalizePath2(initPath);
|
|
24831
24926
|
}
|
|
24832
24927
|
return null;
|
|
24833
24928
|
}
|
|
24834
|
-
const subpath = rest.replace(/\./g,
|
|
24929
|
+
const subpath = rest.replace(/\./g, path49.sep);
|
|
24835
24930
|
const candidates = [
|
|
24836
|
-
`${
|
|
24837
|
-
|
|
24931
|
+
`${path49.join(baseDir, subpath)}.py`,
|
|
24932
|
+
path49.join(baseDir, subpath, "__init__.py")
|
|
24838
24933
|
];
|
|
24839
24934
|
for (const c of candidates) {
|
|
24840
24935
|
if (fs18.existsSync(c) && fs18.statSync(c).isFile())
|
|
@@ -24844,7 +24939,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
24844
24939
|
}
|
|
24845
24940
|
var goModuleCache = new Map;
|
|
24846
24941
|
function findGoModule(fromDir) {
|
|
24847
|
-
const resolved =
|
|
24942
|
+
const resolved = path49.resolve(fromDir);
|
|
24848
24943
|
let cur = resolved;
|
|
24849
24944
|
const walked = [];
|
|
24850
24945
|
for (let i = 0;i < 16; i++) {
|
|
@@ -24856,7 +24951,7 @@ function findGoModule(fromDir) {
|
|
|
24856
24951
|
}
|
|
24857
24952
|
walked.push(cur);
|
|
24858
24953
|
try {
|
|
24859
|
-
const goMod =
|
|
24954
|
+
const goMod = path49.join(cur, "go.mod");
|
|
24860
24955
|
const content = fs18.readFileSync(goMod, "utf-8");
|
|
24861
24956
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
24862
24957
|
if (moduleMatch) {
|
|
@@ -24867,10 +24962,10 @@ function findGoModule(fromDir) {
|
|
|
24867
24962
|
}
|
|
24868
24963
|
} catch {}
|
|
24869
24964
|
try {
|
|
24870
|
-
fs18.accessSync(
|
|
24965
|
+
fs18.accessSync(path49.join(cur, ".git"));
|
|
24871
24966
|
break;
|
|
24872
24967
|
} catch {}
|
|
24873
|
-
const parent =
|
|
24968
|
+
const parent = path49.dirname(cur);
|
|
24874
24969
|
if (parent === cur)
|
|
24875
24970
|
break;
|
|
24876
24971
|
cur = parent;
|
|
@@ -24882,12 +24977,12 @@ function findGoModule(fromDir) {
|
|
|
24882
24977
|
function resolveGoImport(fromDir, importPath) {
|
|
24883
24978
|
let dir = null;
|
|
24884
24979
|
if (importPath.startsWith(".")) {
|
|
24885
|
-
dir =
|
|
24980
|
+
dir = path49.resolve(fromDir, importPath);
|
|
24886
24981
|
} else {
|
|
24887
24982
|
const mod = findGoModule(fromDir);
|
|
24888
24983
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
24889
24984
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
24890
|
-
dir =
|
|
24985
|
+
dir = path49.join(mod.moduleRoot, subpath);
|
|
24891
24986
|
}
|
|
24892
24987
|
}
|
|
24893
24988
|
if (dir === null)
|
|
@@ -24895,7 +24990,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
24895
24990
|
if (!fs18.existsSync(dir) || !fs18.statSync(dir).isDirectory())
|
|
24896
24991
|
return [];
|
|
24897
24992
|
try {
|
|
24898
|
-
return fs18.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(
|
|
24993
|
+
return fs18.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path49.join(dir, f)));
|
|
24899
24994
|
} catch {
|
|
24900
24995
|
return [];
|
|
24901
24996
|
}
|
|
@@ -24934,15 +25029,15 @@ function findTestFilesSync(cwd) {
|
|
|
24934
25029
|
for (const entry of entries) {
|
|
24935
25030
|
if (entry.isDirectory()) {
|
|
24936
25031
|
if (!skipDirs.has(entry.name)) {
|
|
24937
|
-
walk(
|
|
25032
|
+
walk(path49.join(dir, entry.name), visitedInodes);
|
|
24938
25033
|
}
|
|
24939
25034
|
} else if (entry.isFile()) {
|
|
24940
25035
|
const name = entry.name;
|
|
24941
25036
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
24942
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
25037
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path49.sep}tests${path49.sep}`) && name.endsWith(".py");
|
|
24943
25038
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
24944
25039
|
if (isTsTest || isPyTest || isGoTest) {
|
|
24945
|
-
testFiles.push(normalizePath2(
|
|
25040
|
+
testFiles.push(normalizePath2(path49.join(dir, entry.name)));
|
|
24946
25041
|
}
|
|
24947
25042
|
}
|
|
24948
25043
|
}
|
|
@@ -24967,8 +25062,8 @@ function extractImports(content) {
|
|
|
24967
25062
|
];
|
|
24968
25063
|
}
|
|
24969
25064
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
24970
|
-
const ext =
|
|
24971
|
-
const testDir =
|
|
25065
|
+
const ext = path49.extname(testFile).toLowerCase();
|
|
25066
|
+
const testDir = path49.dirname(testFile);
|
|
24972
25067
|
function addEdge(source) {
|
|
24973
25068
|
if (!impactMap[source])
|
|
24974
25069
|
impactMap[source] = [];
|
|
@@ -25042,7 +25137,7 @@ async function buildImpactMap(cwd) {
|
|
|
25042
25137
|
return impactMap;
|
|
25043
25138
|
}
|
|
25044
25139
|
async function loadImpactMap(cwd, options) {
|
|
25045
|
-
const cachePath =
|
|
25140
|
+
const cachePath = path49.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
25046
25141
|
if (fs18.existsSync(cachePath)) {
|
|
25047
25142
|
try {
|
|
25048
25143
|
const content = fs18.readFileSync(cachePath, "utf-8");
|
|
@@ -25075,12 +25170,12 @@ async function loadImpactMap(cwd, options) {
|
|
|
25075
25170
|
return _internals38.buildImpactMap(cwd);
|
|
25076
25171
|
}
|
|
25077
25172
|
async function saveImpactMap(cwd, impactMap) {
|
|
25078
|
-
if (!
|
|
25173
|
+
if (!path49.isAbsolute(cwd)) {
|
|
25079
25174
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
25080
25175
|
}
|
|
25081
25176
|
_internals38.validateProjectRoot(cwd);
|
|
25082
|
-
const cacheDir2 =
|
|
25083
|
-
const cachePath =
|
|
25177
|
+
const cacheDir2 = path49.join(cwd, ".swarm", "cache");
|
|
25178
|
+
const cachePath = path49.join(cacheDir2, "impact-map.json");
|
|
25084
25179
|
if (!fs18.existsSync(cacheDir2)) {
|
|
25085
25180
|
fs18.mkdirSync(cacheDir2, { recursive: true });
|
|
25086
25181
|
}
|
|
@@ -25112,7 +25207,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
25112
25207
|
budgetExceeded = true;
|
|
25113
25208
|
break;
|
|
25114
25209
|
}
|
|
25115
|
-
const normalizedChanged = normalizePath2(
|
|
25210
|
+
const normalizedChanged = normalizePath2(path49.resolve(changedFile));
|
|
25116
25211
|
const tests = impactMap[normalizedChanged];
|
|
25117
25212
|
if (tests && tests.length > 0) {
|
|
25118
25213
|
for (const test of tests) {
|
|
@@ -25126,13 +25221,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
25126
25221
|
if (budgetExceeded)
|
|
25127
25222
|
break;
|
|
25128
25223
|
} else {
|
|
25129
|
-
const changedDir = normalizePath2(
|
|
25130
|
-
const changedInputDir = normalizePath2(
|
|
25224
|
+
const changedDir = normalizePath2(path49.dirname(normalizedChanged));
|
|
25225
|
+
const changedInputDir = normalizePath2(path49.dirname(changedFile));
|
|
25131
25226
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
25132
25227
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
25133
25228
|
}).sort(([sourceA], [sourceB]) => {
|
|
25134
|
-
const sourceDirA = normalizePath2(
|
|
25135
|
-
const sourceDirB = normalizePath2(
|
|
25229
|
+
const sourceDirA = normalizePath2(path49.dirname(sourceA));
|
|
25230
|
+
const sourceDirB = normalizePath2(path49.dirname(sourceB));
|
|
25136
25231
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
25137
25232
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
25138
25233
|
if (exactA !== exactB)
|
|
@@ -25464,7 +25559,7 @@ function detectFlakyTests(allHistory) {
|
|
|
25464
25559
|
|
|
25465
25560
|
// src/test-impact/history-store.ts
|
|
25466
25561
|
import fs19 from "fs";
|
|
25467
|
-
import
|
|
25562
|
+
import path50 from "path";
|
|
25468
25563
|
var MAX_HISTORY_PER_TEST = 20;
|
|
25469
25564
|
var MAX_ERROR_LENGTH = 500;
|
|
25470
25565
|
var MAX_STACK_LENGTH = 200;
|
|
@@ -25476,10 +25571,10 @@ function getHistoryPath(workingDir) {
|
|
|
25476
25571
|
if (!workingDir) {
|
|
25477
25572
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
25478
25573
|
}
|
|
25479
|
-
if (!
|
|
25574
|
+
if (!path50.isAbsolute(workingDir)) {
|
|
25480
25575
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
25481
25576
|
}
|
|
25482
|
-
return
|
|
25577
|
+
return path50.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
25483
25578
|
}
|
|
25484
25579
|
function sanitizeErrorMessage(errorMessage) {
|
|
25485
25580
|
if (errorMessage === undefined) {
|
|
@@ -25571,7 +25666,7 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
25571
25666
|
}
|
|
25572
25667
|
}
|
|
25573
25668
|
const historyPath = getHistoryPath(workingDir);
|
|
25574
|
-
const historyDir =
|
|
25669
|
+
const historyDir = path50.dirname(historyPath);
|
|
25575
25670
|
_internals39.validateProjectRoot(workingDir);
|
|
25576
25671
|
if (!fs19.existsSync(historyDir)) {
|
|
25577
25672
|
fs19.mkdirSync(historyDir, { recursive: true });
|
|
@@ -25701,7 +25796,7 @@ var _internals39 = {
|
|
|
25701
25796
|
|
|
25702
25797
|
// src/tools/resolve-working-directory.ts
|
|
25703
25798
|
import * as fs20 from "fs";
|
|
25704
|
-
import * as
|
|
25799
|
+
import * as path51 from "path";
|
|
25705
25800
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
25706
25801
|
if (workingDirectory == null || workingDirectory === "") {
|
|
25707
25802
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -25738,8 +25833,8 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
25738
25833
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
25739
25834
|
};
|
|
25740
25835
|
}
|
|
25741
|
-
const normalizedDir =
|
|
25742
|
-
const resolvedDir =
|
|
25836
|
+
const normalizedDir = path51.normalize(workingDirectory);
|
|
25837
|
+
const resolvedDir = path51.resolve(normalizedDir);
|
|
25743
25838
|
let statResult;
|
|
25744
25839
|
try {
|
|
25745
25840
|
statResult = fs20.statSync(resolvedDir);
|
|
@@ -25758,7 +25853,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
25758
25853
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
25759
25854
|
return { success: true, directory: resolvedDir };
|
|
25760
25855
|
}
|
|
25761
|
-
const resolvedFallback =
|
|
25856
|
+
const resolvedFallback = path51.resolve(fallbackDirectory);
|
|
25762
25857
|
let fallbackExists = false;
|
|
25763
25858
|
try {
|
|
25764
25859
|
fs20.statSync(resolvedFallback);
|
|
@@ -25767,7 +25862,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
25767
25862
|
fallbackExists = false;
|
|
25768
25863
|
}
|
|
25769
25864
|
if (fallbackExists) {
|
|
25770
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
25865
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path51.sep);
|
|
25771
25866
|
if (isSubdirectory) {
|
|
25772
25867
|
return {
|
|
25773
25868
|
success: false,
|
|
@@ -25790,7 +25885,7 @@ async function estimateFanOut(sourceFiles, cwd) {
|
|
|
25790
25885
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
25791
25886
|
const uniqueTestFiles = new Set;
|
|
25792
25887
|
for (const sourceFile of sourceFiles) {
|
|
25793
|
-
const resolvedPath =
|
|
25888
|
+
const resolvedPath = path52.resolve(cwd, sourceFile);
|
|
25794
25889
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
25795
25890
|
const testFiles = impactMap[normalizedPath];
|
|
25796
25891
|
if (testFiles) {
|
|
@@ -25875,14 +25970,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
25875
25970
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
25876
25971
|
}
|
|
25877
25972
|
function detectGoTest(cwd) {
|
|
25878
|
-
return fs21.existsSync(
|
|
25973
|
+
return fs21.existsSync(path52.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
25879
25974
|
}
|
|
25880
25975
|
function detectJavaMaven(cwd) {
|
|
25881
|
-
return fs21.existsSync(
|
|
25976
|
+
return fs21.existsSync(path52.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
25882
25977
|
}
|
|
25883
25978
|
function detectGradle(cwd) {
|
|
25884
|
-
const hasBuildFile = fs21.existsSync(
|
|
25885
|
-
const hasGradlew = fs21.existsSync(
|
|
25979
|
+
const hasBuildFile = fs21.existsSync(path52.join(cwd, "build.gradle")) || fs21.existsSync(path52.join(cwd, "build.gradle.kts"));
|
|
25980
|
+
const hasGradlew = fs21.existsSync(path52.join(cwd, "gradlew")) || fs21.existsSync(path52.join(cwd, "gradlew.bat"));
|
|
25886
25981
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
25887
25982
|
}
|
|
25888
25983
|
function detectDotnetTest(cwd) {
|
|
@@ -25895,25 +25990,25 @@ function detectDotnetTest(cwd) {
|
|
|
25895
25990
|
}
|
|
25896
25991
|
}
|
|
25897
25992
|
function detectCTest(cwd) {
|
|
25898
|
-
const hasSource = fs21.existsSync(
|
|
25899
|
-
const hasBuildCache = fs21.existsSync(
|
|
25993
|
+
const hasSource = fs21.existsSync(path52.join(cwd, "CMakeLists.txt"));
|
|
25994
|
+
const hasBuildCache = fs21.existsSync(path52.join(cwd, "CMakeCache.txt")) || fs21.existsSync(path52.join(cwd, "build", "CMakeCache.txt"));
|
|
25900
25995
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
25901
25996
|
}
|
|
25902
25997
|
function detectSwiftTest(cwd) {
|
|
25903
|
-
return fs21.existsSync(
|
|
25998
|
+
return fs21.existsSync(path52.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
25904
25999
|
}
|
|
25905
26000
|
function detectDartTest(cwd) {
|
|
25906
|
-
return fs21.existsSync(
|
|
26001
|
+
return fs21.existsSync(path52.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
25907
26002
|
}
|
|
25908
26003
|
function detectRSpec(cwd) {
|
|
25909
|
-
const hasRSpecFile = fs21.existsSync(
|
|
25910
|
-
const hasGemfile = fs21.existsSync(
|
|
25911
|
-
const hasSpecDir = fs21.existsSync(
|
|
26004
|
+
const hasRSpecFile = fs21.existsSync(path52.join(cwd, ".rspec"));
|
|
26005
|
+
const hasGemfile = fs21.existsSync(path52.join(cwd, "Gemfile"));
|
|
26006
|
+
const hasSpecDir = fs21.existsSync(path52.join(cwd, "spec"));
|
|
25912
26007
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
25913
26008
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
25914
26009
|
}
|
|
25915
26010
|
function detectMinitest(cwd) {
|
|
25916
|
-
return fs21.existsSync(
|
|
26011
|
+
return fs21.existsSync(path52.join(cwd, "test")) && (fs21.existsSync(path52.join(cwd, "Gemfile")) || fs21.existsSync(path52.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
25917
26012
|
}
|
|
25918
26013
|
var DISPATCH_FRAMEWORK_MAP = {
|
|
25919
26014
|
bun: "bun",
|
|
@@ -26003,7 +26098,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
26003
26098
|
async function detectTestFramework(cwd) {
|
|
26004
26099
|
const baseDir = cwd;
|
|
26005
26100
|
try {
|
|
26006
|
-
const packageJsonPath =
|
|
26101
|
+
const packageJsonPath = path52.join(baseDir, "package.json");
|
|
26007
26102
|
if (fs21.existsSync(packageJsonPath)) {
|
|
26008
26103
|
const content = fs21.readFileSync(packageJsonPath, "utf-8");
|
|
26009
26104
|
const pkg = JSON.parse(content);
|
|
@@ -26024,16 +26119,16 @@ async function detectTestFramework(cwd) {
|
|
|
26024
26119
|
return "jest";
|
|
26025
26120
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
26026
26121
|
return "mocha";
|
|
26027
|
-
if (fs21.existsSync(
|
|
26122
|
+
if (fs21.existsSync(path52.join(baseDir, "bun.lockb")) || fs21.existsSync(path52.join(baseDir, "bun.lock"))) {
|
|
26028
26123
|
if (scripts.test?.includes("bun"))
|
|
26029
26124
|
return "bun";
|
|
26030
26125
|
}
|
|
26031
26126
|
}
|
|
26032
26127
|
} catch {}
|
|
26033
26128
|
try {
|
|
26034
|
-
const pyprojectTomlPath =
|
|
26035
|
-
const setupCfgPath =
|
|
26036
|
-
const requirementsTxtPath =
|
|
26129
|
+
const pyprojectTomlPath = path52.join(baseDir, "pyproject.toml");
|
|
26130
|
+
const setupCfgPath = path52.join(baseDir, "setup.cfg");
|
|
26131
|
+
const requirementsTxtPath = path52.join(baseDir, "requirements.txt");
|
|
26037
26132
|
if (fs21.existsSync(pyprojectTomlPath)) {
|
|
26038
26133
|
const content = fs21.readFileSync(pyprojectTomlPath, "utf-8");
|
|
26039
26134
|
if (content.includes("[tool.pytest"))
|
|
@@ -26053,7 +26148,7 @@ async function detectTestFramework(cwd) {
|
|
|
26053
26148
|
}
|
|
26054
26149
|
} catch {}
|
|
26055
26150
|
try {
|
|
26056
|
-
const cargoTomlPath =
|
|
26151
|
+
const cargoTomlPath = path52.join(baseDir, "Cargo.toml");
|
|
26057
26152
|
if (fs21.existsSync(cargoTomlPath)) {
|
|
26058
26153
|
const content = fs21.readFileSync(cargoTomlPath, "utf-8");
|
|
26059
26154
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -26064,9 +26159,9 @@ async function detectTestFramework(cwd) {
|
|
|
26064
26159
|
}
|
|
26065
26160
|
} catch {}
|
|
26066
26161
|
try {
|
|
26067
|
-
const pesterConfigPath =
|
|
26068
|
-
const pesterConfigJsonPath =
|
|
26069
|
-
const pesterPs1Path =
|
|
26162
|
+
const pesterConfigPath = path52.join(baseDir, "pester.config.ps1");
|
|
26163
|
+
const pesterConfigJsonPath = path52.join(baseDir, "pester.config.ps1.json");
|
|
26164
|
+
const pesterPs1Path = path52.join(baseDir, "tests.ps1");
|
|
26070
26165
|
if (fs21.existsSync(pesterConfigPath) || fs21.existsSync(pesterConfigJsonPath) || fs21.existsSync(pesterPs1Path)) {
|
|
26071
26166
|
return "pester";
|
|
26072
26167
|
}
|
|
@@ -26095,12 +26190,12 @@ async function detectTestFramework(cwd) {
|
|
|
26095
26190
|
return "none";
|
|
26096
26191
|
}
|
|
26097
26192
|
function detectPhpTest(cwd) {
|
|
26098
|
-
if (fs21.existsSync(
|
|
26193
|
+
if (fs21.existsSync(path52.join(cwd, "artisan")) && fs21.existsSync(path52.join(cwd, "composer.json"))) {
|
|
26099
26194
|
return "php-artisan";
|
|
26100
26195
|
}
|
|
26101
|
-
if (fs21.existsSync(
|
|
26196
|
+
if (fs21.existsSync(path52.join(cwd, "Pest.php")))
|
|
26102
26197
|
return "pest";
|
|
26103
|
-
if (fs21.existsSync(
|
|
26198
|
+
if (fs21.existsSync(path52.join(cwd, "phpunit.xml")) || fs21.existsSync(path52.join(cwd, "phpunit.xml.dist"))) {
|
|
26104
26199
|
return "phpunit";
|
|
26105
26200
|
}
|
|
26106
26201
|
return null;
|
|
@@ -26123,12 +26218,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
26123
26218
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
26124
26219
|
}
|
|
26125
26220
|
function resolveWorkspacePath(file, workingDir) {
|
|
26126
|
-
return
|
|
26221
|
+
return path52.isAbsolute(file) ? path52.resolve(file) : path52.resolve(workingDir, file);
|
|
26127
26222
|
}
|
|
26128
26223
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
26129
26224
|
if (!preferRelative)
|
|
26130
26225
|
return absolutePath;
|
|
26131
|
-
return
|
|
26226
|
+
return path52.relative(workingDir, absolutePath);
|
|
26132
26227
|
}
|
|
26133
26228
|
function dedupePush(target, value) {
|
|
26134
26229
|
if (!target.includes(value)) {
|
|
@@ -26171,18 +26266,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
26171
26266
|
}
|
|
26172
26267
|
}
|
|
26173
26268
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
26174
|
-
const relativeDir =
|
|
26269
|
+
const relativeDir = path52.dirname(relativePath);
|
|
26175
26270
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
26176
26271
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
26177
|
-
const rootDir =
|
|
26178
|
-
return nestedRelativeDir ? [rootDir,
|
|
26272
|
+
const rootDir = path52.join(workingDir, dirName);
|
|
26273
|
+
return nestedRelativeDir ? [rootDir, path52.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
26179
26274
|
});
|
|
26180
26275
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
26181
26276
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
26182
|
-
directories.push(
|
|
26277
|
+
directories.push(path52.join(workingDir, "src/test/java", path52.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
26183
26278
|
}
|
|
26184
26279
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
26185
|
-
directories.push(
|
|
26280
|
+
directories.push(path52.join(workingDir, "src/test/kotlin", path52.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
26186
26281
|
}
|
|
26187
26282
|
return [...new Set(directories)];
|
|
26188
26283
|
}
|
|
@@ -26190,21 +26285,21 @@ function hasCompoundTestExtension(filename) {
|
|
|
26190
26285
|
const lower = filename.toLowerCase();
|
|
26191
26286
|
return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
26192
26287
|
}
|
|
26193
|
-
function isLanguageSpecificTestFile(
|
|
26194
|
-
const lower =
|
|
26288
|
+
function isLanguageSpecificTestFile(basename12) {
|
|
26289
|
+
const lower = basename12.toLowerCase();
|
|
26195
26290
|
if (lower.endsWith("_test.go"))
|
|
26196
26291
|
return true;
|
|
26197
26292
|
if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
|
|
26198
26293
|
return true;
|
|
26199
26294
|
if (lower.endsWith("_spec.rb"))
|
|
26200
26295
|
return true;
|
|
26201
|
-
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(
|
|
26296
|
+
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename12) || basename12.endsWith("Test.java") || basename12.endsWith("Tests.java") || lower.endsWith("it.java")))
|
|
26202
26297
|
return true;
|
|
26203
26298
|
if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
|
|
26204
26299
|
return true;
|
|
26205
|
-
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(
|
|
26300
|
+
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename12) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
|
|
26206
26301
|
return true;
|
|
26207
|
-
if (lower.endsWith(".php") && (/^Test[A-Z]/.test(
|
|
26302
|
+
if (lower.endsWith(".php") && (/^Test[A-Z]/.test(basename12) || basename12.endsWith("Test.php") || basename12.endsWith("Tests.php")))
|
|
26208
26303
|
return true;
|
|
26209
26304
|
if (lower.endsWith(".tests.ps1"))
|
|
26210
26305
|
return true;
|
|
@@ -26212,23 +26307,23 @@ function isLanguageSpecificTestFile(basename11) {
|
|
|
26212
26307
|
}
|
|
26213
26308
|
function isConventionTestFilePath(filePath) {
|
|
26214
26309
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
26215
|
-
const
|
|
26216
|
-
return hasCompoundTestExtension(
|
|
26310
|
+
const basename12 = path52.basename(filePath);
|
|
26311
|
+
return hasCompoundTestExtension(basename12) || basename12.includes(".spec.") || basename12.includes(".test.") || isLanguageSpecificTestFile(basename12) || isTestDirectoryPath(normalizedPath);
|
|
26217
26312
|
}
|
|
26218
26313
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
26219
26314
|
const testFiles = [];
|
|
26220
26315
|
for (const file of sourceFiles) {
|
|
26221
26316
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
26222
|
-
const relativeFile =
|
|
26223
|
-
const
|
|
26224
|
-
const dirname25 =
|
|
26225
|
-
const preferRelativeOutput = !
|
|
26317
|
+
const relativeFile = path52.relative(workingDir, absoluteFile);
|
|
26318
|
+
const basename12 = path52.basename(absoluteFile);
|
|
26319
|
+
const dirname25 = path52.dirname(absoluteFile);
|
|
26320
|
+
const preferRelativeOutput = !path52.isAbsolute(file);
|
|
26226
26321
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
26227
26322
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
26228
26323
|
continue;
|
|
26229
26324
|
}
|
|
26230
|
-
const nameWithoutExt =
|
|
26231
|
-
const ext =
|
|
26325
|
+
const nameWithoutExt = basename12.replace(/\.[^.]+$/, "");
|
|
26326
|
+
const ext = path52.extname(basename12);
|
|
26232
26327
|
const genericTestNames = [
|
|
26233
26328
|
`${nameWithoutExt}.spec${ext}`,
|
|
26234
26329
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -26237,17 +26332,17 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
26237
26332
|
const colocatedCandidates = [
|
|
26238
26333
|
...genericTestNames,
|
|
26239
26334
|
...languageSpecificTestNames
|
|
26240
|
-
].map((candidateName) =>
|
|
26335
|
+
].map((candidateName) => path52.join(dirname25, candidateName));
|
|
26241
26336
|
const testDirectoryNames = [
|
|
26242
|
-
|
|
26337
|
+
basename12,
|
|
26243
26338
|
...genericTestNames,
|
|
26244
26339
|
...languageSpecificTestNames
|
|
26245
26340
|
];
|
|
26246
26341
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
26247
26342
|
const possibleTestFiles = [
|
|
26248
26343
|
...colocatedCandidates,
|
|
26249
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
26250
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
26344
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path52.join(dirname25, dirName, candidateName))),
|
|
26345
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path52.join(candidateDir, candidateName)))
|
|
26251
26346
|
];
|
|
26252
26347
|
for (const testFile of possibleTestFiles) {
|
|
26253
26348
|
if (fs21.existsSync(testFile)) {
|
|
@@ -26268,7 +26363,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26268
26363
|
try {
|
|
26269
26364
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
26270
26365
|
const content = fs21.readFileSync(absoluteTestFile, "utf-8");
|
|
26271
|
-
const testDir =
|
|
26366
|
+
const testDir = path52.dirname(absoluteTestFile);
|
|
26272
26367
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
26273
26368
|
let match;
|
|
26274
26369
|
match = importRegex.exec(content);
|
|
@@ -26276,8 +26371,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26276
26371
|
const importPath = match[1];
|
|
26277
26372
|
let resolvedImport;
|
|
26278
26373
|
if (importPath.startsWith(".")) {
|
|
26279
|
-
resolvedImport =
|
|
26280
|
-
const existingExt =
|
|
26374
|
+
resolvedImport = path52.resolve(testDir, importPath);
|
|
26375
|
+
const existingExt = path52.extname(resolvedImport);
|
|
26281
26376
|
if (!existingExt) {
|
|
26282
26377
|
for (const extToTry of [
|
|
26283
26378
|
".ts",
|
|
@@ -26297,12 +26392,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26297
26392
|
} else {
|
|
26298
26393
|
continue;
|
|
26299
26394
|
}
|
|
26300
|
-
const importBasename =
|
|
26301
|
-
const importDir =
|
|
26395
|
+
const importBasename = path52.basename(resolvedImport, path52.extname(resolvedImport));
|
|
26396
|
+
const importDir = path52.dirname(resolvedImport);
|
|
26302
26397
|
for (const sourceFile of absoluteSourceFiles) {
|
|
26303
|
-
const sourceDir =
|
|
26304
|
-
const sourceBasename =
|
|
26305
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
26398
|
+
const sourceDir = path52.dirname(sourceFile);
|
|
26399
|
+
const sourceBasename = path52.basename(sourceFile, path52.extname(sourceFile));
|
|
26400
|
+
const isRelatedDir = importDir === sourceDir || importDir === path52.join(sourceDir, "__tests__") || importDir === path52.join(sourceDir, "tests") || importDir === path52.join(sourceDir, "test") || importDir === path52.join(sourceDir, "spec");
|
|
26306
26401
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
26307
26402
|
dedupePush(testFiles, testFile);
|
|
26308
26403
|
break;
|
|
@@ -26315,8 +26410,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26315
26410
|
while (match !== null) {
|
|
26316
26411
|
const importPath = match[1];
|
|
26317
26412
|
if (importPath.startsWith(".")) {
|
|
26318
|
-
let resolvedImport =
|
|
26319
|
-
const existingExt =
|
|
26413
|
+
let resolvedImport = path52.resolve(testDir, importPath);
|
|
26414
|
+
const existingExt = path52.extname(resolvedImport);
|
|
26320
26415
|
if (!existingExt) {
|
|
26321
26416
|
for (const extToTry of [
|
|
26322
26417
|
".ts",
|
|
@@ -26333,12 +26428,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26333
26428
|
}
|
|
26334
26429
|
}
|
|
26335
26430
|
}
|
|
26336
|
-
const importDir =
|
|
26337
|
-
const importBasename =
|
|
26431
|
+
const importDir = path52.dirname(resolvedImport);
|
|
26432
|
+
const importBasename = path52.basename(resolvedImport, path52.extname(resolvedImport));
|
|
26338
26433
|
for (const sourceFile of absoluteSourceFiles) {
|
|
26339
|
-
const sourceDir =
|
|
26340
|
-
const sourceBasename =
|
|
26341
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
26434
|
+
const sourceDir = path52.dirname(sourceFile);
|
|
26435
|
+
const sourceBasename = path52.basename(sourceFile, path52.extname(sourceFile));
|
|
26436
|
+
const isRelatedDir = importDir === sourceDir || importDir === path52.join(sourceDir, "__tests__") || importDir === path52.join(sourceDir, "tests") || importDir === path52.join(sourceDir, "test") || importDir === path52.join(sourceDir, "spec");
|
|
26342
26437
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
26343
26438
|
dedupePush(testFiles, testFile);
|
|
26344
26439
|
break;
|
|
@@ -26458,8 +26553,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
26458
26553
|
return ["mvn", "test"];
|
|
26459
26554
|
case "gradle": {
|
|
26460
26555
|
const isWindows = process.platform === "win32";
|
|
26461
|
-
const hasGradlewBat = fs21.existsSync(
|
|
26462
|
-
const hasGradlew = fs21.existsSync(
|
|
26556
|
+
const hasGradlewBat = fs21.existsSync(path52.join(baseDir, "gradlew.bat"));
|
|
26557
|
+
const hasGradlew = fs21.existsSync(path52.join(baseDir, "gradlew"));
|
|
26463
26558
|
if (hasGradlewBat && isWindows)
|
|
26464
26559
|
return ["gradlew.bat", "test"];
|
|
26465
26560
|
if (hasGradlew)
|
|
@@ -26476,7 +26571,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
26476
26571
|
"cmake-build-release",
|
|
26477
26572
|
"out"
|
|
26478
26573
|
];
|
|
26479
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs21.existsSync(
|
|
26574
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs21.existsSync(path52.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
26480
26575
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
26481
26576
|
}
|
|
26482
26577
|
case "swift-test":
|
|
@@ -26526,7 +26621,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
26526
26621
|
}
|
|
26527
26622
|
}
|
|
26528
26623
|
function phpVendorBin2(name) {
|
|
26529
|
-
return
|
|
26624
|
+
return path52.join("vendor", "bin", process.platform === "win32" ? `${name}.bat` : name);
|
|
26530
26625
|
}
|
|
26531
26626
|
function mapFrameworkStatusToResult(status) {
|
|
26532
26627
|
if (typeof status !== "string")
|
|
@@ -26949,11 +27044,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
26949
27044
|
};
|
|
26950
27045
|
}
|
|
26951
27046
|
const startTime = Date.now();
|
|
26952
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
27047
|
+
const vitestJsonOutputPath = framework === "vitest" ? path52.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
26953
27048
|
try {
|
|
26954
27049
|
if (vitestJsonOutputPath) {
|
|
26955
27050
|
try {
|
|
26956
|
-
fs21.mkdirSync(
|
|
27051
|
+
fs21.mkdirSync(path52.dirname(vitestJsonOutputPath), { recursive: true });
|
|
26957
27052
|
if (fs21.existsSync(vitestJsonOutputPath)) {
|
|
26958
27053
|
fs21.unlinkSync(vitestJsonOutputPath);
|
|
26959
27054
|
}
|
|
@@ -27122,10 +27217,10 @@ var SKIP_DIRECTORIES = new Set([
|
|
|
27122
27217
|
]);
|
|
27123
27218
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
27124
27219
|
const normalized = testFile.replace(/\\/g, "/");
|
|
27125
|
-
if (!
|
|
27220
|
+
if (!path52.isAbsolute(testFile))
|
|
27126
27221
|
return normalized;
|
|
27127
|
-
const relative6 =
|
|
27128
|
-
if (relative6.startsWith("..") ||
|
|
27222
|
+
const relative6 = path52.relative(workingDir, testFile);
|
|
27223
|
+
if (relative6.startsWith("..") || path52.isAbsolute(relative6)) {
|
|
27129
27224
|
return normalized;
|
|
27130
27225
|
}
|
|
27131
27226
|
return relative6.replace(/\\/g, "/");
|
|
@@ -27364,7 +27459,7 @@ var test_runner = createSwarmTool({
|
|
|
27364
27459
|
const sourceFiles = args.files.filter((file) => {
|
|
27365
27460
|
if (directTestFiles.includes(file))
|
|
27366
27461
|
return false;
|
|
27367
|
-
const ext =
|
|
27462
|
+
const ext = path52.extname(file).toLowerCase();
|
|
27368
27463
|
return SOURCE_EXTENSIONS.has(ext);
|
|
27369
27464
|
});
|
|
27370
27465
|
const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
|
|
@@ -27410,7 +27505,7 @@ var test_runner = createSwarmTool({
|
|
|
27410
27505
|
if (isConventionTestFilePath(f)) {
|
|
27411
27506
|
return false;
|
|
27412
27507
|
}
|
|
27413
|
-
const ext =
|
|
27508
|
+
const ext = path52.extname(f).toLowerCase();
|
|
27414
27509
|
return SOURCE_EXTENSIONS.has(ext);
|
|
27415
27510
|
});
|
|
27416
27511
|
if (sourceFiles.length === 0) {
|
|
@@ -27460,7 +27555,7 @@ var test_runner = createSwarmTool({
|
|
|
27460
27555
|
if (isConventionTestFilePath(f)) {
|
|
27461
27556
|
return false;
|
|
27462
27557
|
}
|
|
27463
|
-
const ext =
|
|
27558
|
+
const ext = path52.extname(f).toLowerCase();
|
|
27464
27559
|
return SOURCE_EXTENSIONS.has(ext);
|
|
27465
27560
|
});
|
|
27466
27561
|
if (sourceFiles.length === 0) {
|
|
@@ -27512,8 +27607,8 @@ var test_runner = createSwarmTool({
|
|
|
27512
27607
|
}
|
|
27513
27608
|
if (impactResult.impactedTests.length > 0) {
|
|
27514
27609
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
27515
|
-
const relativePath =
|
|
27516
|
-
return
|
|
27610
|
+
const relativePath = path52.relative(workingDir, absPath);
|
|
27611
|
+
return path52.isAbsolute(relativePath) ? absPath : relativePath;
|
|
27517
27612
|
});
|
|
27518
27613
|
} else {
|
|
27519
27614
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -27608,8 +27703,8 @@ function validateDirectoryPath(dir) {
|
|
|
27608
27703
|
if (dir.includes("..")) {
|
|
27609
27704
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
27610
27705
|
}
|
|
27611
|
-
const normalized =
|
|
27612
|
-
const absolutePath =
|
|
27706
|
+
const normalized = path53.normalize(dir);
|
|
27707
|
+
const absolutePath = path53.isAbsolute(normalized) ? normalized : path53.resolve(normalized);
|
|
27613
27708
|
return absolutePath;
|
|
27614
27709
|
}
|
|
27615
27710
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -27632,7 +27727,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
27632
27727
|
}
|
|
27633
27728
|
function getPackageVersion(dir) {
|
|
27634
27729
|
try {
|
|
27635
|
-
const packagePath =
|
|
27730
|
+
const packagePath = path53.join(dir, "package.json");
|
|
27636
27731
|
if (fs22.existsSync(packagePath)) {
|
|
27637
27732
|
const content = fs22.readFileSync(packagePath, "utf-8");
|
|
27638
27733
|
const pkg = JSON.parse(content);
|
|
@@ -27643,7 +27738,7 @@ function getPackageVersion(dir) {
|
|
|
27643
27738
|
}
|
|
27644
27739
|
function getChangelogVersion(dir) {
|
|
27645
27740
|
try {
|
|
27646
|
-
const changelogPath =
|
|
27741
|
+
const changelogPath = path53.join(dir, "CHANGELOG.md");
|
|
27647
27742
|
if (fs22.existsSync(changelogPath)) {
|
|
27648
27743
|
const content = fs22.readFileSync(changelogPath, "utf-8");
|
|
27649
27744
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -27657,7 +27752,7 @@ function getChangelogVersion(dir) {
|
|
|
27657
27752
|
function getVersionFileVersion(dir) {
|
|
27658
27753
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
27659
27754
|
for (const file of possibleFiles) {
|
|
27660
|
-
const filePath =
|
|
27755
|
+
const filePath = path53.join(dir, file);
|
|
27661
27756
|
if (fs22.existsSync(filePath)) {
|
|
27662
27757
|
try {
|
|
27663
27758
|
const content = fs22.readFileSync(filePath, "utf-8").trim();
|
|
@@ -28395,7 +28490,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
28395
28490
|
|
|
28396
28491
|
// src/commands/reset.ts
|
|
28397
28492
|
import * as fs23 from "fs";
|
|
28398
|
-
import * as
|
|
28493
|
+
import * as path54 from "path";
|
|
28399
28494
|
|
|
28400
28495
|
// src/background/circuit-breaker.ts
|
|
28401
28496
|
class CircuitBreaker {
|
|
@@ -29114,7 +29209,7 @@ async function handleResetCommand(directory, args) {
|
|
|
29114
29209
|
}
|
|
29115
29210
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
29116
29211
|
try {
|
|
29117
|
-
const rootPath =
|
|
29212
|
+
const rootPath = path54.join(directory, filename);
|
|
29118
29213
|
if (fs23.existsSync(rootPath)) {
|
|
29119
29214
|
fs23.unlinkSync(rootPath);
|
|
29120
29215
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -29152,14 +29247,14 @@ async function handleResetCommand(directory, args) {
|
|
|
29152
29247
|
|
|
29153
29248
|
// src/commands/reset-session.ts
|
|
29154
29249
|
import * as fs26 from "fs";
|
|
29155
|
-
import * as
|
|
29250
|
+
import * as path57 from "path";
|
|
29156
29251
|
|
|
29157
29252
|
// src/prm/trajectory-store.ts
|
|
29158
29253
|
import * as fs24 from "fs/promises";
|
|
29159
|
-
import * as
|
|
29254
|
+
import * as path55 from "path";
|
|
29160
29255
|
var MAX_TRACKED_TRAJECTORY_SESSIONS = 500;
|
|
29161
29256
|
function getTrajectoryPath(sessionId, directory) {
|
|
29162
|
-
const relativePath =
|
|
29257
|
+
const relativePath = path55.join("trajectories", `${sessionId}.jsonl`);
|
|
29163
29258
|
return validateSwarmPath(directory, relativePath);
|
|
29164
29259
|
}
|
|
29165
29260
|
var _inMemoryTrajectoryCache = new Map;
|
|
@@ -29218,7 +29313,7 @@ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
|
|
|
29218
29313
|
for (const entry of entries) {
|
|
29219
29314
|
if (!entry.isFile())
|
|
29220
29315
|
continue;
|
|
29221
|
-
const filePath =
|
|
29316
|
+
const filePath = path55.join(dirPath, entry.name);
|
|
29222
29317
|
try {
|
|
29223
29318
|
const stat6 = await fs24.stat(filePath);
|
|
29224
29319
|
if (now - stat6.mtimeMs > cutoffMs) {
|
|
@@ -29645,16 +29740,16 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
|
|
|
29645
29740
|
}
|
|
29646
29741
|
// src/prm/replay.ts
|
|
29647
29742
|
import { promises as fs25 } from "fs";
|
|
29648
|
-
import
|
|
29743
|
+
import path56 from "path";
|
|
29649
29744
|
function isPathSafe(targetPath, basePath) {
|
|
29650
|
-
const resolvedTarget =
|
|
29651
|
-
const resolvedBase =
|
|
29652
|
-
const rel =
|
|
29653
|
-
return !rel.startsWith("..") && !
|
|
29745
|
+
const resolvedTarget = path56.resolve(targetPath);
|
|
29746
|
+
const resolvedBase = path56.resolve(basePath);
|
|
29747
|
+
const rel = path56.relative(resolvedBase, resolvedTarget);
|
|
29748
|
+
return !rel.startsWith("..") && !path56.isAbsolute(rel);
|
|
29654
29749
|
}
|
|
29655
29750
|
function isWithinReplaysDir(targetPath) {
|
|
29656
|
-
const resolved =
|
|
29657
|
-
const parts = resolved.split(
|
|
29751
|
+
const resolved = path56.resolve(targetPath);
|
|
29752
|
+
const parts = resolved.split(path56.sep);
|
|
29658
29753
|
for (let i = 0;i < parts.length - 1; i++) {
|
|
29659
29754
|
if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
|
|
29660
29755
|
return true;
|
|
@@ -29667,10 +29762,10 @@ function sanitizeFilename(input) {
|
|
|
29667
29762
|
}
|
|
29668
29763
|
async function startReplayRecording(sessionID, directory) {
|
|
29669
29764
|
try {
|
|
29670
|
-
const replayDir =
|
|
29765
|
+
const replayDir = path56.join(directory, ".swarm", "replays");
|
|
29671
29766
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
29672
29767
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
29673
|
-
const filepath =
|
|
29768
|
+
const filepath = path56.join(replayDir, filename);
|
|
29674
29769
|
if (!isPathSafe(filepath, replayDir)) {
|
|
29675
29770
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
29676
29771
|
return null;
|
|
@@ -29752,7 +29847,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
29752
29847
|
} catch {
|
|
29753
29848
|
results.push("\u274C Failed to delete state.json");
|
|
29754
29849
|
}
|
|
29755
|
-
const sessionDir = statePath ?
|
|
29850
|
+
const sessionDir = statePath ? path57.dirname(statePath) : undefined;
|
|
29756
29851
|
let sessionFiles = [];
|
|
29757
29852
|
if (sessionDir && fs26.existsSync(sessionDir)) {
|
|
29758
29853
|
try {
|
|
@@ -29764,7 +29859,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
29764
29859
|
for (const file of sessionFiles) {
|
|
29765
29860
|
if (file === "state.json")
|
|
29766
29861
|
continue;
|
|
29767
|
-
const filePath =
|
|
29862
|
+
const filePath = path57.join(sessionDir, file);
|
|
29768
29863
|
try {
|
|
29769
29864
|
if (!fs26.existsSync(filePath))
|
|
29770
29865
|
continue;
|
|
@@ -29786,7 +29881,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
29786
29881
|
const chainCount = swarmState.delegationChains.size;
|
|
29787
29882
|
swarmState.delegationChains.clear();
|
|
29788
29883
|
results.push(`\u2705 Cleared ${chainCount} delegation chain(s)`);
|
|
29789
|
-
const worktreesDir =
|
|
29884
|
+
const worktreesDir = path57.resolve(path57.dirname(directory), ".swarm-worktrees");
|
|
29790
29885
|
try {
|
|
29791
29886
|
if (fs26.existsSync(worktreesDir)) {
|
|
29792
29887
|
fs26.rmSync(worktreesDir, { recursive: true, force: true });
|
|
@@ -29819,7 +29914,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
29819
29914
|
}
|
|
29820
29915
|
|
|
29821
29916
|
// src/summaries/manager.ts
|
|
29822
|
-
import * as
|
|
29917
|
+
import * as path58 from "path";
|
|
29823
29918
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
29824
29919
|
function sanitizeSummaryId(id) {
|
|
29825
29920
|
if (!id || id.length === 0) {
|
|
@@ -29843,7 +29938,7 @@ function sanitizeSummaryId(id) {
|
|
|
29843
29938
|
}
|
|
29844
29939
|
async function loadFullOutput(directory, id) {
|
|
29845
29940
|
const sanitizedId = sanitizeSummaryId(id);
|
|
29846
|
-
const relativePath =
|
|
29941
|
+
const relativePath = path58.join("summaries", `${sanitizedId}.json`);
|
|
29847
29942
|
validateSwarmPath(directory, relativePath);
|
|
29848
29943
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
29849
29944
|
if (content === null) {
|
|
@@ -29896,7 +29991,7 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
|
29896
29991
|
|
|
29897
29992
|
// src/commands/rollback.ts
|
|
29898
29993
|
import * as fs27 from "fs";
|
|
29899
|
-
import * as
|
|
29994
|
+
import * as path59 from "path";
|
|
29900
29995
|
function safeParseToolJson(result) {
|
|
29901
29996
|
try {
|
|
29902
29997
|
const jsonStr = typeof result === "string" ? result : result.output;
|
|
@@ -30051,8 +30146,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30051
30146
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
30052
30147
|
continue;
|
|
30053
30148
|
}
|
|
30054
|
-
const src =
|
|
30055
|
-
const dest =
|
|
30149
|
+
const src = path59.join(checkpointDir, file);
|
|
30150
|
+
const dest = path59.join(swarmDir, file);
|
|
30056
30151
|
try {
|
|
30057
30152
|
fs27.cpSync(src, dest, { recursive: true, force: true });
|
|
30058
30153
|
successes.push(file);
|
|
@@ -30071,7 +30166,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30071
30166
|
].join(`
|
|
30072
30167
|
`);
|
|
30073
30168
|
}
|
|
30074
|
-
const existingLedgerPath =
|
|
30169
|
+
const existingLedgerPath = path59.join(swarmDir, "plan-ledger.jsonl");
|
|
30075
30170
|
let ledgerDeletionFailed = false;
|
|
30076
30171
|
if (fs27.existsSync(existingLedgerPath)) {
|
|
30077
30172
|
try {
|
|
@@ -30084,7 +30179,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30084
30179
|
}
|
|
30085
30180
|
if (!ledgerDeletionFailed) {
|
|
30086
30181
|
try {
|
|
30087
|
-
const planJsonPath =
|
|
30182
|
+
const planJsonPath = path59.join(swarmDir, "plan.json");
|
|
30088
30183
|
if (fs27.existsSync(planJsonPath)) {
|
|
30089
30184
|
const planRaw = fs27.readFileSync(planJsonPath, "utf-8");
|
|
30090
30185
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -30132,11 +30227,11 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30132
30227
|
|
|
30133
30228
|
// src/commands/sdd.ts
|
|
30134
30229
|
import * as fs28 from "fs";
|
|
30135
|
-
import * as
|
|
30230
|
+
import * as path60 from "path";
|
|
30136
30231
|
var _internals43 = {
|
|
30137
30232
|
writeProjectedSpecSync
|
|
30138
30233
|
};
|
|
30139
|
-
var SWARM_SPEC_REL =
|
|
30234
|
+
var SWARM_SPEC_REL = path60.join(".swarm", "spec.md");
|
|
30140
30235
|
var USAGE9 = `Usage:
|
|
30141
30236
|
/swarm sdd status [--json] [--source <provider>]
|
|
30142
30237
|
/swarm sdd validate [--json] [--change <id>] [--source <provider>] [--feature <id>]
|
|
@@ -30258,7 +30353,7 @@ ${USAGE9}`;
|
|
|
30258
30353
|
}
|
|
30259
30354
|
const speckitDetection = detectSpeckit(directory);
|
|
30260
30355
|
const speckitPresent = speckitDetection.features.length > 0;
|
|
30261
|
-
const nativeSpecExists = fs28.existsSync(
|
|
30356
|
+
const nativeSpecExists = fs28.existsSync(path60.join(directory, SWARM_SPEC_REL));
|
|
30262
30357
|
if (speckitPresent && !parsed.source && !nativeSpecExists) {
|
|
30263
30358
|
const openspecProjection = buildOpenSpecProjectionSync(directory);
|
|
30264
30359
|
if (openspecProjection !== null) {
|
|
@@ -30328,7 +30423,7 @@ ${USAGE9}`;
|
|
|
30328
30423
|
${USAGE9}`;
|
|
30329
30424
|
}
|
|
30330
30425
|
let useSpeckit = false;
|
|
30331
|
-
const nativeSpecExists = fs28.existsSync(
|
|
30426
|
+
const nativeSpecExists = fs28.existsSync(path60.join(directory, SWARM_SPEC_REL));
|
|
30332
30427
|
if (parsed.source === "speckit") {
|
|
30333
30428
|
useSpeckit = true;
|
|
30334
30429
|
} else if (!parsed.source && !nativeSpecExists) {
|
|
@@ -30482,7 +30577,7 @@ ${USAGE9}`;
|
|
|
30482
30577
|
${USAGE9}`;
|
|
30483
30578
|
}
|
|
30484
30579
|
if (!parsed.dryRun) {
|
|
30485
|
-
const nativeSpecPath =
|
|
30580
|
+
const nativeSpecPath = path60.join(directory, SWARM_SPEC_REL);
|
|
30486
30581
|
if (fs28.existsSync(nativeSpecPath)) {
|
|
30487
30582
|
if (!parsed.overwrite) {
|
|
30488
30583
|
return [
|
|
@@ -30698,10 +30793,10 @@ Ensure this is a git repository with commit history.`;
|
|
|
30698
30793
|
`);
|
|
30699
30794
|
try {
|
|
30700
30795
|
const fs29 = await import("fs/promises");
|
|
30701
|
-
const
|
|
30702
|
-
const reportPath =
|
|
30703
|
-
await fs29.mkdir(
|
|
30704
|
-
const reportTempPath =
|
|
30796
|
+
const path61 = await import("path");
|
|
30797
|
+
const reportPath = path61.join(directory, ".swarm", "simulate-report.md");
|
|
30798
|
+
await fs29.mkdir(path61.dirname(reportPath), { recursive: true });
|
|
30799
|
+
const reportTempPath = path61.join(path61.dirname(reportPath), `${path61.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
30705
30800
|
try {
|
|
30706
30801
|
await fs29.writeFile(reportTempPath, report, "utf-8");
|
|
30707
30802
|
renameSync10(reportTempPath, reportPath);
|
|
@@ -30730,7 +30825,7 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
30730
30825
|
// src/services/status-service.ts
|
|
30731
30826
|
import * as fsSync2 from "fs";
|
|
30732
30827
|
import { readFile as readFile17 } from "fs/promises";
|
|
30733
|
-
import * as
|
|
30828
|
+
import * as path62 from "path";
|
|
30734
30829
|
|
|
30735
30830
|
// src/hooks/extractors.ts
|
|
30736
30831
|
function extractCurrentPhase(planContent) {
|
|
@@ -30775,13 +30870,13 @@ function extractCurrentPhaseFromPlan2(plan) {
|
|
|
30775
30870
|
// src/turbo/lean/state.ts
|
|
30776
30871
|
init_logger();
|
|
30777
30872
|
import * as fs29 from "fs";
|
|
30778
|
-
import * as
|
|
30873
|
+
import * as path61 from "path";
|
|
30779
30874
|
var STATE_FILE3 = "turbo-state.json";
|
|
30780
30875
|
function nowISO3() {
|
|
30781
30876
|
return new Date().toISOString();
|
|
30782
30877
|
}
|
|
30783
30878
|
function ensureSwarmDir2(directory) {
|
|
30784
|
-
const swarmDir =
|
|
30879
|
+
const swarmDir = path61.resolve(directory, ".swarm");
|
|
30785
30880
|
if (!fs29.existsSync(swarmDir)) {
|
|
30786
30881
|
fs29.mkdirSync(swarmDir, { recursive: true });
|
|
30787
30882
|
}
|
|
@@ -30826,7 +30921,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
30826
30921
|
}
|
|
30827
30922
|
function readPersisted2(directory) {
|
|
30828
30923
|
try {
|
|
30829
|
-
const filePath =
|
|
30924
|
+
const filePath = path61.join(directory, ".swarm", STATE_FILE3);
|
|
30830
30925
|
if (!fs29.existsSync(filePath)) {
|
|
30831
30926
|
const seed = emptyPersisted2();
|
|
30832
30927
|
try {
|
|
@@ -30862,7 +30957,7 @@ function writePersisted2(directory, persisted) {
|
|
|
30862
30957
|
let payload;
|
|
30863
30958
|
try {
|
|
30864
30959
|
ensureSwarmDir2(directory);
|
|
30865
|
-
filePath =
|
|
30960
|
+
filePath = path61.join(directory, ".swarm", STATE_FILE3);
|
|
30866
30961
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
30867
30962
|
persisted.updatedAt = nowISO3();
|
|
30868
30963
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -30980,7 +31075,7 @@ var _internals44 = {
|
|
|
30980
31075
|
};
|
|
30981
31076
|
function readSpecStalenessSnapshot(directory) {
|
|
30982
31077
|
try {
|
|
30983
|
-
const p =
|
|
31078
|
+
const p = path62.join(directory, ".swarm", "spec-staleness.json");
|
|
30984
31079
|
if (!fsSync2.existsSync(p))
|
|
30985
31080
|
return { stale: false };
|
|
30986
31081
|
const raw = fsSync2.readFileSync(p, "utf-8");
|
|
@@ -31513,11 +31608,11 @@ function buildStatusMessage2(session, directory, sessionID) {
|
|
|
31513
31608
|
|
|
31514
31609
|
// src/commands/unlink.ts
|
|
31515
31610
|
import { existsSync as existsSync40 } from "fs";
|
|
31516
|
-
import * as
|
|
31611
|
+
import * as path63 from "path";
|
|
31517
31612
|
var DEDUP_THRESHOLD2 = 0.6;
|
|
31518
31613
|
async function copySharedKnowledgeToLocal(linkDir, localSwarmDir) {
|
|
31519
|
-
const sharedPath =
|
|
31520
|
-
const localPath =
|
|
31614
|
+
const sharedPath = path63.join(linkDir, "knowledge.jsonl");
|
|
31615
|
+
const localPath = path63.join(localSwarmDir, "knowledge.jsonl");
|
|
31521
31616
|
if (!existsSync40(sharedPath))
|
|
31522
31617
|
return 0;
|
|
31523
31618
|
const sharedEntries = await readKnowledge(sharedPath);
|
|
@@ -31552,7 +31647,7 @@ async function handleUnlinkCommand(directory, args) {
|
|
|
31552
31647
|
let copied = 0;
|
|
31553
31648
|
if (copyBack) {
|
|
31554
31649
|
try {
|
|
31555
|
-
copied = await copySharedKnowledgeToLocal(linkDir,
|
|
31650
|
+
copied = await copySharedKnowledgeToLocal(linkDir, path63.join(directory, ".swarm"));
|
|
31556
31651
|
} catch (error2) {
|
|
31557
31652
|
return `\u274C Failed to copy shared knowledge back to local: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
31558
31653
|
}
|
|
@@ -31714,7 +31809,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
31714
31809
|
async function handleHelpCommand(ctx) {
|
|
31715
31810
|
const targetCommand = ctx.args.join(" ");
|
|
31716
31811
|
if (!targetCommand) {
|
|
31717
|
-
const { buildHelpText } = await import("./index-
|
|
31812
|
+
const { buildHelpText } = await import("./index-3nd7bz90.js");
|
|
31718
31813
|
return buildHelpText();
|
|
31719
31814
|
}
|
|
31720
31815
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -31723,7 +31818,7 @@ async function handleHelpCommand(ctx) {
|
|
|
31723
31818
|
return _internals46.buildDetailedHelp(resolved.key, resolved.entry);
|
|
31724
31819
|
}
|
|
31725
31820
|
const similar = _internals46.findSimilarCommands(targetCommand);
|
|
31726
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
31821
|
+
const { buildHelpText: fullHelp } = await import("./index-3nd7bz90.js");
|
|
31727
31822
|
if (similar.length > 0) {
|
|
31728
31823
|
return `Command '/swarm ${targetCommand}' not found.
|
|
31729
31824
|
|
|
@@ -31856,7 +31951,7 @@ var COMMAND_REGISTRY = {
|
|
|
31856
31951
|
},
|
|
31857
31952
|
"guardrail explain": {
|
|
31858
31953
|
handler: async (ctx) => {
|
|
31859
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
31954
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-csnawe0d.js");
|
|
31860
31955
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
31861
31956
|
},
|
|
31862
31957
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -32646,24 +32741,24 @@ function validateAliases() {
|
|
|
32646
32741
|
continue;
|
|
32647
32742
|
}
|
|
32648
32743
|
const visited = new Set;
|
|
32649
|
-
const
|
|
32744
|
+
const path64 = [];
|
|
32650
32745
|
let current = target;
|
|
32651
32746
|
while (current) {
|
|
32652
32747
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
32653
32748
|
if (!currentEntry)
|
|
32654
32749
|
break;
|
|
32655
32750
|
if (visited.has(current)) {
|
|
32656
|
-
const cycleStart =
|
|
32751
|
+
const cycleStart = path64.indexOf(current);
|
|
32657
32752
|
const fullChain = [
|
|
32658
32753
|
name,
|
|
32659
|
-
...
|
|
32754
|
+
...path64.slice(0, cycleStart > 0 ? cycleStart : path64.length),
|
|
32660
32755
|
current
|
|
32661
32756
|
].join(" \u2192 ");
|
|
32662
32757
|
errors.push(`Circular alias detected: ${fullChain}`);
|
|
32663
32758
|
break;
|
|
32664
32759
|
}
|
|
32665
32760
|
visited.add(current);
|
|
32666
|
-
|
|
32761
|
+
path64.push(current);
|
|
32667
32762
|
current = currentEntry.aliasOf || "";
|
|
32668
32763
|
}
|
|
32669
32764
|
}
|
|
@@ -34002,7 +34097,7 @@ init_logger();
|
|
|
34002
34097
|
|
|
34003
34098
|
// src/hooks/guardrails/destructive-command.ts
|
|
34004
34099
|
import * as fsSync3 from "fs";
|
|
34005
|
-
import * as
|
|
34100
|
+
import * as path64 from "path";
|
|
34006
34101
|
var DC_MAX_UNWRAP_DEPTH = 5;
|
|
34007
34102
|
var DC_SAFE_TARGETS = new Set([
|
|
34008
34103
|
"node_modules",
|
|
@@ -34166,16 +34261,16 @@ function dcIsRemotePath(p) {
|
|
|
34166
34261
|
return DC_REMOTE_PREFIXES.some((pfx) => p.startsWith(pfx));
|
|
34167
34262
|
}
|
|
34168
34263
|
function dcLstatAncestorWalk(targetPath, cwd) {
|
|
34169
|
-
const normalizedTarget =
|
|
34170
|
-
const normalizedCwd =
|
|
34264
|
+
const normalizedTarget = path64.resolve(cwd, targetPath);
|
|
34265
|
+
const normalizedCwd = path64.resolve(cwd);
|
|
34171
34266
|
const ancestors = [];
|
|
34172
34267
|
let current = normalizedTarget;
|
|
34173
34268
|
while (true) {
|
|
34174
34269
|
ancestors.push(current);
|
|
34175
|
-
const parent =
|
|
34270
|
+
const parent = path64.dirname(current);
|
|
34176
34271
|
if (parent === current)
|
|
34177
34272
|
break;
|
|
34178
|
-
const rel =
|
|
34273
|
+
const rel = path64.relative(normalizedCwd, current);
|
|
34179
34274
|
if (rel === "" || rel.startsWith(".."))
|
|
34180
34275
|
break;
|
|
34181
34276
|
current = parent;
|
|
@@ -34214,14 +34309,14 @@ function dcValidateTargets(targets, cwd) {
|
|
|
34214
34309
|
const lstatBlock = dcLstatAncestorWalk(t, cwd);
|
|
34215
34310
|
if (lstatBlock)
|
|
34216
34311
|
return lstatBlock;
|
|
34217
|
-
const
|
|
34218
|
-
if (t ===
|
|
34312
|
+
const basename13 = path64.basename(t);
|
|
34313
|
+
if (t === basename13 && DC_SAFE_TARGETS.has(t)) {
|
|
34219
34314
|
continue;
|
|
34220
34315
|
}
|
|
34221
34316
|
if (DC_FS_ROOTS.has(t) || DC_FS_ROOTS.has(t.replace(/\//g, "\\"))) {
|
|
34222
34317
|
return `BLOCKED: Destructive command targets filesystem root "${t}"`;
|
|
34223
34318
|
}
|
|
34224
|
-
if (
|
|
34319
|
+
if (path64.isAbsolute(t) || /^[A-Za-z]:/.test(t)) {
|
|
34225
34320
|
for (const blocked of DC_BLOCKED_ABSOLUTE_PREFIXES) {
|
|
34226
34321
|
if (t.startsWith(blocked)) {
|
|
34227
34322
|
return `BLOCKED: Destructive command targets system path "${t}" which is under protected prefix "${blocked}"`;
|
|
@@ -34236,9 +34331,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
34236
34331
|
if (mklinkMatch) {
|
|
34237
34332
|
const target = mklinkMatch[2].trim();
|
|
34238
34333
|
if (!dcHasUnresolvableVars(target)) {
|
|
34239
|
-
const resolved =
|
|
34240
|
-
const rel =
|
|
34241
|
-
if (rel.startsWith("..") ||
|
|
34334
|
+
const resolved = path64.resolve(cwd, target);
|
|
34335
|
+
const rel = path64.relative(cwd, resolved);
|
|
34336
|
+
if (rel.startsWith("..") || path64.isAbsolute(rel)) {
|
|
34242
34337
|
return `BLOCKED: Junction/symlink creation targeting path outside working directory: mklink target "${target}" resolves to "${resolved}" which is outside "${cwd}". Creating junctions to external paths and then deleting them recursively can destroy data.`;
|
|
34243
34338
|
}
|
|
34244
34339
|
}
|
|
@@ -34250,9 +34345,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
34250
34345
|
if (newItemMatch) {
|
|
34251
34346
|
const target = newItemMatch[1].trim();
|
|
34252
34347
|
if (!dcHasUnresolvableVars(target)) {
|
|
34253
|
-
const resolved =
|
|
34254
|
-
const rel =
|
|
34255
|
-
if (rel.startsWith("..") ||
|
|
34348
|
+
const resolved = path64.resolve(cwd, target);
|
|
34349
|
+
const rel = path64.relative(cwd, resolved);
|
|
34350
|
+
if (rel.startsWith("..") || path64.isAbsolute(rel)) {
|
|
34256
34351
|
return `BLOCKED: Junction/symlink creation targeting path outside working directory: New-Item target "${target}" resolves to "${resolved}" which is outside "${cwd}". This pattern caused the K2.6 data-loss incident.`;
|
|
34257
34352
|
}
|
|
34258
34353
|
}
|
|
@@ -34262,9 +34357,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
34262
34357
|
if (lnMatch) {
|
|
34263
34358
|
const target = lnMatch[1].trim();
|
|
34264
34359
|
if (!dcHasUnresolvableVars(target)) {
|
|
34265
|
-
const resolved =
|
|
34266
|
-
const rel =
|
|
34267
|
-
if (rel.startsWith("..") ||
|
|
34360
|
+
const resolved = path64.resolve(cwd, target);
|
|
34361
|
+
const rel = path64.relative(cwd, resolved);
|
|
34362
|
+
if (rel.startsWith("..") || path64.isAbsolute(rel)) {
|
|
34268
34363
|
return `BLOCKED: Symlink creation targeting path outside working directory: ln -s target "${target}" resolves to "${resolved}" which is outside "${cwd}". Symlinks to external paths combined with recursive deletion can destroy data.`;
|
|
34269
34364
|
}
|
|
34270
34365
|
}
|
|
@@ -34635,10 +34730,10 @@ function classifySwarmCommandChatFallbackUse(resolved) {
|
|
|
34635
34730
|
init_executor();
|
|
34636
34731
|
|
|
34637
34732
|
// src/hooks/shell-write-detect.ts
|
|
34638
|
-
import * as
|
|
34733
|
+
import * as path65 from "path";
|
|
34639
34734
|
import parse from "bash-parser";
|
|
34640
|
-
function buildDedupeKey(category, operator,
|
|
34641
|
-
return `${category}|${operator}|${
|
|
34735
|
+
function buildDedupeKey(category, operator, path66) {
|
|
34736
|
+
return `${category}|${operator}|${path66 ?? "null"}`;
|
|
34642
34737
|
}
|
|
34643
34738
|
var REDIRECT_WRITE_TOKENS = new Set([
|
|
34644
34739
|
"GREAT",
|
|
@@ -34698,16 +34793,16 @@ function detectProcessSubstitutionWrites(command) {
|
|
|
34698
34793
|
results.push(builtinResult);
|
|
34699
34794
|
const appendMatch = stage.match(/^\s*(.*?)\s*>>(\s*)(\S+)\s*$/);
|
|
34700
34795
|
if (appendMatch) {
|
|
34701
|
-
const
|
|
34702
|
-
if (
|
|
34703
|
-
results.push({ category: "redirect", operator: ">>", path:
|
|
34796
|
+
const path66 = appendMatch[3];
|
|
34797
|
+
if (path66 && !isNullDevice(path66)) {
|
|
34798
|
+
results.push({ category: "redirect", operator: ">>", path: path66 });
|
|
34704
34799
|
}
|
|
34705
34800
|
} else {
|
|
34706
34801
|
const writeMatch = stage.match(/^\s*(.*?)\s*>(?!>)(\s*)(\S+)\s*$/);
|
|
34707
34802
|
if (writeMatch) {
|
|
34708
|
-
const
|
|
34709
|
-
if (
|
|
34710
|
-
results.push({ category: "redirect", operator: ">", path:
|
|
34803
|
+
const path66 = writeMatch[3];
|
|
34804
|
+
if (path66 && !isNullDevice(path66)) {
|
|
34805
|
+
results.push({ category: "redirect", operator: ">", path: path66 });
|
|
34711
34806
|
}
|
|
34712
34807
|
}
|
|
34713
34808
|
}
|
|
@@ -34881,8 +34976,8 @@ function extractRedirectPath(fileNode) {
|
|
|
34881
34976
|
return null;
|
|
34882
34977
|
return text;
|
|
34883
34978
|
}
|
|
34884
|
-
function isNullDevice(
|
|
34885
|
-
return
|
|
34979
|
+
function isNullDevice(path66) {
|
|
34980
|
+
return path66 === "/dev/null" || path66 === "/dev/zero" || path66 === "/dev/urandom";
|
|
34886
34981
|
}
|
|
34887
34982
|
function isNumeric(s) {
|
|
34888
34983
|
return /^\d+$/.test(s);
|
|
@@ -34902,12 +34997,12 @@ function detectRedirects(cmd) {
|
|
|
34902
34997
|
if (!opType || !REDIRECT_ALL_WRITE_TOKENS.has(opType))
|
|
34903
34998
|
continue;
|
|
34904
34999
|
const fileNode = r.file;
|
|
34905
|
-
const
|
|
35000
|
+
const path66 = extractRedirectPath(fileNode);
|
|
34906
35001
|
const opLabel = operatorLabel(opNode);
|
|
34907
35002
|
if (REDIRECT_WRITE_TOKENS.has(opType)) {
|
|
34908
|
-
results.push({ category: "redirect", operator: opLabel, path:
|
|
35003
|
+
results.push({ category: "redirect", operator: opLabel, path: path66 });
|
|
34909
35004
|
} else if (REDIRECT_HERE_TOKENS.has(opType)) {
|
|
34910
|
-
results.push({ category: "here_doc", operator: opLabel, path:
|
|
35005
|
+
results.push({ category: "here_doc", operator: opLabel, path: path66 });
|
|
34911
35006
|
}
|
|
34912
35007
|
}
|
|
34913
35008
|
return results;
|
|
@@ -34950,9 +35045,9 @@ function detectBuiltinWrites(cmd) {
|
|
|
34950
35045
|
const suffixWords2 = getSuffixWords(cmd);
|
|
34951
35046
|
for (const word of suffixWords2) {
|
|
34952
35047
|
if (word.startsWith("of=")) {
|
|
34953
|
-
const
|
|
34954
|
-
if (
|
|
34955
|
-
results.push({ category: "builtin_write", operator: "dd of=", path:
|
|
35048
|
+
const path66 = word.slice(3);
|
|
35049
|
+
if (path66 && !isNullDevice(path66)) {
|
|
35050
|
+
results.push({ category: "builtin_write", operator: "dd of=", path: path66 });
|
|
34956
35051
|
}
|
|
34957
35052
|
}
|
|
34958
35053
|
}
|
|
@@ -35071,12 +35166,12 @@ function detectNetworkDownloaders(cmd) {
|
|
|
35071
35166
|
for (let i = 0;i < suffixWords.length; i++) {
|
|
35072
35167
|
const word = suffixWords[i];
|
|
35073
35168
|
if (word === "-o" && i + 1 < suffixWords.length) {
|
|
35074
|
-
const
|
|
35075
|
-
if (!
|
|
35169
|
+
const path66 = suffixWords[i + 1];
|
|
35170
|
+
if (!path66.startsWith("-")) {
|
|
35076
35171
|
results.push({
|
|
35077
35172
|
category: "network_download",
|
|
35078
35173
|
operator: "curl -o",
|
|
35079
|
-
path:
|
|
35174
|
+
path: path66
|
|
35080
35175
|
});
|
|
35081
35176
|
}
|
|
35082
35177
|
} else if (word.startsWith("-o") && word.length > 2) {
|
|
@@ -35091,12 +35186,12 @@ function detectNetworkDownloaders(cmd) {
|
|
|
35091
35186
|
for (let i = 0;i < suffixWords.length; i++) {
|
|
35092
35187
|
const word = suffixWords[i];
|
|
35093
35188
|
if (word === "-O" && i + 1 < suffixWords.length) {
|
|
35094
|
-
const
|
|
35095
|
-
if (!
|
|
35189
|
+
const path66 = suffixWords[i + 1];
|
|
35190
|
+
if (!path66.startsWith("-")) {
|
|
35096
35191
|
results.push({
|
|
35097
35192
|
category: "network_download",
|
|
35098
35193
|
operator: "wget -O",
|
|
35099
|
-
path:
|
|
35194
|
+
path: path66
|
|
35100
35195
|
});
|
|
35101
35196
|
}
|
|
35102
35197
|
} else if (word.startsWith("-O") && word.length > 2) {
|
|
@@ -35205,9 +35300,9 @@ function detectGitDestructive(cmd) {
|
|
|
35205
35300
|
if (first === "checkout") {
|
|
35206
35301
|
const dashDashIdx = suffixWords.indexOf("--");
|
|
35207
35302
|
if (dashDashIdx !== -1 && dashDashIdx + 1 < suffixWords.length) {
|
|
35208
|
-
const
|
|
35209
|
-
const op =
|
|
35210
|
-
results.push({ category: "git_destructive", operator: op, path:
|
|
35303
|
+
const path66 = suffixWords[dashDashIdx + 1];
|
|
35304
|
+
const op = path66 === "." ? "git checkout -- ." : "git checkout --";
|
|
35305
|
+
results.push({ category: "git_destructive", operator: op, path: path66 });
|
|
35211
35306
|
}
|
|
35212
35307
|
} else if (first === "restore") {
|
|
35213
35308
|
const hasHard = suffixWords.some((w) => w === "--hard" || w === "-H" || w.startsWith("-") && w.includes("H"));
|
|
@@ -35327,10 +35422,10 @@ function detectPowerShellWrites(command) {
|
|
|
35327
35422
|
if (redirectMatch) {
|
|
35328
35423
|
const beforeRedirect = redirectMatch[1];
|
|
35329
35424
|
const op = redirectMatch[2];
|
|
35330
|
-
const
|
|
35425
|
+
const path66 = redirectMatch[3];
|
|
35331
35426
|
const fdRedirectPattern = /\d>\s*$|\s\d>&$/;
|
|
35332
35427
|
if (!fdRedirectPattern.test(`${beforeRedirect} ${op}`)) {
|
|
35333
|
-
results.push({ category: "redirect", operator: op, path:
|
|
35428
|
+
results.push({ category: "redirect", operator: op, path: path66 });
|
|
35334
35429
|
}
|
|
35335
35430
|
}
|
|
35336
35431
|
const leadingRedirect = innerCommand.match(/^((?:>){1,2})\s+(\S+)$/);
|
|
@@ -35343,12 +35438,12 @@ function detectPowerShellWrites(command) {
|
|
|
35343
35438
|
}
|
|
35344
35439
|
const iwrMatch = trimmed.match(/^(?:Invoke-WebRequest|curl)\s.*?(?:-OutFile\s+(\S+)|-o\s+(\S+))/i);
|
|
35345
35440
|
if (iwrMatch) {
|
|
35346
|
-
const
|
|
35347
|
-
if (
|
|
35441
|
+
const path66 = iwrMatch[1] || iwrMatch[2];
|
|
35442
|
+
if (path66) {
|
|
35348
35443
|
results.push({
|
|
35349
35444
|
category: "network_download",
|
|
35350
35445
|
operator: "Invoke-WebRequest -OutFile",
|
|
35351
|
-
path:
|
|
35446
|
+
path: path66
|
|
35352
35447
|
});
|
|
35353
35448
|
}
|
|
35354
35449
|
}
|
|
@@ -35360,15 +35455,15 @@ function detectPowerShellWrites(command) {
|
|
|
35360
35455
|
const rest = cmd.slice(cmdletMatch[0].length).trim();
|
|
35361
35456
|
const pathFlagMatch = rest.match(/(?:-Path|-FilePath|-LiteralPath)\s+("([^"]+)"|'([^']+)'|(\S+))/i);
|
|
35362
35457
|
if (pathFlagMatch) {
|
|
35363
|
-
const
|
|
35364
|
-
return { category: "redirect", operator: cmdletName, path:
|
|
35458
|
+
const path66 = pathFlagMatch[2] ?? pathFlagMatch[3] ?? pathFlagMatch[4] ?? "";
|
|
35459
|
+
return { category: "redirect", operator: cmdletName, path: path66 };
|
|
35365
35460
|
}
|
|
35366
35461
|
const tokens = rest.match(/(?:[^\s"-]+|"[^"]*"|'[^']*'|-[^\s]+)/g) ?? [];
|
|
35367
35462
|
for (const token of tokens) {
|
|
35368
35463
|
if (token.startsWith("-"))
|
|
35369
35464
|
continue;
|
|
35370
|
-
const
|
|
35371
|
-
return { category: "redirect", operator: cmdletName, path:
|
|
35465
|
+
const path66 = token.replace(/^["']|["']$/g, "");
|
|
35466
|
+
return { category: "redirect", operator: cmdletName, path: path66 };
|
|
35372
35467
|
}
|
|
35373
35468
|
return null;
|
|
35374
35469
|
}
|
|
@@ -35384,9 +35479,9 @@ function detectPowerShellWrites(command) {
|
|
|
35384
35479
|
for (const token of tokens) {
|
|
35385
35480
|
if (token.startsWith("-"))
|
|
35386
35481
|
continue;
|
|
35387
|
-
const
|
|
35388
|
-
if (
|
|
35389
|
-
results.push({ category: "redirect", operator: cmdletName, path:
|
|
35482
|
+
const path66 = token.replace(/^["']|["']$/g, "");
|
|
35483
|
+
if (path66) {
|
|
35484
|
+
results.push({ category: "redirect", operator: cmdletName, path: path66 });
|
|
35390
35485
|
break;
|
|
35391
35486
|
}
|
|
35392
35487
|
}
|
|
@@ -35399,8 +35494,8 @@ function detectPowerShellWrites(command) {
|
|
|
35399
35494
|
const rest = cmd.slice(opMatch[0].length).trim();
|
|
35400
35495
|
const destFlagMatch = rest.match(/-Destination\s+(\S+|"[^"]+"|'[^']+')/i);
|
|
35401
35496
|
if (destFlagMatch) {
|
|
35402
|
-
const
|
|
35403
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
35497
|
+
const path66 = destFlagMatch[1].replace(/^["']|["']$/g, "");
|
|
35498
|
+
return { category: "builtin_write", operator: cmdletName, path: path66 };
|
|
35404
35499
|
}
|
|
35405
35500
|
const tokens = [];
|
|
35406
35501
|
const flagTakingValue = new Set([
|
|
@@ -35439,11 +35534,11 @@ function detectPowerShellWrites(command) {
|
|
|
35439
35534
|
}
|
|
35440
35535
|
}
|
|
35441
35536
|
if (tokens.length >= 2) {
|
|
35442
|
-
const
|
|
35443
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
35537
|
+
const path66 = tokens[tokens.length - 1].replace(/^["']|["']$/g, "");
|
|
35538
|
+
return { category: "builtin_write", operator: cmdletName, path: path66 };
|
|
35444
35539
|
} else if (tokens.length === 1) {
|
|
35445
|
-
const
|
|
35446
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
35540
|
+
const path66 = tokens[0].replace(/^["']|["']$/g, "");
|
|
35541
|
+
return { category: "builtin_write", operator: cmdletName, path: path66 };
|
|
35447
35542
|
}
|
|
35448
35543
|
return null;
|
|
35449
35544
|
}
|
|
@@ -35457,14 +35552,14 @@ function detectPowerShellWrites(command) {
|
|
|
35457
35552
|
const afterCmdlet = pipeFileOpMatch[2].trim();
|
|
35458
35553
|
const destFlagMatch = afterCmdlet.match(/-Destination\s+(\S+|"[^"]+"|'[^']+')/i);
|
|
35459
35554
|
if (destFlagMatch) {
|
|
35460
|
-
const
|
|
35461
|
-
results.push({ category: "builtin_write", operator: cmdletName, path:
|
|
35555
|
+
const path66 = destFlagMatch[1].replace(/^["']|["']$/g, "");
|
|
35556
|
+
results.push({ category: "builtin_write", operator: cmdletName, path: path66 });
|
|
35462
35557
|
} else {
|
|
35463
35558
|
const tokens = afterCmdlet.match(/(?:[^\s"-]+|"[^"]*"|'[^']*'|-[^\s]+)/g) ?? [];
|
|
35464
35559
|
const nonFlagTokens = tokens.filter((t) => !t.startsWith("-") && t.length > 0);
|
|
35465
35560
|
if (nonFlagTokens.length > 0) {
|
|
35466
|
-
const
|
|
35467
|
-
results.push({ category: "builtin_write", operator: cmdletName, path:
|
|
35561
|
+
const path66 = nonFlagTokens[nonFlagTokens.length - 1].replace(/^["']|["']$/g, "");
|
|
35562
|
+
results.push({ category: "builtin_write", operator: cmdletName, path: path66 });
|
|
35468
35563
|
}
|
|
35469
35564
|
}
|
|
35470
35565
|
}
|
|
@@ -35517,10 +35612,10 @@ function detectCmdWrites(command) {
|
|
|
35517
35612
|
if (redirectMatch) {
|
|
35518
35613
|
const beforeRedirect = redirectMatch[1];
|
|
35519
35614
|
const op = redirectMatch[2];
|
|
35520
|
-
const
|
|
35615
|
+
const path66 = redirectMatch[3];
|
|
35521
35616
|
const fdRedirectPattern = /\d>&?$/;
|
|
35522
35617
|
if (!fdRedirectPattern.test(beforeRedirect)) {
|
|
35523
|
-
results.push({ category: "redirect", operator: op, path:
|
|
35618
|
+
results.push({ category: "redirect", operator: op, path: path66 });
|
|
35524
35619
|
}
|
|
35525
35620
|
}
|
|
35526
35621
|
const leadingRedirect = innerCommand.match(/^((?:>){1,2})\s+(\S+)$/);
|
|
@@ -35578,8 +35673,8 @@ function detectCmdWrites(command) {
|
|
|
35578
35673
|
const rawTokens = rest.match(/(\/?[^\s]+|"[^"]*"|'[^']*')/g) ?? [];
|
|
35579
35674
|
const tokens = rawTokens.filter((t) => !t.startsWith("/"));
|
|
35580
35675
|
if (tokens.length > 0) {
|
|
35581
|
-
const
|
|
35582
|
-
return { category: "builtin_write", operator: "del", path:
|
|
35676
|
+
const path66 = tokens[0].replace(/^["']|["']$/g, "");
|
|
35677
|
+
return { category: "builtin_write", operator: "del", path: path66 };
|
|
35583
35678
|
}
|
|
35584
35679
|
return null;
|
|
35585
35680
|
}
|
|
@@ -35589,16 +35684,16 @@ function detectCmdWrites(command) {
|
|
|
35589
35684
|
}
|
|
35590
35685
|
const rdMatch = innerCommand.match(/^rd\s+(?:\/s\s+|\/q\s+)*(\S+)/i);
|
|
35591
35686
|
if (rdMatch) {
|
|
35592
|
-
const
|
|
35593
|
-
if (!
|
|
35594
|
-
results.push({ category: "builtin_write", operator: "rd", path:
|
|
35687
|
+
const path66 = rdMatch[1].replace(/^["']|["']$/g, "");
|
|
35688
|
+
if (!path66.startsWith("/")) {
|
|
35689
|
+
results.push({ category: "builtin_write", operator: "rd", path: path66 });
|
|
35595
35690
|
}
|
|
35596
35691
|
}
|
|
35597
35692
|
const mdMatch = trimmed.match(/^md\s+(\S+)/i);
|
|
35598
35693
|
if (mdMatch) {
|
|
35599
|
-
const
|
|
35600
|
-
if (!
|
|
35601
|
-
results.push({ category: "builtin_write", operator: "md", path:
|
|
35694
|
+
const path66 = mdMatch[1].replace(/^["']|["']$/g, "");
|
|
35695
|
+
if (!path66.startsWith("/")) {
|
|
35696
|
+
results.push({ category: "builtin_write", operator: "md", path: path66 });
|
|
35602
35697
|
}
|
|
35603
35698
|
}
|
|
35604
35699
|
const echoMatch = trimmed.match(/^echo\s+(\S+.*?)\s+((?:>){1,2})\s*(\S+)$/i);
|
|
@@ -35714,10 +35809,10 @@ function resolvePath(pathText, cwd) {
|
|
|
35714
35809
|
return null;
|
|
35715
35810
|
const isWindowsPath = /^[a-zA-Z]:[\\\\/]/.test(cwd) || cwd.includes("\\");
|
|
35716
35811
|
if (isWindowsPath) {
|
|
35717
|
-
return
|
|
35812
|
+
return path65.win32.resolve(cwd, pathText);
|
|
35718
35813
|
}
|
|
35719
|
-
const normalizedRelativeWindowsPath = !
|
|
35720
|
-
return
|
|
35814
|
+
const normalizedRelativeWindowsPath = !path65.posix.isAbsolute(pathText) && !/^[a-zA-Z]:[\\/]/.test(pathText) ? pathText.replace(/\\/g, "/") : pathText;
|
|
35815
|
+
return path65.posix.resolve(cwd, normalizedRelativeWindowsPath);
|
|
35721
35816
|
}
|
|
35722
35817
|
function getCdTarget(cmd) {
|
|
35723
35818
|
if (!cmd || typeof cmd !== "object")
|
|
@@ -35784,7 +35879,7 @@ function collectWritesWithNodes(node, out, cwdStack) {
|
|
|
35784
35879
|
for (const cmd of node.commands) {
|
|
35785
35880
|
const cdTarget = getCdTarget(cmd);
|
|
35786
35881
|
if (cdTarget) {
|
|
35787
|
-
currentStack[0] =
|
|
35882
|
+
currentStack[0] = path65.posix.resolve(currentStack[0] ?? "/", cdTarget);
|
|
35788
35883
|
collectWritesWithNodes(cmd, out, currentStack);
|
|
35789
35884
|
} else {
|
|
35790
35885
|
collectWritesWithNodes(cmd, out, currentStack);
|
|
@@ -35830,7 +35925,7 @@ function collectWritesWithNodes(node, out, cwdStack) {
|
|
|
35830
35925
|
const effectiveCwd = cwdStack[0] ?? "/";
|
|
35831
35926
|
const cdTarget = getCdTarget(node);
|
|
35832
35927
|
if (cdTarget) {
|
|
35833
|
-
cwdStack[0] =
|
|
35928
|
+
cwdStack[0] = path65.posix.resolve(cwdStack[0] ?? "/", cdTarget);
|
|
35834
35929
|
return;
|
|
35835
35930
|
}
|
|
35836
35931
|
const writesFromRedirs = getWritesFromCommandRedirs(node, effectiveCwd);
|
|
@@ -35876,12 +35971,12 @@ function getWritesFromRedirectNode(redirect, _context) {
|
|
|
35876
35971
|
if (!opType || !REDIRECT_ALL_WRITE_TOKENS.has(opType))
|
|
35877
35972
|
return [];
|
|
35878
35973
|
const fileNode = r.file;
|
|
35879
|
-
const
|
|
35974
|
+
const path66 = extractRedirectPath(fileNode);
|
|
35880
35975
|
const opLabel = operatorLabel(opNode);
|
|
35881
35976
|
if (REDIRECT_WRITE_TOKENS.has(opType)) {
|
|
35882
|
-
return [{ category: "redirect", operator: opLabel, path:
|
|
35977
|
+
return [{ category: "redirect", operator: opLabel, path: path66 }];
|
|
35883
35978
|
} else if (REDIRECT_HERE_TOKENS.has(opType)) {
|
|
35884
|
-
return [{ category: "here_doc", operator: opLabel, path:
|
|
35979
|
+
return [{ category: "here_doc", operator: opLabel, path: path66 }];
|
|
35885
35980
|
}
|
|
35886
35981
|
return [];
|
|
35887
35982
|
}
|
|
@@ -36635,7 +36730,7 @@ function evidenceToWorkflowState(evidence) {
|
|
|
36635
36730
|
}
|
|
36636
36731
|
async function readPlanFromDisk(directory) {
|
|
36637
36732
|
try {
|
|
36638
|
-
const planPath =
|
|
36733
|
+
const planPath = path66.join(directory, ".swarm", "plan.json");
|
|
36639
36734
|
const content = await fs30.readFile(planPath, "utf-8");
|
|
36640
36735
|
const parsed = JSON.parse(content);
|
|
36641
36736
|
return PlanSchema.parse(parsed);
|
|
@@ -36646,7 +36741,7 @@ async function readPlanFromDisk(directory) {
|
|
|
36646
36741
|
async function readGateEvidenceFromDisk(directory) {
|
|
36647
36742
|
const evidenceMap = new Map;
|
|
36648
36743
|
try {
|
|
36649
|
-
const evidenceDir =
|
|
36744
|
+
const evidenceDir = path66.join(directory, ".swarm", "evidence");
|
|
36650
36745
|
const entries = await fs30.readdir(evidenceDir, { withFileTypes: true });
|
|
36651
36746
|
for (const entry of entries) {
|
|
36652
36747
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
@@ -36657,7 +36752,7 @@ async function readGateEvidenceFromDisk(directory) {
|
|
|
36657
36752
|
continue;
|
|
36658
36753
|
}
|
|
36659
36754
|
try {
|
|
36660
|
-
const filePath =
|
|
36755
|
+
const filePath = path66.join(evidenceDir, entry.name);
|
|
36661
36756
|
const content = await fs30.readFile(filePath, "utf-8");
|
|
36662
36757
|
const parsed = JSON.parse(content);
|
|
36663
36758
|
if (parsed && typeof parsed.taskId === "string" && Array.isArray(parsed.required_gates)) {
|