opencode-swarm 7.88.4 → 7.89.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{guardrail-explain-xe0wjnxz.js → guardrail-explain-hy0zz0p6.js} +4 -4
- package/dist/cli/{index-rh53rrpt.js → index-1ccnwh54.js} +16 -13
- package/dist/cli/{index-d4hpgf63.js → index-6k31ysgd.js} +1 -1
- package/dist/cli/{index-hs2knbfq.js → index-9w07ye9b.js} +589 -259
- package/dist/cli/{index-e8pk68cc.js → index-axwxkbdd.js} +166 -23
- package/dist/cli/{index-5p1gvn98.js → index-dprk5c5f.js} +8 -4
- package/dist/cli/index.js +3 -3
- package/dist/cli/{knowledge-store-n4x6zyk7.js → knowledge-store-gsy6p46z.js} +1 -1
- package/dist/cli/{skill-generator-s0spm65v.js → skill-generator-1hzfyhth.js} +2 -2
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/link.d.ts +19 -0
- package/dist/commands/registry.d.ts +23 -0
- package/dist/commands/unlink.d.ts +13 -0
- package/dist/hooks/knowledge-events.d.ts +3 -3
- package/dist/hooks/knowledge-link.d.ts +82 -0
- package/dist/hooks/knowledge-validator.d.ts +1 -1
- package/dist/index.js +2078 -1560
- package/dist/knowledge/identity.d.ts +9 -0
- package/dist/session/worktree-link-suggestion.d.ts +27 -0
- package/package.json +1 -1
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
validateActionability,
|
|
21
21
|
validateActionableFields,
|
|
22
22
|
validateLesson
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-1ccnwh54.js";
|
|
24
24
|
import {
|
|
25
25
|
appendKnowledge,
|
|
26
26
|
appendRejectedLesson,
|
|
@@ -31,17 +31,24 @@ import {
|
|
|
31
31
|
enforceKnowledgeCap,
|
|
32
32
|
findNearDuplicate,
|
|
33
33
|
inferTags,
|
|
34
|
+
isLinked,
|
|
34
35
|
normalize,
|
|
35
36
|
readKnowledge,
|
|
37
|
+
readLinkPointer,
|
|
36
38
|
readRejectedLessons,
|
|
37
39
|
readRetractionRecords,
|
|
40
|
+
removeLinkPointer,
|
|
38
41
|
resolveHiveKnowledgePath,
|
|
39
42
|
resolveHiveRejectedPath,
|
|
43
|
+
resolveKnowledgeStoreDir,
|
|
44
|
+
resolveLinkDir,
|
|
40
45
|
resolveSwarmKnowledgePath,
|
|
41
46
|
rewriteKnowledge,
|
|
47
|
+
sanitizeLinkId,
|
|
42
48
|
transactFile,
|
|
43
|
-
transactKnowledge
|
|
44
|
-
|
|
49
|
+
transactKnowledge,
|
|
50
|
+
writeLinkPointer
|
|
51
|
+
} from "./index-axwxkbdd.js";
|
|
45
52
|
import {
|
|
46
53
|
detectStraySwarmDirs,
|
|
47
54
|
readDoctorArtifact,
|
|
@@ -899,7 +906,7 @@ var init_executor = __esm(() => {
|
|
|
899
906
|
// package.json
|
|
900
907
|
var package_default = {
|
|
901
908
|
name: "opencode-swarm",
|
|
902
|
-
version: "7.
|
|
909
|
+
version: "7.89.0",
|
|
903
910
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
904
911
|
main: "dist/index.js",
|
|
905
912
|
types: "dist/index.d.ts",
|
|
@@ -4074,6 +4081,64 @@ function readEarliestSessionStart(directory) {
|
|
|
4074
4081
|
}
|
|
4075
4082
|
}
|
|
4076
4083
|
|
|
4084
|
+
// src/session/worktree-link-suggestion.ts
|
|
4085
|
+
import { execFile } from "child_process";
|
|
4086
|
+
var GIT_TIMEOUT_MS = 1500;
|
|
4087
|
+
var MAX_SUGGESTED_SESSIONS = 500;
|
|
4088
|
+
var _suggestedSessions = new Set;
|
|
4089
|
+
function markSuggested(sessionId) {
|
|
4090
|
+
if (_suggestedSessions.has(sessionId)) {
|
|
4091
|
+
return;
|
|
4092
|
+
}
|
|
4093
|
+
if (_suggestedSessions.size >= MAX_SUGGESTED_SESSIONS) {
|
|
4094
|
+
const oldest = _suggestedSessions.values().next().value;
|
|
4095
|
+
if (oldest !== undefined) {
|
|
4096
|
+
_suggestedSessions.delete(oldest);
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
_suggestedSessions.add(sessionId);
|
|
4100
|
+
}
|
|
4101
|
+
function countWorktrees(directory) {
|
|
4102
|
+
return new Promise((resolve4) => {
|
|
4103
|
+
try {
|
|
4104
|
+
const child = execFile("git", ["-C", directory, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS, windowsHide: true, encoding: "utf-8" }, (err, stdout) => {
|
|
4105
|
+
if (err || typeof stdout !== "string") {
|
|
4106
|
+
resolve4(0);
|
|
4107
|
+
return;
|
|
4108
|
+
}
|
|
4109
|
+
let count = 0;
|
|
4110
|
+
for (const line of stdout.split(`
|
|
4111
|
+
`)) {
|
|
4112
|
+
if (line.startsWith("worktree "))
|
|
4113
|
+
count++;
|
|
4114
|
+
}
|
|
4115
|
+
resolve4(count);
|
|
4116
|
+
});
|
|
4117
|
+
try {
|
|
4118
|
+
child.stdin?.end();
|
|
4119
|
+
} catch {}
|
|
4120
|
+
child.on("error", () => resolve4(0));
|
|
4121
|
+
} catch {
|
|
4122
|
+
resolve4(0);
|
|
4123
|
+
}
|
|
4124
|
+
});
|
|
4125
|
+
}
|
|
4126
|
+
async function maybeSuggestWorktreeLink(directory, sessionId) {
|
|
4127
|
+
try {
|
|
4128
|
+
if (!directory || !sessionId)
|
|
4129
|
+
return;
|
|
4130
|
+
if (_suggestedSessions.has(sessionId))
|
|
4131
|
+
return;
|
|
4132
|
+
markSuggested(sessionId);
|
|
4133
|
+
if (isLinked(directory))
|
|
4134
|
+
return;
|
|
4135
|
+
const worktrees = await countWorktrees(directory);
|
|
4136
|
+
if (worktrees > 1) {
|
|
4137
|
+
console.warn(`[opencode-swarm] Detected ${worktrees} git worktrees of this repo. ` + "Run `/swarm link` in each to share swarm knowledge across them " + "(or `/swarm link <name>` to share with similar projects).");
|
|
4138
|
+
}
|
|
4139
|
+
} catch {}
|
|
4140
|
+
}
|
|
4141
|
+
|
|
4077
4142
|
// src/state/agent-run-context.ts
|
|
4078
4143
|
class AgentRunContext {
|
|
4079
4144
|
runId;
|
|
@@ -4255,6 +4320,9 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
|
|
|
4255
4320
|
try {
|
|
4256
4321
|
recordSessionStart(directory, now);
|
|
4257
4322
|
} catch {}
|
|
4323
|
+
queueMicrotask(() => {
|
|
4324
|
+
maybeSuggestWorktreeLink(directory, sessionId);
|
|
4325
|
+
});
|
|
4258
4326
|
}
|
|
4259
4327
|
telemetry.sessionStarted(sessionId, agentName);
|
|
4260
4328
|
swarmState.activeAgent.set(sessionId, agentName);
|
|
@@ -5239,7 +5307,7 @@ function createSwarmTool(opts) {
|
|
|
5239
5307
|
// src/tools/checkpoint.ts
|
|
5240
5308
|
var CHECKPOINT_LOG_PATH = ".swarm/checkpoints.json";
|
|
5241
5309
|
var MAX_LABEL_LENGTH = 100;
|
|
5242
|
-
var
|
|
5310
|
+
var GIT_TIMEOUT_MS2 = 30000;
|
|
5243
5311
|
var GIT_MAX_BUFFER_BYTES = 5 * 1024 * 1024;
|
|
5244
5312
|
var SHELL_METACHARACTERS = /[;|&$`(){}<>!'"]/;
|
|
5245
5313
|
var SAFE_LABEL_PATTERN = /^[a-zA-Z0-9_ -]+$/;
|
|
@@ -5319,7 +5387,7 @@ function gitExec(args, cwd) {
|
|
|
5319
5387
|
const result = child_process.spawnSync("git", args, {
|
|
5320
5388
|
cwd,
|
|
5321
5389
|
encoding: "utf-8",
|
|
5322
|
-
timeout:
|
|
5390
|
+
timeout: GIT_TIMEOUT_MS2,
|
|
5323
5391
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5324
5392
|
windowsHide: true,
|
|
5325
5393
|
maxBuffer: GIT_MAX_BUFFER_BYTES
|
|
@@ -6177,7 +6245,7 @@ async function runCuratorPostMortem(directory, options = {}) {
|
|
|
6177
6245
|
warnings.push(`Pending proposals capped at ${MAX_PROPOSALS} (had ${proposals.length}); older entries truncated.`);
|
|
6178
6246
|
proposals = proposals.slice(0, MAX_PROPOSALS);
|
|
6179
6247
|
}
|
|
6180
|
-
const unactionablePath = path13.join(directory, "
|
|
6248
|
+
const unactionablePath = path13.join(resolveKnowledgeStoreDir(directory), "knowledge-unactionable.jsonl");
|
|
6181
6249
|
let unactionable = readJsonlFile(unactionablePath, MAX_UNACTIONABLE);
|
|
6182
6250
|
if (unactionable.length > MAX_UNACTIONABLE) {
|
|
6183
6251
|
warnings.push(`Unactionable entries capped at ${MAX_UNACTIONABLE} (had ${unactionable.length}); older entries truncated.`);
|
|
@@ -11288,6 +11356,10 @@ var ACTIVE_STATE_TO_CLEAN = [
|
|
|
11288
11356
|
"swarm.db-shm",
|
|
11289
11357
|
"swarm.db-wal"
|
|
11290
11358
|
];
|
|
11359
|
+
var KNOWLEDGE_FAMILY_ARTIFACTS = new Set([
|
|
11360
|
+
"knowledge.jsonl",
|
|
11361
|
+
"knowledge-rejected.jsonl"
|
|
11362
|
+
]);
|
|
11291
11363
|
var ACTIVE_STATE_DIRS_TO_CLEAN = [
|
|
11292
11364
|
"evidence",
|
|
11293
11365
|
"session",
|
|
@@ -11647,10 +11719,17 @@ async function runArchiveStage(ctx) {
|
|
|
11647
11719
|
try {
|
|
11648
11720
|
await fs11.mkdir(ctx.archiveDir, { recursive: true });
|
|
11649
11721
|
const WAL_SIDECAR_FILES = new Set(["swarm.db-shm", "swarm.db-wal"]);
|
|
11722
|
+
const linkedKnowledgeShared = isLinked(ctx.directory);
|
|
11723
|
+
if (linkedKnowledgeShared) {
|
|
11724
|
+
ctx.warnings.push("Worktree is linked: shared knowledge (knowledge.jsonl, knowledge-rejected.jsonl) lives in the link store and is not archived or cleaned by /swarm close. Manage it via the link.");
|
|
11725
|
+
}
|
|
11650
11726
|
for (const artifact of ARCHIVE_ARTIFACTS) {
|
|
11651
11727
|
if (WAL_SIDECAR_FILES.has(artifact)) {
|
|
11652
11728
|
continue;
|
|
11653
11729
|
}
|
|
11730
|
+
if (linkedKnowledgeShared && KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact)) {
|
|
11731
|
+
continue;
|
|
11732
|
+
}
|
|
11654
11733
|
const srcPath = path24.join(ctx.swarmDir, artifact);
|
|
11655
11734
|
const destPath = path24.join(ctx.archiveDir, artifact);
|
|
11656
11735
|
if (artifact === "swarm.db") {
|
|
@@ -11740,8 +11819,19 @@ async function runArchiveEvidenceRetention(ctx) {
|
|
|
11740
11819
|
async function runCleanStage(ctx) {
|
|
11741
11820
|
let configBackupsRemoved = 0;
|
|
11742
11821
|
const cleanedFiles = [];
|
|
11822
|
+
const linkedKnowledgeShared = isLinked(ctx.directory);
|
|
11823
|
+
if (linkedKnowledgeShared) {
|
|
11824
|
+
for (const artifact of KNOWLEDGE_FAMILY_ARTIFACTS) {
|
|
11825
|
+
if (ctx.archivedActiveStateFiles.has(artifact)) {
|
|
11826
|
+
ctx.warnings.push(`[link-guard] Shared knowledge artifact "${artifact}" appears in ` + "the archive set while this worktree is linked \u2014 archive stage " + "should have skipped it. Artifact will NOT be deleted.");
|
|
11827
|
+
}
|
|
11828
|
+
}
|
|
11829
|
+
}
|
|
11743
11830
|
if (ctx.archivedActiveStateFiles.size > 0) {
|
|
11744
11831
|
for (const artifact of ACTIVE_STATE_TO_CLEAN) {
|
|
11832
|
+
if (linkedKnowledgeShared && KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact)) {
|
|
11833
|
+
continue;
|
|
11834
|
+
}
|
|
11745
11835
|
if (!ctx.archivedActiveStateFiles.has(artifact)) {
|
|
11746
11836
|
const reason = ctx.archiveFailureReasons?.get(artifact);
|
|
11747
11837
|
ctx.warnings.push(reason ? `Preserved ${artifact} because it was not successfully archived: ${reason}.` : `Preserved ${artifact} because it was not successfully archived.`);
|
|
@@ -17975,7 +18065,7 @@ async function handleKnowledgeRestoreCommand(directory, args) {
|
|
|
17975
18065
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
17976
18066
|
}
|
|
17977
18067
|
try {
|
|
17978
|
-
const quarantinePath = join30(directory, "
|
|
18068
|
+
const quarantinePath = join30(resolveKnowledgeStoreDir(directory), "knowledge-quarantined.jsonl");
|
|
17979
18069
|
const entries = await readKnowledge(quarantinePath);
|
|
17980
18070
|
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
17981
18071
|
if ("error" in resolved) {
|
|
@@ -18225,6 +18315,163 @@ var _internals31 = {
|
|
|
18225
18315
|
computeLearningMetrics
|
|
18226
18316
|
};
|
|
18227
18317
|
|
|
18318
|
+
// src/commands/link.ts
|
|
18319
|
+
import { existsSync as existsSync23 } from "fs";
|
|
18320
|
+
import * as path39 from "path";
|
|
18321
|
+
|
|
18322
|
+
// src/knowledge/identity.ts
|
|
18323
|
+
import * as child_process5 from "child_process";
|
|
18324
|
+
import { createHash as createHash4 } from "crypto";
|
|
18325
|
+
import * as path38 from "path";
|
|
18326
|
+
function deriveProjectHash(directory) {
|
|
18327
|
+
const absolutePath = path38.resolve(directory);
|
|
18328
|
+
let hashInput;
|
|
18329
|
+
try {
|
|
18330
|
+
const remoteUrl = child_process5.execSync("git remote get-url origin", {
|
|
18331
|
+
cwd: directory,
|
|
18332
|
+
encoding: "utf-8",
|
|
18333
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
18334
|
+
timeout: 1500
|
|
18335
|
+
}).trim();
|
|
18336
|
+
hashInput = remoteUrl.length > 0 ? remoteUrl : absolutePath;
|
|
18337
|
+
} catch {
|
|
18338
|
+
hashInput = absolutePath;
|
|
18339
|
+
}
|
|
18340
|
+
const hash = createHash4("sha256").update(hashInput).digest("hex");
|
|
18341
|
+
return hash.slice(0, 12);
|
|
18342
|
+
}
|
|
18343
|
+
|
|
18344
|
+
// src/commands/link.ts
|
|
18345
|
+
var DEDUP_THRESHOLD = 0.6;
|
|
18346
|
+
async function mergeLocalKnowledgeIntoLink(localSwarmDir, linkDir) {
|
|
18347
|
+
const localPath = path39.join(localSwarmDir, "knowledge.jsonl");
|
|
18348
|
+
const sharedPath = path39.join(linkDir, "knowledge.jsonl");
|
|
18349
|
+
if (!existsSync23(localPath))
|
|
18350
|
+
return { merged: 0, skipped: 0 };
|
|
18351
|
+
let merged = 0;
|
|
18352
|
+
let skipped = 0;
|
|
18353
|
+
const { readFileSync: readFileSync15 } = await import("fs");
|
|
18354
|
+
let changed = false;
|
|
18355
|
+
await transactKnowledge(sharedPath, (sharedEntries) => {
|
|
18356
|
+
const localEntries = [];
|
|
18357
|
+
try {
|
|
18358
|
+
const content = readFileSync15(localPath, "utf-8");
|
|
18359
|
+
for (const line of content.split(`
|
|
18360
|
+
`)) {
|
|
18361
|
+
if (line.trim()) {
|
|
18362
|
+
try {
|
|
18363
|
+
localEntries.push(JSON.parse(line));
|
|
18364
|
+
} catch {}
|
|
18365
|
+
}
|
|
18366
|
+
}
|
|
18367
|
+
} catch {
|
|
18368
|
+
return null;
|
|
18369
|
+
}
|
|
18370
|
+
if (localEntries.length === 0)
|
|
18371
|
+
return null;
|
|
18372
|
+
const result = [...sharedEntries];
|
|
18373
|
+
const seenIds = new Set(result.map((e) => e.id));
|
|
18374
|
+
changed = false;
|
|
18375
|
+
for (const entry of localEntries) {
|
|
18376
|
+
if (seenIds.has(entry.id)) {
|
|
18377
|
+
skipped++;
|
|
18378
|
+
continue;
|
|
18379
|
+
}
|
|
18380
|
+
if (findNearDuplicate(entry.lesson, result, DEDUP_THRESHOLD)) {
|
|
18381
|
+
skipped++;
|
|
18382
|
+
continue;
|
|
18383
|
+
}
|
|
18384
|
+
result.push(entry);
|
|
18385
|
+
seenIds.add(entry.id);
|
|
18386
|
+
merged++;
|
|
18387
|
+
changed = true;
|
|
18388
|
+
}
|
|
18389
|
+
return changed ? result : null;
|
|
18390
|
+
});
|
|
18391
|
+
return { merged, skipped };
|
|
18392
|
+
}
|
|
18393
|
+
function formatStatus(directory) {
|
|
18394
|
+
const pointer = readLinkPointer(directory);
|
|
18395
|
+
if (!pointer) {
|
|
18396
|
+
return [
|
|
18397
|
+
"\u2139\uFE0F This worktree is NOT linked. Its swarm knowledge is local to `.swarm/`.",
|
|
18398
|
+
"Run `/swarm link` to share knowledge across worktrees of this repo,",
|
|
18399
|
+
"or `/swarm link <name>` to share with deliberately similar projects."
|
|
18400
|
+
].join(`
|
|
18401
|
+
`);
|
|
18402
|
+
}
|
|
18403
|
+
const linkDir = resolveLinkDir(pointer.linkId);
|
|
18404
|
+
const lines = [
|
|
18405
|
+
"\uD83D\uDD17 Linked \u2014 swarm knowledge is shared.",
|
|
18406
|
+
` link id: ${pointer.linkId}`
|
|
18407
|
+
];
|
|
18408
|
+
if (pointer.name)
|
|
18409
|
+
lines.push(` name: ${pointer.name}`);
|
|
18410
|
+
lines.push(` shared at: ${linkDir}`);
|
|
18411
|
+
lines.push(` since: ${pointer.createdAt}`);
|
|
18412
|
+
lines.push("Run `/swarm unlink` to stop sharing (keeps a local copy).");
|
|
18413
|
+
return lines.join(`
|
|
18414
|
+
`);
|
|
18415
|
+
}
|
|
18416
|
+
async function handleLinkCommand(directory, args) {
|
|
18417
|
+
const first = args[0];
|
|
18418
|
+
if (first === "status") {
|
|
18419
|
+
return formatStatus(directory);
|
|
18420
|
+
}
|
|
18421
|
+
const nameArg = args.find((a) => !a.startsWith("--"));
|
|
18422
|
+
let linkId;
|
|
18423
|
+
let displayName;
|
|
18424
|
+
if (nameArg) {
|
|
18425
|
+
const sanitized = sanitizeLinkId(nameArg);
|
|
18426
|
+
if (!sanitized) {
|
|
18427
|
+
return `\u274C Invalid link name "${nameArg}". Use letters, digits, '.', '-', or '_'.`;
|
|
18428
|
+
}
|
|
18429
|
+
linkId = sanitized;
|
|
18430
|
+
displayName = nameArg;
|
|
18431
|
+
} else {
|
|
18432
|
+
try {
|
|
18433
|
+
linkId = deriveProjectHash(directory);
|
|
18434
|
+
} catch (error2) {
|
|
18435
|
+
return `\u274C Failed to derive project hash: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
18436
|
+
}
|
|
18437
|
+
}
|
|
18438
|
+
const existing = readLinkPointer(directory);
|
|
18439
|
+
if (existing && existing.linkId === linkId) {
|
|
18440
|
+
return `\u2139\uFE0F Already linked to "${linkId}".
|
|
18441
|
+
${formatStatus(directory)}`;
|
|
18442
|
+
}
|
|
18443
|
+
const linkDir = resolveLinkDir(linkId);
|
|
18444
|
+
let merge;
|
|
18445
|
+
try {
|
|
18446
|
+
merge = await mergeLocalKnowledgeIntoLink(path39.join(directory, ".swarm"), linkDir);
|
|
18447
|
+
} catch (error2) {
|
|
18448
|
+
return `\u274C Failed to merge local knowledge into the link store: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
18449
|
+
}
|
|
18450
|
+
const pointer = {
|
|
18451
|
+
version: 1,
|
|
18452
|
+
linkId,
|
|
18453
|
+
name: displayName,
|
|
18454
|
+
createdAt: new Date().toISOString(),
|
|
18455
|
+
source: "manual"
|
|
18456
|
+
};
|
|
18457
|
+
try {
|
|
18458
|
+
await writeLinkPointer(directory, pointer);
|
|
18459
|
+
} catch (error2) {
|
|
18460
|
+
return `\u274C Failed to write link pointer: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
18461
|
+
}
|
|
18462
|
+
const relinkNote = existing ? `
|
|
18463
|
+
(Re-linked from previous link "${existing.linkId}".)` : "";
|
|
18464
|
+
const historyNote = merge.merged > 0 ? `
|
|
18465
|
+
note: merged lessons keep their text; their outcome-history counters re-accrue in the shared store.` : "";
|
|
18466
|
+
return [
|
|
18467
|
+
`\uD83D\uDD17 Linked this worktree to shared knowledge store "${linkId}".`,
|
|
18468
|
+
` merged ${merge.merged} local lesson(s) into the shared store` + (merge.skipped > 0 ? ` (${merge.skipped} already present)` : "") + ".",
|
|
18469
|
+
` shared at: ${linkDir}`,
|
|
18470
|
+
"All swarms linked to this id now read and write the same knowledge." + relinkNote + historyNote
|
|
18471
|
+
].join(`
|
|
18472
|
+
`);
|
|
18473
|
+
}
|
|
18474
|
+
|
|
18228
18475
|
// src/commands/loop.ts
|
|
18229
18476
|
var MAX_OBJECTIVE_LEN = 2000;
|
|
18230
18477
|
var DEPTHS2 = new Set(["standard", "exhaustive"]);
|
|
@@ -18340,8 +18587,8 @@ ${USAGE7}`;
|
|
|
18340
18587
|
}
|
|
18341
18588
|
|
|
18342
18589
|
// src/commands/memory.ts
|
|
18343
|
-
import { existsSync as
|
|
18344
|
-
import * as
|
|
18590
|
+
import { existsSync as existsSync26 } from "fs";
|
|
18591
|
+
import * as path46 from "path";
|
|
18345
18592
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18346
18593
|
|
|
18347
18594
|
// src/memory/config.ts
|
|
@@ -18483,11 +18730,11 @@ class MemoryValidationError extends Error {
|
|
|
18483
18730
|
// src/memory/evaluation.ts
|
|
18484
18731
|
import * as fs17 from "fs/promises";
|
|
18485
18732
|
import * as os9 from "os";
|
|
18486
|
-
import * as
|
|
18733
|
+
import * as path44 from "path";
|
|
18487
18734
|
|
|
18488
18735
|
// src/memory/local-jsonl-provider.ts
|
|
18489
18736
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
18490
|
-
import { existsSync as
|
|
18737
|
+
import { existsSync as existsSync24 } from "fs";
|
|
18491
18738
|
import {
|
|
18492
18739
|
appendFile as appendFile3,
|
|
18493
18740
|
mkdir as mkdir10,
|
|
@@ -18495,10 +18742,10 @@ import {
|
|
|
18495
18742
|
rename as rename5,
|
|
18496
18743
|
writeFile as writeFile10
|
|
18497
18744
|
} from "fs/promises";
|
|
18498
|
-
import * as
|
|
18745
|
+
import * as path40 from "path";
|
|
18499
18746
|
|
|
18500
18747
|
// src/memory/schema.ts
|
|
18501
|
-
import { createHash as
|
|
18748
|
+
import { createHash as createHash5 } from "crypto";
|
|
18502
18749
|
|
|
18503
18750
|
// src/memory/redaction.ts
|
|
18504
18751
|
var SECRET_PATTERNS = [
|
|
@@ -18741,7 +18988,7 @@ function stableScopeKey(scope) {
|
|
|
18741
18988
|
}
|
|
18742
18989
|
function computeMemoryContentHash(recordLike) {
|
|
18743
18990
|
const normalized = normalizeMemoryText(recordLike.text).toLowerCase();
|
|
18744
|
-
return
|
|
18991
|
+
return createHash5("sha256").update(`${stableScopeKey(recordLike.scope)}
|
|
18745
18992
|
${recordLike.kind}
|
|
18746
18993
|
${normalized}`).digest("hex");
|
|
18747
18994
|
}
|
|
@@ -19356,7 +19603,7 @@ class LocalJsonlMemoryProvider {
|
|
|
19356
19603
|
pathFor(file) {
|
|
19357
19604
|
const storageDir = this.config.storageDir.replace(/^\.swarm[/\\]?/, "");
|
|
19358
19605
|
const filename = file === "memories" ? "memories.jsonl" : file === "proposals" ? "proposals.jsonl" : "audit.jsonl";
|
|
19359
|
-
return validateSwarmPath(this.rootDirectory,
|
|
19606
|
+
return validateSwarmPath(this.rootDirectory, path40.join(storageDir, filename));
|
|
19360
19607
|
}
|
|
19361
19608
|
async initialize() {
|
|
19362
19609
|
if (this.initialized)
|
|
@@ -19683,7 +19930,7 @@ function validateLoadedProposals(values, config) {
|
|
|
19683
19930
|
return { records, invalidCount };
|
|
19684
19931
|
}
|
|
19685
19932
|
async function readJsonl(filePath) {
|
|
19686
|
-
if (!
|
|
19933
|
+
if (!existsSync24(filePath))
|
|
19687
19934
|
return [];
|
|
19688
19935
|
const content = await readFile12(filePath, "utf-8");
|
|
19689
19936
|
const records = [];
|
|
@@ -19739,12 +19986,12 @@ function parseRecallUsageEvent(event) {
|
|
|
19739
19986
|
}
|
|
19740
19987
|
}
|
|
19741
19988
|
async function appendJsonl(filePath, value) {
|
|
19742
|
-
await mkdir10(
|
|
19989
|
+
await mkdir10(path40.dirname(filePath), { recursive: true });
|
|
19743
19990
|
await appendFile3(filePath, `${JSON.stringify(value)}
|
|
19744
19991
|
`, "utf-8");
|
|
19745
19992
|
}
|
|
19746
19993
|
async function writeJsonlAtomic(filePath, values) {
|
|
19747
|
-
await mkdir10(
|
|
19994
|
+
await mkdir10(path40.dirname(filePath), { recursive: true });
|
|
19748
19995
|
const tmp = `${filePath}.tmp.${randomUUID5()}`;
|
|
19749
19996
|
const content = values.map((value) => JSON.stringify(value)).join(`
|
|
19750
19997
|
`) + (values.length > 0 ? `
|
|
@@ -19755,18 +20002,18 @@ async function writeJsonlAtomic(filePath, values) {
|
|
|
19755
20002
|
|
|
19756
20003
|
// src/memory/provider-pool.ts
|
|
19757
20004
|
import { realpathSync as realpathSync2 } from "fs";
|
|
19758
|
-
import * as
|
|
20005
|
+
import * as path43 from "path";
|
|
19759
20006
|
|
|
19760
20007
|
// src/memory/sqlite-provider.ts
|
|
19761
20008
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
19762
20009
|
import { mkdirSync as mkdirSync15 } from "fs";
|
|
19763
20010
|
import { createRequire as createRequire2 } from "module";
|
|
19764
|
-
import * as
|
|
20011
|
+
import * as path42 from "path";
|
|
19765
20012
|
|
|
19766
20013
|
// src/memory/jsonl-migration.ts
|
|
19767
|
-
import { existsSync as
|
|
20014
|
+
import { existsSync as existsSync25, renameSync as renameSync10, unlinkSync as unlinkSync6 } from "fs";
|
|
19768
20015
|
import { copyFile as copyFile2, mkdir as mkdir11, readFile as readFile13, stat as stat5, writeFile as writeFile11 } from "fs/promises";
|
|
19769
|
-
import * as
|
|
20016
|
+
import * as path41 from "path";
|
|
19770
20017
|
var LEGACY_JSONL_MIGRATION_VERSION = 2;
|
|
19771
20018
|
var LEGACY_JSONL_MIGRATION_NAME = "legacy_jsonl_import_complete";
|
|
19772
20019
|
function resolveMemoryStorageDir(rootDirectory, config = {}) {
|
|
@@ -19782,8 +20029,8 @@ function resolveSqliteDatabasePath(rootDirectory, config = {}) {
|
|
|
19782
20029
|
async function readLegacyJsonl(rootDirectory, config = {}) {
|
|
19783
20030
|
const resolved = resolveConfig(config);
|
|
19784
20031
|
const storageDir = resolveMemoryStorageDir(rootDirectory, resolved);
|
|
19785
|
-
const memoryLoad = await readMemoryJsonl(
|
|
19786
|
-
const proposalLoad = await readProposalJsonl(
|
|
20032
|
+
const memoryLoad = await readMemoryJsonl(path41.join(storageDir, "memories.jsonl"), resolved);
|
|
20033
|
+
const proposalLoad = await readProposalJsonl(path41.join(storageDir, "proposals.jsonl"), resolved);
|
|
19787
20034
|
return {
|
|
19788
20035
|
memories: memoryLoad.records,
|
|
19789
20036
|
proposals: proposalLoad.records,
|
|
@@ -19793,15 +20040,15 @@ async function readLegacyJsonl(rootDirectory, config = {}) {
|
|
|
19793
20040
|
}
|
|
19794
20041
|
async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
19795
20042
|
const storageDir = resolveMemoryStorageDir(rootDirectory, config);
|
|
19796
|
-
const backupDir =
|
|
20043
|
+
const backupDir = path41.join(storageDir, "backups");
|
|
19797
20044
|
await mkdir11(backupDir, { recursive: true });
|
|
19798
20045
|
const results = [];
|
|
19799
20046
|
for (const filename of ["memories.jsonl", "proposals.jsonl"]) {
|
|
19800
|
-
const source =
|
|
19801
|
-
if (!
|
|
20047
|
+
const source = path41.join(storageDir, filename);
|
|
20048
|
+
if (!existsSync25(source))
|
|
19802
20049
|
continue;
|
|
19803
|
-
const backup =
|
|
19804
|
-
if (
|
|
20050
|
+
const backup = path41.join(backupDir, `${filename}.pre-sqlite-migration`);
|
|
20051
|
+
if (existsSync25(backup)) {
|
|
19805
20052
|
results.push({ source, backup, created: false });
|
|
19806
20053
|
continue;
|
|
19807
20054
|
}
|
|
@@ -19811,11 +20058,11 @@ async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
|
19811
20058
|
return results;
|
|
19812
20059
|
}
|
|
19813
20060
|
async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
19814
|
-
const exportDir =
|
|
20061
|
+
const exportDir = path41.join(resolveMemoryStorageDir(rootDirectory, config), "export");
|
|
19815
20062
|
await mkdir11(exportDir, { recursive: true });
|
|
19816
|
-
const memoriesPath =
|
|
19817
|
-
const proposalsPath =
|
|
19818
|
-
const memoriesTempPath =
|
|
20063
|
+
const memoriesPath = path41.join(exportDir, "memories.jsonl");
|
|
20064
|
+
const proposalsPath = path41.join(exportDir, "proposals.jsonl");
|
|
20065
|
+
const memoriesTempPath = path41.join(path41.dirname(memoriesPath), `${path41.basename(memoriesPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
19819
20066
|
try {
|
|
19820
20067
|
await writeFile11(memoriesTempPath, toJsonl(memories), "utf-8");
|
|
19821
20068
|
renameSync10(memoriesTempPath, memoriesPath);
|
|
@@ -19825,7 +20072,7 @@ async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
|
19825
20072
|
} catch {}
|
|
19826
20073
|
throw err;
|
|
19827
20074
|
}
|
|
19828
|
-
const proposalsTempPath =
|
|
20075
|
+
const proposalsTempPath = path41.join(path41.dirname(proposalsPath), `${path41.basename(proposalsPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
19829
20076
|
try {
|
|
19830
20077
|
await writeFile11(proposalsTempPath, toJsonl(proposals), "utf-8");
|
|
19831
20078
|
renameSync10(proposalsTempPath, proposalsPath);
|
|
@@ -19838,9 +20085,9 @@ async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
|
19838
20085
|
return { directory: exportDir, memoriesPath, proposalsPath };
|
|
19839
20086
|
}
|
|
19840
20087
|
async function writeMigrationReport(rootDirectory, report, config = {}) {
|
|
19841
|
-
const reportPath =
|
|
19842
|
-
await mkdir11(
|
|
19843
|
-
const reportTempPath =
|
|
20088
|
+
const reportPath = path41.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
20089
|
+
await mkdir11(path41.dirname(reportPath), { recursive: true });
|
|
20090
|
+
const reportTempPath = path41.join(path41.dirname(reportPath), `${path41.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
19844
20091
|
try {
|
|
19845
20092
|
await writeFile11(reportTempPath, `${JSON.stringify(report, null, 2)}
|
|
19846
20093
|
`, "utf-8");
|
|
@@ -19854,8 +20101,8 @@ async function writeMigrationReport(rootDirectory, report, config = {}) {
|
|
|
19854
20101
|
return reportPath;
|
|
19855
20102
|
}
|
|
19856
20103
|
async function readMigrationReport(rootDirectory, config = {}) {
|
|
19857
|
-
const reportPath =
|
|
19858
|
-
if (!
|
|
20104
|
+
const reportPath = path41.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
20105
|
+
if (!existsSync25(reportPath))
|
|
19859
20106
|
return null;
|
|
19860
20107
|
try {
|
|
19861
20108
|
return JSON.parse(await readFile13(reportPath, "utf-8"));
|
|
@@ -19867,15 +20114,15 @@ async function getLegacyJsonlFileStatus(rootDirectory, config = {}) {
|
|
|
19867
20114
|
const storageDir = resolveMemoryStorageDir(rootDirectory, config);
|
|
19868
20115
|
const statuses = [];
|
|
19869
20116
|
for (const file of ["memories.jsonl", "proposals.jsonl"]) {
|
|
19870
|
-
const filePath =
|
|
20117
|
+
const filePath = path41.join(storageDir, file);
|
|
19871
20118
|
let sizeBytes = 0;
|
|
19872
|
-
if (
|
|
20119
|
+
if (existsSync25(filePath)) {
|
|
19873
20120
|
sizeBytes = (await stat5(filePath)).size;
|
|
19874
20121
|
}
|
|
19875
20122
|
statuses.push({
|
|
19876
20123
|
file,
|
|
19877
20124
|
path: filePath,
|
|
19878
|
-
exists:
|
|
20125
|
+
exists: existsSync25(filePath),
|
|
19879
20126
|
sizeBytes
|
|
19880
20127
|
});
|
|
19881
20128
|
}
|
|
@@ -19956,7 +20203,7 @@ async function readProposalJsonl(filePath, config) {
|
|
|
19956
20203
|
return { records, invalidRows, totalRows: rows.totalRows };
|
|
19957
20204
|
}
|
|
19958
20205
|
async function readJsonlRows(filePath) {
|
|
19959
|
-
if (!
|
|
20206
|
+
if (!existsSync25(filePath)) {
|
|
19960
20207
|
return { rows: [], invalidRows: [], totalRows: 0 };
|
|
19961
20208
|
}
|
|
19962
20209
|
const content = await readFile13(filePath, "utf-8");
|
|
@@ -20175,7 +20422,7 @@ class SQLiteMemoryProvider {
|
|
|
20175
20422
|
}
|
|
20176
20423
|
async doInitialize() {
|
|
20177
20424
|
const dbPath = this.databasePath();
|
|
20178
|
-
mkdirSync15(
|
|
20425
|
+
mkdirSync15(path42.dirname(dbPath), { recursive: true });
|
|
20179
20426
|
const Db = loadDatabaseCtor2();
|
|
20180
20427
|
this.db = new Db(dbPath);
|
|
20181
20428
|
this.db.run("PRAGMA journal_mode = WAL;");
|
|
@@ -21204,7 +21451,7 @@ function resolvePoolKey(directory) {
|
|
|
21204
21451
|
try {
|
|
21205
21452
|
return realpathSync2(directory);
|
|
21206
21453
|
} catch {
|
|
21207
|
-
return
|
|
21454
|
+
return path43.resolve(directory);
|
|
21208
21455
|
}
|
|
21209
21456
|
}
|
|
21210
21457
|
|
|
@@ -21276,7 +21523,7 @@ var DEFAULT_MODES = [
|
|
|
21276
21523
|
];
|
|
21277
21524
|
var DEFAULT_TIMESTAMP = "2026-05-26T12:00:00.000Z";
|
|
21278
21525
|
async function evaluateMemoryRecallFixtures(options) {
|
|
21279
|
-
const fixtureDirectory =
|
|
21526
|
+
const fixtureDirectory = path44.resolve(options.fixtureDirectory);
|
|
21280
21527
|
const providers = options.providers ?? DEFAULT_PROVIDERS;
|
|
21281
21528
|
const modes = options.modes ?? DEFAULT_MODES;
|
|
21282
21529
|
const generatedAt = new Date().toISOString();
|
|
@@ -21285,7 +21532,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
21285
21532
|
for (const fixture of fixtures) {
|
|
21286
21533
|
const materialized = materializeFixture(fixture);
|
|
21287
21534
|
for (const providerName of providers) {
|
|
21288
|
-
const tempRoot = await fs17.realpath(await fs17.mkdtemp(
|
|
21535
|
+
const tempRoot = await fs17.realpath(await fs17.mkdtemp(path44.join(os9.tmpdir(), "swarm-memory-eval-")));
|
|
21289
21536
|
const provider = createEvaluationProvider(providerName, tempRoot);
|
|
21290
21537
|
try {
|
|
21291
21538
|
await provider.initialize?.();
|
|
@@ -21329,7 +21576,7 @@ async function loadRecallEvaluationFixtures(fixtureDirectory) {
|
|
|
21329
21576
|
const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
21330
21577
|
const fixtures = [];
|
|
21331
21578
|
for (const file of files) {
|
|
21332
|
-
const raw = await fs17.readFile(
|
|
21579
|
+
const raw = await fs17.readFile(path44.join(fixtureDirectory, file), "utf-8");
|
|
21333
21580
|
fixtures.push(validateFixture(JSON.parse(raw), file));
|
|
21334
21581
|
}
|
|
21335
21582
|
return fixtures;
|
|
@@ -21606,8 +21853,8 @@ var CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
|
21606
21853
|
}).passthrough();
|
|
21607
21854
|
// src/memory/consolidation-log.ts
|
|
21608
21855
|
import { appendFile as appendFile4, mkdir as mkdir12, readFile as readFile15 } from "fs/promises";
|
|
21609
|
-
import * as
|
|
21610
|
-
var LOG_RELATIVE_PATH =
|
|
21856
|
+
import * as path45 from "path";
|
|
21857
|
+
var LOG_RELATIVE_PATH = path45.join("memory", "consolidation-log.jsonl");
|
|
21611
21858
|
async function readConsolidationLog(directory) {
|
|
21612
21859
|
const filePath = validateSwarmPath(directory, LOG_RELATIVE_PATH);
|
|
21613
21860
|
let raw;
|
|
@@ -21630,7 +21877,7 @@ async function readConsolidationLog(directory) {
|
|
|
21630
21877
|
}
|
|
21631
21878
|
|
|
21632
21879
|
// src/commands/memory.ts
|
|
21633
|
-
var PACKAGE_ROOT =
|
|
21880
|
+
var PACKAGE_ROOT = path46.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
|
|
21634
21881
|
async function handleMemoryCommand(_directory, _args) {
|
|
21635
21882
|
return [
|
|
21636
21883
|
"## Swarm Memory",
|
|
@@ -21688,7 +21935,7 @@ async function handleMemoryStatusCommand(directory, _args) {
|
|
|
21688
21935
|
`- Provider: \`${config.provider}\``,
|
|
21689
21936
|
`- Storage: \`${storageDir}\``,
|
|
21690
21937
|
`- SQLite path: \`${sqlitePath}\``,
|
|
21691
|
-
`- SQLite database exists: \`${
|
|
21938
|
+
`- SQLite database exists: \`${existsSync26(sqlitePath)}\``,
|
|
21692
21939
|
`- Automatic destructive cleanup: \`disabled\``,
|
|
21693
21940
|
"",
|
|
21694
21941
|
"### Legacy JSONL"
|
|
@@ -21928,7 +22175,7 @@ function resolveCommandMemoryConfig(directory) {
|
|
|
21928
22175
|
}
|
|
21929
22176
|
function parseEvaluateArgs(directory, args) {
|
|
21930
22177
|
let json = false;
|
|
21931
|
-
let fixtureDirectory =
|
|
22178
|
+
let fixtureDirectory = path46.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
|
|
21932
22179
|
for (let i = 0;i < args.length; i++) {
|
|
21933
22180
|
const arg = args[i];
|
|
21934
22181
|
if (arg === "--json") {
|
|
@@ -21942,10 +22189,10 @@ function parseEvaluateArgs(directory, args) {
|
|
|
21942
22189
|
error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
|
|
21943
22190
|
};
|
|
21944
22191
|
}
|
|
21945
|
-
const resolvedFixtures =
|
|
21946
|
-
const canonical =
|
|
21947
|
-
const allowedRootA =
|
|
21948
|
-
const allowedRootB =
|
|
22192
|
+
const resolvedFixtures = path46.resolve(directory, next);
|
|
22193
|
+
const canonical = path46.normalize(resolvedFixtures) + path46.sep;
|
|
22194
|
+
const allowedRootA = path46.normalize(directory) + path46.sep;
|
|
22195
|
+
const allowedRootB = path46.normalize(path46.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path46.sep;
|
|
21949
22196
|
if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
|
|
21950
22197
|
return {
|
|
21951
22198
|
error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
|
|
@@ -21984,15 +22231,15 @@ function parseMaintenanceArgs(args, options) {
|
|
|
21984
22231
|
return { limit, confirm };
|
|
21985
22232
|
}
|
|
21986
22233
|
function resolvePackageRootFromModule(modulePath) {
|
|
21987
|
-
const moduleDir =
|
|
21988
|
-
const leaf =
|
|
22234
|
+
const moduleDir = path46.dirname(modulePath);
|
|
22235
|
+
const leaf = path46.basename(moduleDir);
|
|
21989
22236
|
if (leaf === "commands" || leaf === "cli") {
|
|
21990
|
-
return
|
|
22237
|
+
return path46.resolve(moduleDir, "..", "..");
|
|
21991
22238
|
}
|
|
21992
22239
|
if (leaf === "dist") {
|
|
21993
|
-
return
|
|
22240
|
+
return path46.resolve(moduleDir, "..");
|
|
21994
22241
|
}
|
|
21995
|
-
return
|
|
22242
|
+
return path46.resolve(moduleDir, "..");
|
|
21996
22243
|
}
|
|
21997
22244
|
function formatMigrationResult(label, report) {
|
|
21998
22245
|
if (!report) {
|
|
@@ -22687,11 +22934,11 @@ var _internals36 = {
|
|
|
22687
22934
|
|
|
22688
22935
|
// src/services/preflight-service.ts
|
|
22689
22936
|
import * as fs24 from "fs";
|
|
22690
|
-
import * as
|
|
22937
|
+
import * as path53 from "path";
|
|
22691
22938
|
|
|
22692
22939
|
// src/tools/lint.ts
|
|
22693
22940
|
import * as fs18 from "fs";
|
|
22694
|
-
import * as
|
|
22941
|
+
import * as path47 from "path";
|
|
22695
22942
|
|
|
22696
22943
|
// src/utils/path-security.ts
|
|
22697
22944
|
function containsPathTraversal(str) {
|
|
@@ -22747,9 +22994,9 @@ function validateArgs(args) {
|
|
|
22747
22994
|
}
|
|
22748
22995
|
function getLinterCommand(linter, mode, projectDir) {
|
|
22749
22996
|
const isWindows = process.platform === "win32";
|
|
22750
|
-
const binDir =
|
|
22751
|
-
const biomeBin = isWindows ?
|
|
22752
|
-
const eslintBin = isWindows ?
|
|
22997
|
+
const binDir = path47.join(projectDir, "node_modules", ".bin");
|
|
22998
|
+
const biomeBin = isWindows ? path47.join(binDir, "biome.EXE") : path47.join(binDir, "biome");
|
|
22999
|
+
const eslintBin = isWindows ? path47.join(binDir, "eslint.cmd") : path47.join(binDir, "eslint");
|
|
22753
23000
|
switch (linter) {
|
|
22754
23001
|
case "biome":
|
|
22755
23002
|
if (mode === "fix") {
|
|
@@ -22765,7 +23012,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
22765
23012
|
}
|
|
22766
23013
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
22767
23014
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
22768
|
-
const gradlew = fs18.existsSync(
|
|
23015
|
+
const gradlew = fs18.existsSync(path47.join(cwd, gradlewName)) ? path47.join(cwd, gradlewName) : null;
|
|
22769
23016
|
switch (linter) {
|
|
22770
23017
|
case "ruff":
|
|
22771
23018
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -22799,10 +23046,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
22799
23046
|
}
|
|
22800
23047
|
}
|
|
22801
23048
|
function detectRuff(cwd) {
|
|
22802
|
-
if (fs18.existsSync(
|
|
23049
|
+
if (fs18.existsSync(path47.join(cwd, "ruff.toml")))
|
|
22803
23050
|
return isCommandAvailable("ruff");
|
|
22804
23051
|
try {
|
|
22805
|
-
const pyproject =
|
|
23052
|
+
const pyproject = path47.join(cwd, "pyproject.toml");
|
|
22806
23053
|
if (fs18.existsSync(pyproject)) {
|
|
22807
23054
|
const content = fs18.readFileSync(pyproject, "utf-8");
|
|
22808
23055
|
if (content.includes("[tool.ruff]"))
|
|
@@ -22812,19 +23059,19 @@ function detectRuff(cwd) {
|
|
|
22812
23059
|
return false;
|
|
22813
23060
|
}
|
|
22814
23061
|
function detectClippy(cwd) {
|
|
22815
|
-
return fs18.existsSync(
|
|
23062
|
+
return fs18.existsSync(path47.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
22816
23063
|
}
|
|
22817
23064
|
function detectGolangciLint(cwd) {
|
|
22818
|
-
return fs18.existsSync(
|
|
23065
|
+
return fs18.existsSync(path47.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
22819
23066
|
}
|
|
22820
23067
|
function detectCheckstyle(cwd) {
|
|
22821
|
-
const hasMaven = fs18.existsSync(
|
|
22822
|
-
const hasGradle = fs18.existsSync(
|
|
22823
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(
|
|
23068
|
+
const hasMaven = fs18.existsSync(path47.join(cwd, "pom.xml"));
|
|
23069
|
+
const hasGradle = fs18.existsSync(path47.join(cwd, "build.gradle")) || fs18.existsSync(path47.join(cwd, "build.gradle.kts"));
|
|
23070
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(path47.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
22824
23071
|
return (hasMaven || hasGradle) && hasBinary;
|
|
22825
23072
|
}
|
|
22826
23073
|
function detectKtlint(cwd) {
|
|
22827
|
-
const hasKotlin = fs18.existsSync(
|
|
23074
|
+
const hasKotlin = fs18.existsSync(path47.join(cwd, "build.gradle.kts")) || fs18.existsSync(path47.join(cwd, "build.gradle")) || (() => {
|
|
22828
23075
|
try {
|
|
22829
23076
|
return fs18.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
22830
23077
|
} catch {
|
|
@@ -22843,11 +23090,11 @@ function detectDotnetFormat(cwd) {
|
|
|
22843
23090
|
}
|
|
22844
23091
|
}
|
|
22845
23092
|
function detectCppcheck(cwd) {
|
|
22846
|
-
if (fs18.existsSync(
|
|
23093
|
+
if (fs18.existsSync(path47.join(cwd, "CMakeLists.txt"))) {
|
|
22847
23094
|
return isCommandAvailable("cppcheck");
|
|
22848
23095
|
}
|
|
22849
23096
|
try {
|
|
22850
|
-
const dirsToCheck = [cwd,
|
|
23097
|
+
const dirsToCheck = [cwd, path47.join(cwd, "src")];
|
|
22851
23098
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
22852
23099
|
try {
|
|
22853
23100
|
return fs18.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -22861,13 +23108,13 @@ function detectCppcheck(cwd) {
|
|
|
22861
23108
|
}
|
|
22862
23109
|
}
|
|
22863
23110
|
function detectSwiftlint(cwd) {
|
|
22864
|
-
return fs18.existsSync(
|
|
23111
|
+
return fs18.existsSync(path47.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
22865
23112
|
}
|
|
22866
23113
|
function detectDartAnalyze(cwd) {
|
|
22867
|
-
return fs18.existsSync(
|
|
23114
|
+
return fs18.existsSync(path47.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
22868
23115
|
}
|
|
22869
23116
|
function detectRubocop(cwd) {
|
|
22870
|
-
return (fs18.existsSync(
|
|
23117
|
+
return (fs18.existsSync(path47.join(cwd, "Gemfile")) || fs18.existsSync(path47.join(cwd, "gems.rb")) || fs18.existsSync(path47.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
22871
23118
|
}
|
|
22872
23119
|
function detectAdditionalLinter(cwd) {
|
|
22873
23120
|
if (detectRuff(cwd))
|
|
@@ -22895,10 +23142,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
22895
23142
|
function findBinInAncestors(startDir, binName) {
|
|
22896
23143
|
let dir = startDir;
|
|
22897
23144
|
while (true) {
|
|
22898
|
-
const candidate =
|
|
23145
|
+
const candidate = path47.join(dir, "node_modules", ".bin", binName);
|
|
22899
23146
|
if (fs18.existsSync(candidate))
|
|
22900
23147
|
return candidate;
|
|
22901
|
-
const parent =
|
|
23148
|
+
const parent = path47.dirname(dir);
|
|
22902
23149
|
if (parent === dir)
|
|
22903
23150
|
break;
|
|
22904
23151
|
dir = parent;
|
|
@@ -22907,10 +23154,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
22907
23154
|
}
|
|
22908
23155
|
function findBinInEnvPath(binName) {
|
|
22909
23156
|
const searchPath = process.env.PATH ?? "";
|
|
22910
|
-
for (const dir of searchPath.split(
|
|
23157
|
+
for (const dir of searchPath.split(path47.delimiter)) {
|
|
22911
23158
|
if (!dir)
|
|
22912
23159
|
continue;
|
|
22913
|
-
const candidate =
|
|
23160
|
+
const candidate = path47.join(dir, binName);
|
|
22914
23161
|
if (fs18.existsSync(candidate))
|
|
22915
23162
|
return candidate;
|
|
22916
23163
|
}
|
|
@@ -22923,13 +23170,13 @@ async function detectAvailableLinter(directory) {
|
|
|
22923
23170
|
return null;
|
|
22924
23171
|
const projectDir = directory;
|
|
22925
23172
|
const isWindows = process.platform === "win32";
|
|
22926
|
-
const biomeBin = isWindows ?
|
|
22927
|
-
const eslintBin = isWindows ?
|
|
23173
|
+
const biomeBin = isWindows ? path47.join(projectDir, "node_modules", ".bin", "biome.EXE") : path47.join(projectDir, "node_modules", ".bin", "biome");
|
|
23174
|
+
const eslintBin = isWindows ? path47.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path47.join(projectDir, "node_modules", ".bin", "eslint");
|
|
22928
23175
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
22929
23176
|
if (localResult)
|
|
22930
23177
|
return localResult;
|
|
22931
|
-
const biomeAncestor = findBinInAncestors(
|
|
22932
|
-
const eslintAncestor = findBinInAncestors(
|
|
23178
|
+
const biomeAncestor = findBinInAncestors(path47.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
23179
|
+
const eslintAncestor = findBinInAncestors(path47.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
22933
23180
|
if (biomeAncestor || eslintAncestor) {
|
|
22934
23181
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
22935
23182
|
}
|
|
@@ -22948,7 +23195,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
22948
23195
|
stderr: "pipe"
|
|
22949
23196
|
});
|
|
22950
23197
|
const biomeExit = biomeProc.exited;
|
|
22951
|
-
const timeout = new Promise((
|
|
23198
|
+
const timeout = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), DETECT_TIMEOUT));
|
|
22952
23199
|
const result = await Promise.race([biomeExit, timeout]);
|
|
22953
23200
|
if (result === "timeout") {
|
|
22954
23201
|
biomeProc.kill();
|
|
@@ -22962,7 +23209,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
22962
23209
|
stderr: "pipe"
|
|
22963
23210
|
});
|
|
22964
23211
|
const eslintExit = eslintProc.exited;
|
|
22965
|
-
const timeout = new Promise((
|
|
23212
|
+
const timeout = new Promise((resolve14) => setTimeout(() => resolve14("timeout"), DETECT_TIMEOUT));
|
|
22966
23213
|
const result = await Promise.race([eslintExit, timeout]);
|
|
22967
23214
|
if (result === "timeout") {
|
|
22968
23215
|
eslintProc.kill();
|
|
@@ -23143,7 +23390,7 @@ var _internals37 = {
|
|
|
23143
23390
|
|
|
23144
23391
|
// src/tools/secretscan.ts
|
|
23145
23392
|
import * as fs19 from "fs";
|
|
23146
|
-
import * as
|
|
23393
|
+
import * as path48 from "path";
|
|
23147
23394
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
23148
23395
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
23149
23396
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -23370,7 +23617,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
23370
23617
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
23371
23618
|
}
|
|
23372
23619
|
function loadSecretScanIgnore(scanDir) {
|
|
23373
|
-
const ignorePath =
|
|
23620
|
+
const ignorePath = path48.join(scanDir, ".secretscanignore");
|
|
23374
23621
|
try {
|
|
23375
23622
|
if (!fs19.existsSync(ignorePath))
|
|
23376
23623
|
return [];
|
|
@@ -23393,7 +23640,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
23393
23640
|
if (exactNames.has(entry))
|
|
23394
23641
|
return true;
|
|
23395
23642
|
for (const pattern of globPatterns) {
|
|
23396
|
-
if (
|
|
23643
|
+
if (path48.matchesGlob(relPath, pattern))
|
|
23397
23644
|
return true;
|
|
23398
23645
|
}
|
|
23399
23646
|
return false;
|
|
@@ -23414,7 +23661,7 @@ function validateDirectoryInput(dir) {
|
|
|
23414
23661
|
return null;
|
|
23415
23662
|
}
|
|
23416
23663
|
function isBinaryFile(filePath, buffer) {
|
|
23417
|
-
const ext =
|
|
23664
|
+
const ext = path48.extname(filePath).toLowerCase();
|
|
23418
23665
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
23419
23666
|
return true;
|
|
23420
23667
|
}
|
|
@@ -23551,9 +23798,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
23551
23798
|
return false;
|
|
23552
23799
|
}
|
|
23553
23800
|
function isPathWithinScope(realPath, scanDir) {
|
|
23554
|
-
const resolvedScanDir =
|
|
23555
|
-
const resolvedRealPath =
|
|
23556
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
23801
|
+
const resolvedScanDir = path48.resolve(scanDir);
|
|
23802
|
+
const resolvedRealPath = path48.resolve(realPath);
|
|
23803
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path48.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
23557
23804
|
}
|
|
23558
23805
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
23559
23806
|
skippedDirs: 0,
|
|
@@ -23579,8 +23826,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
23579
23826
|
return a.localeCompare(b);
|
|
23580
23827
|
});
|
|
23581
23828
|
for (const entry of entries) {
|
|
23582
|
-
const fullPath =
|
|
23583
|
-
const relPath =
|
|
23829
|
+
const fullPath = path48.join(dir, entry);
|
|
23830
|
+
const relPath = path48.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
23584
23831
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
23585
23832
|
stats.skippedDirs++;
|
|
23586
23833
|
continue;
|
|
@@ -23615,7 +23862,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
23615
23862
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
23616
23863
|
files.push(...subFiles);
|
|
23617
23864
|
} else if (lstat2.isFile()) {
|
|
23618
|
-
const ext =
|
|
23865
|
+
const ext = path48.extname(fullPath).toLowerCase();
|
|
23619
23866
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
23620
23867
|
files.push(fullPath);
|
|
23621
23868
|
} else {
|
|
@@ -23681,7 +23928,7 @@ var secretscan = createSwarmTool({
|
|
|
23681
23928
|
}
|
|
23682
23929
|
}
|
|
23683
23930
|
try {
|
|
23684
|
-
const _scanDirRaw =
|
|
23931
|
+
const _scanDirRaw = path48.resolve(directory);
|
|
23685
23932
|
const scanDir = (() => {
|
|
23686
23933
|
try {
|
|
23687
23934
|
return fs19.realpathSync(_scanDirRaw);
|
|
@@ -23844,11 +24091,11 @@ var _internals38 = {
|
|
|
23844
24091
|
|
|
23845
24092
|
// src/tools/test-runner.ts
|
|
23846
24093
|
import * as fs23 from "fs";
|
|
23847
|
-
import * as
|
|
24094
|
+
import * as path52 from "path";
|
|
23848
24095
|
|
|
23849
24096
|
// src/test-impact/analyzer.ts
|
|
23850
24097
|
import fs20 from "fs";
|
|
23851
|
-
import
|
|
24098
|
+
import path49 from "path";
|
|
23852
24099
|
var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
23853
24100
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
23854
24101
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -23889,8 +24136,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
23889
24136
|
if (!importPath.startsWith(".")) {
|
|
23890
24137
|
return null;
|
|
23891
24138
|
}
|
|
23892
|
-
const resolved =
|
|
23893
|
-
if (
|
|
24139
|
+
const resolved = path49.resolve(fromDir, importPath);
|
|
24140
|
+
if (path49.extname(resolved)) {
|
|
23894
24141
|
if (fs20.existsSync(resolved) && fs20.statSync(resolved).isFile()) {
|
|
23895
24142
|
return normalizePath2(resolved);
|
|
23896
24143
|
}
|
|
@@ -23910,20 +24157,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
23910
24157
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
23911
24158
|
let baseDir = fromDir;
|
|
23912
24159
|
for (let i = 1;i < leadingDots; i++) {
|
|
23913
|
-
baseDir =
|
|
24160
|
+
baseDir = path49.dirname(baseDir);
|
|
23914
24161
|
}
|
|
23915
24162
|
const rest = module.slice(leadingDots);
|
|
23916
24163
|
if (rest.length === 0) {
|
|
23917
|
-
const initPath =
|
|
24164
|
+
const initPath = path49.join(baseDir, "__init__.py");
|
|
23918
24165
|
if (fs20.existsSync(initPath) && fs20.statSync(initPath).isFile()) {
|
|
23919
24166
|
return normalizePath2(initPath);
|
|
23920
24167
|
}
|
|
23921
24168
|
return null;
|
|
23922
24169
|
}
|
|
23923
|
-
const subpath = rest.replace(/\./g,
|
|
24170
|
+
const subpath = rest.replace(/\./g, path49.sep);
|
|
23924
24171
|
const candidates = [
|
|
23925
|
-
`${
|
|
23926
|
-
|
|
24172
|
+
`${path49.join(baseDir, subpath)}.py`,
|
|
24173
|
+
path49.join(baseDir, subpath, "__init__.py")
|
|
23927
24174
|
];
|
|
23928
24175
|
for (const c of candidates) {
|
|
23929
24176
|
if (fs20.existsSync(c) && fs20.statSync(c).isFile())
|
|
@@ -23933,7 +24180,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
23933
24180
|
}
|
|
23934
24181
|
var goModuleCache = new Map;
|
|
23935
24182
|
function findGoModule(fromDir) {
|
|
23936
|
-
const resolved =
|
|
24183
|
+
const resolved = path49.resolve(fromDir);
|
|
23937
24184
|
let cur = resolved;
|
|
23938
24185
|
const walked = [];
|
|
23939
24186
|
for (let i = 0;i < 16; i++) {
|
|
@@ -23945,7 +24192,7 @@ function findGoModule(fromDir) {
|
|
|
23945
24192
|
}
|
|
23946
24193
|
walked.push(cur);
|
|
23947
24194
|
try {
|
|
23948
|
-
const goMod =
|
|
24195
|
+
const goMod = path49.join(cur, "go.mod");
|
|
23949
24196
|
const content = fs20.readFileSync(goMod, "utf-8");
|
|
23950
24197
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
23951
24198
|
if (moduleMatch) {
|
|
@@ -23956,10 +24203,10 @@ function findGoModule(fromDir) {
|
|
|
23956
24203
|
}
|
|
23957
24204
|
} catch {}
|
|
23958
24205
|
try {
|
|
23959
|
-
fs20.accessSync(
|
|
24206
|
+
fs20.accessSync(path49.join(cur, ".git"));
|
|
23960
24207
|
break;
|
|
23961
24208
|
} catch {}
|
|
23962
|
-
const parent =
|
|
24209
|
+
const parent = path49.dirname(cur);
|
|
23963
24210
|
if (parent === cur)
|
|
23964
24211
|
break;
|
|
23965
24212
|
cur = parent;
|
|
@@ -23971,12 +24218,12 @@ function findGoModule(fromDir) {
|
|
|
23971
24218
|
function resolveGoImport(fromDir, importPath) {
|
|
23972
24219
|
let dir = null;
|
|
23973
24220
|
if (importPath.startsWith(".")) {
|
|
23974
|
-
dir =
|
|
24221
|
+
dir = path49.resolve(fromDir, importPath);
|
|
23975
24222
|
} else {
|
|
23976
24223
|
const mod = findGoModule(fromDir);
|
|
23977
24224
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
23978
24225
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
23979
|
-
dir =
|
|
24226
|
+
dir = path49.join(mod.moduleRoot, subpath);
|
|
23980
24227
|
}
|
|
23981
24228
|
}
|
|
23982
24229
|
if (dir === null)
|
|
@@ -23984,7 +24231,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
23984
24231
|
if (!fs20.existsSync(dir) || !fs20.statSync(dir).isDirectory())
|
|
23985
24232
|
return [];
|
|
23986
24233
|
try {
|
|
23987
|
-
return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(
|
|
24234
|
+
return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path49.join(dir, f)));
|
|
23988
24235
|
} catch {
|
|
23989
24236
|
return [];
|
|
23990
24237
|
}
|
|
@@ -24023,15 +24270,15 @@ function findTestFilesSync(cwd) {
|
|
|
24023
24270
|
for (const entry of entries) {
|
|
24024
24271
|
if (entry.isDirectory()) {
|
|
24025
24272
|
if (!skipDirs.has(entry.name)) {
|
|
24026
|
-
walk(
|
|
24273
|
+
walk(path49.join(dir, entry.name), visitedInodes);
|
|
24027
24274
|
}
|
|
24028
24275
|
} else if (entry.isFile()) {
|
|
24029
24276
|
const name = entry.name;
|
|
24030
24277
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
24031
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
24278
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path49.sep}tests${path49.sep}`) && name.endsWith(".py");
|
|
24032
24279
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
24033
24280
|
if (isTsTest || isPyTest || isGoTest) {
|
|
24034
|
-
testFiles.push(normalizePath2(
|
|
24281
|
+
testFiles.push(normalizePath2(path49.join(dir, entry.name)));
|
|
24035
24282
|
}
|
|
24036
24283
|
}
|
|
24037
24284
|
}
|
|
@@ -24056,8 +24303,8 @@ function extractImports(content) {
|
|
|
24056
24303
|
];
|
|
24057
24304
|
}
|
|
24058
24305
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
24059
|
-
const ext =
|
|
24060
|
-
const testDir =
|
|
24306
|
+
const ext = path49.extname(testFile).toLowerCase();
|
|
24307
|
+
const testDir = path49.dirname(testFile);
|
|
24061
24308
|
function addEdge(source) {
|
|
24062
24309
|
if (!impactMap[source])
|
|
24063
24310
|
impactMap[source] = [];
|
|
@@ -24130,7 +24377,7 @@ async function buildImpactMap(cwd) {
|
|
|
24130
24377
|
return impactMap;
|
|
24131
24378
|
}
|
|
24132
24379
|
async function loadImpactMap(cwd, options) {
|
|
24133
|
-
const cachePath =
|
|
24380
|
+
const cachePath = path49.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
24134
24381
|
if (fs20.existsSync(cachePath)) {
|
|
24135
24382
|
try {
|
|
24136
24383
|
const content = fs20.readFileSync(cachePath, "utf-8");
|
|
@@ -24163,12 +24410,12 @@ async function loadImpactMap(cwd, options) {
|
|
|
24163
24410
|
return _internals39.buildImpactMap(cwd);
|
|
24164
24411
|
}
|
|
24165
24412
|
async function saveImpactMap(cwd, impactMap) {
|
|
24166
|
-
if (!
|
|
24413
|
+
if (!path49.isAbsolute(cwd)) {
|
|
24167
24414
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
24168
24415
|
}
|
|
24169
24416
|
_internals39.validateProjectRoot(cwd);
|
|
24170
|
-
const cacheDir2 =
|
|
24171
|
-
const cachePath =
|
|
24417
|
+
const cacheDir2 = path49.join(cwd, ".swarm", "cache");
|
|
24418
|
+
const cachePath = path49.join(cacheDir2, "impact-map.json");
|
|
24172
24419
|
if (!fs20.existsSync(cacheDir2)) {
|
|
24173
24420
|
fs20.mkdirSync(cacheDir2, { recursive: true });
|
|
24174
24421
|
}
|
|
@@ -24200,7 +24447,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
24200
24447
|
budgetExceeded = true;
|
|
24201
24448
|
break;
|
|
24202
24449
|
}
|
|
24203
|
-
const normalizedChanged = normalizePath2(
|
|
24450
|
+
const normalizedChanged = normalizePath2(path49.resolve(changedFile));
|
|
24204
24451
|
const tests = impactMap[normalizedChanged];
|
|
24205
24452
|
if (tests && tests.length > 0) {
|
|
24206
24453
|
for (const test of tests) {
|
|
@@ -24214,13 +24461,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
24214
24461
|
if (budgetExceeded)
|
|
24215
24462
|
break;
|
|
24216
24463
|
} else {
|
|
24217
|
-
const changedDir = normalizePath2(
|
|
24218
|
-
const changedInputDir = normalizePath2(
|
|
24464
|
+
const changedDir = normalizePath2(path49.dirname(normalizedChanged));
|
|
24465
|
+
const changedInputDir = normalizePath2(path49.dirname(changedFile));
|
|
24219
24466
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
24220
24467
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
24221
24468
|
}).sort(([sourceA], [sourceB]) => {
|
|
24222
|
-
const sourceDirA = normalizePath2(
|
|
24223
|
-
const sourceDirB = normalizePath2(
|
|
24469
|
+
const sourceDirA = normalizePath2(path49.dirname(sourceA));
|
|
24470
|
+
const sourceDirB = normalizePath2(path49.dirname(sourceB));
|
|
24224
24471
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
24225
24472
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
24226
24473
|
if (exactA !== exactB)
|
|
@@ -24547,7 +24794,7 @@ function detectFlakyTests(allHistory) {
|
|
|
24547
24794
|
|
|
24548
24795
|
// src/test-impact/history-store.ts
|
|
24549
24796
|
import fs21 from "fs";
|
|
24550
|
-
import
|
|
24797
|
+
import path50 from "path";
|
|
24551
24798
|
var MAX_HISTORY_PER_TEST = 20;
|
|
24552
24799
|
var MAX_ERROR_LENGTH = 500;
|
|
24553
24800
|
var MAX_STACK_LENGTH = 200;
|
|
@@ -24559,10 +24806,10 @@ function getHistoryPath(workingDir) {
|
|
|
24559
24806
|
if (!workingDir) {
|
|
24560
24807
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
24561
24808
|
}
|
|
24562
|
-
if (!
|
|
24809
|
+
if (!path50.isAbsolute(workingDir)) {
|
|
24563
24810
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
24564
24811
|
}
|
|
24565
|
-
return
|
|
24812
|
+
return path50.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
24566
24813
|
}
|
|
24567
24814
|
function sanitizeErrorMessage(errorMessage) {
|
|
24568
24815
|
if (errorMessage === undefined) {
|
|
@@ -24654,7 +24901,7 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
24654
24901
|
}
|
|
24655
24902
|
}
|
|
24656
24903
|
const historyPath = getHistoryPath(workingDir);
|
|
24657
|
-
const historyDir =
|
|
24904
|
+
const historyDir = path50.dirname(historyPath);
|
|
24658
24905
|
_internals40.validateProjectRoot(workingDir);
|
|
24659
24906
|
if (!fs21.existsSync(historyDir)) {
|
|
24660
24907
|
fs21.mkdirSync(historyDir, { recursive: true });
|
|
@@ -24784,7 +25031,7 @@ var _internals40 = {
|
|
|
24784
25031
|
|
|
24785
25032
|
// src/tools/resolve-working-directory.ts
|
|
24786
25033
|
import * as fs22 from "fs";
|
|
24787
|
-
import * as
|
|
25034
|
+
import * as path51 from "path";
|
|
24788
25035
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
24789
25036
|
if (workingDirectory == null || workingDirectory === "") {
|
|
24790
25037
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -24816,15 +25063,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24816
25063
|
};
|
|
24817
25064
|
}
|
|
24818
25065
|
}
|
|
24819
|
-
const rawPathParts = workingDirectory.split(
|
|
25066
|
+
const rawPathParts = workingDirectory.split(path51.sep);
|
|
24820
25067
|
if (rawPathParts.includes("..")) {
|
|
24821
25068
|
return {
|
|
24822
25069
|
success: false,
|
|
24823
25070
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
24824
25071
|
};
|
|
24825
25072
|
}
|
|
24826
|
-
const normalizedDir =
|
|
24827
|
-
const resolvedDir =
|
|
25073
|
+
const normalizedDir = path51.normalize(workingDirectory);
|
|
25074
|
+
const resolvedDir = path51.resolve(normalizedDir);
|
|
24828
25075
|
let statResult;
|
|
24829
25076
|
try {
|
|
24830
25077
|
statResult = fs22.statSync(resolvedDir);
|
|
@@ -24843,7 +25090,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24843
25090
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
24844
25091
|
return { success: true, directory: resolvedDir };
|
|
24845
25092
|
}
|
|
24846
|
-
const resolvedFallback =
|
|
25093
|
+
const resolvedFallback = path51.resolve(fallbackDirectory);
|
|
24847
25094
|
let fallbackExists = false;
|
|
24848
25095
|
try {
|
|
24849
25096
|
fs22.statSync(resolvedFallback);
|
|
@@ -24852,7 +25099,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24852
25099
|
fallbackExists = false;
|
|
24853
25100
|
}
|
|
24854
25101
|
if (fallbackExists) {
|
|
24855
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
25102
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path51.sep);
|
|
24856
25103
|
if (isSubdirectory) {
|
|
24857
25104
|
return {
|
|
24858
25105
|
success: false,
|
|
@@ -24875,7 +25122,7 @@ async function estimateFanOut(sourceFiles, cwd) {
|
|
|
24875
25122
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
24876
25123
|
const uniqueTestFiles = new Set;
|
|
24877
25124
|
for (const sourceFile of sourceFiles) {
|
|
24878
|
-
const resolvedPath =
|
|
25125
|
+
const resolvedPath = path52.resolve(cwd, sourceFile);
|
|
24879
25126
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
24880
25127
|
const testFiles = impactMap[normalizedPath];
|
|
24881
25128
|
if (testFiles) {
|
|
@@ -24960,14 +25207,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
24960
25207
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
24961
25208
|
}
|
|
24962
25209
|
function detectGoTest(cwd) {
|
|
24963
|
-
return fs23.existsSync(
|
|
25210
|
+
return fs23.existsSync(path52.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
24964
25211
|
}
|
|
24965
25212
|
function detectJavaMaven(cwd) {
|
|
24966
|
-
return fs23.existsSync(
|
|
25213
|
+
return fs23.existsSync(path52.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
24967
25214
|
}
|
|
24968
25215
|
function detectGradle(cwd) {
|
|
24969
|
-
const hasBuildFile = fs23.existsSync(
|
|
24970
|
-
const hasGradlew = fs23.existsSync(
|
|
25216
|
+
const hasBuildFile = fs23.existsSync(path52.join(cwd, "build.gradle")) || fs23.existsSync(path52.join(cwd, "build.gradle.kts"));
|
|
25217
|
+
const hasGradlew = fs23.existsSync(path52.join(cwd, "gradlew")) || fs23.existsSync(path52.join(cwd, "gradlew.bat"));
|
|
24971
25218
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
24972
25219
|
}
|
|
24973
25220
|
function detectDotnetTest(cwd) {
|
|
@@ -24980,25 +25227,25 @@ function detectDotnetTest(cwd) {
|
|
|
24980
25227
|
}
|
|
24981
25228
|
}
|
|
24982
25229
|
function detectCTest(cwd) {
|
|
24983
|
-
const hasSource = fs23.existsSync(
|
|
24984
|
-
const hasBuildCache = fs23.existsSync(
|
|
25230
|
+
const hasSource = fs23.existsSync(path52.join(cwd, "CMakeLists.txt"));
|
|
25231
|
+
const hasBuildCache = fs23.existsSync(path52.join(cwd, "CMakeCache.txt")) || fs23.existsSync(path52.join(cwd, "build", "CMakeCache.txt"));
|
|
24985
25232
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
24986
25233
|
}
|
|
24987
25234
|
function detectSwiftTest(cwd) {
|
|
24988
|
-
return fs23.existsSync(
|
|
25235
|
+
return fs23.existsSync(path52.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
24989
25236
|
}
|
|
24990
25237
|
function detectDartTest(cwd) {
|
|
24991
|
-
return fs23.existsSync(
|
|
25238
|
+
return fs23.existsSync(path52.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
24992
25239
|
}
|
|
24993
25240
|
function detectRSpec(cwd) {
|
|
24994
|
-
const hasRSpecFile = fs23.existsSync(
|
|
24995
|
-
const hasGemfile = fs23.existsSync(
|
|
24996
|
-
const hasSpecDir = fs23.existsSync(
|
|
25241
|
+
const hasRSpecFile = fs23.existsSync(path52.join(cwd, ".rspec"));
|
|
25242
|
+
const hasGemfile = fs23.existsSync(path52.join(cwd, "Gemfile"));
|
|
25243
|
+
const hasSpecDir = fs23.existsSync(path52.join(cwd, "spec"));
|
|
24997
25244
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
24998
25245
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
24999
25246
|
}
|
|
25000
25247
|
function detectMinitest(cwd) {
|
|
25001
|
-
return fs23.existsSync(
|
|
25248
|
+
return fs23.existsSync(path52.join(cwd, "test")) && (fs23.existsSync(path52.join(cwd, "Gemfile")) || fs23.existsSync(path52.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
25002
25249
|
}
|
|
25003
25250
|
var DISPATCH_FRAMEWORK_MAP = {
|
|
25004
25251
|
bun: "bun",
|
|
@@ -25083,7 +25330,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
25083
25330
|
async function detectTestFramework(cwd) {
|
|
25084
25331
|
const baseDir = cwd;
|
|
25085
25332
|
try {
|
|
25086
|
-
const packageJsonPath =
|
|
25333
|
+
const packageJsonPath = path52.join(baseDir, "package.json");
|
|
25087
25334
|
if (fs23.existsSync(packageJsonPath)) {
|
|
25088
25335
|
const content = fs23.readFileSync(packageJsonPath, "utf-8");
|
|
25089
25336
|
const pkg = JSON.parse(content);
|
|
@@ -25104,16 +25351,16 @@ async function detectTestFramework(cwd) {
|
|
|
25104
25351
|
return "jest";
|
|
25105
25352
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
25106
25353
|
return "mocha";
|
|
25107
|
-
if (fs23.existsSync(
|
|
25354
|
+
if (fs23.existsSync(path52.join(baseDir, "bun.lockb")) || fs23.existsSync(path52.join(baseDir, "bun.lock"))) {
|
|
25108
25355
|
if (scripts.test?.includes("bun"))
|
|
25109
25356
|
return "bun";
|
|
25110
25357
|
}
|
|
25111
25358
|
}
|
|
25112
25359
|
} catch {}
|
|
25113
25360
|
try {
|
|
25114
|
-
const pyprojectTomlPath =
|
|
25115
|
-
const setupCfgPath =
|
|
25116
|
-
const requirementsTxtPath =
|
|
25361
|
+
const pyprojectTomlPath = path52.join(baseDir, "pyproject.toml");
|
|
25362
|
+
const setupCfgPath = path52.join(baseDir, "setup.cfg");
|
|
25363
|
+
const requirementsTxtPath = path52.join(baseDir, "requirements.txt");
|
|
25117
25364
|
if (fs23.existsSync(pyprojectTomlPath)) {
|
|
25118
25365
|
const content = fs23.readFileSync(pyprojectTomlPath, "utf-8");
|
|
25119
25366
|
if (content.includes("[tool.pytest"))
|
|
@@ -25133,7 +25380,7 @@ async function detectTestFramework(cwd) {
|
|
|
25133
25380
|
}
|
|
25134
25381
|
} catch {}
|
|
25135
25382
|
try {
|
|
25136
|
-
const cargoTomlPath =
|
|
25383
|
+
const cargoTomlPath = path52.join(baseDir, "Cargo.toml");
|
|
25137
25384
|
if (fs23.existsSync(cargoTomlPath)) {
|
|
25138
25385
|
const content = fs23.readFileSync(cargoTomlPath, "utf-8");
|
|
25139
25386
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -25144,9 +25391,9 @@ async function detectTestFramework(cwd) {
|
|
|
25144
25391
|
}
|
|
25145
25392
|
} catch {}
|
|
25146
25393
|
try {
|
|
25147
|
-
const pesterConfigPath =
|
|
25148
|
-
const pesterConfigJsonPath =
|
|
25149
|
-
const pesterPs1Path =
|
|
25394
|
+
const pesterConfigPath = path52.join(baseDir, "pester.config.ps1");
|
|
25395
|
+
const pesterConfigJsonPath = path52.join(baseDir, "pester.config.ps1.json");
|
|
25396
|
+
const pesterPs1Path = path52.join(baseDir, "tests.ps1");
|
|
25150
25397
|
if (fs23.existsSync(pesterConfigPath) || fs23.existsSync(pesterConfigJsonPath) || fs23.existsSync(pesterPs1Path)) {
|
|
25151
25398
|
return "pester";
|
|
25152
25399
|
}
|
|
@@ -25189,12 +25436,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
25189
25436
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
25190
25437
|
}
|
|
25191
25438
|
function resolveWorkspacePath(file, workingDir) {
|
|
25192
|
-
return
|
|
25439
|
+
return path52.isAbsolute(file) ? path52.resolve(file) : path52.resolve(workingDir, file);
|
|
25193
25440
|
}
|
|
25194
25441
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
25195
25442
|
if (!preferRelative)
|
|
25196
25443
|
return absolutePath;
|
|
25197
|
-
return
|
|
25444
|
+
return path52.relative(workingDir, absolutePath);
|
|
25198
25445
|
}
|
|
25199
25446
|
function dedupePush(target, value) {
|
|
25200
25447
|
if (!target.includes(value)) {
|
|
@@ -25231,18 +25478,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
25231
25478
|
}
|
|
25232
25479
|
}
|
|
25233
25480
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
25234
|
-
const relativeDir =
|
|
25481
|
+
const relativeDir = path52.dirname(relativePath);
|
|
25235
25482
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
25236
25483
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
25237
|
-
const rootDir =
|
|
25238
|
-
return nestedRelativeDir ? [rootDir,
|
|
25484
|
+
const rootDir = path52.join(workingDir, dirName);
|
|
25485
|
+
return nestedRelativeDir ? [rootDir, path52.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
25239
25486
|
});
|
|
25240
25487
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
25241
25488
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
25242
|
-
directories.push(
|
|
25489
|
+
directories.push(path52.join(workingDir, "src/test/java", path52.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
25243
25490
|
}
|
|
25244
25491
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
25245
|
-
directories.push(
|
|
25492
|
+
directories.push(path52.join(workingDir, "src/test/kotlin", path52.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
25246
25493
|
}
|
|
25247
25494
|
return [...new Set(directories)];
|
|
25248
25495
|
}
|
|
@@ -25270,23 +25517,23 @@ function isLanguageSpecificTestFile(basename9) {
|
|
|
25270
25517
|
}
|
|
25271
25518
|
function isConventionTestFilePath(filePath) {
|
|
25272
25519
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
25273
|
-
const basename9 =
|
|
25520
|
+
const basename9 = path52.basename(filePath);
|
|
25274
25521
|
return hasCompoundTestExtension(basename9) || basename9.includes(".spec.") || basename9.includes(".test.") || isLanguageSpecificTestFile(basename9) || isTestDirectoryPath(normalizedPath);
|
|
25275
25522
|
}
|
|
25276
25523
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
25277
25524
|
const testFiles = [];
|
|
25278
25525
|
for (const file of sourceFiles) {
|
|
25279
25526
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
25280
|
-
const relativeFile =
|
|
25281
|
-
const basename9 =
|
|
25282
|
-
const
|
|
25283
|
-
const preferRelativeOutput = !
|
|
25527
|
+
const relativeFile = path52.relative(workingDir, absoluteFile);
|
|
25528
|
+
const basename9 = path52.basename(absoluteFile);
|
|
25529
|
+
const dirname25 = path52.dirname(absoluteFile);
|
|
25530
|
+
const preferRelativeOutput = !path52.isAbsolute(file);
|
|
25284
25531
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
25285
25532
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
25286
25533
|
continue;
|
|
25287
25534
|
}
|
|
25288
25535
|
const nameWithoutExt = basename9.replace(/\.[^.]+$/, "");
|
|
25289
|
-
const ext =
|
|
25536
|
+
const ext = path52.extname(basename9);
|
|
25290
25537
|
const genericTestNames = [
|
|
25291
25538
|
`${nameWithoutExt}.spec${ext}`,
|
|
25292
25539
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -25295,7 +25542,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
25295
25542
|
const colocatedCandidates = [
|
|
25296
25543
|
...genericTestNames,
|
|
25297
25544
|
...languageSpecificTestNames
|
|
25298
|
-
].map((candidateName) =>
|
|
25545
|
+
].map((candidateName) => path52.join(dirname25, candidateName));
|
|
25299
25546
|
const testDirectoryNames = [
|
|
25300
25547
|
basename9,
|
|
25301
25548
|
...genericTestNames,
|
|
@@ -25304,8 +25551,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
25304
25551
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
25305
25552
|
const possibleTestFiles = [
|
|
25306
25553
|
...colocatedCandidates,
|
|
25307
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
25308
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
25554
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path52.join(dirname25, dirName, candidateName))),
|
|
25555
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path52.join(candidateDir, candidateName)))
|
|
25309
25556
|
];
|
|
25310
25557
|
for (const testFile of possibleTestFiles) {
|
|
25311
25558
|
if (fs23.existsSync(testFile)) {
|
|
@@ -25326,7 +25573,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25326
25573
|
try {
|
|
25327
25574
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
25328
25575
|
const content = fs23.readFileSync(absoluteTestFile, "utf-8");
|
|
25329
|
-
const testDir =
|
|
25576
|
+
const testDir = path52.dirname(absoluteTestFile);
|
|
25330
25577
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
25331
25578
|
let match;
|
|
25332
25579
|
match = importRegex.exec(content);
|
|
@@ -25334,8 +25581,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25334
25581
|
const importPath = match[1];
|
|
25335
25582
|
let resolvedImport;
|
|
25336
25583
|
if (importPath.startsWith(".")) {
|
|
25337
|
-
resolvedImport =
|
|
25338
|
-
const existingExt =
|
|
25584
|
+
resolvedImport = path52.resolve(testDir, importPath);
|
|
25585
|
+
const existingExt = path52.extname(resolvedImport);
|
|
25339
25586
|
if (!existingExt) {
|
|
25340
25587
|
for (const extToTry of [
|
|
25341
25588
|
".ts",
|
|
@@ -25355,12 +25602,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25355
25602
|
} else {
|
|
25356
25603
|
continue;
|
|
25357
25604
|
}
|
|
25358
|
-
const importBasename =
|
|
25359
|
-
const importDir =
|
|
25605
|
+
const importBasename = path52.basename(resolvedImport, path52.extname(resolvedImport));
|
|
25606
|
+
const importDir = path52.dirname(resolvedImport);
|
|
25360
25607
|
for (const sourceFile of absoluteSourceFiles) {
|
|
25361
|
-
const sourceDir =
|
|
25362
|
-
const sourceBasename =
|
|
25363
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
25608
|
+
const sourceDir = path52.dirname(sourceFile);
|
|
25609
|
+
const sourceBasename = path52.basename(sourceFile, path52.extname(sourceFile));
|
|
25610
|
+
const isRelatedDir = importDir === sourceDir || importDir === path52.join(sourceDir, "__tests__") || importDir === path52.join(sourceDir, "tests") || importDir === path52.join(sourceDir, "test") || importDir === path52.join(sourceDir, "spec");
|
|
25364
25611
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
25365
25612
|
dedupePush(testFiles, testFile);
|
|
25366
25613
|
break;
|
|
@@ -25373,8 +25620,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25373
25620
|
while (match !== null) {
|
|
25374
25621
|
const importPath = match[1];
|
|
25375
25622
|
if (importPath.startsWith(".")) {
|
|
25376
|
-
let resolvedImport =
|
|
25377
|
-
const existingExt =
|
|
25623
|
+
let resolvedImport = path52.resolve(testDir, importPath);
|
|
25624
|
+
const existingExt = path52.extname(resolvedImport);
|
|
25378
25625
|
if (!existingExt) {
|
|
25379
25626
|
for (const extToTry of [
|
|
25380
25627
|
".ts",
|
|
@@ -25391,12 +25638,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25391
25638
|
}
|
|
25392
25639
|
}
|
|
25393
25640
|
}
|
|
25394
|
-
const importDir =
|
|
25395
|
-
const importBasename =
|
|
25641
|
+
const importDir = path52.dirname(resolvedImport);
|
|
25642
|
+
const importBasename = path52.basename(resolvedImport, path52.extname(resolvedImport));
|
|
25396
25643
|
for (const sourceFile of absoluteSourceFiles) {
|
|
25397
|
-
const sourceDir =
|
|
25398
|
-
const sourceBasename =
|
|
25399
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
25644
|
+
const sourceDir = path52.dirname(sourceFile);
|
|
25645
|
+
const sourceBasename = path52.basename(sourceFile, path52.extname(sourceFile));
|
|
25646
|
+
const isRelatedDir = importDir === sourceDir || importDir === path52.join(sourceDir, "__tests__") || importDir === path52.join(sourceDir, "tests") || importDir === path52.join(sourceDir, "test") || importDir === path52.join(sourceDir, "spec");
|
|
25400
25647
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
25401
25648
|
dedupePush(testFiles, testFile);
|
|
25402
25649
|
break;
|
|
@@ -25516,8 +25763,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
25516
25763
|
return ["mvn", "test"];
|
|
25517
25764
|
case "gradle": {
|
|
25518
25765
|
const isWindows = process.platform === "win32";
|
|
25519
|
-
const hasGradlewBat = fs23.existsSync(
|
|
25520
|
-
const hasGradlew = fs23.existsSync(
|
|
25766
|
+
const hasGradlewBat = fs23.existsSync(path52.join(baseDir, "gradlew.bat"));
|
|
25767
|
+
const hasGradlew = fs23.existsSync(path52.join(baseDir, "gradlew"));
|
|
25521
25768
|
if (hasGradlewBat && isWindows)
|
|
25522
25769
|
return ["gradlew.bat", "test"];
|
|
25523
25770
|
if (hasGradlew)
|
|
@@ -25534,7 +25781,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
25534
25781
|
"cmake-build-release",
|
|
25535
25782
|
"out"
|
|
25536
25783
|
];
|
|
25537
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(
|
|
25784
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(path52.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
25538
25785
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
25539
25786
|
}
|
|
25540
25787
|
case "swift-test":
|
|
@@ -25968,11 +26215,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
25968
26215
|
};
|
|
25969
26216
|
}
|
|
25970
26217
|
const startTime = Date.now();
|
|
25971
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
26218
|
+
const vitestJsonOutputPath = framework === "vitest" ? path52.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
25972
26219
|
try {
|
|
25973
26220
|
if (vitestJsonOutputPath) {
|
|
25974
26221
|
try {
|
|
25975
|
-
fs23.mkdirSync(
|
|
26222
|
+
fs23.mkdirSync(path52.dirname(vitestJsonOutputPath), { recursive: true });
|
|
25976
26223
|
if (fs23.existsSync(vitestJsonOutputPath)) {
|
|
25977
26224
|
fs23.unlinkSync(vitestJsonOutputPath);
|
|
25978
26225
|
}
|
|
@@ -25983,9 +26230,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
25983
26230
|
stderr: "pipe",
|
|
25984
26231
|
cwd
|
|
25985
26232
|
});
|
|
25986
|
-
const timeoutPromise = new Promise((
|
|
26233
|
+
const timeoutPromise = new Promise((resolve17) => setTimeout(() => {
|
|
25987
26234
|
proc.kill();
|
|
25988
|
-
|
|
26235
|
+
resolve17(-1);
|
|
25989
26236
|
}, timeout_ms));
|
|
25990
26237
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
25991
26238
|
Promise.race([proc.exited, timeoutPromise]),
|
|
@@ -26140,10 +26387,10 @@ var SKIP_DIRECTORIES = new Set([
|
|
|
26140
26387
|
]);
|
|
26141
26388
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
26142
26389
|
const normalized = testFile.replace(/\\/g, "/");
|
|
26143
|
-
if (!
|
|
26390
|
+
if (!path52.isAbsolute(testFile))
|
|
26144
26391
|
return normalized;
|
|
26145
|
-
const relative8 =
|
|
26146
|
-
if (relative8.startsWith("..") ||
|
|
26392
|
+
const relative8 = path52.relative(workingDir, testFile);
|
|
26393
|
+
if (relative8.startsWith("..") || path52.isAbsolute(relative8)) {
|
|
26147
26394
|
return normalized;
|
|
26148
26395
|
}
|
|
26149
26396
|
return relative8.replace(/\\/g, "/");
|
|
@@ -26382,7 +26629,7 @@ var test_runner = createSwarmTool({
|
|
|
26382
26629
|
const sourceFiles = args.files.filter((file) => {
|
|
26383
26630
|
if (directTestFiles.includes(file))
|
|
26384
26631
|
return false;
|
|
26385
|
-
const ext =
|
|
26632
|
+
const ext = path52.extname(file).toLowerCase();
|
|
26386
26633
|
return SOURCE_EXTENSIONS.has(ext);
|
|
26387
26634
|
});
|
|
26388
26635
|
const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
|
|
@@ -26428,7 +26675,7 @@ var test_runner = createSwarmTool({
|
|
|
26428
26675
|
if (isConventionTestFilePath(f)) {
|
|
26429
26676
|
return false;
|
|
26430
26677
|
}
|
|
26431
|
-
const ext =
|
|
26678
|
+
const ext = path52.extname(f).toLowerCase();
|
|
26432
26679
|
return SOURCE_EXTENSIONS.has(ext);
|
|
26433
26680
|
});
|
|
26434
26681
|
if (sourceFiles.length === 0) {
|
|
@@ -26478,7 +26725,7 @@ var test_runner = createSwarmTool({
|
|
|
26478
26725
|
if (isConventionTestFilePath(f)) {
|
|
26479
26726
|
return false;
|
|
26480
26727
|
}
|
|
26481
|
-
const ext =
|
|
26728
|
+
const ext = path52.extname(f).toLowerCase();
|
|
26482
26729
|
return SOURCE_EXTENSIONS.has(ext);
|
|
26483
26730
|
});
|
|
26484
26731
|
if (sourceFiles.length === 0) {
|
|
@@ -26530,8 +26777,8 @@ var test_runner = createSwarmTool({
|
|
|
26530
26777
|
}
|
|
26531
26778
|
if (impactResult.impactedTests.length > 0) {
|
|
26532
26779
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
26533
|
-
const relativePath =
|
|
26534
|
-
return
|
|
26780
|
+
const relativePath = path52.relative(workingDir, absPath);
|
|
26781
|
+
return path52.isAbsolute(relativePath) ? absPath : relativePath;
|
|
26535
26782
|
});
|
|
26536
26783
|
} else {
|
|
26537
26784
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -26626,8 +26873,8 @@ function validateDirectoryPath(dir) {
|
|
|
26626
26873
|
if (dir.includes("..")) {
|
|
26627
26874
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
26628
26875
|
}
|
|
26629
|
-
const normalized =
|
|
26630
|
-
const absolutePath =
|
|
26876
|
+
const normalized = path53.normalize(dir);
|
|
26877
|
+
const absolutePath = path53.isAbsolute(normalized) ? normalized : path53.resolve(normalized);
|
|
26631
26878
|
return absolutePath;
|
|
26632
26879
|
}
|
|
26633
26880
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -26650,7 +26897,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
26650
26897
|
}
|
|
26651
26898
|
function getPackageVersion(dir) {
|
|
26652
26899
|
try {
|
|
26653
|
-
const packagePath =
|
|
26900
|
+
const packagePath = path53.join(dir, "package.json");
|
|
26654
26901
|
if (fs24.existsSync(packagePath)) {
|
|
26655
26902
|
const content = fs24.readFileSync(packagePath, "utf-8");
|
|
26656
26903
|
const pkg = JSON.parse(content);
|
|
@@ -26661,7 +26908,7 @@ function getPackageVersion(dir) {
|
|
|
26661
26908
|
}
|
|
26662
26909
|
function getChangelogVersion(dir) {
|
|
26663
26910
|
try {
|
|
26664
|
-
const changelogPath =
|
|
26911
|
+
const changelogPath = path53.join(dir, "CHANGELOG.md");
|
|
26665
26912
|
if (fs24.existsSync(changelogPath)) {
|
|
26666
26913
|
const content = fs24.readFileSync(changelogPath, "utf-8");
|
|
26667
26914
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -26675,7 +26922,7 @@ function getChangelogVersion(dir) {
|
|
|
26675
26922
|
function getVersionFileVersion(dir) {
|
|
26676
26923
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
26677
26924
|
for (const file of possibleFiles) {
|
|
26678
|
-
const filePath =
|
|
26925
|
+
const filePath = path53.join(dir, file);
|
|
26679
26926
|
if (fs24.existsSync(filePath)) {
|
|
26680
26927
|
try {
|
|
26681
26928
|
const content = fs24.readFileSync(filePath, "utf-8").trim();
|
|
@@ -27413,7 +27660,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
27413
27660
|
|
|
27414
27661
|
// src/commands/reset.ts
|
|
27415
27662
|
import * as fs25 from "fs";
|
|
27416
|
-
import * as
|
|
27663
|
+
import * as path54 from "path";
|
|
27417
27664
|
|
|
27418
27665
|
// src/background/circuit-breaker.ts
|
|
27419
27666
|
class CircuitBreaker {
|
|
@@ -27465,13 +27712,13 @@ class CircuitBreaker {
|
|
|
27465
27712
|
if (this.config.callTimeoutMs <= 0) {
|
|
27466
27713
|
return fn();
|
|
27467
27714
|
}
|
|
27468
|
-
return new Promise((
|
|
27715
|
+
return new Promise((resolve18, reject) => {
|
|
27469
27716
|
const timeout = setTimeout(() => {
|
|
27470
27717
|
reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
|
|
27471
27718
|
}, this.config.callTimeoutMs);
|
|
27472
27719
|
fn().then((result) => {
|
|
27473
27720
|
clearTimeout(timeout);
|
|
27474
|
-
|
|
27721
|
+
resolve18(result);
|
|
27475
27722
|
}).catch((error2) => {
|
|
27476
27723
|
clearTimeout(timeout);
|
|
27477
27724
|
reject(error2);
|
|
@@ -27755,7 +28002,7 @@ class AutomationQueue {
|
|
|
27755
28002
|
|
|
27756
28003
|
// src/background/worker.ts
|
|
27757
28004
|
function sleep(ms) {
|
|
27758
|
-
return new Promise((
|
|
28005
|
+
return new Promise((resolve18) => setTimeout(resolve18, ms));
|
|
27759
28006
|
}
|
|
27760
28007
|
|
|
27761
28008
|
class WorkerManager {
|
|
@@ -28130,7 +28377,7 @@ async function handleResetCommand(directory, args) {
|
|
|
28130
28377
|
}
|
|
28131
28378
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
28132
28379
|
try {
|
|
28133
|
-
const rootPath =
|
|
28380
|
+
const rootPath = path54.join(directory, filename);
|
|
28134
28381
|
if (fs25.existsSync(rootPath)) {
|
|
28135
28382
|
fs25.unlinkSync(rootPath);
|
|
28136
28383
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -28168,7 +28415,7 @@ async function handleResetCommand(directory, args) {
|
|
|
28168
28415
|
|
|
28169
28416
|
// src/commands/reset-session.ts
|
|
28170
28417
|
import * as fs27 from "fs";
|
|
28171
|
-
import * as
|
|
28418
|
+
import * as path56 from "path";
|
|
28172
28419
|
|
|
28173
28420
|
// src/hooks/trajectory-logger.ts
|
|
28174
28421
|
var callStartTimes = new Map;
|
|
@@ -28575,16 +28822,16 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
|
|
|
28575
28822
|
}
|
|
28576
28823
|
// src/prm/replay.ts
|
|
28577
28824
|
import { promises as fs26 } from "fs";
|
|
28578
|
-
import
|
|
28825
|
+
import path55 from "path";
|
|
28579
28826
|
function isPathSafe(targetPath, basePath) {
|
|
28580
|
-
const resolvedTarget =
|
|
28581
|
-
const resolvedBase =
|
|
28582
|
-
const rel =
|
|
28583
|
-
return !rel.startsWith("..") && !
|
|
28827
|
+
const resolvedTarget = path55.resolve(targetPath);
|
|
28828
|
+
const resolvedBase = path55.resolve(basePath);
|
|
28829
|
+
const rel = path55.relative(resolvedBase, resolvedTarget);
|
|
28830
|
+
return !rel.startsWith("..") && !path55.isAbsolute(rel);
|
|
28584
28831
|
}
|
|
28585
28832
|
function isWithinReplaysDir(targetPath) {
|
|
28586
|
-
const resolved =
|
|
28587
|
-
const parts = resolved.split(
|
|
28833
|
+
const resolved = path55.resolve(targetPath);
|
|
28834
|
+
const parts = resolved.split(path55.sep);
|
|
28588
28835
|
for (let i = 0;i < parts.length - 1; i++) {
|
|
28589
28836
|
if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
|
|
28590
28837
|
return true;
|
|
@@ -28597,10 +28844,10 @@ function sanitizeFilename(input) {
|
|
|
28597
28844
|
}
|
|
28598
28845
|
async function startReplayRecording(sessionID, directory) {
|
|
28599
28846
|
try {
|
|
28600
|
-
const replayDir =
|
|
28847
|
+
const replayDir = path55.join(directory, ".swarm", "replays");
|
|
28601
28848
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
28602
28849
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
28603
|
-
const filepath =
|
|
28850
|
+
const filepath = path55.join(replayDir, filename);
|
|
28604
28851
|
if (!isPathSafe(filepath, replayDir)) {
|
|
28605
28852
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
28606
28853
|
return null;
|
|
@@ -28678,7 +28925,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28678
28925
|
} catch {
|
|
28679
28926
|
results.push("\u274C Failed to delete state.json");
|
|
28680
28927
|
}
|
|
28681
|
-
const sessionDir =
|
|
28928
|
+
const sessionDir = path56.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
28682
28929
|
let sessionFiles = [];
|
|
28683
28930
|
if (fs27.existsSync(sessionDir)) {
|
|
28684
28931
|
try {
|
|
@@ -28690,7 +28937,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28690
28937
|
for (const file of sessionFiles) {
|
|
28691
28938
|
if (file === "state.json")
|
|
28692
28939
|
continue;
|
|
28693
|
-
const filePath =
|
|
28940
|
+
const filePath = path56.join(sessionDir, file);
|
|
28694
28941
|
try {
|
|
28695
28942
|
if (!fs27.existsSync(filePath))
|
|
28696
28943
|
continue;
|
|
@@ -28725,7 +28972,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28725
28972
|
}
|
|
28726
28973
|
|
|
28727
28974
|
// src/summaries/manager.ts
|
|
28728
|
-
import * as
|
|
28975
|
+
import * as path57 from "path";
|
|
28729
28976
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
28730
28977
|
function sanitizeSummaryId(id) {
|
|
28731
28978
|
if (!id || id.length === 0) {
|
|
@@ -28749,7 +28996,7 @@ function sanitizeSummaryId(id) {
|
|
|
28749
28996
|
}
|
|
28750
28997
|
async function loadFullOutput(directory, id) {
|
|
28751
28998
|
const sanitizedId = sanitizeSummaryId(id);
|
|
28752
|
-
const relativePath =
|
|
28999
|
+
const relativePath = path57.join("summaries", `${sanitizedId}.json`);
|
|
28753
29000
|
validateSwarmPath(directory, relativePath);
|
|
28754
29001
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
28755
29002
|
if (content === null) {
|
|
@@ -28802,7 +29049,7 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
|
28802
29049
|
|
|
28803
29050
|
// src/commands/rollback.ts
|
|
28804
29051
|
import * as fs28 from "fs";
|
|
28805
|
-
import * as
|
|
29052
|
+
import * as path58 from "path";
|
|
28806
29053
|
async function handleRollbackCommand(directory, args) {
|
|
28807
29054
|
const phaseArg = args[0];
|
|
28808
29055
|
if (!phaseArg) {
|
|
@@ -28868,8 +29115,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28868
29115
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
28869
29116
|
continue;
|
|
28870
29117
|
}
|
|
28871
|
-
const src =
|
|
28872
|
-
const dest =
|
|
29118
|
+
const src = path58.join(checkpointDir, file);
|
|
29119
|
+
const dest = path58.join(swarmDir, file);
|
|
28873
29120
|
try {
|
|
28874
29121
|
fs28.cpSync(src, dest, { recursive: true, force: true });
|
|
28875
29122
|
successes.push(file);
|
|
@@ -28888,7 +29135,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28888
29135
|
].join(`
|
|
28889
29136
|
`);
|
|
28890
29137
|
}
|
|
28891
|
-
const existingLedgerPath =
|
|
29138
|
+
const existingLedgerPath = path58.join(swarmDir, "plan-ledger.jsonl");
|
|
28892
29139
|
let ledgerDeletionFailed = false;
|
|
28893
29140
|
if (fs28.existsSync(existingLedgerPath)) {
|
|
28894
29141
|
try {
|
|
@@ -28901,7 +29148,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28901
29148
|
}
|
|
28902
29149
|
if (!ledgerDeletionFailed) {
|
|
28903
29150
|
try {
|
|
28904
|
-
const planJsonPath =
|
|
29151
|
+
const planJsonPath = path58.join(swarmDir, "plan.json");
|
|
28905
29152
|
if (fs28.existsSync(planJsonPath)) {
|
|
28906
29153
|
const planRaw = fs28.readFileSync(planJsonPath, "utf-8");
|
|
28907
29154
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -29162,10 +29409,10 @@ Ensure this is a git repository with commit history.`;
|
|
|
29162
29409
|
`);
|
|
29163
29410
|
try {
|
|
29164
29411
|
const fs29 = await import("fs/promises");
|
|
29165
|
-
const
|
|
29166
|
-
const reportPath =
|
|
29167
|
-
await fs29.mkdir(
|
|
29168
|
-
const reportTempPath =
|
|
29412
|
+
const path59 = await import("path");
|
|
29413
|
+
const reportPath = path59.join(directory, ".swarm", "simulate-report.md");
|
|
29414
|
+
await fs29.mkdir(path59.dirname(reportPath), { recursive: true });
|
|
29415
|
+
const reportTempPath = path59.join(path59.dirname(reportPath), `${path59.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
29169
29416
|
try {
|
|
29170
29417
|
await fs29.writeFile(reportTempPath, report, "utf-8");
|
|
29171
29418
|
renameSync11(reportTempPath, reportPath);
|
|
@@ -29194,18 +29441,18 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
29194
29441
|
// src/services/status-service.ts
|
|
29195
29442
|
import * as fsSync3 from "fs";
|
|
29196
29443
|
import { readFile as readFile16 } from "fs/promises";
|
|
29197
|
-
import * as
|
|
29444
|
+
import * as path60 from "path";
|
|
29198
29445
|
|
|
29199
29446
|
// src/turbo/lean/state.ts
|
|
29200
29447
|
init_logger();
|
|
29201
29448
|
import * as fs29 from "fs";
|
|
29202
|
-
import * as
|
|
29449
|
+
import * as path59 from "path";
|
|
29203
29450
|
var STATE_FILE3 = "turbo-state.json";
|
|
29204
29451
|
function nowISO3() {
|
|
29205
29452
|
return new Date().toISOString();
|
|
29206
29453
|
}
|
|
29207
29454
|
function ensureSwarmDir2(directory) {
|
|
29208
|
-
const swarmDir =
|
|
29455
|
+
const swarmDir = path59.resolve(directory, ".swarm");
|
|
29209
29456
|
if (!fs29.existsSync(swarmDir)) {
|
|
29210
29457
|
fs29.mkdirSync(swarmDir, { recursive: true });
|
|
29211
29458
|
}
|
|
@@ -29250,7 +29497,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
29250
29497
|
}
|
|
29251
29498
|
function readPersisted2(directory) {
|
|
29252
29499
|
try {
|
|
29253
|
-
const filePath =
|
|
29500
|
+
const filePath = path59.join(directory, ".swarm", STATE_FILE3);
|
|
29254
29501
|
if (!fs29.existsSync(filePath)) {
|
|
29255
29502
|
const seed = emptyPersisted2();
|
|
29256
29503
|
try {
|
|
@@ -29286,7 +29533,7 @@ function writePersisted2(directory, persisted) {
|
|
|
29286
29533
|
let payload;
|
|
29287
29534
|
try {
|
|
29288
29535
|
ensureSwarmDir2(directory);
|
|
29289
|
-
filePath =
|
|
29536
|
+
filePath = path59.join(directory, ".swarm", STATE_FILE3);
|
|
29290
29537
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
29291
29538
|
persisted.updatedAt = nowISO3();
|
|
29292
29539
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -29404,7 +29651,7 @@ var _internals43 = {
|
|
|
29404
29651
|
};
|
|
29405
29652
|
function readSpecStalenessSnapshot(directory) {
|
|
29406
29653
|
try {
|
|
29407
|
-
const p =
|
|
29654
|
+
const p = path60.join(directory, ".swarm", "spec-staleness.json");
|
|
29408
29655
|
if (!fsSync3.existsSync(p))
|
|
29409
29656
|
return { stale: false };
|
|
29410
29657
|
const raw = fsSync3.readFileSync(p, "utf-8");
|
|
@@ -29496,7 +29743,7 @@ async function getStatusData(directory, agents) {
|
|
|
29496
29743
|
}
|
|
29497
29744
|
status.recentEscalations = await readRecentEscalations(directory);
|
|
29498
29745
|
status.pendingProposals = await countProposals(directory);
|
|
29499
|
-
status.unactionableQueueDepth = await safeLineCount(
|
|
29746
|
+
status.unactionableQueueDepth = await safeLineCount(resolveUnactionablePath(directory));
|
|
29500
29747
|
status.insightCandidatesPending = await safeLineCount(validateSwarmPath(directory, "insight-candidates.jsonl"));
|
|
29501
29748
|
return enrichWithLeanTurbo(status, directory);
|
|
29502
29749
|
}
|
|
@@ -29935,6 +30182,66 @@ function buildStatusMessage2(session, directory, sessionID) {
|
|
|
29935
30182
|
`);
|
|
29936
30183
|
}
|
|
29937
30184
|
|
|
30185
|
+
// src/commands/unlink.ts
|
|
30186
|
+
import { existsSync as existsSync36 } from "fs";
|
|
30187
|
+
import * as path61 from "path";
|
|
30188
|
+
var DEDUP_THRESHOLD2 = 0.6;
|
|
30189
|
+
async function copySharedKnowledgeToLocal(linkDir, localSwarmDir) {
|
|
30190
|
+
const sharedPath = path61.join(linkDir, "knowledge.jsonl");
|
|
30191
|
+
const localPath = path61.join(localSwarmDir, "knowledge.jsonl");
|
|
30192
|
+
if (!existsSync36(sharedPath))
|
|
30193
|
+
return 0;
|
|
30194
|
+
const sharedEntries = await readKnowledge(sharedPath);
|
|
30195
|
+
if (sharedEntries.length === 0)
|
|
30196
|
+
return 0;
|
|
30197
|
+
let copied = 0;
|
|
30198
|
+
await transactKnowledge(localPath, (localEntries) => {
|
|
30199
|
+
const result = [...localEntries];
|
|
30200
|
+
const seenIds = new Set(result.map((e) => e.id));
|
|
30201
|
+
let changed = false;
|
|
30202
|
+
for (const entry of sharedEntries) {
|
|
30203
|
+
if (seenIds.has(entry.id))
|
|
30204
|
+
continue;
|
|
30205
|
+
if (findNearDuplicate(entry.lesson, result, DEDUP_THRESHOLD2))
|
|
30206
|
+
continue;
|
|
30207
|
+
result.push(entry);
|
|
30208
|
+
seenIds.add(entry.id);
|
|
30209
|
+
copied++;
|
|
30210
|
+
changed = true;
|
|
30211
|
+
}
|
|
30212
|
+
return changed ? result : null;
|
|
30213
|
+
});
|
|
30214
|
+
return copied;
|
|
30215
|
+
}
|
|
30216
|
+
async function handleUnlinkCommand(directory, args) {
|
|
30217
|
+
const pointer = readLinkPointer(directory);
|
|
30218
|
+
if (!pointer) {
|
|
30219
|
+
return "\u2139\uFE0F This worktree is not linked. Nothing to unlink.";
|
|
30220
|
+
}
|
|
30221
|
+
const copyBack = !args.includes("--no-copy");
|
|
30222
|
+
const linkDir = resolveLinkDir(pointer.linkId);
|
|
30223
|
+
let copied = 0;
|
|
30224
|
+
if (copyBack) {
|
|
30225
|
+
try {
|
|
30226
|
+
copied = await copySharedKnowledgeToLocal(linkDir, path61.join(directory, ".swarm"));
|
|
30227
|
+
} catch (error2) {
|
|
30228
|
+
return `\u274C Failed to copy shared knowledge back to local: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
30229
|
+
}
|
|
30230
|
+
}
|
|
30231
|
+
try {
|
|
30232
|
+
await removeLinkPointer(directory);
|
|
30233
|
+
} catch (error2) {
|
|
30234
|
+
return `\u274C Failed to remove link pointer: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
30235
|
+
}
|
|
30236
|
+
const copyNote = copyBack ? ` copied ${copied} shared lesson(s) back into local \`.swarm/knowledge.jsonl\`.` : " shared lessons were NOT copied back (--no-copy).";
|
|
30237
|
+
return [
|
|
30238
|
+
`\uD83D\uDD13 Unlinked this worktree from shared knowledge store "${pointer.linkId}".`,
|
|
30239
|
+
copyNote,
|
|
30240
|
+
"This worktree now uses its local `.swarm/` knowledge again."
|
|
30241
|
+
].join(`
|
|
30242
|
+
`);
|
|
30243
|
+
}
|
|
30244
|
+
|
|
29938
30245
|
// src/commands/write-retro.ts
|
|
29939
30246
|
async function handleWriteRetroCommand(directory, args) {
|
|
29940
30247
|
if (args.length === 0 || !args[0] || args[0].trim() === "") {
|
|
@@ -30071,7 +30378,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
30071
30378
|
async function handleHelpCommand(ctx) {
|
|
30072
30379
|
const targetCommand = ctx.args.join(" ");
|
|
30073
30380
|
if (!targetCommand) {
|
|
30074
|
-
const { buildHelpText } = await import("./index-
|
|
30381
|
+
const { buildHelpText } = await import("./index-dprk5c5f.js");
|
|
30075
30382
|
return buildHelpText();
|
|
30076
30383
|
}
|
|
30077
30384
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -30080,7 +30387,7 @@ async function handleHelpCommand(ctx) {
|
|
|
30080
30387
|
return _internals45.buildDetailedHelp(resolved.key, resolved.entry);
|
|
30081
30388
|
}
|
|
30082
30389
|
const similar = _internals45.findSimilarCommands(targetCommand);
|
|
30083
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
30390
|
+
const { buildHelpText: fullHelp } = await import("./index-dprk5c5f.js");
|
|
30084
30391
|
if (similar.length > 0) {
|
|
30085
30392
|
return `Command '/swarm ${targetCommand}' not found.
|
|
30086
30393
|
|
|
@@ -30213,7 +30520,7 @@ var COMMAND_REGISTRY = {
|
|
|
30213
30520
|
},
|
|
30214
30521
|
"guardrail explain": {
|
|
30215
30522
|
handler: async (ctx) => {
|
|
30216
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
30523
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-hy0zz0p6.js");
|
|
30217
30524
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
30218
30525
|
},
|
|
30219
30526
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -30676,6 +30983,29 @@ Subcommands:
|
|
|
30676
30983
|
category: "config",
|
|
30677
30984
|
toolPolicy: "none"
|
|
30678
30985
|
},
|
|
30986
|
+
link: {
|
|
30987
|
+
handler: (ctx) => handleLinkCommand(ctx.directory, ctx.args),
|
|
30988
|
+
description: "Tie this worktree to a shared swarm knowledge store [name]",
|
|
30989
|
+
details: "Links the current worktree to a shared knowledge store so multiple swarms working on the same project (e.g. separate git worktrees) pool their lessons instead of each keeping an isolated .swarm/knowledge.jsonl. With no name, ties all worktrees of the same repo via the project hash; with a name, ties any worktrees/repos that use the same name. Existing local lessons are merged (deduped) into the shared store. Use `/swarm link status` to inspect.",
|
|
30990
|
+
args: "[<name> | status]",
|
|
30991
|
+
category: "utility",
|
|
30992
|
+
toolPolicy: "none"
|
|
30993
|
+
},
|
|
30994
|
+
"link status": {
|
|
30995
|
+
handler: (ctx) => handleLinkCommand(ctx.directory, ["status"]),
|
|
30996
|
+
description: "Show whether this worktree shares knowledge via a link",
|
|
30997
|
+
subcommandOf: "link",
|
|
30998
|
+
category: "utility",
|
|
30999
|
+
toolPolicy: "none"
|
|
31000
|
+
},
|
|
31001
|
+
unlink: {
|
|
31002
|
+
handler: (ctx) => handleUnlinkCommand(ctx.directory, ctx.args),
|
|
31003
|
+
description: "Stop sharing swarm knowledge for this worktree [--no-copy]",
|
|
31004
|
+
details: "Unlinks the current worktree from its shared knowledge store and returns it to a local .swarm/knowledge.jsonl. By default the shared lessons are copied back into the local store (deduped) so nothing is lost; pass --no-copy to skip the copy-back.",
|
|
31005
|
+
args: "[--no-copy]",
|
|
31006
|
+
category: "utility",
|
|
31007
|
+
toolPolicy: "none"
|
|
31008
|
+
},
|
|
30679
31009
|
promote: {
|
|
30680
31010
|
handler: (ctx) => handlePromoteCommand(ctx.directory, ctx.args),
|
|
30681
31011
|
description: "Manually promote lesson to hive knowledge",
|
|
@@ -30961,24 +31291,24 @@ function validateAliases() {
|
|
|
30961
31291
|
}
|
|
30962
31292
|
aliasTargets.get(target).push(name);
|
|
30963
31293
|
const visited = new Set;
|
|
30964
|
-
const
|
|
31294
|
+
const path62 = [];
|
|
30965
31295
|
let current = target;
|
|
30966
31296
|
while (current) {
|
|
30967
31297
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
30968
31298
|
if (!currentEntry)
|
|
30969
31299
|
break;
|
|
30970
31300
|
if (visited.has(current)) {
|
|
30971
|
-
const cycleStart =
|
|
31301
|
+
const cycleStart = path62.indexOf(current);
|
|
30972
31302
|
const fullChain = [
|
|
30973
31303
|
name,
|
|
30974
|
-
...
|
|
31304
|
+
...path62.slice(0, cycleStart > 0 ? cycleStart : path62.length),
|
|
30975
31305
|
current
|
|
30976
31306
|
].join(" \u2192 ");
|
|
30977
31307
|
errors.push(`Circular alias detected: ${fullChain}`);
|
|
30978
31308
|
break;
|
|
30979
31309
|
}
|
|
30980
31310
|
visited.add(current);
|
|
30981
|
-
|
|
31311
|
+
path62.push(current);
|
|
30982
31312
|
current = currentEntry.aliasOf || "";
|
|
30983
31313
|
}
|
|
30984
31314
|
}
|
|
@@ -31144,4 +31474,4 @@ ${text}`;
|
|
|
31144
31474
|
};
|
|
31145
31475
|
}
|
|
31146
31476
|
|
|
31147
|
-
export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS, _internals45 as _internals, resolveCommand };
|
|
31477
|
+
export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS, _internals45 as _internals, resolveCommand };
|