opencode-swarm 7.107.1 → 7.107.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{curator-np2ky29t.js → curator-1nr4qszq.js} +6 -6
- package/dist/cli/{curator-drift-6ad8mxxb.js → curator-drift-ed7p5mfy.js} +2 -2
- package/dist/cli/{curator-llm-factory-gdhtm1hh.js → curator-llm-factory-x9tk7e6m.js} +6 -6
- package/dist/cli/{evidence-summary-service-dh44gevz.js → evidence-summary-service-9r28ds8t.js} +3 -3
- package/dist/cli/{guardrail-explain-414smfg4.js → guardrail-explain-etdrhd4d.js} +7 -7
- package/dist/cli/{guardrail-log-fsc85hwa.js → guardrail-log-2rns4g6d.js} +2 -2
- package/dist/cli/{hive-promoter-y9r8d315.js → hive-promoter-j4e6rfa6.js} +6 -6
- package/dist/cli/{index-87d4wsv9.js → index-502f6np6.js} +8 -8
- package/dist/cli/{index-mpe0yk9s.js → index-57ymmh7h.js} +5 -3
- package/dist/cli/{index-357p0baj.js → index-91j1sqzm.js} +14 -2
- package/dist/cli/{index-gt514nt1.js → index-cyzzdbvw.js} +1058 -873
- package/dist/cli/{index-t4hbye3v.js → index-hkpw4wwa.js} +1 -1
- package/dist/cli/{index-jjp5qrjv.js → index-kzfkggjx.js} +97 -39
- package/dist/cli/{index-w8dzxnx4.js → index-m1xjr58n.js} +1 -1
- package/dist/cli/{index-fxtrk7y8.js → index-tgtmbf3r.js} +1 -1
- package/dist/cli/{index-7v734syt.js → index-w15984gg.js} +2 -2
- package/dist/cli/index.js +6 -6
- package/dist/cli/{pending-delegations-46xf2n2e.js → pending-delegations-ws51m1e1.js} +1 -1
- package/dist/cli/{pr-subscriptions-3c34rnm1.js → pr-subscriptions-0dpn4epk.js} +2 -2
- package/dist/commands/handoff.d.ts +2 -1
- package/dist/commands/registry.d.ts +4 -4
- package/dist/config/bundled-skills.d.ts +3 -5
- package/dist/hooks/guardrails/file-authority.d.ts +1 -1
- package/dist/hooks/knowledge-injector.d.ts +3 -0
- package/dist/hooks/knowledge-reader.d.ts +17 -0
- package/dist/hooks/semantic-diff-injection.d.ts +19 -0
- package/dist/index.js +340 -332
- package/dist/services/directive-predicate-runner.d.ts +1 -1
- package/dist/session/snapshot-writer.d.ts +4 -0
- package/dist/tools/external-skill-discover.d.ts +11 -0
- package/dist/tools/knowledge-remove.d.ts +11 -0
- package/dist/tools/pre-check-batch.d.ts +4 -0
- package/dist/turbo/lean/evidence.d.ts +22 -0
- package/dist/turbo/lean/integration.d.ts +6 -1
- package/dist/turbo/lean/reviewer.d.ts +6 -1
- package/dist/turbo/lean/runner.d.ts +10 -1
- package/dist/utils/untrusted-markdown.d.ts +1 -0
- package/dist/worktree/merge.d.ts +1 -0
- package/package.json +1 -1
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
savePlan,
|
|
45
45
|
transientBackoff,
|
|
46
46
|
validateProjectRoot
|
|
47
|
-
} from "./index-
|
|
47
|
+
} from "./index-kzfkggjx.js";
|
|
48
48
|
import {
|
|
49
49
|
_internals as _internals2,
|
|
50
50
|
_internals1 as _internals3,
|
|
@@ -136,7 +136,7 @@ import {
|
|
|
136
136
|
resolveSpeckitProjection,
|
|
137
137
|
validateSpeckit,
|
|
138
138
|
writeProjectedSpecSync
|
|
139
|
-
} from "./index-
|
|
139
|
+
} from "./index-91j1sqzm.js";
|
|
140
140
|
import {
|
|
141
141
|
SandboxCapabilityProbe,
|
|
142
142
|
_internals,
|
|
@@ -154,12 +154,12 @@ import {
|
|
|
154
154
|
listActive,
|
|
155
155
|
subscribe,
|
|
156
156
|
unsubscribe
|
|
157
|
-
} from "./index-
|
|
157
|
+
} from "./index-hkpw4wwa.js";
|
|
158
158
|
import {
|
|
159
159
|
readSwarmFileAsync,
|
|
160
160
|
safeHook,
|
|
161
161
|
validateSwarmPath
|
|
162
|
-
} from "./index-
|
|
162
|
+
} from "./index-57ymmh7h.js";
|
|
163
163
|
import {
|
|
164
164
|
deepMerge
|
|
165
165
|
} from "./index-p0arc26j.js";
|
|
@@ -329,7 +329,7 @@ var init_bubblewrap = __esm(() => {
|
|
|
329
329
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
330
330
|
import { mkdtempSync as mkdtempSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
331
331
|
import * as os8 from "os";
|
|
332
|
-
import * as
|
|
332
|
+
import * as path35 from "path";
|
|
333
333
|
function probeSandboxExec() {
|
|
334
334
|
try {
|
|
335
335
|
const result = spawnSync4("sandbox-exec", ["--version"], {
|
|
@@ -357,8 +357,8 @@ function probeSandboxExec() {
|
|
|
357
357
|
function shellEscape2(s) {
|
|
358
358
|
return s.replace(/'/g, "'\\''");
|
|
359
359
|
}
|
|
360
|
-
function sbplEscapePath(
|
|
361
|
-
const withoutControlChars =
|
|
360
|
+
function sbplEscapePath(path36) {
|
|
361
|
+
const withoutControlChars = path36.split("").filter((ch) => {
|
|
362
362
|
const cp = ch.codePointAt(0);
|
|
363
363
|
return cp >= 32 && cp !== 127;
|
|
364
364
|
}).join("");
|
|
@@ -434,8 +434,8 @@ class MacOSSandboxExecutor {
|
|
|
434
434
|
const profile = buildSandboxProfile(allScopes, temp);
|
|
435
435
|
let profilePath;
|
|
436
436
|
try {
|
|
437
|
-
const profileDir = mkdtempSync2(
|
|
438
|
-
profilePath =
|
|
437
|
+
const profileDir = mkdtempSync2(path35.join(os8.tmpdir(), "sandbox-"));
|
|
438
|
+
profilePath = path35.join(profileDir, `profile-${process.pid}-${Date.now()}.sb`);
|
|
439
439
|
writeFileSync6(profilePath, profile, { mode: 384 });
|
|
440
440
|
} catch (err) {
|
|
441
441
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -542,7 +542,7 @@ var init_edge_cases = () => {};
|
|
|
542
542
|
// src/sandbox/win32/restricted-environment-executor.ts
|
|
543
543
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
544
544
|
import * as os9 from "os";
|
|
545
|
-
import * as
|
|
545
|
+
import * as path36 from "path";
|
|
546
546
|
function probeWindowsSandbox() {
|
|
547
547
|
try {
|
|
548
548
|
const result = spawnSync5("cmd", ["/c", "echo", "ok"], {
|
|
@@ -589,7 +589,7 @@ function isPathInScopes(command, scopes) {
|
|
|
589
589
|
const paths = command.match(pathPattern) || [];
|
|
590
590
|
if (paths.length === 0)
|
|
591
591
|
return true;
|
|
592
|
-
const normalizedPaths = paths.map((p) =>
|
|
592
|
+
const normalizedPaths = paths.map((p) => path36.win32.resolve(p));
|
|
593
593
|
const normalizedScopes = scopes.map((s) => s.toLowerCase().replace(/\\+$/, ""));
|
|
594
594
|
return normalizedPaths.every((p) => {
|
|
595
595
|
const lower = p.toLowerCase();
|
|
@@ -724,9 +724,9 @@ var init_restricted_environment_executor = __esm(() => {
|
|
|
724
724
|
|
|
725
725
|
// src/sandbox/win32/native-sandbox-executor.ts
|
|
726
726
|
import * as crypto3 from "crypto";
|
|
727
|
-
import * as
|
|
727
|
+
import * as fs12 from "fs";
|
|
728
728
|
import * as os10 from "os";
|
|
729
|
-
import * as
|
|
729
|
+
import * as path37 from "path";
|
|
730
730
|
|
|
731
731
|
class NativeWindowsSandboxExecutor {
|
|
732
732
|
mechanism;
|
|
@@ -788,12 +788,12 @@ class NativeWindowsSandboxExecutor {
|
|
|
788
788
|
policy.workspace_roots = scopePaths.length > 0 ? scopePaths : [workspaceRoot];
|
|
789
789
|
policy.writable_roots = policy.workspace_roots;
|
|
790
790
|
const policyJson = JSON.stringify(policy);
|
|
791
|
-
const policyDir =
|
|
791
|
+
const policyDir = path37.join(os10.tmpdir(), "swarm-sandbox-policies");
|
|
792
792
|
try {
|
|
793
|
-
|
|
793
|
+
fs12.mkdirSync(policyDir, { recursive: true });
|
|
794
794
|
} catch {}
|
|
795
|
-
const policyFile =
|
|
796
|
-
|
|
795
|
+
const policyFile = path37.join(policyDir, `${runId}.json`);
|
|
796
|
+
fs12.writeFileSync(policyFile, policyJson, "utf-8");
|
|
797
797
|
const mode = this._probeResult.mode === "none" ? "auto" : this._probeResult.mode;
|
|
798
798
|
const escapedBinary = binary.includes(" ") ? `"${binary}"` : binary;
|
|
799
799
|
const escapedPolicyFile = policyFile.includes(" ") ? `"${policyFile}"` : policyFile;
|
|
@@ -924,8 +924,8 @@ var init_executor = __esm(() => {
|
|
|
924
924
|
});
|
|
925
925
|
|
|
926
926
|
// src/state.ts
|
|
927
|
-
import * as
|
|
928
|
-
import * as
|
|
927
|
+
import * as fs32 from "fs/promises";
|
|
928
|
+
import * as path69 from "path";
|
|
929
929
|
|
|
930
930
|
// src/db/qa-gate-profile.ts
|
|
931
931
|
import { createHash } from "crypto";
|
|
@@ -5646,7 +5646,7 @@ function getDeferredWarnings() {
|
|
|
5646
5646
|
}
|
|
5647
5647
|
|
|
5648
5648
|
// src/config/bundled-skills.ts
|
|
5649
|
-
import
|
|
5649
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
5650
5650
|
import * as fsp from "fs/promises";
|
|
5651
5651
|
import * as path8 from "path";
|
|
5652
5652
|
var BUNDLED_PROJECT_SKILLS = [
|
|
@@ -5679,10 +5679,6 @@ var BUNDLED_PROJECT_SKILLS = [
|
|
|
5679
5679
|
];
|
|
5680
5680
|
var MAX_SKILL_FILES = 64;
|
|
5681
5681
|
var MAX_SKILL_BYTES = 512000;
|
|
5682
|
-
var syncedProjectSkillTargets = new Set;
|
|
5683
|
-
function getSyncCacheKey(projectDirectory, packageRoot) {
|
|
5684
|
-
return `${path8.resolve(projectDirectory)}\x00${path8.resolve(packageRoot)}`;
|
|
5685
|
-
}
|
|
5686
5682
|
function warnBundledSkillSyncFailure(err) {
|
|
5687
5683
|
const message = err instanceof Error ? err.message : String(err);
|
|
5688
5684
|
console.warn(`[opencode-swarm] Could not install bundled project skills; continuing without sync: ${message}`);
|
|
@@ -5737,7 +5733,7 @@ async function collectBundledSkillFilesBoundedAsync(sourceDir, state, relativeDi
|
|
|
5737
5733
|
}
|
|
5738
5734
|
return files;
|
|
5739
5735
|
}
|
|
5740
|
-
async function rollbackCopiedFilesAsync(copiedFiles, destDir) {
|
|
5736
|
+
async function rollbackCopiedFilesAsync(copiedFiles, destDir, overwrittenFiles = []) {
|
|
5741
5737
|
const safeDestDir = path8.resolve(destDir);
|
|
5742
5738
|
const dirs = new Set;
|
|
5743
5739
|
for (const copiedFile of copiedFiles) {
|
|
@@ -5750,6 +5746,15 @@ async function rollbackCopiedFilesAsync(copiedFiles, destDir) {
|
|
|
5750
5746
|
} catch {}
|
|
5751
5747
|
dirs.add(path8.dirname(resolvedFile));
|
|
5752
5748
|
}
|
|
5749
|
+
for (const overwritten of overwrittenFiles.reverse()) {
|
|
5750
|
+
const resolvedFile = path8.resolve(overwritten.path);
|
|
5751
|
+
const relative2 = path8.relative(safeDestDir, resolvedFile);
|
|
5752
|
+
if (relative2.startsWith("..") || path8.isAbsolute(relative2))
|
|
5753
|
+
continue;
|
|
5754
|
+
try {
|
|
5755
|
+
await fsp.writeFile(resolvedFile, overwritten.contents);
|
|
5756
|
+
} catch {}
|
|
5757
|
+
}
|
|
5753
5758
|
for (const dir of [...dirs].sort((a, b) => b.length - a.length)) {
|
|
5754
5759
|
const relative2 = path8.relative(safeDestDir, path8.resolve(dir));
|
|
5755
5760
|
if (relative2.startsWith("..") || path8.isAbsolute(relative2))
|
|
@@ -5759,39 +5764,58 @@ async function rollbackCopiedFilesAsync(copiedFiles, destDir) {
|
|
|
5759
5764
|
} catch {}
|
|
5760
5765
|
}
|
|
5761
5766
|
}
|
|
5767
|
+
async function copyFileAtomicAsync(sourcePath, destPath) {
|
|
5768
|
+
const tempPath = path8.join(path8.dirname(destPath), `.${path8.basename(destPath)}.tmp.${randomUUID3()}`);
|
|
5769
|
+
try {
|
|
5770
|
+
await fsp.copyFile(sourcePath, tempPath);
|
|
5771
|
+
await fsp.rename(tempPath, destPath);
|
|
5772
|
+
} catch (err) {
|
|
5773
|
+
try {
|
|
5774
|
+
await fsp.rm(tempPath, { force: true });
|
|
5775
|
+
} catch {}
|
|
5776
|
+
throw err;
|
|
5777
|
+
}
|
|
5778
|
+
}
|
|
5762
5779
|
async function copyBundledDirectoryBoundedAsync(sourceDir, destDir) {
|
|
5763
5780
|
const files = await collectBundledSkillFilesBoundedAsync(sourceDir, {
|
|
5764
5781
|
files: 0,
|
|
5765
5782
|
bytes: 0
|
|
5766
5783
|
});
|
|
5767
5784
|
const copiedFiles = [];
|
|
5785
|
+
const overwrittenFiles = [];
|
|
5768
5786
|
try {
|
|
5769
5787
|
for (const file of files) {
|
|
5770
5788
|
const sourcePath = path8.join(sourceDir, file.relativePath);
|
|
5771
5789
|
const destPath = path8.join(destDir, file.relativePath);
|
|
5772
5790
|
await fsp.mkdir(path8.dirname(destPath), { recursive: true });
|
|
5773
|
-
|
|
5774
|
-
await
|
|
5791
|
+
if (await pathExistsAsync(destPath)) {
|
|
5792
|
+
if (await isSymbolicLinkAsync(destPath)) {
|
|
5793
|
+
throw new Error("refusing to overwrite symlinked bundled skill file");
|
|
5794
|
+
}
|
|
5795
|
+
const [sourceContents, destContents] = await Promise.all([
|
|
5796
|
+
fsp.readFile(sourcePath),
|
|
5797
|
+
fsp.readFile(destPath)
|
|
5798
|
+
]);
|
|
5799
|
+
if (sourceContents.equals(destContents)) {
|
|
5800
|
+
continue;
|
|
5801
|
+
}
|
|
5802
|
+
overwrittenFiles.push({ path: destPath, contents: destContents });
|
|
5803
|
+
await copyFileAtomicAsync(sourcePath, destPath);
|
|
5804
|
+
} else {
|
|
5805
|
+
await copyFileAtomicAsync(sourcePath, destPath);
|
|
5775
5806
|
copiedFiles.push(destPath);
|
|
5776
|
-
} catch (err) {
|
|
5777
|
-
if (err.code !== "EEXIST")
|
|
5778
|
-
throw err;
|
|
5779
5807
|
}
|
|
5780
5808
|
}
|
|
5781
5809
|
} catch (err) {
|
|
5782
|
-
await rollbackCopiedFilesAsync(copiedFiles, destDir);
|
|
5810
|
+
await rollbackCopiedFilesAsync(copiedFiles, destDir, overwrittenFiles);
|
|
5783
5811
|
throw err;
|
|
5784
5812
|
}
|
|
5785
5813
|
}
|
|
5786
5814
|
async function syncBundledProjectSkillsIfMissingAsync(projectDirectory, packageRoot, quiet = false) {
|
|
5787
5815
|
try {
|
|
5788
|
-
const cacheKey = getSyncCacheKey(projectDirectory, packageRoot);
|
|
5789
|
-
if (syncedProjectSkillTargets.has(cacheKey))
|
|
5790
|
-
return;
|
|
5791
5816
|
const sourceRoot = path8.join(packageRoot, ".opencode", "skills");
|
|
5792
5817
|
const opencodeDir = path8.join(projectDirectory, ".opencode");
|
|
5793
5818
|
const skillsDir = path8.join(opencodeDir, "skills");
|
|
5794
|
-
let sawBundledSource = false;
|
|
5795
5819
|
if (!await ensureNotSymlinkedDirectoryAsync(opencodeDir))
|
|
5796
5820
|
return;
|
|
5797
5821
|
if (!await ensureNotSymlinkedDirectoryAsync(skillsDir))
|
|
@@ -5800,21 +5824,15 @@ async function syncBundledProjectSkillsIfMissingAsync(projectDirectory, packageR
|
|
|
5800
5824
|
const sourceDir = path8.join(sourceRoot, slug);
|
|
5801
5825
|
const sourceSkill = path8.join(sourceDir, "SKILL.md");
|
|
5802
5826
|
const destDir = path8.join(skillsDir, slug);
|
|
5803
|
-
const destSkill = path8.join(destDir, "SKILL.md");
|
|
5804
5827
|
if (!await pathExistsAsync(sourceSkill))
|
|
5805
5828
|
continue;
|
|
5806
|
-
sawBundledSource = true;
|
|
5807
|
-
if (await pathExistsAsync(destSkill))
|
|
5808
|
-
continue;
|
|
5809
5829
|
if (!await ensureNotSymlinkedDirectoryAsync(destDir))
|
|
5810
5830
|
continue;
|
|
5811
5831
|
await copyBundledDirectoryBoundedAsync(sourceDir, destDir);
|
|
5812
5832
|
if (!quiet) {
|
|
5813
|
-
console.warn(`[opencode-swarm]
|
|
5833
|
+
console.warn(`[opencode-swarm] Synchronized bundled skill .opencode/skills/${slug}/SKILL.md for first-class /swarm command support`);
|
|
5814
5834
|
}
|
|
5815
5835
|
}
|
|
5816
|
-
if (sawBundledSource)
|
|
5817
|
-
syncedProjectSkillTargets.add(cacheKey);
|
|
5818
5836
|
} catch (err) {
|
|
5819
5837
|
if (!quiet)
|
|
5820
5838
|
warnBundledSkillSyncFailure(err);
|
|
@@ -6092,7 +6110,7 @@ async function handleAutoProceedCommand(_directory, args, sessionID) {
|
|
|
6092
6110
|
}
|
|
6093
6111
|
|
|
6094
6112
|
// src/services/cost-accounting.ts
|
|
6095
|
-
import * as
|
|
6113
|
+
import * as fs2 from "fs";
|
|
6096
6114
|
import * as os5 from "os";
|
|
6097
6115
|
import * as path10 from "path";
|
|
6098
6116
|
function summarizeTelemetryCosts(directory) {
|
|
@@ -6110,15 +6128,15 @@ function readTelemetryEvents(directory) {
|
|
|
6110
6128
|
path10.join(swarmDir, "telemetry.jsonl.1"),
|
|
6111
6129
|
path10.join(swarmDir, "telemetry.jsonl")
|
|
6112
6130
|
];
|
|
6113
|
-
const tmpDir =
|
|
6131
|
+
const tmpDir = fs2.mkdtempSync(path10.join(os5.tmpdir(), "telemetry-snapshot-"));
|
|
6114
6132
|
const snapshotFiles = [];
|
|
6115
6133
|
try {
|
|
6116
6134
|
for (const file of files) {
|
|
6117
|
-
if (!
|
|
6135
|
+
if (!fs2.existsSync(file))
|
|
6118
6136
|
continue;
|
|
6119
6137
|
const snap = path10.join(tmpDir, path10.basename(file));
|
|
6120
6138
|
try {
|
|
6121
|
-
|
|
6139
|
+
fs2.copyFileSync(file, snap);
|
|
6122
6140
|
snapshotFiles.push(snap);
|
|
6123
6141
|
} catch {}
|
|
6124
6142
|
}
|
|
@@ -6127,7 +6145,7 @@ function readTelemetryEvents(directory) {
|
|
|
6127
6145
|
for (const file of snapshotFiles) {
|
|
6128
6146
|
let content = "";
|
|
6129
6147
|
try {
|
|
6130
|
-
content =
|
|
6148
|
+
content = fs2.readFileSync(file, "utf-8");
|
|
6131
6149
|
} catch {
|
|
6132
6150
|
continue;
|
|
6133
6151
|
}
|
|
@@ -6145,10 +6163,10 @@ function readTelemetryEvents(directory) {
|
|
|
6145
6163
|
try {
|
|
6146
6164
|
for (const f of snapshotFiles) {
|
|
6147
6165
|
try {
|
|
6148
|
-
|
|
6166
|
+
fs2.unlinkSync(f);
|
|
6149
6167
|
} catch {}
|
|
6150
6168
|
}
|
|
6151
|
-
|
|
6169
|
+
fs2.rmdirSync(tmpDir);
|
|
6152
6170
|
} catch {}
|
|
6153
6171
|
return events;
|
|
6154
6172
|
}
|
|
@@ -6672,7 +6690,7 @@ async function handleBrainstormCommand(_directory, args) {
|
|
|
6672
6690
|
|
|
6673
6691
|
// src/tools/checkpoint.ts
|
|
6674
6692
|
import * as child_process from "child_process";
|
|
6675
|
-
import * as
|
|
6693
|
+
import * as fs3 from "fs";
|
|
6676
6694
|
import * as path11 from "path";
|
|
6677
6695
|
|
|
6678
6696
|
// src/tools/create-tool.ts
|
|
@@ -6765,8 +6783,8 @@ function getCheckpointLogPath(directory) {
|
|
|
6765
6783
|
function readCheckpointLog(directory) {
|
|
6766
6784
|
const logPath = getCheckpointLogPath(directory);
|
|
6767
6785
|
try {
|
|
6768
|
-
if (
|
|
6769
|
-
const content =
|
|
6786
|
+
if (fs3.existsSync(logPath)) {
|
|
6787
|
+
const content = fs3.readFileSync(logPath, "utf-8");
|
|
6770
6788
|
const parsed = JSON.parse(content);
|
|
6771
6789
|
if (!parsed.checkpoints || !Array.isArray(parsed.checkpoints)) {
|
|
6772
6790
|
return { version: 1, checkpoints: [] };
|
|
@@ -6779,12 +6797,12 @@ function readCheckpointLog(directory) {
|
|
|
6779
6797
|
function writeCheckpointLog(log2, directory) {
|
|
6780
6798
|
const logPath = getCheckpointLogPath(directory);
|
|
6781
6799
|
const dir = path11.dirname(logPath);
|
|
6782
|
-
if (!
|
|
6783
|
-
|
|
6800
|
+
if (!fs3.existsSync(dir)) {
|
|
6801
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
6784
6802
|
}
|
|
6785
6803
|
const tempPath = `${logPath}.tmp`;
|
|
6786
|
-
|
|
6787
|
-
|
|
6804
|
+
fs3.writeFileSync(tempPath, JSON.stringify(log2, null, 2), "utf-8");
|
|
6805
|
+
fs3.renameSync(tempPath, logPath);
|
|
6788
6806
|
}
|
|
6789
6807
|
function gitExec(args, cwd) {
|
|
6790
6808
|
for (let attempt = 0;attempt < MAX_TRANSIENT_RETRIES; attempt++) {
|
|
@@ -6818,7 +6836,7 @@ function appendRetentionEvent(directory, event) {
|
|
|
6818
6836
|
const eventsPath = path11.join(directory, ".swarm", "events.jsonl");
|
|
6819
6837
|
const line = `${JSON.stringify({ ...event, timestamp: new Date().toISOString() })}
|
|
6820
6838
|
`;
|
|
6821
|
-
|
|
6839
|
+
fs3.appendFileSync(eventsPath, line);
|
|
6822
6840
|
} catch {}
|
|
6823
6841
|
}
|
|
6824
6842
|
function getCurrentSha(directory) {
|
|
@@ -6922,13 +6940,15 @@ function handleRestore(label, directory) {
|
|
|
6922
6940
|
error: `checkpoint not found: "${label}"`
|
|
6923
6941
|
}, null, 2);
|
|
6924
6942
|
}
|
|
6925
|
-
|
|
6943
|
+
const logBeforeReset = log2;
|
|
6944
|
+
gitExec(["reset", "--hard", checkpoint.sha], directory);
|
|
6945
|
+
writeCheckpointLog(logBeforeReset, directory);
|
|
6926
6946
|
return JSON.stringify({
|
|
6927
6947
|
action: "restore",
|
|
6928
6948
|
success: true,
|
|
6929
6949
|
label,
|
|
6930
6950
|
sha: checkpoint.sha,
|
|
6931
|
-
message: `Restored to checkpoint: "${label}" (
|
|
6951
|
+
message: `Restored to checkpoint: "${label}" (hard reset)`
|
|
6932
6952
|
}, null, 2);
|
|
6933
6953
|
} catch (e) {
|
|
6934
6954
|
const errorMessage = e instanceof Error ? `restore failed: ${e.message}` : "restore failed: unknown error";
|
|
@@ -6978,7 +6998,7 @@ function handleDelete(label, directory) {
|
|
|
6978
6998
|
}
|
|
6979
6999
|
}
|
|
6980
7000
|
var checkpoint = createSwarmTool({
|
|
6981
|
-
description: "Save, restore, list, and delete git checkpoints. " + "Use save to create a named snapshot, restore to return to a checkpoint
|
|
7001
|
+
description: "Save, restore, list, and delete git checkpoints. " + "Use save to create a named snapshot, restore to return tracked files to a checkpoint, " + "list to see all checkpoints, and delete to remove a checkpoint from the log. " + "Git commits are preserved on delete.",
|
|
6982
7002
|
args: {
|
|
6983
7003
|
action: exports_external.string().describe("Action to perform: save, restore, list, or delete"),
|
|
6984
7004
|
label: exports_external.string().optional().describe("Checkpoint label (required for save, restore, delete)")
|
|
@@ -7180,8 +7200,8 @@ async function handleClarifyCommand(_directory, args) {
|
|
|
7180
7200
|
// src/commands/close.ts
|
|
7181
7201
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
7182
7202
|
import * as fsSync from "fs";
|
|
7183
|
-
import { promises as
|
|
7184
|
-
import
|
|
7203
|
+
import { promises as fs10 } from "fs";
|
|
7204
|
+
import path28 from "path";
|
|
7185
7205
|
|
|
7186
7206
|
// src/hooks/curator-postmortem.ts
|
|
7187
7207
|
import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync4 } from "fs";
|
|
@@ -7900,11 +7920,11 @@ var _internals8 = {
|
|
|
7900
7920
|
return KnowledgeConfigSchema2.parse({});
|
|
7901
7921
|
},
|
|
7902
7922
|
applyCuratorKnowledgeUpdates: async (directory, recommendations, knowledgeConfig) => {
|
|
7903
|
-
const { applyCuratorKnowledgeUpdates } = await import("./curator-
|
|
7923
|
+
const { applyCuratorKnowledgeUpdates } = await import("./curator-1nr4qszq.js");
|
|
7904
7924
|
return applyCuratorKnowledgeUpdates(directory, recommendations, knowledgeConfig);
|
|
7905
7925
|
},
|
|
7906
7926
|
checkHivePromotions: async (entries, knowledgeConfig) => {
|
|
7907
|
-
const { checkHivePromotions } = await import("./hive-promoter-
|
|
7927
|
+
const { checkHivePromotions } = await import("./hive-promoter-j4e6rfa6.js");
|
|
7908
7928
|
return checkHivePromotions(entries, knowledgeConfig);
|
|
7909
7929
|
},
|
|
7910
7930
|
applyProposalTriage: async (directory, triage) => {
|
|
@@ -7954,7 +7974,7 @@ var _internals8 = {
|
|
|
7954
7974
|
return result;
|
|
7955
7975
|
},
|
|
7956
7976
|
readPriorDriftReports: async (directory) => {
|
|
7957
|
-
const { readPriorDriftReports } = await import("./curator-drift-
|
|
7977
|
+
const { readPriorDriftReports } = await import("./curator-drift-ed7p5mfy.js");
|
|
7958
7978
|
return readPriorDriftReports(directory);
|
|
7959
7979
|
},
|
|
7960
7980
|
readSwarmKnowledge: (directory) => readKnowledge(resolveSwarmKnowledgePath(directory))
|
|
@@ -7964,8 +7984,8 @@ var _internals8 = {
|
|
|
7964
7984
|
import path16 from "path";
|
|
7965
7985
|
|
|
7966
7986
|
// src/hooks/curator.ts
|
|
7967
|
-
import { randomUUID as
|
|
7968
|
-
import * as
|
|
7987
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
7988
|
+
import * as fs5 from "fs";
|
|
7969
7989
|
import * as path15 from "path";
|
|
7970
7990
|
|
|
7971
7991
|
// src/hooks/knowledge-escalator.ts
|
|
@@ -8403,12 +8423,12 @@ function formatLearningSummary(metrics) {
|
|
|
8403
8423
|
|
|
8404
8424
|
// src/services/skill-reviser.ts
|
|
8405
8425
|
init_logger();
|
|
8406
|
-
import { readFile as
|
|
8426
|
+
import { readFile as readFile5, rename as rename4, writeFile as writeFile5 } from "fs/promises";
|
|
8407
8427
|
|
|
8408
8428
|
// src/services/skill-improver-quota.ts
|
|
8409
8429
|
var import_proper_lockfile = __toESM(require_proper_lockfile(), 1);
|
|
8410
8430
|
import { existsSync as existsSync8 } from "fs";
|
|
8411
|
-
import { mkdir as mkdir4, readFile as
|
|
8431
|
+
import { mkdir as mkdir4, readFile as readFile4, rename as rename3, writeFile as writeFile4 } from "fs/promises";
|
|
8412
8432
|
import * as path13 from "path";
|
|
8413
8433
|
var LOCK_ACQUIRE_TIMEOUT_MS = 1e4;
|
|
8414
8434
|
var LOCK_RETRY_OPTS = {
|
|
@@ -8453,7 +8473,7 @@ async function readState(filePath) {
|
|
|
8453
8473
|
if (!existsSync8(filePath))
|
|
8454
8474
|
return null;
|
|
8455
8475
|
try {
|
|
8456
|
-
const raw = await
|
|
8476
|
+
const raw = await readFile4(filePath, "utf-8");
|
|
8457
8477
|
const parsed = JSON.parse(raw);
|
|
8458
8478
|
if (typeof parsed.date !== "string" || typeof parsed.calls_used !== "number" || typeof parsed.max_calls !== "number" || parsed.window !== "utc" && parsed.window !== "local") {
|
|
8459
8479
|
return null;
|
|
@@ -8466,8 +8486,8 @@ async function readState(filePath) {
|
|
|
8466
8486
|
async function writeState(filePath, state) {
|
|
8467
8487
|
await mkdir4(path13.dirname(filePath), { recursive: true });
|
|
8468
8488
|
const tmp = `${filePath}.tmp-${process.pid}`;
|
|
8469
|
-
await
|
|
8470
|
-
await
|
|
8489
|
+
await writeFile4(tmp, JSON.stringify(state, null, 2), "utf-8");
|
|
8490
|
+
await rename3(tmp, filePath);
|
|
8471
8491
|
}
|
|
8472
8492
|
async function getQuotaState(directory, opts) {
|
|
8473
8493
|
const filePath = resolveQuotaPath(directory, opts.scope);
|
|
@@ -8544,7 +8564,7 @@ var MAX_REVISION_CALLS_PER_PHASE = 3;
|
|
|
8544
8564
|
var DEFAULT_MAX_CALLS = 10;
|
|
8545
8565
|
async function getSkillVersion(skillPath) {
|
|
8546
8566
|
try {
|
|
8547
|
-
const content = await
|
|
8567
|
+
const content = await readFile5(skillPath, "utf-8");
|
|
8548
8568
|
const match = content.match(/^version:\s*(\d+)\s*$/m);
|
|
8549
8569
|
return match ? parseInt(match[1], 10) : 1;
|
|
8550
8570
|
} catch {
|
|
@@ -8681,8 +8701,8 @@ async function reviseSkill(params) {
|
|
|
8681
8701
|
};
|
|
8682
8702
|
}
|
|
8683
8703
|
const tmpPath = `${params.skillPath}.tmp-${process.pid}-${Date.now()}`;
|
|
8684
|
-
await
|
|
8685
|
-
await
|
|
8704
|
+
await writeFile5(tmpPath, revised, "utf-8");
|
|
8705
|
+
await rename4(tmpPath, params.skillPath);
|
|
8686
8706
|
const newVersion = params.currentVersion + 1;
|
|
8687
8707
|
const entry = {
|
|
8688
8708
|
version: newVersion,
|
|
@@ -8758,9 +8778,9 @@ async function reviseSkill(params) {
|
|
|
8758
8778
|
};
|
|
8759
8779
|
}
|
|
8760
8780
|
const tmpPath = `${params.skillPath}.tmp-${process.pid}-${Date.now()}`;
|
|
8761
|
-
await
|
|
8781
|
+
await writeFile5(tmpPath, `${finalOutput}
|
|
8762
8782
|
`, "utf-8");
|
|
8763
|
-
await
|
|
8783
|
+
await rename4(tmpPath, params.skillPath);
|
|
8764
8784
|
const newVersion = expectedVersion;
|
|
8765
8785
|
const entry = {
|
|
8766
8786
|
version: newVersion,
|
|
@@ -8814,7 +8834,7 @@ init_logger();
|
|
|
8814
8834
|
|
|
8815
8835
|
// src/hooks/skill-usage-log.ts
|
|
8816
8836
|
import * as crypto2 from "crypto";
|
|
8817
|
-
import * as
|
|
8837
|
+
import * as fs4 from "fs";
|
|
8818
8838
|
import * as path14 from "path";
|
|
8819
8839
|
function resolveLogPath(directory) {
|
|
8820
8840
|
return validateSwarmPath(directory, "skill-usage.jsonl");
|
|
@@ -8824,16 +8844,16 @@ function normalizeComplianceVerdict(verdict) {
|
|
|
8824
8844
|
}
|
|
8825
8845
|
var _internals10 = {
|
|
8826
8846
|
generateId: () => crypto2.randomUUID(),
|
|
8827
|
-
appendFileSync:
|
|
8828
|
-
readFileSync:
|
|
8829
|
-
writeFileSync:
|
|
8830
|
-
renameSync:
|
|
8831
|
-
mkdirSync:
|
|
8832
|
-
existsSync:
|
|
8833
|
-
statSync:
|
|
8834
|
-
openSync:
|
|
8835
|
-
readSync:
|
|
8836
|
-
closeSync:
|
|
8847
|
+
appendFileSync: fs4.appendFileSync.bind(fs4),
|
|
8848
|
+
readFileSync: fs4.readFileSync.bind(fs4),
|
|
8849
|
+
writeFileSync: fs4.writeFileSync.bind(fs4),
|
|
8850
|
+
renameSync: fs4.renameSync.bind(fs4),
|
|
8851
|
+
mkdirSync: fs4.mkdirSync.bind(fs4),
|
|
8852
|
+
existsSync: fs4.existsSync.bind(fs4),
|
|
8853
|
+
statSync: fs4.statSync.bind(fs4),
|
|
8854
|
+
openSync: fs4.openSync.bind(fs4),
|
|
8855
|
+
readSync: fs4.readSync.bind(fs4),
|
|
8856
|
+
closeSync: fs4.closeSync.bind(fs4),
|
|
8837
8857
|
pruneSkillUsageLog,
|
|
8838
8858
|
resolveSourceKnowledgeIds,
|
|
8839
8859
|
applySkillUsageFeedback,
|
|
@@ -9340,7 +9360,7 @@ var _internals11 = {
|
|
|
9340
9360
|
retireOrMarkStale,
|
|
9341
9361
|
retireSkill,
|
|
9342
9362
|
getArchivedKnowledgeIds,
|
|
9343
|
-
readFileAsync: (filePath, encoding) => import("fs/promises").then((
|
|
9363
|
+
readFileAsync: (filePath, encoding) => import("fs/promises").then((fs6) => fs6.readFile(filePath, encoding)),
|
|
9344
9364
|
readKnowledge,
|
|
9345
9365
|
reviseSkill,
|
|
9346
9366
|
getSkillVersion,
|
|
@@ -9393,13 +9413,25 @@ async function autoRetireSkills(directory, _curatorKnowledgePath, excludeSlugs)
|
|
|
9393
9413
|
warn(`[curator] ${observations[observations.length - 1]}`);
|
|
9394
9414
|
continue;
|
|
9395
9415
|
}
|
|
9396
|
-
|
|
9397
|
-
if (
|
|
9398
|
-
|
|
9399
|
-
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
|
|
9416
|
+
let archivedSourceMatched = false;
|
|
9417
|
+
if (allArchivedIds.size > 0) {
|
|
9418
|
+
try {
|
|
9419
|
+
const content = await _internals11.readFileAsync(active.path, "utf-8");
|
|
9420
|
+
const sourceIds = _internals11.parseDraftFrontmatter(content)?.sourceKnowledgeIds ?? [];
|
|
9421
|
+
archivedSourceMatched = sourceIds.some((id) => allArchivedIds.has(id));
|
|
9422
|
+
} catch {
|
|
9423
|
+
archivedSourceMatched = false;
|
|
9424
|
+
}
|
|
9425
|
+
}
|
|
9426
|
+
if (archivedSourceMatched) {
|
|
9427
|
+
const result = await _internals11.retireOrMarkStale(directory, path15.dirname(active.path), allArchivedIds);
|
|
9428
|
+
if (result.action === "retire") {
|
|
9429
|
+
observations.push(`Skill '${active.slug}' auto-retired: all source knowledge entries archived`);
|
|
9430
|
+
warn(`[curator] ${observations[observations.length - 1]}`);
|
|
9431
|
+
} else if (result.action === "stale") {
|
|
9432
|
+
observations.push(`Skill '${active.slug}' marked stale: some source knowledge entries archived`);
|
|
9433
|
+
warn(`[curator] ${observations[observations.length - 1]}`);
|
|
9434
|
+
}
|
|
9403
9435
|
}
|
|
9404
9436
|
}
|
|
9405
9437
|
} catch (autoRetireErr) {
|
|
@@ -9424,6 +9456,29 @@ function parseKnowledgeRecommendationsWithDiagnostics(llmOutput) {
|
|
|
9424
9456
|
continue;
|
|
9425
9457
|
const match = trimmed.match(/^-\s+entry\s+(\S+)\s+\(([^)]+)\):\s+(.+)$/i);
|
|
9426
9458
|
if (!match) {
|
|
9459
|
+
const newCandidate = trimmed.match(/^-\s+new candidate:\s+(.+)$/i);
|
|
9460
|
+
if (newCandidate) {
|
|
9461
|
+
const text2 = newCandidate[1].trim().replace(/\s+\([^)]+\)$/, "");
|
|
9462
|
+
recommendations.push({
|
|
9463
|
+
action: "promote",
|
|
9464
|
+
entry_id: undefined,
|
|
9465
|
+
lesson: text2,
|
|
9466
|
+
reason: text2
|
|
9467
|
+
});
|
|
9468
|
+
continue;
|
|
9469
|
+
}
|
|
9470
|
+
const staleEntry = trimmed.match(/^-\s+entry\s+(\S+)\s+appears stale:\s+(.+)$/i);
|
|
9471
|
+
if (staleEntry) {
|
|
9472
|
+
const uuid2 = staleEntry[1];
|
|
9473
|
+
const text2 = staleEntry[2].trim().replace(/\s+\([^)]+\)$/, "");
|
|
9474
|
+
recommendations.push({
|
|
9475
|
+
action: "archive",
|
|
9476
|
+
entry_id: UUID_V4.test(uuid2) ? uuid2 : undefined,
|
|
9477
|
+
lesson: text2,
|
|
9478
|
+
reason: text2
|
|
9479
|
+
});
|
|
9480
|
+
continue;
|
|
9481
|
+
}
|
|
9427
9482
|
diagnostics.push({
|
|
9428
9483
|
section: "OBSERVATIONS",
|
|
9429
9484
|
line: trimmed,
|
|
@@ -9567,16 +9622,16 @@ function arrayOfStrings(v) {
|
|
|
9567
9622
|
function readLatestPostMortemDigest(directory) {
|
|
9568
9623
|
try {
|
|
9569
9624
|
const swarmDir = path15.join(directory, ".swarm");
|
|
9570
|
-
if (!
|
|
9625
|
+
if (!fs5.existsSync(swarmDir))
|
|
9571
9626
|
return null;
|
|
9572
|
-
const candidates =
|
|
9627
|
+
const candidates = fs5.readdirSync(swarmDir).filter((name) => /^post-mortem-[^/\\]+\.md$/.test(name)).map((name) => {
|
|
9573
9628
|
const filePath = path15.join(swarmDir, name);
|
|
9574
|
-
return { name, filePath, mtimeMs:
|
|
9629
|
+
return { name, filePath, mtimeMs: fs5.statSync(filePath).mtimeMs };
|
|
9575
9630
|
}).sort((a, b) => b.mtimeMs - a.mtimeMs);
|
|
9576
9631
|
const latest = candidates[0];
|
|
9577
9632
|
if (!latest)
|
|
9578
9633
|
return null;
|
|
9579
|
-
const content =
|
|
9634
|
+
const content = fs5.readFileSync(latest.filePath, "utf-8");
|
|
9580
9635
|
const summary = content.match(/SUMMARY:\s*\n([\s\S]*?)(?:\n[A-Z_]+:|\n##|$)/);
|
|
9581
9636
|
const body = (summary?.[1]?.trim() || content.slice(0, 1500)).slice(0, 1500);
|
|
9582
9637
|
return `${latest.name}
|
|
@@ -9613,7 +9668,7 @@ async function readCuratorSummary(directory) {
|
|
|
9613
9668
|
}
|
|
9614
9669
|
async function writeCuratorSummary(directory, summary) {
|
|
9615
9670
|
const resolvedPath = validateSwarmPath(directory, "curator-summary.json");
|
|
9616
|
-
|
|
9671
|
+
fs5.mkdirSync(path15.dirname(resolvedPath), { recursive: true });
|
|
9617
9672
|
await bunWrite(resolvedPath, JSON.stringify(summary, null, 2));
|
|
9618
9673
|
}
|
|
9619
9674
|
function normalizeAgentName(name) {
|
|
@@ -10054,7 +10109,7 @@ async function runCuratorPhase(directory, phase, agentsDispatched, config, knowl
|
|
|
10054
10109
|
if (knowledgeApplicationFindings.length > 0) {
|
|
10055
10110
|
try {
|
|
10056
10111
|
const evidenceDir = path15.join(directory, ".swarm", "evidence", String(phase));
|
|
10057
|
-
|
|
10112
|
+
fs5.mkdirSync(evidenceDir, { recursive: true });
|
|
10058
10113
|
const findingsPath = path15.join(evidenceDir, "curator-findings.json");
|
|
10059
10114
|
await bunWrite(findingsPath, JSON.stringify({ findings: knowledgeApplicationFindings }, null, 2));
|
|
10060
10115
|
} catch (err) {
|
|
@@ -10357,7 +10412,7 @@ async function applyCuratorKnowledgeUpdates(directory, recommendations, knowledg
|
|
|
10357
10412
|
}
|
|
10358
10413
|
const now = new Date().toISOString();
|
|
10359
10414
|
const newEntry = {
|
|
10360
|
-
id:
|
|
10415
|
+
id: randomUUID5(),
|
|
10361
10416
|
tier: "swarm",
|
|
10362
10417
|
lesson,
|
|
10363
10418
|
category: rec.category ?? "other",
|
|
@@ -10674,18 +10729,18 @@ async function promoteFromSwarm(directory, lessonId) {
|
|
|
10674
10729
|
// src/hooks/knowledge-curator.ts
|
|
10675
10730
|
import { createHash as createHash4 } from "crypto";
|
|
10676
10731
|
import { existsSync as existsSync13 } from "fs";
|
|
10677
|
-
import { appendFile as appendFile2, mkdir as mkdir6, readFile as
|
|
10732
|
+
import { appendFile as appendFile2, mkdir as mkdir6, readFile as readFile8, writeFile as writeFile8 } from "fs/promises";
|
|
10678
10733
|
import * as path21 from "path";
|
|
10679
10734
|
|
|
10680
10735
|
// src/services/synonym-map.ts
|
|
10681
10736
|
var import_proper_lockfile2 = __toESM(require_proper_lockfile(), 1);
|
|
10682
10737
|
import {
|
|
10683
10738
|
mkdir as mkdir5,
|
|
10684
|
-
readFile as
|
|
10685
|
-
rename as
|
|
10739
|
+
readFile as readFile6,
|
|
10740
|
+
rename as rename5,
|
|
10686
10741
|
stat as stat3,
|
|
10687
10742
|
unlink,
|
|
10688
|
-
writeFile as
|
|
10743
|
+
writeFile as writeFile6
|
|
10689
10744
|
} from "fs/promises";
|
|
10690
10745
|
import * as path17 from "path";
|
|
10691
10746
|
var SYNONYM_MAP_FILENAME = "synonym-map.json";
|
|
@@ -10835,7 +10890,7 @@ async function readSynonymMap(directory, maxPairs = DEFAULT_MAX_PAIRS) {
|
|
|
10835
10890
|
const st = await stat3(filePath);
|
|
10836
10891
|
if (st.size > ceiling)
|
|
10837
10892
|
return emptySynonymMap();
|
|
10838
|
-
const raw = await
|
|
10893
|
+
const raw = await readFile6(filePath, "utf-8");
|
|
10839
10894
|
return coerceSynonymMap(JSON.parse(raw), maxPairs);
|
|
10840
10895
|
} catch {
|
|
10841
10896
|
return emptySynonymMap();
|
|
@@ -10845,8 +10900,8 @@ async function writeSynonymMapAtomic(filePath, map) {
|
|
|
10845
10900
|
await mkdir5(path17.dirname(filePath), { recursive: true });
|
|
10846
10901
|
const tmp = `${filePath}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`;
|
|
10847
10902
|
try {
|
|
10848
|
-
await
|
|
10849
|
-
await
|
|
10903
|
+
await writeFile6(tmp, JSON.stringify(map, null, 2), "utf-8");
|
|
10904
|
+
await rename5(tmp, filePath);
|
|
10850
10905
|
} finally {
|
|
10851
10906
|
try {
|
|
10852
10907
|
await unlink(tmp);
|
|
@@ -10919,17 +10974,17 @@ function reinforceSwarmKnowledgeEntry(entry, confirmation) {
|
|
|
10919
10974
|
|
|
10920
10975
|
// src/hooks/micro-reflector.ts
|
|
10921
10976
|
import { existsSync as existsSync12 } from "fs";
|
|
10922
|
-
import { readFile as
|
|
10977
|
+
import { readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
|
|
10923
10978
|
import * as path20 from "path";
|
|
10924
10979
|
init_logger();
|
|
10925
10980
|
|
|
10926
10981
|
// src/hooks/skill-propagation-gate.ts
|
|
10927
|
-
import * as
|
|
10982
|
+
import * as fs7 from "fs";
|
|
10928
10983
|
import * as path19 from "path";
|
|
10929
10984
|
init_logger();
|
|
10930
10985
|
|
|
10931
10986
|
// src/hooks/skill-scoring.ts
|
|
10932
|
-
import * as
|
|
10987
|
+
import * as fs6 from "fs";
|
|
10933
10988
|
import * as path18 from "path";
|
|
10934
10989
|
var FREQUENCY_CAP = 10;
|
|
10935
10990
|
var FREQUENCY_WEIGHT = 0.3;
|
|
@@ -10997,6 +11052,9 @@ function normalizeTriggerList(values) {
|
|
|
10997
11052
|
}
|
|
10998
11053
|
return out;
|
|
10999
11054
|
}
|
|
11055
|
+
function finiteRankValue(value) {
|
|
11056
|
+
return Number.isFinite(value) ? value : 0;
|
|
11057
|
+
}
|
|
11000
11058
|
function parseInlineStringList(rawValue) {
|
|
11001
11059
|
const trimmed = rawValue.trim();
|
|
11002
11060
|
if (!trimmed)
|
|
@@ -11103,13 +11161,13 @@ function parseSkillFrontmatter(content, skillPath) {
|
|
|
11103
11161
|
return meta;
|
|
11104
11162
|
}
|
|
11105
11163
|
function readFilePrefix(filePath) {
|
|
11106
|
-
const fd =
|
|
11164
|
+
const fd = fs6.openSync(filePath, "r");
|
|
11107
11165
|
try {
|
|
11108
11166
|
const buffer = Buffer.alloc(SKILL_FRONTMATTER_READ_BYTES);
|
|
11109
|
-
const bytesRead =
|
|
11167
|
+
const bytesRead = fs6.readSync(fd, buffer, 0, SKILL_FRONTMATTER_READ_BYTES, 0);
|
|
11110
11168
|
return buffer.toString("utf-8", 0, bytesRead);
|
|
11111
11169
|
} finally {
|
|
11112
|
-
|
|
11170
|
+
fs6.closeSync(fd);
|
|
11113
11171
|
}
|
|
11114
11172
|
}
|
|
11115
11173
|
function readSkillMetadata(skillPath, directory) {
|
|
@@ -11215,15 +11273,19 @@ function rankSkillsForContext(skills, taskContext, directory) {
|
|
|
11215
11273
|
const complianceRate = entriesWithVerdict.length > 0 ? compliantCount / entriesWithVerdict.length : 0;
|
|
11216
11274
|
results.push({
|
|
11217
11275
|
skillPath,
|
|
11218
|
-
score,
|
|
11276
|
+
score: finiteRankValue(score),
|
|
11219
11277
|
usageCount: skillEntries.length,
|
|
11220
11278
|
complianceRate
|
|
11221
11279
|
});
|
|
11222
11280
|
}
|
|
11223
11281
|
results.sort((a, b) => {
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11282
|
+
const scoreDelta = finiteRankValue(b.score) - finiteRankValue(a.score);
|
|
11283
|
+
if (scoreDelta !== 0)
|
|
11284
|
+
return scoreDelta;
|
|
11285
|
+
const usageDelta = b.usageCount - a.usageCount;
|
|
11286
|
+
if (usageDelta !== 0)
|
|
11287
|
+
return usageDelta;
|
|
11288
|
+
return a.skillPath.localeCompare(b.skillPath);
|
|
11227
11289
|
});
|
|
11228
11290
|
return results;
|
|
11229
11291
|
}
|
|
@@ -11258,7 +11320,7 @@ function formatSkillIndexWithContext(skills, directory) {
|
|
|
11258
11320
|
const usageLogPath = path18.join(directory, ".swarm", "skill-usage.jsonl");
|
|
11259
11321
|
let hasHistory = false;
|
|
11260
11322
|
try {
|
|
11261
|
-
const stat4 =
|
|
11323
|
+
const stat4 = fs6.statSync(usageLogPath);
|
|
11262
11324
|
hasHistory = stat4.size > 0;
|
|
11263
11325
|
} catch {}
|
|
11264
11326
|
if (!hasHistory) {
|
|
@@ -11421,13 +11483,13 @@ var SKILL_SEARCH_ROOTS = [
|
|
|
11421
11483
|
];
|
|
11422
11484
|
var MAX_SCORING_SESSION_ENTRIES = 500;
|
|
11423
11485
|
var _internals13 = {
|
|
11424
|
-
readdirSync:
|
|
11425
|
-
existsSync:
|
|
11426
|
-
statSync:
|
|
11427
|
-
mkdirSync:
|
|
11428
|
-
appendFileSync:
|
|
11429
|
-
readFileSync:
|
|
11430
|
-
writeFileSync:
|
|
11486
|
+
readdirSync: fs7.readdirSync.bind(fs7),
|
|
11487
|
+
existsSync: fs7.existsSync.bind(fs7),
|
|
11488
|
+
statSync: fs7.statSync.bind(fs7),
|
|
11489
|
+
mkdirSync: fs7.mkdirSync.bind(fs7),
|
|
11490
|
+
appendFileSync: fs7.appendFileSync.bind(fs7),
|
|
11491
|
+
readFileSync: fs7.readFileSync.bind(fs7),
|
|
11492
|
+
writeFileSync: fs7.writeFileSync.bind(fs7),
|
|
11431
11493
|
skillPropagationGateBefore: null,
|
|
11432
11494
|
skillPropagationTransformScan: null,
|
|
11433
11495
|
SKILL_CAPABLE_AGENTS,
|
|
@@ -11948,7 +12010,7 @@ async function readTaskTrajectory(directory, taskId) {
|
|
|
11948
12010
|
const filePath = validateSwarmPath(directory, rel);
|
|
11949
12011
|
if (!existsSync12(filePath))
|
|
11950
12012
|
return [];
|
|
11951
|
-
const content = await
|
|
12013
|
+
const content = await readFile7(filePath, "utf-8");
|
|
11952
12014
|
const out = [];
|
|
11953
12015
|
for (const line of content.split(`
|
|
11954
12016
|
`)) {
|
|
@@ -12418,11 +12480,11 @@ async function consumeInsightCandidates(directory, batchLimit = MESO_INSIGHT_BAT
|
|
|
12418
12480
|
if (!existsSync13(filePath))
|
|
12419
12481
|
return [];
|
|
12420
12482
|
const consumed = [];
|
|
12421
|
-
await transactFile(filePath, async (p) => readInsightJsonl(await
|
|
12483
|
+
await transactFile(filePath, async (p) => readInsightJsonl(await readFile8(p, "utf-8").catch(() => "")), async (p, data) => {
|
|
12422
12484
|
const body = data.length === 0 ? "" : `${data.map((c) => JSON.stringify(c)).join(`
|
|
12423
12485
|
`)}
|
|
12424
12486
|
`;
|
|
12425
|
-
await
|
|
12487
|
+
await writeFile8(p, body, "utf-8");
|
|
12426
12488
|
}, (all) => {
|
|
12427
12489
|
if (all.length === 0)
|
|
12428
12490
|
return null;
|
|
@@ -12902,7 +12964,7 @@ var _internals15 = {
|
|
|
12902
12964
|
|
|
12903
12965
|
// src/scope/scope-persistence.ts
|
|
12904
12966
|
var import_proper_lockfile3 = __toESM(require_proper_lockfile(), 1);
|
|
12905
|
-
import * as
|
|
12967
|
+
import * as fs8 from "fs";
|
|
12906
12968
|
import * as path22 from "path";
|
|
12907
12969
|
var DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
|
|
12908
12970
|
var LOCK_STALE_MS = 30 * 1000;
|
|
@@ -12938,12 +13000,12 @@ function getScopesDir(directory) {
|
|
|
12938
13000
|
}
|
|
12939
13001
|
function clearAllScopes(directory) {
|
|
12940
13002
|
try {
|
|
12941
|
-
|
|
13003
|
+
fs8.rmSync(getScopesDir(directory), { recursive: true, force: true });
|
|
12942
13004
|
} catch {}
|
|
12943
13005
|
}
|
|
12944
13006
|
|
|
12945
13007
|
// src/services/session-reflection.ts
|
|
12946
|
-
import { promises as
|
|
13008
|
+
import { promises as fs9 } from "fs";
|
|
12947
13009
|
import * as path23 from "path";
|
|
12948
13010
|
|
|
12949
13011
|
// src/hooks/abort-utils.ts
|
|
@@ -13106,12 +13168,12 @@ async function gatherRetroLessonsAndTaxonomy(directory) {
|
|
|
13106
13168
|
const taxonomy = {};
|
|
13107
13169
|
try {
|
|
13108
13170
|
const evidenceDir = path23.join(directory, ".swarm", "evidence");
|
|
13109
|
-
const entries = await
|
|
13171
|
+
const entries = await fs9.readdir(evidenceDir);
|
|
13110
13172
|
const retroDirs = entries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
13111
13173
|
for (const retroDir of retroDirs) {
|
|
13112
13174
|
const evidencePath = path23.join(evidenceDir, retroDir, "evidence.json");
|
|
13113
13175
|
try {
|
|
13114
|
-
const content = await
|
|
13176
|
+
const content = await fs9.readFile(evidencePath, "utf-8");
|
|
13115
13177
|
const parsed = JSON.parse(content);
|
|
13116
13178
|
const bundleEntries = parsed.entries ?? [parsed];
|
|
13117
13179
|
for (const entry of bundleEntries) {
|
|
@@ -13139,13 +13201,13 @@ async function gatherGateFailures(directory) {
|
|
|
13139
13201
|
const failures = new Map;
|
|
13140
13202
|
try {
|
|
13141
13203
|
const evidenceDir = path23.join(directory, ".swarm", "evidence");
|
|
13142
|
-
const entries = await
|
|
13204
|
+
const entries = await fs9.readdir(evidenceDir);
|
|
13143
13205
|
for (const entry of entries) {
|
|
13144
13206
|
if (entry.startsWith("retro-"))
|
|
13145
13207
|
continue;
|
|
13146
13208
|
const evidencePath = path23.join(evidenceDir, entry, "evidence.json");
|
|
13147
13209
|
try {
|
|
13148
|
-
const content = await
|
|
13210
|
+
const content = await fs9.readFile(evidencePath, "utf-8");
|
|
13149
13211
|
const parsed = JSON.parse(content);
|
|
13150
13212
|
const bundleEntries = parsed.entries ?? [parsed];
|
|
13151
13213
|
for (const e of bundleEntries) {
|
|
@@ -13337,18 +13399,18 @@ async function writeSessionReflection(directory, result) {
|
|
|
13337
13399
|
lines.push(result.architectReport);
|
|
13338
13400
|
const content = lines.join(`
|
|
13339
13401
|
`);
|
|
13340
|
-
await
|
|
13402
|
+
await fs9.writeFile(reflectionPath, content, "utf-8");
|
|
13341
13403
|
return reflectionPath;
|
|
13342
13404
|
}
|
|
13343
13405
|
|
|
13344
13406
|
// src/services/skill-improver.ts
|
|
13345
13407
|
import { existsSync as existsSync15 } from "fs";
|
|
13346
|
-
import { mkdir as mkdir8, readFile as
|
|
13408
|
+
import { mkdir as mkdir8, readFile as readFile9, rename as rename6, writeFile as writeFile10 } from "fs/promises";
|
|
13347
13409
|
import * as path25 from "path";
|
|
13348
13410
|
init_logger();
|
|
13349
13411
|
|
|
13350
13412
|
// src/services/trajectory-cluster.ts
|
|
13351
|
-
import { mkdir as mkdir7, writeFile as
|
|
13413
|
+
import { mkdir as mkdir7, writeFile as writeFile9 } from "fs/promises";
|
|
13352
13414
|
import * as path24 from "path";
|
|
13353
13415
|
init_logger();
|
|
13354
13416
|
var MACRO_TRAJECTORY_WINDOW = 200;
|
|
@@ -13486,7 +13548,7 @@ async function writeMotifProposals(directory, opts = {}) {
|
|
|
13486
13548
|
for (const motif of motifs.slice(0, max)) {
|
|
13487
13549
|
const slug = `motif-${slugify(motif.signature)}`;
|
|
13488
13550
|
const filePath = path24.join(proposalsDir, `${slug}.md`);
|
|
13489
|
-
await
|
|
13551
|
+
await writeFile9(filePath, buildMotifProposal(motif), "utf-8");
|
|
13490
13552
|
result.proposalsWritten.push(filePath);
|
|
13491
13553
|
}
|
|
13492
13554
|
return result;
|
|
@@ -13631,7 +13693,7 @@ async function writeSuccessMotifProposals(directory, opts = {}) {
|
|
|
13631
13693
|
for (const motif of motifs.slice(0, max)) {
|
|
13632
13694
|
const slug = workflowSlug(motif.signature);
|
|
13633
13695
|
const filePath = path24.join(proposalsDir, `${slug}.md`);
|
|
13634
|
-
await
|
|
13696
|
+
await writeFile9(filePath, buildWorkflowProposal(motif), "utf-8");
|
|
13635
13697
|
result.proposalsWritten.push(filePath);
|
|
13636
13698
|
}
|
|
13637
13699
|
return result;
|
|
@@ -13755,8 +13817,8 @@ function timestampSlug(d) {
|
|
|
13755
13817
|
async function atomicWrite(p, content) {
|
|
13756
13818
|
await mkdir8(path25.dirname(p), { recursive: true });
|
|
13757
13819
|
const tmp = `${p}.tmp-${process.pid}-${Date.now()}`;
|
|
13758
|
-
await
|
|
13759
|
-
await
|
|
13820
|
+
await writeFile10(tmp, content, "utf-8");
|
|
13821
|
+
await rename6(tmp, p);
|
|
13760
13822
|
}
|
|
13761
13823
|
async function gatherInventory(directory) {
|
|
13762
13824
|
const swarm = await readKnowledge(resolveSwarmKnowledgePath(directory));
|
|
@@ -13770,7 +13832,7 @@ async function gatherInventory(directory) {
|
|
|
13770
13832
|
for (const skill of skills.active) {
|
|
13771
13833
|
let content;
|
|
13772
13834
|
try {
|
|
13773
|
-
content = await
|
|
13835
|
+
content = await readFile9(skill.path, "utf-8");
|
|
13774
13836
|
} catch {
|
|
13775
13837
|
continue;
|
|
13776
13838
|
}
|
|
@@ -13946,7 +14008,7 @@ async function reconcileStaleActiveSkills(directory, options = {}) {
|
|
|
13946
14008
|
for (const skill of skills.active) {
|
|
13947
14009
|
let content;
|
|
13948
14010
|
try {
|
|
13949
|
-
content = await
|
|
14011
|
+
content = await readFile9(skill.path, "utf-8");
|
|
13950
14012
|
} catch {
|
|
13951
14013
|
continue;
|
|
13952
14014
|
}
|
|
@@ -14268,6 +14330,8 @@ function readEarliestSessionStart(directory) {
|
|
|
14268
14330
|
}
|
|
14269
14331
|
|
|
14270
14332
|
// src/tools/write-retro.ts
|
|
14333
|
+
import { existsSync as existsSync17 } from "fs";
|
|
14334
|
+
import path27 from "path";
|
|
14271
14335
|
async function executeWriteRetro(args, directory) {
|
|
14272
14336
|
if (/^(CON|PRN|AUX|NUL|COM[0-9]|LPT[0-9])(:|$)/i.test(directory)) {
|
|
14273
14337
|
return JSON.stringify({
|
|
@@ -14275,6 +14339,12 @@ async function executeWriteRetro(args, directory) {
|
|
|
14275
14339
|
message: "Invalid directory: reserved device name"
|
|
14276
14340
|
}, null, 2);
|
|
14277
14341
|
}
|
|
14342
|
+
if (!existsSync17(path27.join(directory, ".swarm"))) {
|
|
14343
|
+
return JSON.stringify({
|
|
14344
|
+
success: false,
|
|
14345
|
+
message: `Cannot write evidence in "${directory}" \u2014 no .swarm/ folder was found. Run write_retro from an initialized project root.`
|
|
14346
|
+
}, null, 2);
|
|
14347
|
+
}
|
|
14278
14348
|
const phase = args.phase;
|
|
14279
14349
|
if (!Number.isInteger(phase) || phase < 1) {
|
|
14280
14350
|
return JSON.stringify({
|
|
@@ -14682,20 +14752,20 @@ function countSessionKnowledgeEntries(entries, sessionStart, fallbackCount) {
|
|
|
14682
14752
|
async function copyDirRecursiveWithFailures(src, dest) {
|
|
14683
14753
|
let count = 0;
|
|
14684
14754
|
const failures = [];
|
|
14685
|
-
const entries = await
|
|
14686
|
-
await
|
|
14755
|
+
const entries = await fs10.readdir(src);
|
|
14756
|
+
await fs10.mkdir(dest, { recursive: true });
|
|
14687
14757
|
for (const entry of entries) {
|
|
14688
|
-
const srcEntry =
|
|
14689
|
-
const destEntry =
|
|
14758
|
+
const srcEntry = path28.join(src, entry);
|
|
14759
|
+
const destEntry = path28.join(dest, entry);
|
|
14690
14760
|
try {
|
|
14691
|
-
const stat4 = await
|
|
14761
|
+
const stat4 = await fs10.stat(srcEntry);
|
|
14692
14762
|
if (stat4.isDirectory()) {
|
|
14693
14763
|
const subResult = await copyDirRecursiveWithFailures(srcEntry, destEntry);
|
|
14694
14764
|
count += subResult.copied;
|
|
14695
14765
|
failures.push(...subResult.failures);
|
|
14696
14766
|
} else {
|
|
14697
14767
|
try {
|
|
14698
|
-
await
|
|
14768
|
+
await fs10.copyFile(srcEntry, destEntry);
|
|
14699
14769
|
count++;
|
|
14700
14770
|
} catch (err) {
|
|
14701
14771
|
const errno = err?.code;
|
|
@@ -14871,20 +14941,20 @@ async function runFinalizeStage(ctx) {
|
|
|
14871
14941
|
ctx.warnings.push(`Session retrospective write threw: ${retroError instanceof Error ? retroError.message : String(retroError)}`);
|
|
14872
14942
|
}
|
|
14873
14943
|
}
|
|
14874
|
-
const lessonsFilePath =
|
|
14944
|
+
const lessonsFilePath = path28.join(ctx.swarmDir, "close-lessons.md");
|
|
14875
14945
|
try {
|
|
14876
|
-
const lessonsText = await
|
|
14946
|
+
const lessonsText = await fs10.readFile(lessonsFilePath, "utf-8");
|
|
14877
14947
|
ctx.explicitLessons = lessonsText.split(`
|
|
14878
14948
|
`).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
14879
14949
|
} catch {}
|
|
14880
14950
|
try {
|
|
14881
|
-
const evidenceDir =
|
|
14882
|
-
const evidenceEntries = await
|
|
14951
|
+
const evidenceDir = path28.join(ctx.swarmDir, "evidence");
|
|
14952
|
+
const evidenceEntries = await fs10.readdir(evidenceDir);
|
|
14883
14953
|
const retroDirs = evidenceEntries.filter((e) => e.startsWith("retro-")).sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
14884
14954
|
for (const retroDir of retroDirs) {
|
|
14885
|
-
const evidencePath =
|
|
14955
|
+
const evidencePath = path28.join(evidenceDir, retroDir, "evidence.json");
|
|
14886
14956
|
try {
|
|
14887
|
-
const content = await
|
|
14957
|
+
const content = await fs10.readFile(evidencePath, "utf-8");
|
|
14888
14958
|
const parsed = JSON.parse(content);
|
|
14889
14959
|
const entries = parsed.entries ?? [parsed];
|
|
14890
14960
|
for (const entry of entries) {
|
|
@@ -14928,7 +14998,7 @@ async function runFinalizeStage(ctx) {
|
|
|
14928
14998
|
console.warn("[close-command] curateAndStoreSwarm error:", error2);
|
|
14929
14999
|
}
|
|
14930
15000
|
if (ctx.curationSucceeded && ctx.allLessons.length > 0) {
|
|
14931
|
-
await
|
|
15001
|
+
await fs10.unlink(lessonsFilePath).catch(() => {});
|
|
14932
15002
|
}
|
|
14933
15003
|
if (ctx.curationSucceeded) {
|
|
14934
15004
|
if (ctx.config.hive_enabled === false) {} else {
|
|
@@ -15066,7 +15136,7 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
15066
15136
|
let checkpointVerified = false;
|
|
15067
15137
|
try {
|
|
15068
15138
|
const result = spawnSync2("sqlite3", [srcPath, "PRAGMA wal_checkpoint(TRUNCATE);"], {
|
|
15069
|
-
cwd:
|
|
15139
|
+
cwd: path28.dirname(srcPath),
|
|
15070
15140
|
encoding: "utf-8",
|
|
15071
15141
|
stdio: ["ignore", "pipe", "pipe"],
|
|
15072
15142
|
timeout: 1e4,
|
|
@@ -15077,7 +15147,7 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
15077
15147
|
const code = result.error.code;
|
|
15078
15148
|
if (code === "ENOENT") {
|
|
15079
15149
|
try {
|
|
15080
|
-
await
|
|
15150
|
+
await fs10.copyFile(srcPath, destPath);
|
|
15081
15151
|
return {
|
|
15082
15152
|
success: true,
|
|
15083
15153
|
reason: "copied without WAL checkpoint (sqlite3 CLI unavailable)"
|
|
@@ -15116,7 +15186,7 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
15116
15186
|
};
|
|
15117
15187
|
}
|
|
15118
15188
|
try {
|
|
15119
|
-
await
|
|
15189
|
+
await fs10.copyFile(srcPath, destPath);
|
|
15120
15190
|
if (checkpointVerified) {
|
|
15121
15191
|
return { success: true };
|
|
15122
15192
|
}
|
|
@@ -15134,9 +15204,9 @@ async function copySqliteSafe(srcPath, destPath) {
|
|
|
15134
15204
|
async function runArchiveStage(ctx) {
|
|
15135
15205
|
ctx.timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
15136
15206
|
ctx.archiveSuffix = Math.random().toString(36).slice(2, 8);
|
|
15137
|
-
ctx.archiveDir =
|
|
15207
|
+
ctx.archiveDir = path28.join(ctx.swarmDir, "archive", `swarm-${ctx.timestamp}-${ctx.archiveSuffix}`);
|
|
15138
15208
|
try {
|
|
15139
|
-
await
|
|
15209
|
+
await fs10.mkdir(ctx.archiveDir, { recursive: true });
|
|
15140
15210
|
const WAL_SIDECAR_FILES = new Set(["swarm.db-shm", "swarm.db-wal"]);
|
|
15141
15211
|
const linkedKnowledgeShared = isLinked(ctx.directory);
|
|
15142
15212
|
if (linkedKnowledgeShared) {
|
|
@@ -15149,8 +15219,8 @@ async function runArchiveStage(ctx) {
|
|
|
15149
15219
|
if (linkedKnowledgeShared && KNOWLEDGE_FAMILY_ARTIFACTS.has(artifact)) {
|
|
15150
15220
|
continue;
|
|
15151
15221
|
}
|
|
15152
|
-
const srcPath =
|
|
15153
|
-
const destPath =
|
|
15222
|
+
const srcPath = path28.join(ctx.swarmDir, artifact);
|
|
15223
|
+
const destPath = path28.join(ctx.archiveDir, artifact);
|
|
15154
15224
|
if (artifact === "swarm.db") {
|
|
15155
15225
|
const result = await copySqliteSafe(srcPath, destPath);
|
|
15156
15226
|
if (result.skipped) {} else if (result.success) {
|
|
@@ -15166,7 +15236,7 @@ async function runArchiveStage(ctx) {
|
|
|
15166
15236
|
}
|
|
15167
15237
|
} else {
|
|
15168
15238
|
try {
|
|
15169
|
-
await
|
|
15239
|
+
await fs10.copyFile(srcPath, destPath);
|
|
15170
15240
|
ctx.archivedFileCount++;
|
|
15171
15241
|
if (ACTIVE_STATE_TO_CLEAN.includes(artifact)) {
|
|
15172
15242
|
ctx.archivedActiveStateFiles.add(artifact);
|
|
@@ -15181,12 +15251,12 @@ async function runArchiveStage(ctx) {
|
|
|
15181
15251
|
}
|
|
15182
15252
|
}
|
|
15183
15253
|
}
|
|
15184
|
-
const dynamicArchiveArtifacts = (await
|
|
15254
|
+
const dynamicArchiveArtifacts = (await fs10.readdir(ctx.swarmDir).catch(() => [])).filter((name) => /^post-mortem-[^/\\]+\.md$/.test(name) || /^drift-report-phase-\d+\.json$/.test(name));
|
|
15185
15255
|
for (const artifact of dynamicArchiveArtifacts) {
|
|
15186
|
-
const srcPath =
|
|
15187
|
-
const destPath =
|
|
15256
|
+
const srcPath = path28.join(ctx.swarmDir, artifact);
|
|
15257
|
+
const destPath = path28.join(ctx.archiveDir, artifact);
|
|
15188
15258
|
try {
|
|
15189
|
-
await
|
|
15259
|
+
await fs10.copyFile(srcPath, destPath);
|
|
15190
15260
|
ctx.archivedFileCount++;
|
|
15191
15261
|
ctx.archivedActiveStateFiles.add(artifact);
|
|
15192
15262
|
} catch (err) {
|
|
@@ -15199,8 +15269,8 @@ async function runArchiveStage(ctx) {
|
|
|
15199
15269
|
}
|
|
15200
15270
|
}
|
|
15201
15271
|
for (const dirName of ACTIVE_STATE_DIRS_TO_CLEAN) {
|
|
15202
|
-
const srcDir =
|
|
15203
|
-
const destDir =
|
|
15272
|
+
const srcDir = path28.join(ctx.swarmDir, dirName);
|
|
15273
|
+
const destDir = path28.join(ctx.archiveDir, dirName);
|
|
15204
15274
|
try {
|
|
15205
15275
|
const result = await copyDirRecursiveWithFailures(srcDir, destDir);
|
|
15206
15276
|
ctx.archivedFileCount += result.copied;
|
|
@@ -15277,9 +15347,9 @@ async function runCleanStage(ctx) {
|
|
|
15277
15347
|
ctx.warnings.push(reason ? `Preserved ${artifact} because it was not successfully archived: ${reason}.` : `Preserved ${artifact} because it was not successfully archived.`);
|
|
15278
15348
|
continue;
|
|
15279
15349
|
}
|
|
15280
|
-
const filePath =
|
|
15350
|
+
const filePath = path28.join(ctx.swarmDir, artifact);
|
|
15281
15351
|
try {
|
|
15282
|
-
await
|
|
15352
|
+
await fs10.unlink(filePath);
|
|
15283
15353
|
cleanedFiles.push(artifact);
|
|
15284
15354
|
} catch (err) {
|
|
15285
15355
|
const errno = err?.code;
|
|
@@ -15297,7 +15367,7 @@ async function runCleanStage(ctx) {
|
|
|
15297
15367
|
continue;
|
|
15298
15368
|
}
|
|
15299
15369
|
try {
|
|
15300
|
-
await
|
|
15370
|
+
await fs10.unlink(path28.join(ctx.swarmDir, artifact));
|
|
15301
15371
|
cleanedFiles.push(artifact);
|
|
15302
15372
|
} catch (err) {
|
|
15303
15373
|
const errno = err?.code;
|
|
@@ -15311,18 +15381,18 @@ async function runCleanStage(ctx) {
|
|
|
15311
15381
|
if (!ctx.archivedActiveStateDirs.has(dirName)) {
|
|
15312
15382
|
continue;
|
|
15313
15383
|
}
|
|
15314
|
-
const dirPath =
|
|
15384
|
+
const dirPath = path28.join(ctx.swarmDir, dirName);
|
|
15315
15385
|
try {
|
|
15316
|
-
await
|
|
15386
|
+
await fs10.rm(dirPath, { recursive: true, force: true });
|
|
15317
15387
|
cleanedFiles.push(`${dirName}/`);
|
|
15318
15388
|
} catch {}
|
|
15319
15389
|
}
|
|
15320
15390
|
try {
|
|
15321
|
-
const swarmFiles = await
|
|
15391
|
+
const swarmFiles = await fs10.readdir(ctx.swarmDir);
|
|
15322
15392
|
const configBackups = swarmFiles.filter((f) => f.startsWith("config-backup-") && f.endsWith(".json"));
|
|
15323
15393
|
for (const backup of configBackups) {
|
|
15324
15394
|
try {
|
|
15325
|
-
await
|
|
15395
|
+
await fs10.unlink(path28.join(ctx.swarmDir, backup));
|
|
15326
15396
|
configBackupsRemoved++;
|
|
15327
15397
|
} catch (err) {
|
|
15328
15398
|
const errno = err?.code;
|
|
@@ -15335,7 +15405,7 @@ async function runCleanStage(ctx) {
|
|
|
15335
15405
|
const ledgerSiblings = swarmFiles.filter((f) => (f.startsWith("plan-ledger.archived-") || f.startsWith("plan-ledger.backup-")) && f.endsWith(".jsonl"));
|
|
15336
15406
|
for (const sibling of ledgerSiblings) {
|
|
15337
15407
|
try {
|
|
15338
|
-
await
|
|
15408
|
+
await fs10.unlink(path28.join(ctx.swarmDir, sibling));
|
|
15339
15409
|
} catch (err) {
|
|
15340
15410
|
const errno = err?.code;
|
|
15341
15411
|
if (errno === "ENOENT") {} else {
|
|
@@ -15353,16 +15423,16 @@ async function runCleanStage(ctx) {
|
|
|
15353
15423
|
}
|
|
15354
15424
|
let swarmPlanFilesRemoved = 0;
|
|
15355
15425
|
const candidates = [
|
|
15356
|
-
|
|
15357
|
-
|
|
15358
|
-
|
|
15359
|
-
|
|
15360
|
-
|
|
15361
|
-
|
|
15426
|
+
path28.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.json"),
|
|
15427
|
+
path28.join(ctx.directory, ".swarm", "plan-export", "SWARM_PLAN.md"),
|
|
15428
|
+
path28.join(ctx.directory, ".swarm", "SWARM_PLAN.json"),
|
|
15429
|
+
path28.join(ctx.directory, ".swarm", "SWARM_PLAN.md"),
|
|
15430
|
+
path28.join(ctx.directory, "SWARM_PLAN.json"),
|
|
15431
|
+
path28.join(ctx.directory, "SWARM_PLAN.md")
|
|
15362
15432
|
];
|
|
15363
15433
|
for (const candidate of candidates) {
|
|
15364
15434
|
try {
|
|
15365
|
-
await
|
|
15435
|
+
await fs10.unlink(candidate);
|
|
15366
15436
|
swarmPlanFilesRemoved++;
|
|
15367
15437
|
} catch (err) {
|
|
15368
15438
|
if (err?.code !== "ENOENT") {
|
|
@@ -15372,11 +15442,11 @@ async function runCleanStage(ctx) {
|
|
|
15372
15442
|
}
|
|
15373
15443
|
let tmpFilesRemoved = 0;
|
|
15374
15444
|
try {
|
|
15375
|
-
const swarmFiles = await
|
|
15445
|
+
const swarmFiles = await fs10.readdir(ctx.swarmDir);
|
|
15376
15446
|
const tmpFiles = swarmFiles.filter((f) => f.startsWith(".tmp."));
|
|
15377
15447
|
for (const tmp of tmpFiles) {
|
|
15378
15448
|
try {
|
|
15379
|
-
await
|
|
15449
|
+
await fs10.unlink(path28.join(ctx.swarmDir, tmp));
|
|
15380
15450
|
tmpFilesRemoved++;
|
|
15381
15451
|
} catch (err) {
|
|
15382
15452
|
const errno = err?.code;
|
|
@@ -15398,7 +15468,7 @@ async function runCleanStage(ctx) {
|
|
|
15398
15468
|
}
|
|
15399
15469
|
for (const terminalFile of TERMINAL_STATE_FILES) {
|
|
15400
15470
|
try {
|
|
15401
|
-
await
|
|
15471
|
+
await fs10.unlink(path28.join(ctx.swarmDir, terminalFile));
|
|
15402
15472
|
if (!cleanedFiles.includes(terminalFile)) {
|
|
15403
15473
|
cleanedFiles.push(terminalFile);
|
|
15404
15474
|
}
|
|
@@ -15411,7 +15481,7 @@ async function runCleanStage(ctx) {
|
|
|
15411
15481
|
}
|
|
15412
15482
|
}
|
|
15413
15483
|
clearAllScopes(ctx.directory);
|
|
15414
|
-
const contextPath =
|
|
15484
|
+
const contextPath = path28.join(ctx.swarmDir, "context.md");
|
|
15415
15485
|
const contextContent = [
|
|
15416
15486
|
"# Context",
|
|
15417
15487
|
"",
|
|
@@ -15423,9 +15493,9 @@ async function runCleanStage(ctx) {
|
|
|
15423
15493
|
""
|
|
15424
15494
|
].join(`
|
|
15425
15495
|
`);
|
|
15426
|
-
const contextTempPath =
|
|
15496
|
+
const contextTempPath = path28.join(path28.dirname(contextPath), `${path28.basename(contextPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
15427
15497
|
try {
|
|
15428
|
-
await
|
|
15498
|
+
await fs10.writeFile(contextTempPath, contextContent, "utf-8");
|
|
15429
15499
|
fsSync.renameSync(contextTempPath, contextPath);
|
|
15430
15500
|
} catch (error2) {
|
|
15431
15501
|
try {
|
|
@@ -15487,7 +15557,7 @@ async function runAlignStage(ctx) {
|
|
|
15487
15557
|
return { gitAlignResult, prunedBranches };
|
|
15488
15558
|
}
|
|
15489
15559
|
async function handleCloseCommand(directory, args, options = {}) {
|
|
15490
|
-
const swarmDir =
|
|
15560
|
+
const swarmDir = path28.join(directory, ".swarm");
|
|
15491
15561
|
try {
|
|
15492
15562
|
const stat4 = fsSync.lstatSync(swarmDir);
|
|
15493
15563
|
if (stat4.isSymbolicLink()) {
|
|
@@ -15501,18 +15571,18 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
15501
15571
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
15502
15572
|
let planExists = false;
|
|
15503
15573
|
let planData = {
|
|
15504
|
-
title:
|
|
15574
|
+
title: path28.basename(directory) || "Ad-hoc session",
|
|
15505
15575
|
phases: []
|
|
15506
15576
|
};
|
|
15507
15577
|
try {
|
|
15508
|
-
const content = await
|
|
15578
|
+
const content = await fs10.readFile(planPath, "utf-8");
|
|
15509
15579
|
planData = JSON.parse(content);
|
|
15510
15580
|
planExists = true;
|
|
15511
15581
|
} catch (error2) {
|
|
15512
15582
|
if (error2?.code !== "ENOENT") {
|
|
15513
15583
|
return `\u274C Failed to read plan.json: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
15514
15584
|
}
|
|
15515
|
-
const swarmDirExists = await
|
|
15585
|
+
const swarmDirExists = await fs10.access(swarmDir).then(() => true).catch(() => false);
|
|
15516
15586
|
if (!swarmDirExists) {
|
|
15517
15587
|
return `\u274C No .swarm/ directory found in ${directory}. Run /swarm close from the project root, or run /swarm plan first.`;
|
|
15518
15588
|
}
|
|
@@ -15526,15 +15596,15 @@ async function handleCloseCommand(directory, args, options = {}) {
|
|
|
15526
15596
|
}
|
|
15527
15597
|
try {
|
|
15528
15598
|
if (!planExists) {
|
|
15529
|
-
const archiveDir =
|
|
15599
|
+
const archiveDir = path28.join(swarmDir, "archive");
|
|
15530
15600
|
try {
|
|
15531
|
-
const archiveEntries = await
|
|
15601
|
+
const archiveEntries = await fs10.readdir(archiveDir);
|
|
15532
15602
|
const hasArchiveBundle = archiveEntries.some((entry) => entry.startsWith("swarm-"));
|
|
15533
15603
|
if (hasArchiveBundle) {
|
|
15534
15604
|
const hasActiveState = [
|
|
15535
15605
|
...ACTIVE_STATE_TO_CLEAN,
|
|
15536
15606
|
...ACTIVE_STATE_DIRS_TO_CLEAN
|
|
15537
|
-
].some((entry) => fsSync.existsSync(
|
|
15607
|
+
].some((entry) => fsSync.existsSync(path28.join(swarmDir, entry)));
|
|
15538
15608
|
if (!hasActiveState) {
|
|
15539
15609
|
return `\u2705 Already finalized \u2014 nothing to do.
|
|
15540
15610
|
|
|
@@ -15662,9 +15732,9 @@ This project was already finalized in a previous /swarm close run. The plan has
|
|
|
15662
15732
|
...ctx.warnings.length > 0 ? ["## Warnings", ...ctx.warnings.map((w) => `- ${w}`), ""] : []
|
|
15663
15733
|
].join(`
|
|
15664
15734
|
`);
|
|
15665
|
-
const closeSummaryTempPath =
|
|
15735
|
+
const closeSummaryTempPath = path28.join(path28.dirname(closeSummaryPath), `${path28.basename(closeSummaryPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
15666
15736
|
try {
|
|
15667
|
-
await
|
|
15737
|
+
await fs10.writeFile(closeSummaryTempPath, summaryContent, "utf-8");
|
|
15668
15738
|
fsSync.renameSync(closeSummaryTempPath, closeSummaryPath);
|
|
15669
15739
|
} catch (error2) {
|
|
15670
15740
|
try {
|
|
@@ -16006,14 +16076,14 @@ function buildStatusMessage(session, plan) {
|
|
|
16006
16076
|
|
|
16007
16077
|
// src/commands/config.ts
|
|
16008
16078
|
import * as os6 from "os";
|
|
16009
|
-
import * as
|
|
16079
|
+
import * as path29 from "path";
|
|
16010
16080
|
function getUserConfigDir2() {
|
|
16011
|
-
return process.env.XDG_CONFIG_HOME ||
|
|
16081
|
+
return process.env.XDG_CONFIG_HOME || path29.join(os6.homedir(), ".config");
|
|
16012
16082
|
}
|
|
16013
16083
|
async function handleConfigCommand(directory, _args) {
|
|
16014
16084
|
const config = loadPluginConfig(directory);
|
|
16015
|
-
const userConfigPath =
|
|
16016
|
-
const projectConfigPath =
|
|
16085
|
+
const userConfigPath = path29.join(getUserConfigDir2(), "opencode", "opencode-swarm.json");
|
|
16086
|
+
const projectConfigPath = path29.join(directory, ".opencode", "opencode-swarm.json");
|
|
16017
16087
|
const lines = [
|
|
16018
16088
|
"## Swarm Configuration",
|
|
16019
16089
|
"",
|
|
@@ -16031,9 +16101,9 @@ async function handleConfigCommand(directory, _args) {
|
|
|
16031
16101
|
}
|
|
16032
16102
|
|
|
16033
16103
|
// src/services/skill-consolidation.ts
|
|
16034
|
-
import { existsSync as
|
|
16035
|
-
import { mkdir as mkdir9, readFile as
|
|
16036
|
-
import * as
|
|
16104
|
+
import { existsSync as existsSync19 } from "fs";
|
|
16105
|
+
import { mkdir as mkdir9, readFile as readFile10, rename as rename7, writeFile as writeFile11 } from "fs/promises";
|
|
16106
|
+
import * as path30 from "path";
|
|
16037
16107
|
|
|
16038
16108
|
// src/utils/timeout.ts
|
|
16039
16109
|
async function withTimeout(promise, ms, timeoutError) {
|
|
@@ -16058,14 +16128,14 @@ var DEFAULT_CONSOLIDATION_MAX_CALLS_PER_RUN = 1;
|
|
|
16058
16128
|
var CONSOLIDATION_RUN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
16059
16129
|
var runningByDirectory = new Map;
|
|
16060
16130
|
function consolidationStatePath(directory) {
|
|
16061
|
-
return
|
|
16131
|
+
return path30.join(directory, ".swarm", "skill-improver", "consolidation-state.json");
|
|
16062
16132
|
}
|
|
16063
16133
|
async function readState2(directory) {
|
|
16064
16134
|
const filePath = consolidationStatePath(directory);
|
|
16065
|
-
if (!
|
|
16135
|
+
if (!existsSync19(filePath))
|
|
16066
16136
|
return {};
|
|
16067
16137
|
try {
|
|
16068
|
-
const parsed = JSON.parse(await
|
|
16138
|
+
const parsed = JSON.parse(await readFile10(filePath, "utf-8"));
|
|
16069
16139
|
if (!parsed || typeof parsed !== "object")
|
|
16070
16140
|
return {};
|
|
16071
16141
|
return parsed;
|
|
@@ -16074,10 +16144,10 @@ async function readState2(directory) {
|
|
|
16074
16144
|
}
|
|
16075
16145
|
}
|
|
16076
16146
|
async function atomicWrite2(filePath, content) {
|
|
16077
|
-
await mkdir9(
|
|
16147
|
+
await mkdir9(path30.dirname(filePath), { recursive: true });
|
|
16078
16148
|
const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
16079
|
-
await
|
|
16080
|
-
await
|
|
16149
|
+
await writeFile11(tmp, content, "utf-8");
|
|
16150
|
+
await rename7(tmp, filePath);
|
|
16081
16151
|
}
|
|
16082
16152
|
async function writeState2(directory, state) {
|
|
16083
16153
|
await atomicWrite2(consolidationStatePath(directory), `${JSON.stringify(state, null, 2)}
|
|
@@ -16154,7 +16224,7 @@ async function runSkillConsolidationInner(req) {
|
|
|
16154
16224
|
};
|
|
16155
16225
|
}
|
|
16156
16226
|
async function runSkillConsolidation(req) {
|
|
16157
|
-
const key =
|
|
16227
|
+
const key = path30.resolve(req.directory);
|
|
16158
16228
|
const existing = runningByDirectory.get(key);
|
|
16159
16229
|
if (existing) {
|
|
16160
16230
|
return {
|
|
@@ -16355,8 +16425,8 @@ async function handleCouncilCommand(_directory, args) {
|
|
|
16355
16425
|
|
|
16356
16426
|
// src/commands/coupling.ts
|
|
16357
16427
|
import { randomBytes } from "crypto";
|
|
16358
|
-
import * as
|
|
16359
|
-
import * as
|
|
16428
|
+
import * as fs11 from "fs";
|
|
16429
|
+
import * as path32 from "path";
|
|
16360
16430
|
|
|
16361
16431
|
// src/turbo/epic/cochange-source.ts
|
|
16362
16432
|
import * as child_process3 from "child_process";
|
|
@@ -16364,9 +16434,9 @@ import { promisify as promisify2 } from "util";
|
|
|
16364
16434
|
|
|
16365
16435
|
// src/tools/co-change-analyzer.ts
|
|
16366
16436
|
import * as child_process2 from "child_process";
|
|
16367
|
-
import { randomUUID as
|
|
16368
|
-
import { readdir as readdir2, readFile as
|
|
16369
|
-
import * as
|
|
16437
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
16438
|
+
import { readdir as readdir2, readFile as readFile11, stat as stat4 } from "fs/promises";
|
|
16439
|
+
import * as path31 from "path";
|
|
16370
16440
|
import { promisify } from "util";
|
|
16371
16441
|
function getExecFileAsync() {
|
|
16372
16442
|
return promisify(child_process2.execFile);
|
|
@@ -16470,7 +16540,7 @@ async function scanSourceFiles(dir) {
|
|
|
16470
16540
|
try {
|
|
16471
16541
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
16472
16542
|
for (const entry of entries) {
|
|
16473
|
-
const fullPath =
|
|
16543
|
+
const fullPath = path31.join(dir, entry.name);
|
|
16474
16544
|
if (entry.isDirectory()) {
|
|
16475
16545
|
if (skipDirs.has(entry.name)) {
|
|
16476
16546
|
continue;
|
|
@@ -16478,7 +16548,7 @@ async function scanSourceFiles(dir) {
|
|
|
16478
16548
|
const subFiles = await scanSourceFiles(fullPath);
|
|
16479
16549
|
results.push(...subFiles);
|
|
16480
16550
|
} else if (entry.isFile()) {
|
|
16481
|
-
const ext =
|
|
16551
|
+
const ext = path31.extname(entry.name);
|
|
16482
16552
|
if ([".ts", ".tsx", ".js", ".jsx", ".mjs"].includes(ext)) {
|
|
16483
16553
|
results.push(fullPath);
|
|
16484
16554
|
}
|
|
@@ -16492,7 +16562,7 @@ async function getStaticEdges(directory) {
|
|
|
16492
16562
|
const sourceFiles = await scanSourceFiles(directory);
|
|
16493
16563
|
for (const sourceFile of sourceFiles) {
|
|
16494
16564
|
try {
|
|
16495
|
-
const content = await
|
|
16565
|
+
const content = await readFile11(sourceFile, "utf-8");
|
|
16496
16566
|
const importRegex = /(?:import|require)\s*(?:\(?\s*['"`]|.*?from\s+['"`])([^'"`]+)['"`]/g;
|
|
16497
16567
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
16498
16568
|
const importPath = match[1].trim();
|
|
@@ -16500,8 +16570,8 @@ async function getStaticEdges(directory) {
|
|
|
16500
16570
|
continue;
|
|
16501
16571
|
}
|
|
16502
16572
|
try {
|
|
16503
|
-
const sourceDir =
|
|
16504
|
-
const resolvedPath =
|
|
16573
|
+
const sourceDir = path31.dirname(sourceFile);
|
|
16574
|
+
const resolvedPath = path31.resolve(sourceDir, importPath);
|
|
16505
16575
|
const extensions = [
|
|
16506
16576
|
"",
|
|
16507
16577
|
".ts",
|
|
@@ -16526,8 +16596,8 @@ async function getStaticEdges(directory) {
|
|
|
16526
16596
|
if (!targetFile) {
|
|
16527
16597
|
continue;
|
|
16528
16598
|
}
|
|
16529
|
-
const relSource =
|
|
16530
|
-
const relTarget =
|
|
16599
|
+
const relSource = path31.relative(directory, sourceFile).replace(/\\/g, "/");
|
|
16600
|
+
const relTarget = path31.relative(directory, targetFile).replace(/\\/g, "/");
|
|
16531
16601
|
const [key] = relSource < relTarget ? [`${relSource}::${relTarget}`, relSource, relTarget] : [`${relTarget}::${relSource}`, relTarget, relSource];
|
|
16532
16602
|
edges.add(key);
|
|
16533
16603
|
} catch {}
|
|
@@ -16539,7 +16609,7 @@ async function getStaticEdges(directory) {
|
|
|
16539
16609
|
function isTestImplementationPair(fileA, fileB) {
|
|
16540
16610
|
const testPatterns = [".test.ts", ".test.js", ".spec.ts", ".spec.js"];
|
|
16541
16611
|
const getBaseName = (filePath) => {
|
|
16542
|
-
const base =
|
|
16612
|
+
const base = path31.basename(filePath);
|
|
16543
16613
|
for (const pattern of testPatterns) {
|
|
16544
16614
|
if (base.endsWith(pattern)) {
|
|
16545
16615
|
return base.slice(0, -pattern.length);
|
|
@@ -16549,16 +16619,16 @@ function isTestImplementationPair(fileA, fileB) {
|
|
|
16549
16619
|
};
|
|
16550
16620
|
const baseA = getBaseName(fileA);
|
|
16551
16621
|
const baseB = getBaseName(fileB);
|
|
16552
|
-
return baseA === baseB && baseA !==
|
|
16622
|
+
return baseA === baseB && baseA !== path31.basename(fileA) && baseA !== path31.basename(fileB);
|
|
16553
16623
|
}
|
|
16554
16624
|
function hasSharedPrefix(fileA, fileB) {
|
|
16555
|
-
const dirA =
|
|
16556
|
-
const dirB =
|
|
16625
|
+
const dirA = path31.dirname(fileA);
|
|
16626
|
+
const dirB = path31.dirname(fileB);
|
|
16557
16627
|
if (dirA !== dirB) {
|
|
16558
16628
|
return false;
|
|
16559
16629
|
}
|
|
16560
|
-
const baseA =
|
|
16561
|
-
const baseB =
|
|
16630
|
+
const baseA = path31.basename(fileA).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
16631
|
+
const baseB = path31.basename(fileB).replace(/\.(ts|js|tsx|jsx|mjs)$/, "");
|
|
16562
16632
|
if (baseA.startsWith(baseB) || baseB.startsWith(baseA)) {
|
|
16563
16633
|
return true;
|
|
16564
16634
|
}
|
|
@@ -16613,8 +16683,8 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
16613
16683
|
const entries = [];
|
|
16614
16684
|
const now = new Date().toISOString();
|
|
16615
16685
|
for (const pair of pairs.slice(0, 10)) {
|
|
16616
|
-
const baseA =
|
|
16617
|
-
const baseB =
|
|
16686
|
+
const baseA = path31.basename(pair.fileA);
|
|
16687
|
+
const baseB = path31.basename(pair.fileB);
|
|
16618
16688
|
let lesson = `Files ${pair.fileA} and ${pair.fileB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
16619
16689
|
if (lesson.length > 280) {
|
|
16620
16690
|
lesson = `Files ${baseA} and ${baseB} co-change with NPMI=${pair.npmi.toFixed(3)} but have no import relationship. This hidden coupling suggests a shared architectural concern \u2014 changes to one likely require changes to the other.`;
|
|
@@ -16627,7 +16697,7 @@ function darkMatterToKnowledgeEntries(pairs, projectName) {
|
|
|
16627
16697
|
}
|
|
16628
16698
|
const confidence = Math.min(0.3 + 0.2 * Math.min(pair.coChangeCount / 10, 1), 0.5);
|
|
16629
16699
|
entries.push({
|
|
16630
|
-
id:
|
|
16700
|
+
id: randomUUID6(),
|
|
16631
16701
|
tier: "swarm",
|
|
16632
16702
|
lesson,
|
|
16633
16703
|
category: "architecture",
|
|
@@ -17040,17 +17110,17 @@ function parseArgs3(args) {
|
|
|
17040
17110
|
return parsed;
|
|
17041
17111
|
}
|
|
17042
17112
|
function persistReportJson(directory, report) {
|
|
17043
|
-
const epicDir =
|
|
17044
|
-
|
|
17045
|
-
const filePath =
|
|
17113
|
+
const epicDir = path32.join(directory, ".swarm", "epic");
|
|
17114
|
+
fs11.mkdirSync(epicDir, { recursive: true });
|
|
17115
|
+
const filePath = path32.join(epicDir, "coupling-report.json");
|
|
17046
17116
|
const tmpPath = `${filePath}.tmp.${randomBytes(8).toString("hex")}`;
|
|
17047
|
-
|
|
17117
|
+
fs11.writeFileSync(tmpPath, `${JSON.stringify(report, null, 2)}
|
|
17048
17118
|
`, "utf-8");
|
|
17049
17119
|
try {
|
|
17050
|
-
|
|
17120
|
+
fs11.renameSync(tmpPath, filePath);
|
|
17051
17121
|
} catch (err) {
|
|
17052
17122
|
try {
|
|
17053
|
-
|
|
17123
|
+
fs11.unlinkSync(tmpPath);
|
|
17054
17124
|
} catch {}
|
|
17055
17125
|
throw err;
|
|
17056
17126
|
}
|
|
@@ -17101,7 +17171,7 @@ Usage: /swarm coupling [--phase <n>] [--threshold <-1..1>] [--min-co-changes <n>
|
|
|
17101
17171
|
persistStatus = {
|
|
17102
17172
|
requested: true,
|
|
17103
17173
|
written: true,
|
|
17104
|
-
path:
|
|
17174
|
+
path: path32.relative(directory, writtenAt).replace(/\\/g, "/")
|
|
17105
17175
|
};
|
|
17106
17176
|
} catch (err) {
|
|
17107
17177
|
persistStatus = {
|
|
@@ -17140,8 +17210,8 @@ var _internals22 = {
|
|
|
17140
17210
|
loadCuratorDeps: async () => {
|
|
17141
17211
|
const [{ CuratorConfigSchema }, curator, { createCuratorLLMDelegate: createCuratorLLMDelegate2 }] = await Promise.all([
|
|
17142
17212
|
import("./schema-vw2ffhe9.js"),
|
|
17143
|
-
import("./curator-
|
|
17144
|
-
import("./curator-llm-factory-
|
|
17213
|
+
import("./curator-1nr4qszq.js"),
|
|
17214
|
+
import("./curator-llm-factory-x9tk7e6m.js")
|
|
17145
17215
|
]);
|
|
17146
17216
|
return { CuratorConfigSchema, curator, createCuratorLLMDelegate: createCuratorLLMDelegate2 };
|
|
17147
17217
|
}
|
|
@@ -17233,7 +17303,7 @@ function formatCurationSummary(summary) {
|
|
|
17233
17303
|
}
|
|
17234
17304
|
|
|
17235
17305
|
// src/commands/dark-matter.ts
|
|
17236
|
-
import
|
|
17306
|
+
import path33 from "path";
|
|
17237
17307
|
async function handleDarkMatterCommand(directory, args) {
|
|
17238
17308
|
const options = {};
|
|
17239
17309
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -17265,7 +17335,7 @@ Ensure this is a git repository with commit history.`;
|
|
|
17265
17335
|
const output = formatDarkMatterOutput(pairs);
|
|
17266
17336
|
if (pairs.length > 0) {
|
|
17267
17337
|
try {
|
|
17268
|
-
const projectName =
|
|
17338
|
+
const projectName = path33.basename(path33.resolve(directory));
|
|
17269
17339
|
const entries = darkMatterToKnowledgeEntries(pairs, projectName);
|
|
17270
17340
|
if (entries.length > 0) {
|
|
17271
17341
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
@@ -17631,13 +17701,13 @@ ${USAGE5}`;
|
|
|
17631
17701
|
|
|
17632
17702
|
// src/services/diagnose-service.ts
|
|
17633
17703
|
import * as child_process4 from "child_process";
|
|
17634
|
-
import { existsSync as
|
|
17635
|
-
import
|
|
17704
|
+
import { existsSync as existsSync22, readdirSync as readdirSync4, readFileSync as readFileSync11, statSync as statSync7 } from "fs";
|
|
17705
|
+
import * as path38 from "path";
|
|
17636
17706
|
import { fileURLToPath } from "url";
|
|
17637
17707
|
// package.json
|
|
17638
17708
|
var package_default = {
|
|
17639
17709
|
name: "opencode-swarm",
|
|
17640
|
-
version: "7.107.
|
|
17710
|
+
version: "7.107.3",
|
|
17641
17711
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
17642
17712
|
main: "dist/index.js",
|
|
17643
17713
|
types: "dist/index.d.ts",
|
|
@@ -17745,44 +17815,44 @@ var package_default = {
|
|
|
17745
17815
|
|
|
17746
17816
|
// src/config/cache-paths.ts
|
|
17747
17817
|
import * as os7 from "os";
|
|
17748
|
-
import * as
|
|
17818
|
+
import * as path34 from "path";
|
|
17749
17819
|
function getPluginConfigDir() {
|
|
17750
|
-
return
|
|
17820
|
+
return path34.join(process.env.XDG_CONFIG_HOME || path34.join(os7.homedir(), ".config"), "opencode");
|
|
17751
17821
|
}
|
|
17752
17822
|
function getPluginCachePaths() {
|
|
17753
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
17823
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path34.join(os7.homedir(), ".cache");
|
|
17754
17824
|
const configDir = getPluginConfigDir();
|
|
17755
17825
|
const paths = [
|
|
17756
|
-
|
|
17757
|
-
|
|
17758
|
-
|
|
17826
|
+
path34.join(cacheBase, "opencode", "node_modules", "opencode-swarm"),
|
|
17827
|
+
path34.join(cacheBase, "opencode", "packages", "opencode-swarm@latest"),
|
|
17828
|
+
path34.join(configDir, "node_modules", "opencode-swarm")
|
|
17759
17829
|
];
|
|
17760
17830
|
if (process.platform === "darwin") {
|
|
17761
|
-
const libCaches =
|
|
17762
|
-
paths.push(
|
|
17831
|
+
const libCaches = path34.join(os7.homedir(), "Library", "Caches");
|
|
17832
|
+
paths.push(path34.join(libCaches, "opencode", "node_modules", "opencode-swarm"), path34.join(libCaches, "opencode", "packages", "opencode-swarm@latest"));
|
|
17763
17833
|
}
|
|
17764
17834
|
if (process.platform === "win32") {
|
|
17765
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
17766
|
-
const appData = process.env.APPDATA ||
|
|
17767
|
-
paths.push(
|
|
17835
|
+
const localAppData = process.env.LOCALAPPDATA || path34.join(os7.homedir(), "AppData", "Local");
|
|
17836
|
+
const appData = process.env.APPDATA || path34.join(os7.homedir(), "AppData", "Roaming");
|
|
17837
|
+
paths.push(path34.join(localAppData, "opencode", "node_modules", "opencode-swarm"), path34.join(localAppData, "opencode", "packages", "opencode-swarm@latest"), path34.join(appData, "opencode", "node_modules", "opencode-swarm"));
|
|
17768
17838
|
}
|
|
17769
17839
|
return paths;
|
|
17770
17840
|
}
|
|
17771
17841
|
function getPluginLockFilePaths() {
|
|
17772
|
-
const cacheBase = process.env.XDG_CACHE_HOME ||
|
|
17842
|
+
const cacheBase = process.env.XDG_CACHE_HOME || path34.join(os7.homedir(), ".cache");
|
|
17773
17843
|
const configDir = getPluginConfigDir();
|
|
17774
17844
|
const paths = [
|
|
17775
|
-
|
|
17776
|
-
|
|
17777
|
-
|
|
17845
|
+
path34.join(cacheBase, "opencode", "bun.lock"),
|
|
17846
|
+
path34.join(cacheBase, "opencode", "bun.lockb"),
|
|
17847
|
+
path34.join(configDir, "package-lock.json")
|
|
17778
17848
|
];
|
|
17779
17849
|
if (process.platform === "darwin") {
|
|
17780
|
-
const libCaches =
|
|
17781
|
-
paths.push(
|
|
17850
|
+
const libCaches = path34.join(os7.homedir(), "Library", "Caches");
|
|
17851
|
+
paths.push(path34.join(libCaches, "opencode", "bun.lock"), path34.join(libCaches, "opencode", "bun.lockb"));
|
|
17782
17852
|
}
|
|
17783
17853
|
if (process.platform === "win32") {
|
|
17784
|
-
const localAppData = process.env.LOCALAPPDATA ||
|
|
17785
|
-
paths.push(
|
|
17854
|
+
const localAppData = process.env.LOCALAPPDATA || path34.join(os7.homedir(), "AppData", "Local");
|
|
17855
|
+
paths.push(path34.join(localAppData, "opencode", "bun.lock"), path34.join(localAppData, "opencode", "bun.lockb"));
|
|
17786
17856
|
}
|
|
17787
17857
|
return paths;
|
|
17788
17858
|
}
|
|
@@ -17792,11 +17862,11 @@ init_capability_probe();
|
|
|
17792
17862
|
init_executor();
|
|
17793
17863
|
|
|
17794
17864
|
// src/services/knowledge-diagnostics.ts
|
|
17795
|
-
import { existsSync as
|
|
17796
|
-
import { readFile as
|
|
17865
|
+
import { existsSync as existsSync21 } from "fs";
|
|
17866
|
+
import { readFile as readFile12 } from "fs/promises";
|
|
17797
17867
|
|
|
17798
17868
|
// src/services/version-check.ts
|
|
17799
|
-
import { existsSync as
|
|
17869
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync13, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
17800
17870
|
import { homedir as homedir6 } from "os";
|
|
17801
17871
|
import { join as join32 } from "path";
|
|
17802
17872
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -17812,10 +17882,10 @@ function cacheFile() {
|
|
|
17812
17882
|
}
|
|
17813
17883
|
function readVersionCache() {
|
|
17814
17884
|
try {
|
|
17815
|
-
const
|
|
17816
|
-
if (!
|
|
17885
|
+
const path38 = cacheFile();
|
|
17886
|
+
if (!existsSync20(path38))
|
|
17817
17887
|
return null;
|
|
17818
|
-
const raw = readFileSync10(
|
|
17888
|
+
const raw = readFileSync10(path38, "utf-8");
|
|
17819
17889
|
const parsed = JSON.parse(raw);
|
|
17820
17890
|
if (typeof parsed?.checkedAt !== "number")
|
|
17821
17891
|
return null;
|
|
@@ -17867,9 +17937,9 @@ var SEVEN_DAYS_MS2 = 7 * 24 * 60 * 60 * 1000;
|
|
|
17867
17937
|
var UNACTIONABLE_BACKLOG_WARN = 100;
|
|
17868
17938
|
var INSIGHT_BACKLOG_WARN = 50;
|
|
17869
17939
|
async function readRawLines(filePath) {
|
|
17870
|
-
if (!
|
|
17940
|
+
if (!existsSync21(filePath))
|
|
17871
17941
|
return { entries: [], corrupt: 0 };
|
|
17872
|
-
const content = await
|
|
17942
|
+
const content = await readFile12(filePath, "utf-8");
|
|
17873
17943
|
const entries = [];
|
|
17874
17944
|
let corrupt = 0;
|
|
17875
17945
|
for (const line of content.split(`
|
|
@@ -17992,10 +18062,10 @@ async function computeKnowledgeDebug(directory) {
|
|
|
17992
18062
|
};
|
|
17993
18063
|
}
|
|
17994
18064
|
async function safeJsonlCount(filePath) {
|
|
17995
|
-
if (!filePath || !
|
|
18065
|
+
if (!filePath || !existsSync21(filePath))
|
|
17996
18066
|
return 0;
|
|
17997
18067
|
try {
|
|
17998
|
-
const content = await
|
|
18068
|
+
const content = await readFile12(filePath, "utf-8");
|
|
17999
18069
|
let n = 0;
|
|
18000
18070
|
for (const line of content.split(`
|
|
18001
18071
|
`)) {
|
|
@@ -18070,8 +18140,8 @@ var REQUIRED_CACHE_GRAMMAR_ASSETS = [
|
|
|
18070
18140
|
"tree-sitter-typescript.wasm"
|
|
18071
18141
|
];
|
|
18072
18142
|
function resolveCachePackageRoot(cachePath) {
|
|
18073
|
-
const nestedPackageRoot =
|
|
18074
|
-
return
|
|
18143
|
+
const nestedPackageRoot = path38.join(cachePath, "node_modules", "opencode-swarm");
|
|
18144
|
+
return existsSync22(nestedPackageRoot) ? nestedPackageRoot : cachePath;
|
|
18075
18145
|
}
|
|
18076
18146
|
var _internals26 = {
|
|
18077
18147
|
detectSandboxCapability: () => sandboxCapabilityProbe.detect(),
|
|
@@ -18322,7 +18392,7 @@ async function checkConfigBackups(directory) {
|
|
|
18322
18392
|
}
|
|
18323
18393
|
async function checkGitRepository(directory) {
|
|
18324
18394
|
try {
|
|
18325
|
-
if (!
|
|
18395
|
+
if (!existsSync22(directory) || !statSync7(directory).isDirectory()) {
|
|
18326
18396
|
return {
|
|
18327
18397
|
name: "Git Repository",
|
|
18328
18398
|
status: "\u274C",
|
|
@@ -18386,8 +18456,8 @@ async function checkSpecStaleness(directory, plan) {
|
|
|
18386
18456
|
};
|
|
18387
18457
|
}
|
|
18388
18458
|
async function checkConfigParseability(directory) {
|
|
18389
|
-
const configPath =
|
|
18390
|
-
if (!
|
|
18459
|
+
const configPath = path38.join(directory, ".opencode/opencode-swarm.json");
|
|
18460
|
+
if (!existsSync22(configPath)) {
|
|
18391
18461
|
return {
|
|
18392
18462
|
name: "Config Parseability",
|
|
18393
18463
|
status: "\u2705",
|
|
@@ -18415,7 +18485,7 @@ function resolveGrammarDir(thisDir) {
|
|
|
18415
18485
|
const normalized = thisDir.replace(/\\/g, "/");
|
|
18416
18486
|
const isSource = normalized.endsWith("/src/services");
|
|
18417
18487
|
const isCliBundle = normalized.endsWith("/cli");
|
|
18418
|
-
return isSource || isCliBundle ?
|
|
18488
|
+
return isSource || isCliBundle ? path38.join(thisDir, "..", "lang", "grammars") : path38.join(thisDir, "lang", "grammars");
|
|
18419
18489
|
}
|
|
18420
18490
|
async function checkGrammarWasmFiles() {
|
|
18421
18491
|
const grammarFiles = [
|
|
@@ -18439,14 +18509,14 @@ async function checkGrammarWasmFiles() {
|
|
|
18439
18509
|
"tree-sitter-ini.wasm",
|
|
18440
18510
|
"tree-sitter-regex.wasm"
|
|
18441
18511
|
];
|
|
18442
|
-
const thisDir =
|
|
18512
|
+
const thisDir = path38.dirname(fileURLToPath(import.meta.url));
|
|
18443
18513
|
const grammarDir = resolveGrammarDir(thisDir);
|
|
18444
18514
|
const missing = [];
|
|
18445
|
-
if (!
|
|
18515
|
+
if (!existsSync22(path38.join(grammarDir, "tree-sitter.wasm"))) {
|
|
18446
18516
|
missing.push("tree-sitter.wasm (core runtime)");
|
|
18447
18517
|
}
|
|
18448
18518
|
for (const file of grammarFiles) {
|
|
18449
|
-
if (!
|
|
18519
|
+
if (!existsSync22(path38.join(grammarDir, file))) {
|
|
18450
18520
|
missing.push(file);
|
|
18451
18521
|
}
|
|
18452
18522
|
}
|
|
@@ -18464,8 +18534,8 @@ async function checkGrammarWasmFiles() {
|
|
|
18464
18534
|
};
|
|
18465
18535
|
}
|
|
18466
18536
|
async function checkCheckpointManifest(directory) {
|
|
18467
|
-
const manifestPath =
|
|
18468
|
-
if (!
|
|
18537
|
+
const manifestPath = path38.join(directory, ".swarm/checkpoints.json");
|
|
18538
|
+
if (!existsSync22(manifestPath)) {
|
|
18469
18539
|
return {
|
|
18470
18540
|
name: "Checkpoint Manifest",
|
|
18471
18541
|
status: "\u2705",
|
|
@@ -18516,8 +18586,8 @@ async function checkCheckpointManifest(directory) {
|
|
|
18516
18586
|
}
|
|
18517
18587
|
}
|
|
18518
18588
|
async function checkEventStreamIntegrity(directory) {
|
|
18519
|
-
const eventsPath =
|
|
18520
|
-
if (!
|
|
18589
|
+
const eventsPath = path38.join(directory, ".swarm/events.jsonl");
|
|
18590
|
+
if (!existsSync22(eventsPath)) {
|
|
18521
18591
|
return {
|
|
18522
18592
|
name: "Event Stream",
|
|
18523
18593
|
status: "\u2705",
|
|
@@ -18557,8 +18627,8 @@ async function checkEventStreamIntegrity(directory) {
|
|
|
18557
18627
|
}
|
|
18558
18628
|
}
|
|
18559
18629
|
async function checkSteeringDirectives(directory) {
|
|
18560
|
-
const eventsPath =
|
|
18561
|
-
if (!
|
|
18630
|
+
const eventsPath = path38.join(directory, ".swarm/events.jsonl");
|
|
18631
|
+
if (!existsSync22(eventsPath)) {
|
|
18562
18632
|
return {
|
|
18563
18633
|
name: "Steering Directives",
|
|
18564
18634
|
status: "\u2705",
|
|
@@ -18613,8 +18683,8 @@ async function checkCurator(directory) {
|
|
|
18613
18683
|
detail: "Disabled (enable via curator.enabled)"
|
|
18614
18684
|
};
|
|
18615
18685
|
}
|
|
18616
|
-
const summaryPath =
|
|
18617
|
-
if (!
|
|
18686
|
+
const summaryPath = path38.join(directory, ".swarm/curator-summary.json");
|
|
18687
|
+
if (!existsSync22(summaryPath)) {
|
|
18618
18688
|
return {
|
|
18619
18689
|
name: "Curator",
|
|
18620
18690
|
status: "\u2705",
|
|
@@ -18815,8 +18885,8 @@ async function getDiagnoseData(directory) {
|
|
|
18815
18885
|
checks.push(await checkCurator(directory));
|
|
18816
18886
|
checks.push(await checkKnowledgeHealth(directory));
|
|
18817
18887
|
try {
|
|
18818
|
-
const evidenceDir =
|
|
18819
|
-
const snapshotFiles =
|
|
18888
|
+
const evidenceDir = path38.join(directory, ".swarm", "evidence");
|
|
18889
|
+
const snapshotFiles = existsSync22(evidenceDir) ? readdirSync4(evidenceDir).filter((f) => f.startsWith("agent-tools-") && f.endsWith(".json")) : [];
|
|
18820
18890
|
if (snapshotFiles.length > 0) {
|
|
18821
18891
|
const latest = snapshotFiles.sort().pop();
|
|
18822
18892
|
checks.push({
|
|
@@ -18849,14 +18919,14 @@ async function getDiagnoseData(directory) {
|
|
|
18849
18919
|
const cacheRows = [];
|
|
18850
18920
|
for (const cachePath of cachePaths) {
|
|
18851
18921
|
try {
|
|
18852
|
-
if (!
|
|
18922
|
+
if (!existsSync22(cachePath)) {
|
|
18853
18923
|
cacheRows.push(`\u2B1C ${cachePath} \u2014 absent`);
|
|
18854
18924
|
continue;
|
|
18855
18925
|
}
|
|
18856
18926
|
const packageRoot = resolveCachePackageRoot(cachePath);
|
|
18857
18927
|
const cacheLabel = packageRoot === cachePath ? cachePath : `${cachePath} -> ${packageRoot}`;
|
|
18858
|
-
const missingGrammarAssets = REQUIRED_CACHE_GRAMMAR_ASSETS.filter((file) => !
|
|
18859
|
-
const pkgJsonPath =
|
|
18928
|
+
const missingGrammarAssets = REQUIRED_CACHE_GRAMMAR_ASSETS.filter((file) => !existsSync22(path38.join(packageRoot, "dist", "lang", "grammars", file)));
|
|
18929
|
+
const pkgJsonPath = path38.join(packageRoot, "package.json");
|
|
18860
18930
|
try {
|
|
18861
18931
|
const raw = readFileSync11(pkgJsonPath, "utf-8");
|
|
18862
18932
|
const parsed = JSON.parse(raw);
|
|
@@ -19231,10 +19301,10 @@ function decideEpicActivation(tasks, cochangePairs, commitsObserved, options) {
|
|
|
19231
19301
|
|
|
19232
19302
|
// src/turbo/epic/calibration.ts
|
|
19233
19303
|
init_logger();
|
|
19234
|
-
import * as
|
|
19235
|
-
import * as
|
|
19304
|
+
import * as fs13 from "fs";
|
|
19305
|
+
import * as path39 from "path";
|
|
19236
19306
|
var STATE_FILE = "calibration.json";
|
|
19237
|
-
var STATE_REL_DIR =
|
|
19307
|
+
var STATE_REL_DIR = path39.join(".swarm", "epic");
|
|
19238
19308
|
function nowISO() {
|
|
19239
19309
|
return new Date().toISOString();
|
|
19240
19310
|
}
|
|
@@ -19256,13 +19326,13 @@ function markUnreadable(directory, reason) {
|
|
|
19256
19326
|
error(`[epic/calibration] state file unreadable for ${directory}: ${reason} \u2014 failing closed`);
|
|
19257
19327
|
}
|
|
19258
19328
|
function repairCalibrationUnreadable(directory) {
|
|
19259
|
-
const filePath =
|
|
19260
|
-
if (!
|
|
19329
|
+
const filePath = path39.join(directory, STATE_REL_DIR, STATE_FILE);
|
|
19330
|
+
if (!fs13.existsSync(filePath)) {
|
|
19261
19331
|
stateUnreadableMap.delete(directory);
|
|
19262
19332
|
return;
|
|
19263
19333
|
}
|
|
19264
19334
|
try {
|
|
19265
|
-
const raw =
|
|
19335
|
+
const raw = fs13.readFileSync(filePath, "utf-8");
|
|
19266
19336
|
const parsed = JSON.parse(raw);
|
|
19267
19337
|
if (!isValidCalibrationShape(parsed)) {
|
|
19268
19338
|
stateUnreadableMap.set(directory, true);
|
|
@@ -19288,9 +19358,9 @@ function isValidCalibrationShape(candidate) {
|
|
|
19288
19358
|
return true;
|
|
19289
19359
|
}
|
|
19290
19360
|
function ensureSwarmEpicDir(directory) {
|
|
19291
|
-
const dir =
|
|
19292
|
-
if (!
|
|
19293
|
-
|
|
19361
|
+
const dir = path39.resolve(directory, STATE_REL_DIR);
|
|
19362
|
+
if (!fs13.existsSync(dir)) {
|
|
19363
|
+
fs13.mkdirSync(dir, { recursive: true });
|
|
19294
19364
|
}
|
|
19295
19365
|
return dir;
|
|
19296
19366
|
}
|
|
@@ -19300,18 +19370,18 @@ function loadCalibrationState(directory) {
|
|
|
19300
19370
|
if (stateUnreadableMap.get(directory))
|
|
19301
19371
|
return null;
|
|
19302
19372
|
}
|
|
19303
|
-
const filePath =
|
|
19373
|
+
const filePath = path39.join(directory, STATE_REL_DIR, STATE_FILE);
|
|
19304
19374
|
try {
|
|
19305
|
-
if (!
|
|
19375
|
+
if (!fs13.existsSync(filePath)) {
|
|
19306
19376
|
const seed = emptyCalibrationState();
|
|
19307
19377
|
try {
|
|
19308
19378
|
ensureSwarmEpicDir(directory);
|
|
19309
|
-
|
|
19379
|
+
fs13.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
|
|
19310
19380
|
`, "utf-8");
|
|
19311
19381
|
} catch {}
|
|
19312
19382
|
return seed;
|
|
19313
19383
|
}
|
|
19314
|
-
const raw =
|
|
19384
|
+
const raw = fs13.readFileSync(filePath, "utf-8");
|
|
19315
19385
|
const parsed = JSON.parse(raw);
|
|
19316
19386
|
if (!isValidCalibrationShape(parsed)) {
|
|
19317
19387
|
markUnreadable(directory, `malformed shape (version=${parsed?.version}, hotModuleAdditions type=${Array.isArray(parsed?.hotModuleAdditions) ? "array" : typeof parsed?.hotModuleAdditions})`);
|
|
@@ -19326,36 +19396,36 @@ function loadCalibrationState(directory) {
|
|
|
19326
19396
|
|
|
19327
19397
|
// src/turbo/epic/divergence-recorder.ts
|
|
19328
19398
|
init_logger();
|
|
19329
|
-
import * as
|
|
19330
|
-
import * as
|
|
19331
|
-
var EVIDENCE_REL_DIR =
|
|
19399
|
+
import * as fs14 from "fs";
|
|
19400
|
+
import * as path40 from "path";
|
|
19401
|
+
var EVIDENCE_REL_DIR = path40.join(".swarm", "epic");
|
|
19332
19402
|
var EVIDENCE_FILE = "divergence.jsonl";
|
|
19333
19403
|
var MAX_TAIL_BYTES2 = 16 * 1024 * 1024;
|
|
19334
19404
|
function readDivergenceHistory(directory, options) {
|
|
19335
|
-
const filePath =
|
|
19336
|
-
if (!
|
|
19405
|
+
const filePath = path40.join(directory, EVIDENCE_REL_DIR, EVIDENCE_FILE);
|
|
19406
|
+
if (!fs14.existsSync(filePath)) {
|
|
19337
19407
|
return [];
|
|
19338
19408
|
}
|
|
19339
19409
|
const maxBytes = options?.maxBytes ?? MAX_TAIL_BYTES2;
|
|
19340
19410
|
let raw;
|
|
19341
19411
|
let tailTruncated = false;
|
|
19342
19412
|
try {
|
|
19343
|
-
const stat5 =
|
|
19413
|
+
const stat5 = fs14.statSync(filePath);
|
|
19344
19414
|
if (Number.isFinite(maxBytes) && stat5.size > maxBytes) {
|
|
19345
|
-
const fd =
|
|
19415
|
+
const fd = fs14.openSync(filePath, "r");
|
|
19346
19416
|
try {
|
|
19347
19417
|
const buf = Buffer.alloc(maxBytes);
|
|
19348
19418
|
const offset = stat5.size - maxBytes;
|
|
19349
|
-
|
|
19419
|
+
fs14.readSync(fd, buf, 0, maxBytes, offset);
|
|
19350
19420
|
raw = buf.toString("utf-8");
|
|
19351
19421
|
tailTruncated = true;
|
|
19352
19422
|
} finally {
|
|
19353
19423
|
try {
|
|
19354
|
-
|
|
19424
|
+
fs14.closeSync(fd);
|
|
19355
19425
|
} catch {}
|
|
19356
19426
|
}
|
|
19357
19427
|
} else {
|
|
19358
|
-
raw =
|
|
19428
|
+
raw = fs14.readFileSync(filePath, "utf-8");
|
|
19359
19429
|
}
|
|
19360
19430
|
} catch {
|
|
19361
19431
|
return [];
|
|
@@ -19380,16 +19450,16 @@ function readDivergenceHistory(directory, options) {
|
|
|
19380
19450
|
}
|
|
19381
19451
|
|
|
19382
19452
|
// src/turbo/epic/promotion-evidence.ts
|
|
19383
|
-
import * as
|
|
19384
|
-
import * as
|
|
19385
|
-
var EVIDENCE_REL_DIR2 =
|
|
19453
|
+
import * as fs15 from "fs";
|
|
19454
|
+
import * as path41 from "path";
|
|
19455
|
+
var EVIDENCE_REL_DIR2 = path41.join(".swarm", "evidence");
|
|
19386
19456
|
var EVIDENCE_FILE2 = "epic-promotions.jsonl";
|
|
19387
19457
|
function readPromotionEvidence(directory) {
|
|
19388
|
-
const filePath =
|
|
19389
|
-
if (!
|
|
19458
|
+
const filePath = path41.join(directory, EVIDENCE_REL_DIR2, EVIDENCE_FILE2);
|
|
19459
|
+
if (!fs15.existsSync(filePath)) {
|
|
19390
19460
|
return [];
|
|
19391
19461
|
}
|
|
19392
|
-
const raw =
|
|
19462
|
+
const raw = fs15.readFileSync(filePath, "utf-8");
|
|
19393
19463
|
const lines = raw.split(`
|
|
19394
19464
|
`).filter((l) => l.trim().length > 0);
|
|
19395
19465
|
const records = [];
|
|
@@ -19894,7 +19964,7 @@ async function handleEvidenceCommand(directory, args) {
|
|
|
19894
19964
|
return formatTaskEvidenceMarkdown(evidenceData);
|
|
19895
19965
|
}
|
|
19896
19966
|
async function handleEvidenceSummaryCommand(directory) {
|
|
19897
|
-
const { buildEvidenceSummary } = await import("./evidence-summary-service-
|
|
19967
|
+
const { buildEvidenceSummary } = await import("./evidence-summary-service-9r28ds8t.js");
|
|
19898
19968
|
const artifact = await buildEvidenceSummary(directory);
|
|
19899
19969
|
if (!artifact) {
|
|
19900
19970
|
return "No plan found. Run `/swarm plan` to check plan status.";
|
|
@@ -19958,8 +20028,8 @@ async function handleExportCommand(directory, _args) {
|
|
|
19958
20028
|
}
|
|
19959
20029
|
// src/full-auto/state.ts
|
|
19960
20030
|
var import_proper_lockfile4 = __toESM(require_proper_lockfile(), 1);
|
|
19961
|
-
import * as
|
|
19962
|
-
import * as
|
|
20031
|
+
import * as fs16 from "fs";
|
|
20032
|
+
import * as path42 from "path";
|
|
19963
20033
|
init_logger();
|
|
19964
20034
|
var lockfile4 = import_proper_lockfile4.default;
|
|
19965
20035
|
var STATE_FILE2 = "full-auto-state.json";
|
|
@@ -19967,9 +20037,9 @@ function nowISO2() {
|
|
|
19967
20037
|
return new Date().toISOString();
|
|
19968
20038
|
}
|
|
19969
20039
|
function ensureSwarmDir(directory) {
|
|
19970
|
-
const swarmDir =
|
|
19971
|
-
if (!
|
|
19972
|
-
|
|
20040
|
+
const swarmDir = path42.resolve(directory, ".swarm");
|
|
20041
|
+
if (!fs16.existsSync(swarmDir)) {
|
|
20042
|
+
fs16.mkdirSync(swarmDir, { recursive: true });
|
|
19973
20043
|
}
|
|
19974
20044
|
return swarmDir;
|
|
19975
20045
|
}
|
|
@@ -20027,7 +20097,7 @@ function withStateLock(directory, fn) {
|
|
|
20027
20097
|
let release;
|
|
20028
20098
|
try {
|
|
20029
20099
|
const lockTarget = validateSwarmPath(directory, STATE_FILE2);
|
|
20030
|
-
if (!
|
|
20100
|
+
if (!fs16.existsSync(lockTarget)) {
|
|
20031
20101
|
ensureSwarmDir(directory);
|
|
20032
20102
|
const seed = {
|
|
20033
20103
|
version: 2,
|
|
@@ -20035,7 +20105,7 @@ function withStateLock(directory, fn) {
|
|
|
20035
20105
|
oversightSequence: 0,
|
|
20036
20106
|
sessions: {}
|
|
20037
20107
|
};
|
|
20038
|
-
|
|
20108
|
+
fs16.writeFileSync(lockTarget, `${JSON.stringify(seed, null, 2)}
|
|
20039
20109
|
`, "utf-8");
|
|
20040
20110
|
}
|
|
20041
20111
|
release = lockfile4.lockSync(lockTarget, {
|
|
@@ -20085,7 +20155,7 @@ function readPersisted(directory) {
|
|
|
20085
20155
|
const filePath = validateSwarmPath(directory, STATE_FILE2);
|
|
20086
20156
|
let stats;
|
|
20087
20157
|
try {
|
|
20088
|
-
stats =
|
|
20158
|
+
stats = fs16.statSync(filePath);
|
|
20089
20159
|
} catch {
|
|
20090
20160
|
clearStateUnreadable();
|
|
20091
20161
|
readCache.delete(filePath);
|
|
@@ -20096,7 +20166,7 @@ function readPersisted(directory) {
|
|
|
20096
20166
|
clearStateUnreadable();
|
|
20097
20167
|
return structuredClone(cached.state);
|
|
20098
20168
|
}
|
|
20099
|
-
const raw =
|
|
20169
|
+
const raw = fs16.readFileSync(filePath, "utf-8");
|
|
20100
20170
|
const parsed = JSON.parse(raw);
|
|
20101
20171
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 2 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
|
|
20102
20172
|
markStateUnreadable(`malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
|
|
@@ -20121,8 +20191,8 @@ function readPersisted(directory) {
|
|
|
20121
20191
|
error(`[full-auto/state] Failed to read ${STATE_FILE2}: ${reason} \u2014 attempting .bak recovery`);
|
|
20122
20192
|
try {
|
|
20123
20193
|
const bakPath = validateSwarmPath(directory, `${STATE_FILE2}.bak`);
|
|
20124
|
-
if (
|
|
20125
|
-
const raw =
|
|
20194
|
+
if (fs16.existsSync(bakPath)) {
|
|
20195
|
+
const raw = fs16.readFileSync(bakPath, "utf-8");
|
|
20126
20196
|
const parsed = JSON.parse(raw);
|
|
20127
20197
|
if (parsed?.version === 2 && parsed.sessions && !Array.isArray(parsed.sessions)) {
|
|
20128
20198
|
warn(`[full-auto/state] Recovered from ${STATE_FILE2}.bak`);
|
|
@@ -20162,23 +20232,23 @@ function writePersisted(directory, persisted) {
|
|
|
20162
20232
|
throw new Error(`Full-Auto state persistence prepare failed: ${msg}`);
|
|
20163
20233
|
}
|
|
20164
20234
|
try {
|
|
20165
|
-
if (
|
|
20166
|
-
|
|
20235
|
+
if (fs16.existsSync(filePath)) {
|
|
20236
|
+
fs16.copyFileSync(filePath, bakPath);
|
|
20167
20237
|
}
|
|
20168
20238
|
} catch {}
|
|
20169
20239
|
try {
|
|
20170
|
-
|
|
20240
|
+
fs16.writeFileSync(tmpPath, payload, "utf-8");
|
|
20171
20241
|
try {
|
|
20172
|
-
const fd =
|
|
20242
|
+
const fd = fs16.openSync(tmpPath, "r+");
|
|
20173
20243
|
try {
|
|
20174
|
-
|
|
20244
|
+
fs16.fsyncSync(fd);
|
|
20175
20245
|
} finally {
|
|
20176
|
-
|
|
20246
|
+
fs16.closeSync(fd);
|
|
20177
20247
|
}
|
|
20178
20248
|
} catch {}
|
|
20179
|
-
|
|
20249
|
+
fs16.renameSync(tmpPath, filePath);
|
|
20180
20250
|
readCache.delete(filePath);
|
|
20181
|
-
const readback =
|
|
20251
|
+
const readback = fs16.readFileSync(filePath, "utf-8");
|
|
20182
20252
|
const parsed = JSON.parse(readback);
|
|
20183
20253
|
if (parsed?.version !== 2) {
|
|
20184
20254
|
throw new Error("Round-trip readback returned wrong version");
|
|
@@ -20779,7 +20849,7 @@ var _internals29 = {
|
|
|
20779
20849
|
|
|
20780
20850
|
// src/session/snapshot-writer.ts
|
|
20781
20851
|
import { closeSync as closeSync6, fsyncSync as fsyncSync2, mkdirSync as mkdirSync18, openSync as openSync6, renameSync as renameSync9 } from "fs";
|
|
20782
|
-
import * as
|
|
20852
|
+
import * as path43 from "path";
|
|
20783
20853
|
var _writeInFlight = Promise.resolve();
|
|
20784
20854
|
function serializeAgentSession(s) {
|
|
20785
20855
|
const gateLog = {};
|
|
@@ -20832,6 +20902,12 @@ function serializeAgentSession(s) {
|
|
|
20832
20902
|
lastCoderDelegationTaskId: s.lastCoderDelegationTaskId ?? null,
|
|
20833
20903
|
currentTaskId: s.currentTaskId ?? null,
|
|
20834
20904
|
turboMode: s.turboMode ?? false,
|
|
20905
|
+
...s.turboStrategy !== undefined && { turboStrategy: s.turboStrategy },
|
|
20906
|
+
leanTurboActive: s.leanTurboActive ?? false,
|
|
20907
|
+
...s.leanTurboCurrentPhase !== undefined && {
|
|
20908
|
+
leanTurboCurrentPhase: s.leanTurboCurrentPhase
|
|
20909
|
+
},
|
|
20910
|
+
epicModeActive: s.epicModeActive ?? false,
|
|
20835
20911
|
gateLog,
|
|
20836
20912
|
reviewerCallCount,
|
|
20837
20913
|
lastGateFailure: s.lastGateFailure ?? null,
|
|
@@ -20886,7 +20962,7 @@ async function writeSnapshot(directory, state) {
|
|
|
20886
20962
|
}
|
|
20887
20963
|
const content = JSON.stringify(snapshot, null, 2);
|
|
20888
20964
|
const resolvedPath = validateSwarmPath(directory, "session/state.json");
|
|
20889
|
-
const dir =
|
|
20965
|
+
const dir = path43.dirname(resolvedPath);
|
|
20890
20966
|
mkdirSync18(dir, { recursive: true });
|
|
20891
20967
|
const tempPath = `${resolvedPath}.tmp.${Date.now()}.${Math.random().toString(36).slice(2)}`;
|
|
20892
20968
|
await bunWrite(tempPath, content);
|
|
@@ -20922,13 +20998,21 @@ var _internals30 = {
|
|
|
20922
20998
|
};
|
|
20923
20999
|
|
|
20924
21000
|
// src/commands/handoff.ts
|
|
20925
|
-
|
|
21001
|
+
var HANDOFF_SOURCE_SESSION_PREFIX = "<!-- opencode-swarm-handoff-source-session:";
|
|
21002
|
+
function formatSessionScopedHandoffMarkdown(markdown, sessionID) {
|
|
21003
|
+
if (!sessionID) {
|
|
21004
|
+
return markdown;
|
|
21005
|
+
}
|
|
21006
|
+
return `${HANDOFF_SOURCE_SESSION_PREFIX} ${encodeURIComponent(sessionID)} -->
|
|
21007
|
+
${markdown}`;
|
|
21008
|
+
}
|
|
21009
|
+
async function handleHandoffCommand(directory, _args, sessionID) {
|
|
20926
21010
|
const handoffData = await getHandoffData(directory);
|
|
20927
21011
|
const markdown = formatHandoffMarkdown(handoffData);
|
|
20928
21012
|
try {
|
|
20929
21013
|
const resolvedPath = validateSwarmPath(directory, "handoff.md");
|
|
20930
21014
|
const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
|
|
20931
|
-
await bunWrite(tempPath, markdown);
|
|
21015
|
+
await bunWrite(tempPath, formatSessionScopedHandoffMarkdown(markdown, sessionID));
|
|
20932
21016
|
try {
|
|
20933
21017
|
renameSync10(tempPath, resolvedPath);
|
|
20934
21018
|
} catch (renameErr) {
|
|
@@ -21389,23 +21473,23 @@ ${USAGE6}`;
|
|
|
21389
21473
|
}
|
|
21390
21474
|
|
|
21391
21475
|
// src/commands/knowledge.ts
|
|
21392
|
-
import { join as
|
|
21476
|
+
import { join as join38 } from "path";
|
|
21393
21477
|
|
|
21394
21478
|
// src/hooks/knowledge-migrator.ts
|
|
21395
21479
|
init_logger();
|
|
21396
|
-
import { randomUUID as
|
|
21397
|
-
import { existsSync as
|
|
21398
|
-
import { mkdir as mkdir10, readFile as
|
|
21480
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
21481
|
+
import { existsSync as existsSync27, readFileSync as readFileSync16 } from "fs";
|
|
21482
|
+
import { mkdir as mkdir10, readFile as readFile13, writeFile as writeFile12 } from "fs/promises";
|
|
21399
21483
|
import * as os11 from "os";
|
|
21400
|
-
import * as
|
|
21484
|
+
import * as path44 from "path";
|
|
21401
21485
|
|
|
21402
21486
|
// src/hooks/knowledge-types.ts
|
|
21403
21487
|
var KNOWLEDGE_SCHEMA_VERSION = 2;
|
|
21404
21488
|
|
|
21405
21489
|
// src/hooks/knowledge-migrator.ts
|
|
21406
21490
|
async function migrateKnowledgeToExternal(_directory, _config) {
|
|
21407
|
-
const externalSentinelPath =
|
|
21408
|
-
const contextPath =
|
|
21491
|
+
const externalSentinelPath = path44.join(_directory, ".swarm", ".knowledge-external-migrated");
|
|
21492
|
+
const contextPath = path44.join(_directory, ".swarm", "context.md");
|
|
21409
21493
|
if (_internals32.existsSync(externalSentinelPath)) {
|
|
21410
21494
|
return {
|
|
21411
21495
|
migrated: false,
|
|
@@ -21463,17 +21547,17 @@ var _internals32 = {
|
|
|
21463
21547
|
inferProjectName,
|
|
21464
21548
|
writeSentinel,
|
|
21465
21549
|
resolveLegacyHiveKnowledgePath,
|
|
21466
|
-
existsSync:
|
|
21550
|
+
existsSync: existsSync27,
|
|
21467
21551
|
readFileSync: readFileSync16,
|
|
21468
|
-
readFile:
|
|
21552
|
+
readFile: readFile13,
|
|
21469
21553
|
mkdir: mkdir10,
|
|
21470
|
-
writeFile:
|
|
21554
|
+
writeFile: writeFile12
|
|
21471
21555
|
};
|
|
21472
21556
|
async function migrateContextToKnowledge(directory, config) {
|
|
21473
|
-
const sentinelPath =
|
|
21474
|
-
const contextPath =
|
|
21557
|
+
const sentinelPath = path44.join(directory, ".swarm", ".knowledge-migrated");
|
|
21558
|
+
const contextPath = path44.join(directory, ".swarm", "context.md");
|
|
21475
21559
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
21476
|
-
if (
|
|
21560
|
+
if (existsSync27(sentinelPath)) {
|
|
21477
21561
|
return {
|
|
21478
21562
|
migrated: false,
|
|
21479
21563
|
entriesMigrated: 0,
|
|
@@ -21482,7 +21566,7 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
21482
21566
|
skippedReason: "sentinel-exists"
|
|
21483
21567
|
};
|
|
21484
21568
|
}
|
|
21485
|
-
if (!
|
|
21569
|
+
if (!existsSync27(contextPath)) {
|
|
21486
21570
|
return {
|
|
21487
21571
|
migrated: false,
|
|
21488
21572
|
entriesMigrated: 0,
|
|
@@ -21491,7 +21575,7 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
21491
21575
|
skippedReason: "no-context-file"
|
|
21492
21576
|
};
|
|
21493
21577
|
}
|
|
21494
|
-
const contextContent = await
|
|
21578
|
+
const contextContent = await readFile13(contextPath, "utf-8");
|
|
21495
21579
|
if (contextContent.trim().length === 0) {
|
|
21496
21580
|
return {
|
|
21497
21581
|
migrated: false,
|
|
@@ -21535,7 +21619,7 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
21535
21619
|
}
|
|
21536
21620
|
const inferredTags = inferTags(raw.text);
|
|
21537
21621
|
const entry = {
|
|
21538
|
-
id:
|
|
21622
|
+
id: randomUUID8(),
|
|
21539
21623
|
tier: "swarm",
|
|
21540
21624
|
lesson: _internals32.truncateLesson(raw.text),
|
|
21541
21625
|
category: raw.categoryHint ?? _internals32.inferCategoryFromText(raw.text),
|
|
@@ -21573,8 +21657,8 @@ async function migrateContextToKnowledge(directory, config) {
|
|
|
21573
21657
|
async function migrateHiveKnowledgeLegacy(config) {
|
|
21574
21658
|
const legacyHivePath = _internals32.resolveLegacyHiveKnowledgePath();
|
|
21575
21659
|
const canonicalHivePath = resolveHiveKnowledgePath();
|
|
21576
|
-
const sentinelPath =
|
|
21577
|
-
if (
|
|
21660
|
+
const sentinelPath = path44.join(path44.dirname(canonicalHivePath), ".hive-knowledge-migrated");
|
|
21661
|
+
if (existsSync27(sentinelPath)) {
|
|
21578
21662
|
return {
|
|
21579
21663
|
migrated: false,
|
|
21580
21664
|
entriesMigrated: 0,
|
|
@@ -21583,7 +21667,7 @@ async function migrateHiveKnowledgeLegacy(config) {
|
|
|
21583
21667
|
skippedReason: "sentinel-exists"
|
|
21584
21668
|
};
|
|
21585
21669
|
}
|
|
21586
|
-
if (!
|
|
21670
|
+
if (!existsSync27(legacyHivePath)) {
|
|
21587
21671
|
return {
|
|
21588
21672
|
migrated: false,
|
|
21589
21673
|
entriesMigrated: 0,
|
|
@@ -21635,7 +21719,7 @@ async function migrateHiveKnowledgeLegacy(config) {
|
|
|
21635
21719
|
const scopeTag = legacyEntry.scope_tag || "global";
|
|
21636
21720
|
const legacyId = legacyEntry.id;
|
|
21637
21721
|
const existingIds = new Set(existingHiveEntries.map((e) => e.id));
|
|
21638
|
-
const resolvedId = legacyId && existingIds.has(legacyId) ?
|
|
21722
|
+
const resolvedId = legacyId && existingIds.has(legacyId) ? randomUUID8() : legacyId || randomUUID8();
|
|
21639
21723
|
if (legacyId && existingIds.has(legacyId)) {
|
|
21640
21724
|
warn(`[knowledge-migrator] Legacy entry ID collision for "${legacyId}", generating new UUID`);
|
|
21641
21725
|
}
|
|
@@ -21784,8 +21868,8 @@ function truncateLesson2(text) {
|
|
|
21784
21868
|
return `${text.slice(0, 277)}...`;
|
|
21785
21869
|
}
|
|
21786
21870
|
function inferProjectName(directory) {
|
|
21787
|
-
const packageJsonPath =
|
|
21788
|
-
if (
|
|
21871
|
+
const packageJsonPath = path44.join(directory, "package.json");
|
|
21872
|
+
if (existsSync27(packageJsonPath)) {
|
|
21789
21873
|
try {
|
|
21790
21874
|
const pkg = JSON.parse(readFileSync16(packageJsonPath, "utf-8"));
|
|
21791
21875
|
if (pkg.name && typeof pkg.name === "string") {
|
|
@@ -21793,7 +21877,7 @@ function inferProjectName(directory) {
|
|
|
21793
21877
|
}
|
|
21794
21878
|
} catch {}
|
|
21795
21879
|
}
|
|
21796
|
-
return
|
|
21880
|
+
return path44.basename(directory);
|
|
21797
21881
|
}
|
|
21798
21882
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
21799
21883
|
const sentinel = {
|
|
@@ -21805,7 +21889,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
21805
21889
|
schema_version: 1,
|
|
21806
21890
|
migration_tool: "knowledge-migrator.ts"
|
|
21807
21891
|
};
|
|
21808
|
-
await _internals32.mkdir(
|
|
21892
|
+
await _internals32.mkdir(path44.dirname(sentinelPath), { recursive: true });
|
|
21809
21893
|
await _internals32.writeFile(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
21810
21894
|
}
|
|
21811
21895
|
function resolveLegacyHiveKnowledgePath() {
|
|
@@ -21813,13 +21897,13 @@ function resolveLegacyHiveKnowledgePath() {
|
|
|
21813
21897
|
const home = process.env.HOME || os11.homedir();
|
|
21814
21898
|
let dataDir;
|
|
21815
21899
|
if (platform === "win32") {
|
|
21816
|
-
dataDir =
|
|
21900
|
+
dataDir = path44.join(process.env.LOCALAPPDATA || path44.join(home, "AppData", "Local"), "opencode-swarm", "Data");
|
|
21817
21901
|
} else if (platform === "darwin") {
|
|
21818
|
-
dataDir =
|
|
21902
|
+
dataDir = path44.join(home, "Library", "Application Support", "opencode-swarm");
|
|
21819
21903
|
} else {
|
|
21820
|
-
dataDir =
|
|
21904
|
+
dataDir = path44.join(process.env.XDG_DATA_HOME || path44.join(home, ".local", "share"), "opencode-swarm");
|
|
21821
21905
|
}
|
|
21822
|
-
return
|
|
21906
|
+
return path44.join(dataDir, "hive-knowledge.jsonl");
|
|
21823
21907
|
}
|
|
21824
21908
|
|
|
21825
21909
|
// src/commands/knowledge.ts
|
|
@@ -21873,7 +21957,7 @@ async function handleKnowledgeRestoreCommand(directory, args) {
|
|
|
21873
21957
|
return "Invalid entry ID. IDs must be 1-64 characters: letters, digits, hyphens, underscores only.";
|
|
21874
21958
|
}
|
|
21875
21959
|
try {
|
|
21876
|
-
const quarantinePath =
|
|
21960
|
+
const quarantinePath = join38(resolveKnowledgeStoreDir(directory), "knowledge-quarantined.jsonl");
|
|
21877
21961
|
const entries = await readKnowledge(quarantinePath);
|
|
21878
21962
|
const resolved = resolveEntryByPrefix(entries, inputId);
|
|
21879
21963
|
if ("error" in resolved) {
|
|
@@ -22124,15 +22208,15 @@ var _internals33 = {
|
|
|
22124
22208
|
};
|
|
22125
22209
|
|
|
22126
22210
|
// src/commands/link.ts
|
|
22127
|
-
import { existsSync as
|
|
22128
|
-
import * as
|
|
22211
|
+
import { existsSync as existsSync28 } from "fs";
|
|
22212
|
+
import * as path46 from "path";
|
|
22129
22213
|
|
|
22130
22214
|
// src/knowledge/identity.ts
|
|
22131
22215
|
import * as child_process5 from "child_process";
|
|
22132
22216
|
import { createHash as createHash5 } from "crypto";
|
|
22133
|
-
import * as
|
|
22217
|
+
import * as path45 from "path";
|
|
22134
22218
|
function deriveProjectHash(directory) {
|
|
22135
|
-
const absolutePath =
|
|
22219
|
+
const absolutePath = path45.resolve(directory);
|
|
22136
22220
|
let hashInput;
|
|
22137
22221
|
try {
|
|
22138
22222
|
const remoteUrl = child_process5.execSync("git remote get-url origin", {
|
|
@@ -22152,9 +22236,9 @@ function deriveProjectHash(directory) {
|
|
|
22152
22236
|
// src/commands/link.ts
|
|
22153
22237
|
var DEDUP_THRESHOLD = 0.6;
|
|
22154
22238
|
async function mergeLocalKnowledgeIntoLink(localSwarmDir, linkDir) {
|
|
22155
|
-
const localPath =
|
|
22156
|
-
const sharedPath =
|
|
22157
|
-
if (!
|
|
22239
|
+
const localPath = path46.join(localSwarmDir, "knowledge.jsonl");
|
|
22240
|
+
const sharedPath = path46.join(linkDir, "knowledge.jsonl");
|
|
22241
|
+
if (!existsSync28(localPath))
|
|
22158
22242
|
return { merged: 0, skipped: 0 };
|
|
22159
22243
|
let merged = 0;
|
|
22160
22244
|
let skipped = 0;
|
|
@@ -22251,7 +22335,7 @@ ${formatStatus(directory)}`;
|
|
|
22251
22335
|
const linkDir = resolveLinkDir(linkId);
|
|
22252
22336
|
let merge;
|
|
22253
22337
|
try {
|
|
22254
|
-
merge = await mergeLocalKnowledgeIntoLink(
|
|
22338
|
+
merge = await mergeLocalKnowledgeIntoLink(path46.join(directory, ".swarm"), linkDir);
|
|
22255
22339
|
} catch (error2) {
|
|
22256
22340
|
return `\u274C Failed to merge local knowledge into the link store: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
22257
22341
|
}
|
|
@@ -22447,13 +22531,13 @@ ${USAGE7}`;
|
|
|
22447
22531
|
}
|
|
22448
22532
|
|
|
22449
22533
|
// src/commands/memory.ts
|
|
22450
|
-
import { existsSync as
|
|
22451
|
-
import * as
|
|
22534
|
+
import { existsSync as existsSync29 } from "fs";
|
|
22535
|
+
import * as path49 from "path";
|
|
22452
22536
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
22453
22537
|
// src/memory/evaluation.ts
|
|
22454
|
-
import * as
|
|
22538
|
+
import * as fs17 from "fs/promises";
|
|
22455
22539
|
import * as os12 from "os";
|
|
22456
|
-
import * as
|
|
22540
|
+
import * as path47 from "path";
|
|
22457
22541
|
var DEFAULT_PROVIDERS = [
|
|
22458
22542
|
"local-jsonl",
|
|
22459
22543
|
"sqlite"
|
|
@@ -22465,7 +22549,7 @@ var DEFAULT_MODES = [
|
|
|
22465
22549
|
];
|
|
22466
22550
|
var DEFAULT_TIMESTAMP = "2026-05-26T12:00:00.000Z";
|
|
22467
22551
|
async function evaluateMemoryRecallFixtures(options) {
|
|
22468
|
-
const fixtureDirectory =
|
|
22552
|
+
const fixtureDirectory = path47.resolve(options.fixtureDirectory);
|
|
22469
22553
|
const providers = options.providers ?? DEFAULT_PROVIDERS;
|
|
22470
22554
|
const modes = options.modes ?? DEFAULT_MODES;
|
|
22471
22555
|
const generatedAt = new Date().toISOString();
|
|
@@ -22474,7 +22558,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
22474
22558
|
for (const fixture of fixtures) {
|
|
22475
22559
|
const materialized = materializeFixture(fixture);
|
|
22476
22560
|
for (const providerName of providers) {
|
|
22477
|
-
const tempRoot = await
|
|
22561
|
+
const tempRoot = await fs17.realpath(await fs17.mkdtemp(path47.join(os12.tmpdir(), "swarm-memory-eval-")));
|
|
22478
22562
|
const provider = createEvaluationProvider(providerName, tempRoot);
|
|
22479
22563
|
try {
|
|
22480
22564
|
await provider.initialize?.();
|
|
@@ -22517,7 +22601,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
22517
22601
|
async function rmTempRoot(tempRoot) {
|
|
22518
22602
|
for (let attempt = 0;attempt < 10; attempt++) {
|
|
22519
22603
|
try {
|
|
22520
|
-
await
|
|
22604
|
+
await fs17.rm(tempRoot, { recursive: true, force: true });
|
|
22521
22605
|
return;
|
|
22522
22606
|
} catch (err) {
|
|
22523
22607
|
if (attempt === 9)
|
|
@@ -22527,11 +22611,11 @@ async function rmTempRoot(tempRoot) {
|
|
|
22527
22611
|
}
|
|
22528
22612
|
}
|
|
22529
22613
|
async function loadRecallEvaluationFixtures(fixtureDirectory) {
|
|
22530
|
-
const entries = await
|
|
22614
|
+
const entries = await fs17.readdir(fixtureDirectory, { withFileTypes: true });
|
|
22531
22615
|
const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
22532
22616
|
const fixtures = [];
|
|
22533
22617
|
for (const file of files) {
|
|
22534
|
-
const raw = await
|
|
22618
|
+
const raw = await fs17.readFile(path47.join(fixtureDirectory, file), "utf-8");
|
|
22535
22619
|
fixtures.push(validateFixture(JSON.parse(raw), file));
|
|
22536
22620
|
}
|
|
22537
22621
|
return fixtures;
|
|
@@ -22807,14 +22891,14 @@ var CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
|
22807
22891
|
curatorMemoryDecisions: exports_external.array(CuratorMemoryDecisionSchema).max(20).optional()
|
|
22808
22892
|
}).passthrough();
|
|
22809
22893
|
// src/memory/consolidation-log.ts
|
|
22810
|
-
import { appendFile as appendFile3, mkdir as mkdir11, readFile as
|
|
22811
|
-
import * as
|
|
22812
|
-
var LOG_RELATIVE_PATH =
|
|
22894
|
+
import { appendFile as appendFile3, mkdir as mkdir11, readFile as readFile15 } from "fs/promises";
|
|
22895
|
+
import * as path48 from "path";
|
|
22896
|
+
var LOG_RELATIVE_PATH = path48.join("memory", "consolidation-log.jsonl");
|
|
22813
22897
|
async function readConsolidationLog(directory) {
|
|
22814
22898
|
const filePath = validateSwarmPath(directory, LOG_RELATIVE_PATH);
|
|
22815
22899
|
let raw;
|
|
22816
22900
|
try {
|
|
22817
|
-
raw = await
|
|
22901
|
+
raw = await readFile15(filePath, "utf-8");
|
|
22818
22902
|
} catch {
|
|
22819
22903
|
return [];
|
|
22820
22904
|
}
|
|
@@ -22832,7 +22916,7 @@ async function readConsolidationLog(directory) {
|
|
|
22832
22916
|
}
|
|
22833
22917
|
|
|
22834
22918
|
// src/commands/memory.ts
|
|
22835
|
-
var PACKAGE_ROOT =
|
|
22919
|
+
var PACKAGE_ROOT = path49.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
|
|
22836
22920
|
async function handleMemoryCommand(_directory, _args) {
|
|
22837
22921
|
return [
|
|
22838
22922
|
"## Swarm Memory",
|
|
@@ -22891,7 +22975,7 @@ async function handleMemoryStatusCommand(directory, _args) {
|
|
|
22891
22975
|
`- Provider: \`${config.provider}\``,
|
|
22892
22976
|
`- Storage: \`${storageDir}\``,
|
|
22893
22977
|
`- SQLite path: \`${sqlitePath}\``,
|
|
22894
|
-
`- SQLite database exists: \`${
|
|
22978
|
+
`- SQLite database exists: \`${existsSync29(sqlitePath)}\``,
|
|
22895
22979
|
`- Automatic destructive cleanup: \`disabled\``,
|
|
22896
22980
|
"",
|
|
22897
22981
|
"### Legacy JSONL"
|
|
@@ -23189,7 +23273,7 @@ function resolveCommandMemoryConfig(directory) {
|
|
|
23189
23273
|
}
|
|
23190
23274
|
function parseEvaluateArgs(directory, args) {
|
|
23191
23275
|
let json = false;
|
|
23192
|
-
let fixtureDirectory =
|
|
23276
|
+
let fixtureDirectory = path49.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
|
|
23193
23277
|
for (let i = 0;i < args.length; i++) {
|
|
23194
23278
|
const arg = args[i];
|
|
23195
23279
|
if (arg === "--json") {
|
|
@@ -23203,10 +23287,10 @@ function parseEvaluateArgs(directory, args) {
|
|
|
23203
23287
|
error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
|
|
23204
23288
|
};
|
|
23205
23289
|
}
|
|
23206
|
-
const resolvedFixtures =
|
|
23207
|
-
const canonical =
|
|
23208
|
-
const allowedRootA =
|
|
23209
|
-
const allowedRootB =
|
|
23290
|
+
const resolvedFixtures = path49.resolve(directory, next);
|
|
23291
|
+
const canonical = path49.normalize(resolvedFixtures) + path49.sep;
|
|
23292
|
+
const allowedRootA = path49.normalize(directory) + path49.sep;
|
|
23293
|
+
const allowedRootB = path49.normalize(path49.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path49.sep;
|
|
23210
23294
|
if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
|
|
23211
23295
|
return {
|
|
23212
23296
|
error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
|
|
@@ -23245,15 +23329,15 @@ function parseMaintenanceArgs(args, options) {
|
|
|
23245
23329
|
return { limit, confirm };
|
|
23246
23330
|
}
|
|
23247
23331
|
function resolvePackageRootFromModule(modulePath) {
|
|
23248
|
-
const moduleDir =
|
|
23249
|
-
const leaf =
|
|
23332
|
+
const moduleDir = path49.dirname(modulePath);
|
|
23333
|
+
const leaf = path49.basename(moduleDir);
|
|
23250
23334
|
if (leaf === "commands" || leaf === "cli") {
|
|
23251
|
-
return
|
|
23335
|
+
return path49.resolve(moduleDir, "..", "..");
|
|
23252
23336
|
}
|
|
23253
23337
|
if (leaf === "dist") {
|
|
23254
|
-
return
|
|
23338
|
+
return path49.resolve(moduleDir, "..");
|
|
23255
23339
|
}
|
|
23256
|
-
return
|
|
23340
|
+
return path49.resolve(moduleDir, "..");
|
|
23257
23341
|
}
|
|
23258
23342
|
function formatMigrationResult(label, report) {
|
|
23259
23343
|
if (!report) {
|
|
@@ -23987,12 +24071,12 @@ var _internals39 = {
|
|
|
23987
24071
|
};
|
|
23988
24072
|
|
|
23989
24073
|
// src/services/preflight-service.ts
|
|
23990
|
-
import * as
|
|
23991
|
-
import * as
|
|
24074
|
+
import * as fs24 from "fs";
|
|
24075
|
+
import * as path56 from "path";
|
|
23992
24076
|
|
|
23993
24077
|
// src/tools/lint.ts
|
|
23994
|
-
import * as
|
|
23995
|
-
import * as
|
|
24078
|
+
import * as fs18 from "fs";
|
|
24079
|
+
import * as path50 from "path";
|
|
23996
24080
|
|
|
23997
24081
|
// src/utils/path-security.ts
|
|
23998
24082
|
function containsPathTraversal(str) {
|
|
@@ -24048,9 +24132,9 @@ function validateArgs(args) {
|
|
|
24048
24132
|
}
|
|
24049
24133
|
function getLinterCommand(linter, mode, projectDir) {
|
|
24050
24134
|
const isWindows = process.platform === "win32";
|
|
24051
|
-
const binDir =
|
|
24052
|
-
const biomeBin = isWindows ?
|
|
24053
|
-
const eslintBin = isWindows ?
|
|
24135
|
+
const binDir = path50.join(projectDir, "node_modules", ".bin");
|
|
24136
|
+
const biomeBin = isWindows ? path50.join(binDir, "biome.EXE") : path50.join(binDir, "biome");
|
|
24137
|
+
const eslintBin = isWindows ? path50.join(binDir, "eslint.cmd") : path50.join(binDir, "eslint");
|
|
24054
24138
|
switch (linter) {
|
|
24055
24139
|
case "biome":
|
|
24056
24140
|
if (mode === "fix") {
|
|
@@ -24066,7 +24150,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
24066
24150
|
}
|
|
24067
24151
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
24068
24152
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
24069
|
-
const gradlew =
|
|
24153
|
+
const gradlew = fs18.existsSync(path50.join(cwd, gradlewName)) ? path50.join(cwd, gradlewName) : null;
|
|
24070
24154
|
switch (linter) {
|
|
24071
24155
|
case "ruff":
|
|
24072
24156
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -24100,12 +24184,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
24100
24184
|
}
|
|
24101
24185
|
}
|
|
24102
24186
|
function detectRuff(cwd) {
|
|
24103
|
-
if (
|
|
24187
|
+
if (fs18.existsSync(path50.join(cwd, "ruff.toml")))
|
|
24104
24188
|
return isCommandAvailable("ruff");
|
|
24105
24189
|
try {
|
|
24106
|
-
const pyproject =
|
|
24107
|
-
if (
|
|
24108
|
-
const content =
|
|
24190
|
+
const pyproject = path50.join(cwd, "pyproject.toml");
|
|
24191
|
+
if (fs18.existsSync(pyproject)) {
|
|
24192
|
+
const content = fs18.readFileSync(pyproject, "utf-8");
|
|
24109
24193
|
if (content.includes("[tool.ruff]"))
|
|
24110
24194
|
return isCommandAvailable("ruff");
|
|
24111
24195
|
}
|
|
@@ -24113,21 +24197,21 @@ function detectRuff(cwd) {
|
|
|
24113
24197
|
return false;
|
|
24114
24198
|
}
|
|
24115
24199
|
function detectClippy(cwd) {
|
|
24116
|
-
return
|
|
24200
|
+
return fs18.existsSync(path50.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
24117
24201
|
}
|
|
24118
24202
|
function detectGolangciLint(cwd) {
|
|
24119
|
-
return
|
|
24203
|
+
return fs18.existsSync(path50.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
24120
24204
|
}
|
|
24121
24205
|
function detectCheckstyle(cwd) {
|
|
24122
|
-
const hasMaven =
|
|
24123
|
-
const hasGradle =
|
|
24124
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (
|
|
24206
|
+
const hasMaven = fs18.existsSync(path50.join(cwd, "pom.xml"));
|
|
24207
|
+
const hasGradle = fs18.existsSync(path50.join(cwd, "build.gradle")) || fs18.existsSync(path50.join(cwd, "build.gradle.kts"));
|
|
24208
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(path50.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
24125
24209
|
return (hasMaven || hasGradle) && hasBinary;
|
|
24126
24210
|
}
|
|
24127
24211
|
function detectKtlint(cwd) {
|
|
24128
|
-
const hasKotlin =
|
|
24212
|
+
const hasKotlin = fs18.existsSync(path50.join(cwd, "build.gradle.kts")) || fs18.existsSync(path50.join(cwd, "build.gradle")) || (() => {
|
|
24129
24213
|
try {
|
|
24130
|
-
return
|
|
24214
|
+
return fs18.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
24131
24215
|
} catch {
|
|
24132
24216
|
return false;
|
|
24133
24217
|
}
|
|
@@ -24136,7 +24220,7 @@ function detectKtlint(cwd) {
|
|
|
24136
24220
|
}
|
|
24137
24221
|
function detectDotnetFormat(cwd) {
|
|
24138
24222
|
try {
|
|
24139
|
-
const files =
|
|
24223
|
+
const files = fs18.readdirSync(cwd);
|
|
24140
24224
|
const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
|
|
24141
24225
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
24142
24226
|
} catch {
|
|
@@ -24144,14 +24228,14 @@ function detectDotnetFormat(cwd) {
|
|
|
24144
24228
|
}
|
|
24145
24229
|
}
|
|
24146
24230
|
function detectCppcheck(cwd) {
|
|
24147
|
-
if (
|
|
24231
|
+
if (fs18.existsSync(path50.join(cwd, "CMakeLists.txt"))) {
|
|
24148
24232
|
return isCommandAvailable("cppcheck");
|
|
24149
24233
|
}
|
|
24150
24234
|
try {
|
|
24151
|
-
const dirsToCheck = [cwd,
|
|
24235
|
+
const dirsToCheck = [cwd, path50.join(cwd, "src")];
|
|
24152
24236
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
24153
24237
|
try {
|
|
24154
|
-
return
|
|
24238
|
+
return fs18.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
24155
24239
|
} catch {
|
|
24156
24240
|
return false;
|
|
24157
24241
|
}
|
|
@@ -24162,13 +24246,13 @@ function detectCppcheck(cwd) {
|
|
|
24162
24246
|
}
|
|
24163
24247
|
}
|
|
24164
24248
|
function detectSwiftlint(cwd) {
|
|
24165
|
-
return
|
|
24249
|
+
return fs18.existsSync(path50.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
24166
24250
|
}
|
|
24167
24251
|
function detectDartAnalyze(cwd) {
|
|
24168
|
-
return
|
|
24252
|
+
return fs18.existsSync(path50.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
24169
24253
|
}
|
|
24170
24254
|
function detectRubocop(cwd) {
|
|
24171
|
-
return (
|
|
24255
|
+
return (fs18.existsSync(path50.join(cwd, "Gemfile")) || fs18.existsSync(path50.join(cwd, "gems.rb")) || fs18.existsSync(path50.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
24172
24256
|
}
|
|
24173
24257
|
function detectAdditionalLinter(cwd) {
|
|
24174
24258
|
if (detectRuff(cwd))
|
|
@@ -24196,10 +24280,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
24196
24280
|
function findBinInAncestors(startDir, binName) {
|
|
24197
24281
|
let dir = startDir;
|
|
24198
24282
|
while (true) {
|
|
24199
|
-
const candidate =
|
|
24200
|
-
if (
|
|
24283
|
+
const candidate = path50.join(dir, "node_modules", ".bin", binName);
|
|
24284
|
+
if (fs18.existsSync(candidate))
|
|
24201
24285
|
return candidate;
|
|
24202
|
-
const parent =
|
|
24286
|
+
const parent = path50.dirname(dir);
|
|
24203
24287
|
if (parent === dir)
|
|
24204
24288
|
break;
|
|
24205
24289
|
dir = parent;
|
|
@@ -24208,11 +24292,11 @@ function findBinInAncestors(startDir, binName) {
|
|
|
24208
24292
|
}
|
|
24209
24293
|
function findBinInEnvPath(binName) {
|
|
24210
24294
|
const searchPath = process.env.PATH ?? "";
|
|
24211
|
-
for (const dir of searchPath.split(
|
|
24295
|
+
for (const dir of searchPath.split(path50.delimiter)) {
|
|
24212
24296
|
if (!dir)
|
|
24213
24297
|
continue;
|
|
24214
|
-
const candidate =
|
|
24215
|
-
if (
|
|
24298
|
+
const candidate = path50.join(dir, binName);
|
|
24299
|
+
if (fs18.existsSync(candidate))
|
|
24216
24300
|
return candidate;
|
|
24217
24301
|
}
|
|
24218
24302
|
return null;
|
|
@@ -24220,17 +24304,17 @@ function findBinInEnvPath(binName) {
|
|
|
24220
24304
|
async function detectAvailableLinter(directory) {
|
|
24221
24305
|
if (!directory)
|
|
24222
24306
|
return null;
|
|
24223
|
-
if (!
|
|
24307
|
+
if (!fs18.existsSync(directory))
|
|
24224
24308
|
return null;
|
|
24225
24309
|
const projectDir = directory;
|
|
24226
24310
|
const isWindows = process.platform === "win32";
|
|
24227
|
-
const biomeBin = isWindows ?
|
|
24228
|
-
const eslintBin = isWindows ?
|
|
24311
|
+
const biomeBin = isWindows ? path50.join(projectDir, "node_modules", ".bin", "biome.EXE") : path50.join(projectDir, "node_modules", ".bin", "biome");
|
|
24312
|
+
const eslintBin = isWindows ? path50.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path50.join(projectDir, "node_modules", ".bin", "eslint");
|
|
24229
24313
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
24230
24314
|
if (localResult)
|
|
24231
24315
|
return localResult;
|
|
24232
|
-
const biomeAncestor = findBinInAncestors(
|
|
24233
|
-
const eslintAncestor = findBinInAncestors(
|
|
24316
|
+
const biomeAncestor = findBinInAncestors(path50.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
24317
|
+
const eslintAncestor = findBinInAncestors(path50.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
24234
24318
|
if (biomeAncestor || eslintAncestor) {
|
|
24235
24319
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
24236
24320
|
}
|
|
@@ -24253,7 +24337,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
24253
24337
|
const result = await Promise.race([biomeExit, timeout]);
|
|
24254
24338
|
if (result === "timeout") {
|
|
24255
24339
|
biomeProc.kill();
|
|
24256
|
-
} else if (biomeProc.exitCode === 0 &&
|
|
24340
|
+
} else if (biomeProc.exitCode === 0 && fs18.existsSync(biomeBin)) {
|
|
24257
24341
|
return "biome";
|
|
24258
24342
|
}
|
|
24259
24343
|
} catch {}
|
|
@@ -24267,7 +24351,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
24267
24351
|
const result = await Promise.race([eslintExit, timeout]);
|
|
24268
24352
|
if (result === "timeout") {
|
|
24269
24353
|
eslintProc.kill();
|
|
24270
|
-
} else if (eslintProc.exitCode === 0 &&
|
|
24354
|
+
} else if (eslintProc.exitCode === 0 && fs18.existsSync(eslintBin)) {
|
|
24271
24355
|
return "eslint";
|
|
24272
24356
|
}
|
|
24273
24357
|
} catch {}
|
|
@@ -24443,8 +24527,8 @@ var _internals40 = {
|
|
|
24443
24527
|
};
|
|
24444
24528
|
|
|
24445
24529
|
// src/tools/secretscan.ts
|
|
24446
|
-
import * as
|
|
24447
|
-
import * as
|
|
24530
|
+
import * as fs19 from "fs";
|
|
24531
|
+
import * as path51 from "path";
|
|
24448
24532
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
24449
24533
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
24450
24534
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -24671,11 +24755,11 @@ function isGlobOrPathPattern(pattern) {
|
|
|
24671
24755
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
24672
24756
|
}
|
|
24673
24757
|
function loadSecretScanIgnore(scanDir) {
|
|
24674
|
-
const ignorePath =
|
|
24758
|
+
const ignorePath = path51.join(scanDir, ".secretscanignore");
|
|
24675
24759
|
try {
|
|
24676
|
-
if (!
|
|
24760
|
+
if (!fs19.existsSync(ignorePath))
|
|
24677
24761
|
return [];
|
|
24678
|
-
const content =
|
|
24762
|
+
const content = fs19.readFileSync(ignorePath, "utf8");
|
|
24679
24763
|
const patterns = [];
|
|
24680
24764
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
24681
24765
|
const line = rawLine.trim();
|
|
@@ -24694,7 +24778,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
24694
24778
|
if (exactNames.has(entry))
|
|
24695
24779
|
return true;
|
|
24696
24780
|
for (const pattern of globPatterns) {
|
|
24697
|
-
if (
|
|
24781
|
+
if (path51.matchesGlob(relPath, pattern))
|
|
24698
24782
|
return true;
|
|
24699
24783
|
}
|
|
24700
24784
|
return false;
|
|
@@ -24715,7 +24799,7 @@ function validateDirectoryInput(dir) {
|
|
|
24715
24799
|
return null;
|
|
24716
24800
|
}
|
|
24717
24801
|
function isBinaryFile(filePath, buffer) {
|
|
24718
|
-
const ext =
|
|
24802
|
+
const ext = path51.extname(filePath).toLowerCase();
|
|
24719
24803
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
24720
24804
|
return true;
|
|
24721
24805
|
}
|
|
@@ -24790,11 +24874,11 @@ function createRedactedContext(line, findings) {
|
|
|
24790
24874
|
result += line.slice(lastEnd);
|
|
24791
24875
|
return result;
|
|
24792
24876
|
}
|
|
24793
|
-
var O_NOFOLLOW = process.platform !== "win32" ?
|
|
24877
|
+
var O_NOFOLLOW = process.platform !== "win32" ? fs19.constants.O_NOFOLLOW : undefined;
|
|
24794
24878
|
function scanFileForSecrets(filePath) {
|
|
24795
24879
|
const findings = [];
|
|
24796
24880
|
try {
|
|
24797
|
-
const lstat2 =
|
|
24881
|
+
const lstat2 = fs19.lstatSync(filePath);
|
|
24798
24882
|
if (lstat2.isSymbolicLink()) {
|
|
24799
24883
|
return findings;
|
|
24800
24884
|
}
|
|
@@ -24803,14 +24887,14 @@ function scanFileForSecrets(filePath) {
|
|
|
24803
24887
|
}
|
|
24804
24888
|
let buffer;
|
|
24805
24889
|
if (O_NOFOLLOW !== undefined) {
|
|
24806
|
-
const fd =
|
|
24890
|
+
const fd = fs19.openSync(filePath, "r", O_NOFOLLOW);
|
|
24807
24891
|
try {
|
|
24808
|
-
buffer =
|
|
24892
|
+
buffer = fs19.readFileSync(fd);
|
|
24809
24893
|
} finally {
|
|
24810
|
-
|
|
24894
|
+
fs19.closeSync(fd);
|
|
24811
24895
|
}
|
|
24812
24896
|
} else {
|
|
24813
|
-
buffer =
|
|
24897
|
+
buffer = fs19.readFileSync(filePath);
|
|
24814
24898
|
}
|
|
24815
24899
|
if (isBinaryFile(filePath, buffer)) {
|
|
24816
24900
|
return findings;
|
|
@@ -24852,9 +24936,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
24852
24936
|
return false;
|
|
24853
24937
|
}
|
|
24854
24938
|
function isPathWithinScope(realPath, scanDir) {
|
|
24855
|
-
const resolvedScanDir =
|
|
24856
|
-
const resolvedRealPath =
|
|
24857
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
24939
|
+
const resolvedScanDir = path51.resolve(scanDir);
|
|
24940
|
+
const resolvedRealPath = path51.resolve(realPath);
|
|
24941
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path51.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
24858
24942
|
}
|
|
24859
24943
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
24860
24944
|
skippedDirs: 0,
|
|
@@ -24865,7 +24949,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
24865
24949
|
const files = [];
|
|
24866
24950
|
let entries;
|
|
24867
24951
|
try {
|
|
24868
|
-
entries =
|
|
24952
|
+
entries = fs19.readdirSync(dir);
|
|
24869
24953
|
} catch {
|
|
24870
24954
|
stats.fileErrors++;
|
|
24871
24955
|
return files;
|
|
@@ -24880,15 +24964,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
24880
24964
|
return a.localeCompare(b);
|
|
24881
24965
|
});
|
|
24882
24966
|
for (const entry of entries) {
|
|
24883
|
-
const fullPath =
|
|
24884
|
-
const relPath =
|
|
24967
|
+
const fullPath = path51.join(dir, entry);
|
|
24968
|
+
const relPath = path51.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
24885
24969
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
24886
24970
|
stats.skippedDirs++;
|
|
24887
24971
|
continue;
|
|
24888
24972
|
}
|
|
24889
24973
|
let lstat2;
|
|
24890
24974
|
try {
|
|
24891
|
-
lstat2 =
|
|
24975
|
+
lstat2 = fs19.lstatSync(fullPath);
|
|
24892
24976
|
} catch {
|
|
24893
24977
|
stats.fileErrors++;
|
|
24894
24978
|
continue;
|
|
@@ -24900,7 +24984,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
24900
24984
|
if (lstat2.isDirectory()) {
|
|
24901
24985
|
let realPath;
|
|
24902
24986
|
try {
|
|
24903
|
-
realPath =
|
|
24987
|
+
realPath = fs19.realpathSync(fullPath);
|
|
24904
24988
|
} catch {
|
|
24905
24989
|
stats.fileErrors++;
|
|
24906
24990
|
continue;
|
|
@@ -24916,7 +25000,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
24916
25000
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
24917
25001
|
files.push(...subFiles);
|
|
24918
25002
|
} else if (lstat2.isFile()) {
|
|
24919
|
-
const ext =
|
|
25003
|
+
const ext = path51.extname(fullPath).toLowerCase();
|
|
24920
25004
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
24921
25005
|
files.push(fullPath);
|
|
24922
25006
|
} else {
|
|
@@ -24982,15 +25066,15 @@ var secretscan = createSwarmTool({
|
|
|
24982
25066
|
}
|
|
24983
25067
|
}
|
|
24984
25068
|
try {
|
|
24985
|
-
const _scanDirRaw =
|
|
25069
|
+
const _scanDirRaw = path51.resolve(directory);
|
|
24986
25070
|
const scanDir = (() => {
|
|
24987
25071
|
try {
|
|
24988
|
-
return
|
|
25072
|
+
return fs19.realpathSync(_scanDirRaw);
|
|
24989
25073
|
} catch {
|
|
24990
25074
|
return _scanDirRaw;
|
|
24991
25075
|
}
|
|
24992
25076
|
})();
|
|
24993
|
-
if (!
|
|
25077
|
+
if (!fs19.existsSync(scanDir)) {
|
|
24994
25078
|
const errorResult = {
|
|
24995
25079
|
error: "directory not found",
|
|
24996
25080
|
scan_dir: directory,
|
|
@@ -25001,7 +25085,7 @@ var secretscan = createSwarmTool({
|
|
|
25001
25085
|
};
|
|
25002
25086
|
return JSON.stringify(errorResult, null, 2);
|
|
25003
25087
|
}
|
|
25004
|
-
const dirStat =
|
|
25088
|
+
const dirStat = fs19.statSync(scanDir);
|
|
25005
25089
|
if (!dirStat.isDirectory()) {
|
|
25006
25090
|
const errorResult = {
|
|
25007
25091
|
error: "target must be a directory, not a file",
|
|
@@ -25052,7 +25136,7 @@ var secretscan = createSwarmTool({
|
|
|
25052
25136
|
break;
|
|
25053
25137
|
const fileFindings = scanFileForSecrets(filePath);
|
|
25054
25138
|
try {
|
|
25055
|
-
const stat5 =
|
|
25139
|
+
const stat5 = fs19.statSync(filePath);
|
|
25056
25140
|
if (stat5.size > MAX_FILE_SIZE_BYTES) {
|
|
25057
25141
|
skippedFiles++;
|
|
25058
25142
|
continue;
|
|
@@ -25144,12 +25228,12 @@ var _internals41 = {
|
|
|
25144
25228
|
};
|
|
25145
25229
|
|
|
25146
25230
|
// src/tools/test-runner.ts
|
|
25147
|
-
import * as
|
|
25148
|
-
import * as
|
|
25231
|
+
import * as fs23 from "fs";
|
|
25232
|
+
import * as path55 from "path";
|
|
25149
25233
|
|
|
25150
25234
|
// src/test-impact/analyzer.ts
|
|
25151
|
-
import
|
|
25152
|
-
import
|
|
25235
|
+
import fs20 from "fs";
|
|
25236
|
+
import path52 from "path";
|
|
25153
25237
|
var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
25154
25238
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
25155
25239
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -25176,7 +25260,7 @@ function sharedTrailingSegments(a, b) {
|
|
|
25176
25260
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
25177
25261
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
25178
25262
|
try {
|
|
25179
|
-
const stat5 =
|
|
25263
|
+
const stat5 = fs20.statSync(sourcePath);
|
|
25180
25264
|
if (stat5.mtimeMs > generatedAtMs) {
|
|
25181
25265
|
return true;
|
|
25182
25266
|
}
|
|
@@ -25190,15 +25274,15 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
25190
25274
|
if (!importPath.startsWith(".")) {
|
|
25191
25275
|
return null;
|
|
25192
25276
|
}
|
|
25193
|
-
const resolved =
|
|
25194
|
-
if (
|
|
25195
|
-
if (
|
|
25277
|
+
const resolved = path52.resolve(fromDir, importPath);
|
|
25278
|
+
if (path52.extname(resolved)) {
|
|
25279
|
+
if (fs20.existsSync(resolved) && fs20.statSync(resolved).isFile()) {
|
|
25196
25280
|
return normalizePath2(resolved);
|
|
25197
25281
|
}
|
|
25198
25282
|
} else {
|
|
25199
25283
|
for (const ext of EXTENSIONS_TO_TRY) {
|
|
25200
25284
|
const withExt = resolved + ext;
|
|
25201
|
-
if (
|
|
25285
|
+
if (fs20.existsSync(withExt) && fs20.statSync(withExt).isFile()) {
|
|
25202
25286
|
return normalizePath2(withExt);
|
|
25203
25287
|
}
|
|
25204
25288
|
}
|
|
@@ -25211,30 +25295,30 @@ function resolvePythonImport(fromDir, module) {
|
|
|
25211
25295
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
25212
25296
|
let baseDir = fromDir;
|
|
25213
25297
|
for (let i = 1;i < leadingDots; i++) {
|
|
25214
|
-
baseDir =
|
|
25298
|
+
baseDir = path52.dirname(baseDir);
|
|
25215
25299
|
}
|
|
25216
25300
|
const rest = module.slice(leadingDots);
|
|
25217
25301
|
if (rest.length === 0) {
|
|
25218
|
-
const initPath =
|
|
25219
|
-
if (
|
|
25302
|
+
const initPath = path52.join(baseDir, "__init__.py");
|
|
25303
|
+
if (fs20.existsSync(initPath) && fs20.statSync(initPath).isFile()) {
|
|
25220
25304
|
return normalizePath2(initPath);
|
|
25221
25305
|
}
|
|
25222
25306
|
return null;
|
|
25223
25307
|
}
|
|
25224
|
-
const subpath = rest.replace(/\./g,
|
|
25308
|
+
const subpath = rest.replace(/\./g, path52.sep);
|
|
25225
25309
|
const candidates = [
|
|
25226
|
-
`${
|
|
25227
|
-
|
|
25310
|
+
`${path52.join(baseDir, subpath)}.py`,
|
|
25311
|
+
path52.join(baseDir, subpath, "__init__.py")
|
|
25228
25312
|
];
|
|
25229
25313
|
for (const c of candidates) {
|
|
25230
|
-
if (
|
|
25314
|
+
if (fs20.existsSync(c) && fs20.statSync(c).isFile())
|
|
25231
25315
|
return normalizePath2(c);
|
|
25232
25316
|
}
|
|
25233
25317
|
return null;
|
|
25234
25318
|
}
|
|
25235
25319
|
var goModuleCache = new Map;
|
|
25236
25320
|
function findGoModule(fromDir) {
|
|
25237
|
-
const resolved =
|
|
25321
|
+
const resolved = path52.resolve(fromDir);
|
|
25238
25322
|
let cur = resolved;
|
|
25239
25323
|
const walked = [];
|
|
25240
25324
|
for (let i = 0;i < 16; i++) {
|
|
@@ -25246,8 +25330,8 @@ function findGoModule(fromDir) {
|
|
|
25246
25330
|
}
|
|
25247
25331
|
walked.push(cur);
|
|
25248
25332
|
try {
|
|
25249
|
-
const goMod =
|
|
25250
|
-
const content =
|
|
25333
|
+
const goMod = path52.join(cur, "go.mod");
|
|
25334
|
+
const content = fs20.readFileSync(goMod, "utf-8");
|
|
25251
25335
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
25252
25336
|
if (moduleMatch) {
|
|
25253
25337
|
const result = { moduleRoot: cur, modulePath: moduleMatch[1] };
|
|
@@ -25257,10 +25341,10 @@ function findGoModule(fromDir) {
|
|
|
25257
25341
|
}
|
|
25258
25342
|
} catch {}
|
|
25259
25343
|
try {
|
|
25260
|
-
|
|
25344
|
+
fs20.accessSync(path52.join(cur, ".git"));
|
|
25261
25345
|
break;
|
|
25262
25346
|
} catch {}
|
|
25263
|
-
const parent =
|
|
25347
|
+
const parent = path52.dirname(cur);
|
|
25264
25348
|
if (parent === cur)
|
|
25265
25349
|
break;
|
|
25266
25350
|
cur = parent;
|
|
@@ -25272,20 +25356,20 @@ function findGoModule(fromDir) {
|
|
|
25272
25356
|
function resolveGoImport(fromDir, importPath) {
|
|
25273
25357
|
let dir = null;
|
|
25274
25358
|
if (importPath.startsWith(".")) {
|
|
25275
|
-
dir =
|
|
25359
|
+
dir = path52.resolve(fromDir, importPath);
|
|
25276
25360
|
} else {
|
|
25277
25361
|
const mod = findGoModule(fromDir);
|
|
25278
25362
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
25279
25363
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
25280
|
-
dir =
|
|
25364
|
+
dir = path52.join(mod.moduleRoot, subpath);
|
|
25281
25365
|
}
|
|
25282
25366
|
}
|
|
25283
25367
|
if (dir === null)
|
|
25284
25368
|
return [];
|
|
25285
|
-
if (!
|
|
25369
|
+
if (!fs20.existsSync(dir) || !fs20.statSync(dir).isDirectory())
|
|
25286
25370
|
return [];
|
|
25287
25371
|
try {
|
|
25288
|
-
return
|
|
25372
|
+
return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path52.join(dir, f)));
|
|
25289
25373
|
} catch {
|
|
25290
25374
|
return [];
|
|
25291
25375
|
}
|
|
@@ -25305,13 +25389,13 @@ function findTestFilesSync(cwd) {
|
|
|
25305
25389
|
function walk(dir, visitedInodes) {
|
|
25306
25390
|
let entries;
|
|
25307
25391
|
try {
|
|
25308
|
-
entries =
|
|
25392
|
+
entries = fs20.readdirSync(dir, { withFileTypes: true });
|
|
25309
25393
|
} catch {
|
|
25310
25394
|
return;
|
|
25311
25395
|
}
|
|
25312
25396
|
let dirInode;
|
|
25313
25397
|
try {
|
|
25314
|
-
dirInode =
|
|
25398
|
+
dirInode = fs20.statSync(dir).ino;
|
|
25315
25399
|
} catch {
|
|
25316
25400
|
return;
|
|
25317
25401
|
}
|
|
@@ -25324,15 +25408,15 @@ function findTestFilesSync(cwd) {
|
|
|
25324
25408
|
for (const entry of entries) {
|
|
25325
25409
|
if (entry.isDirectory()) {
|
|
25326
25410
|
if (!skipDirs.has(entry.name)) {
|
|
25327
|
-
walk(
|
|
25411
|
+
walk(path52.join(dir, entry.name), visitedInodes);
|
|
25328
25412
|
}
|
|
25329
25413
|
} else if (entry.isFile()) {
|
|
25330
25414
|
const name = entry.name;
|
|
25331
25415
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
25332
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
25416
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path52.sep}tests${path52.sep}`) && name.endsWith(".py");
|
|
25333
25417
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
25334
25418
|
if (isTsTest || isPyTest || isGoTest) {
|
|
25335
|
-
testFiles.push(normalizePath2(
|
|
25419
|
+
testFiles.push(normalizePath2(path52.join(dir, entry.name)));
|
|
25336
25420
|
}
|
|
25337
25421
|
}
|
|
25338
25422
|
}
|
|
@@ -25357,8 +25441,8 @@ function extractImports(content) {
|
|
|
25357
25441
|
];
|
|
25358
25442
|
}
|
|
25359
25443
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
25360
|
-
const ext =
|
|
25361
|
-
const testDir =
|
|
25444
|
+
const ext = path52.extname(testFile).toLowerCase();
|
|
25445
|
+
const testDir = path52.dirname(testFile);
|
|
25362
25446
|
function addEdge(source) {
|
|
25363
25447
|
if (!impactMap[source])
|
|
25364
25448
|
impactMap[source] = [];
|
|
@@ -25395,12 +25479,13 @@ function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
|
25395
25479
|
}
|
|
25396
25480
|
}
|
|
25397
25481
|
async function buildImpactMapInternal(cwd) {
|
|
25482
|
+
_clearGoModuleCache();
|
|
25398
25483
|
const testFiles = findTestFilesSync(cwd);
|
|
25399
25484
|
const impactMap = {};
|
|
25400
25485
|
for (const testFile of testFiles) {
|
|
25401
25486
|
let content;
|
|
25402
25487
|
try {
|
|
25403
|
-
content =
|
|
25488
|
+
content = fs20.readFileSync(testFile, "utf-8");
|
|
25404
25489
|
} catch {
|
|
25405
25490
|
continue;
|
|
25406
25491
|
}
|
|
@@ -25431,10 +25516,10 @@ async function buildImpactMap(cwd) {
|
|
|
25431
25516
|
return impactMap;
|
|
25432
25517
|
}
|
|
25433
25518
|
async function loadImpactMap(cwd, options) {
|
|
25434
|
-
const cachePath =
|
|
25435
|
-
if (
|
|
25519
|
+
const cachePath = path52.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
25520
|
+
if (fs20.existsSync(cachePath)) {
|
|
25436
25521
|
try {
|
|
25437
|
-
const content =
|
|
25522
|
+
const content = fs20.readFileSync(cachePath, "utf-8");
|
|
25438
25523
|
const data = JSON.parse(content);
|
|
25439
25524
|
if (data.map !== null && typeof data.map === "object" && !Array.isArray(data.map)) {
|
|
25440
25525
|
const map = data.map;
|
|
@@ -25464,21 +25549,21 @@ async function loadImpactMap(cwd, options) {
|
|
|
25464
25549
|
return _internals42.buildImpactMap(cwd);
|
|
25465
25550
|
}
|
|
25466
25551
|
async function saveImpactMap(cwd, impactMap) {
|
|
25467
|
-
if (!
|
|
25552
|
+
if (!path52.isAbsolute(cwd)) {
|
|
25468
25553
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
25469
25554
|
}
|
|
25470
25555
|
_internals42.validateProjectRoot(cwd);
|
|
25471
|
-
const cacheDir2 =
|
|
25472
|
-
const cachePath =
|
|
25473
|
-
if (!
|
|
25474
|
-
|
|
25556
|
+
const cacheDir2 = path52.join(cwd, ".swarm", "cache");
|
|
25557
|
+
const cachePath = path52.join(cacheDir2, "impact-map.json");
|
|
25558
|
+
if (!fs20.existsSync(cacheDir2)) {
|
|
25559
|
+
fs20.mkdirSync(cacheDir2, { recursive: true });
|
|
25475
25560
|
}
|
|
25476
25561
|
const data = {
|
|
25477
25562
|
generatedAt: new Date().toISOString(),
|
|
25478
25563
|
fileCount: Object.keys(impactMap).length,
|
|
25479
25564
|
map: impactMap
|
|
25480
25565
|
};
|
|
25481
|
-
|
|
25566
|
+
fs20.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
25482
25567
|
}
|
|
25483
25568
|
async function analyzeImpact(changedFiles, cwd, budget) {
|
|
25484
25569
|
if (!Array.isArray(changedFiles)) {
|
|
@@ -25501,7 +25586,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
25501
25586
|
budgetExceeded = true;
|
|
25502
25587
|
break;
|
|
25503
25588
|
}
|
|
25504
|
-
const normalizedChanged = normalizePath2(
|
|
25589
|
+
const normalizedChanged = normalizePath2(path52.resolve(changedFile));
|
|
25505
25590
|
const tests = impactMap[normalizedChanged];
|
|
25506
25591
|
if (tests && tests.length > 0) {
|
|
25507
25592
|
for (const test of tests) {
|
|
@@ -25515,13 +25600,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
25515
25600
|
if (budgetExceeded)
|
|
25516
25601
|
break;
|
|
25517
25602
|
} else {
|
|
25518
|
-
const changedDir = normalizePath2(
|
|
25519
|
-
const changedInputDir = normalizePath2(
|
|
25603
|
+
const changedDir = normalizePath2(path52.dirname(normalizedChanged));
|
|
25604
|
+
const changedInputDir = normalizePath2(path52.dirname(changedFile));
|
|
25520
25605
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
25521
25606
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
25522
25607
|
}).sort(([sourceA], [sourceB]) => {
|
|
25523
|
-
const sourceDirA = normalizePath2(
|
|
25524
|
-
const sourceDirB = normalizePath2(
|
|
25608
|
+
const sourceDirA = normalizePath2(path52.dirname(sourceA));
|
|
25609
|
+
const sourceDirB = normalizePath2(path52.dirname(sourceB));
|
|
25525
25610
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
25526
25611
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
25527
25612
|
if (exactA !== exactB)
|
|
@@ -25847,8 +25932,8 @@ function detectFlakyTests(allHistory) {
|
|
|
25847
25932
|
}
|
|
25848
25933
|
|
|
25849
25934
|
// src/test-impact/history-store.ts
|
|
25850
|
-
import
|
|
25851
|
-
import
|
|
25935
|
+
import fs21 from "fs";
|
|
25936
|
+
import path53 from "path";
|
|
25852
25937
|
var MAX_HISTORY_PER_TEST = 20;
|
|
25853
25938
|
var MAX_ERROR_LENGTH = 500;
|
|
25854
25939
|
var MAX_STACK_LENGTH = 200;
|
|
@@ -25860,10 +25945,10 @@ function getHistoryPath(workingDir) {
|
|
|
25860
25945
|
if (!workingDir) {
|
|
25861
25946
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
25862
25947
|
}
|
|
25863
|
-
if (!
|
|
25948
|
+
if (!path53.isAbsolute(workingDir)) {
|
|
25864
25949
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
25865
25950
|
}
|
|
25866
|
-
return
|
|
25951
|
+
return path53.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
25867
25952
|
}
|
|
25868
25953
|
function sanitizeErrorMessage(errorMessage) {
|
|
25869
25954
|
if (errorMessage === undefined) {
|
|
@@ -25955,10 +26040,10 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
25955
26040
|
}
|
|
25956
26041
|
}
|
|
25957
26042
|
const historyPath = getHistoryPath(workingDir);
|
|
25958
|
-
const historyDir =
|
|
26043
|
+
const historyDir = path53.dirname(historyPath);
|
|
25959
26044
|
_internals43.validateProjectRoot(workingDir);
|
|
25960
|
-
if (!
|
|
25961
|
-
|
|
26045
|
+
if (!fs21.existsSync(historyDir)) {
|
|
26046
|
+
fs21.mkdirSync(historyDir, { recursive: true });
|
|
25962
26047
|
}
|
|
25963
26048
|
withHistoryWriteLock(historyPath, () => {
|
|
25964
26049
|
const existingRecords = readAllRecords(historyPath);
|
|
@@ -25992,13 +26077,13 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
25992
26077
|
`)}
|
|
25993
26078
|
`;
|
|
25994
26079
|
const tempPath = `${historyPath}.tmp`;
|
|
25995
|
-
|
|
25996
|
-
|
|
26080
|
+
fs21.writeFileSync(tempPath, content, "utf-8");
|
|
26081
|
+
fs21.renameSync(tempPath, historyPath);
|
|
25997
26082
|
} catch (err) {
|
|
25998
26083
|
try {
|
|
25999
26084
|
const tempPath = `${historyPath}.tmp`;
|
|
26000
|
-
if (
|
|
26001
|
-
|
|
26085
|
+
if (fs21.existsSync(tempPath)) {
|
|
26086
|
+
fs21.unlinkSync(tempPath);
|
|
26002
26087
|
}
|
|
26003
26088
|
} catch {}
|
|
26004
26089
|
throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -26010,7 +26095,7 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
26010
26095
|
const deadline = Date.now() + HISTORY_WRITE_LOCK_TIMEOUT_MS;
|
|
26011
26096
|
while (true) {
|
|
26012
26097
|
try {
|
|
26013
|
-
|
|
26098
|
+
fs21.mkdirSync(lockPath);
|
|
26014
26099
|
break;
|
|
26015
26100
|
} catch (error2) {
|
|
26016
26101
|
const code = error2 instanceof Error && "code" in error2 ? error2.code : undefined;
|
|
@@ -26021,9 +26106,9 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
26021
26106
|
throw new Error(`Timed out waiting for test history lock: ${historyPath}`);
|
|
26022
26107
|
}
|
|
26023
26108
|
try {
|
|
26024
|
-
const lockStat =
|
|
26109
|
+
const lockStat = fs21.statSync(lockPath);
|
|
26025
26110
|
if (Date.now() - lockStat.mtimeMs >= HISTORY_WRITE_LOCK_STALE_MS) {
|
|
26026
|
-
|
|
26111
|
+
fs21.rmSync(lockPath, { recursive: true, force: true });
|
|
26027
26112
|
continue;
|
|
26028
26113
|
}
|
|
26029
26114
|
} catch {}
|
|
@@ -26038,7 +26123,7 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
26038
26123
|
return fn();
|
|
26039
26124
|
} finally {
|
|
26040
26125
|
try {
|
|
26041
|
-
|
|
26126
|
+
fs21.rmSync(lockPath, { recursive: true, force: true });
|
|
26042
26127
|
} catch {}
|
|
26043
26128
|
}
|
|
26044
26129
|
function sleepSync(ms) {
|
|
@@ -26047,11 +26132,11 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
26047
26132
|
}
|
|
26048
26133
|
}
|
|
26049
26134
|
function readAllRecords(historyPath) {
|
|
26050
|
-
if (!
|
|
26135
|
+
if (!fs21.existsSync(historyPath)) {
|
|
26051
26136
|
return [];
|
|
26052
26137
|
}
|
|
26053
26138
|
try {
|
|
26054
|
-
const content =
|
|
26139
|
+
const content = fs21.readFileSync(historyPath, "utf-8");
|
|
26055
26140
|
const lines = content.split(`
|
|
26056
26141
|
`);
|
|
26057
26142
|
const records = [];
|
|
@@ -26084,8 +26169,8 @@ var _internals43 = {
|
|
|
26084
26169
|
};
|
|
26085
26170
|
|
|
26086
26171
|
// src/tools/resolve-working-directory.ts
|
|
26087
|
-
import * as
|
|
26088
|
-
import * as
|
|
26172
|
+
import * as fs22 from "fs";
|
|
26173
|
+
import * as path54 from "path";
|
|
26089
26174
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
26090
26175
|
if (workingDirectory == null || workingDirectory === "") {
|
|
26091
26176
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -26108,14 +26193,12 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
26108
26193
|
message: "Invalid working_directory: null bytes are not allowed"
|
|
26109
26194
|
};
|
|
26110
26195
|
}
|
|
26111
|
-
|
|
26112
|
-
|
|
26113
|
-
|
|
26114
|
-
|
|
26115
|
-
|
|
26116
|
-
|
|
26117
|
-
};
|
|
26118
|
-
}
|
|
26196
|
+
const reservedDevicePattern = /^(NUL|CON|AUX|COM[1-9]|LPT[1-9])(\..*)?$/i;
|
|
26197
|
+
if (workingDirectory.startsWith("\\\\") || process.platform === "win32" && reservedDevicePattern.test(workingDirectory)) {
|
|
26198
|
+
return {
|
|
26199
|
+
success: false,
|
|
26200
|
+
message: "Invalid working_directory: Windows device paths are not allowed"
|
|
26201
|
+
};
|
|
26119
26202
|
}
|
|
26120
26203
|
const rawPathParts = workingDirectory.split(/[\\/]/);
|
|
26121
26204
|
if (rawPathParts.includes("..")) {
|
|
@@ -26124,11 +26207,11 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
26124
26207
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
26125
26208
|
};
|
|
26126
26209
|
}
|
|
26127
|
-
const normalizedDir =
|
|
26128
|
-
const resolvedDir =
|
|
26210
|
+
const normalizedDir = path54.normalize(workingDirectory);
|
|
26211
|
+
const resolvedDir = path54.resolve(normalizedDir);
|
|
26129
26212
|
let statResult;
|
|
26130
26213
|
try {
|
|
26131
|
-
statResult =
|
|
26214
|
+
statResult = fs22.statSync(resolvedDir);
|
|
26132
26215
|
} catch {
|
|
26133
26216
|
return {
|
|
26134
26217
|
success: false,
|
|
@@ -26144,16 +26227,16 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
26144
26227
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
26145
26228
|
return { success: true, directory: resolvedDir };
|
|
26146
26229
|
}
|
|
26147
|
-
const resolvedFallback =
|
|
26230
|
+
const resolvedFallback = path54.resolve(fallbackDirectory);
|
|
26148
26231
|
let fallbackExists = false;
|
|
26149
26232
|
try {
|
|
26150
|
-
|
|
26233
|
+
fs22.statSync(resolvedFallback);
|
|
26151
26234
|
fallbackExists = true;
|
|
26152
26235
|
} catch {
|
|
26153
26236
|
fallbackExists = false;
|
|
26154
26237
|
}
|
|
26155
26238
|
if (fallbackExists) {
|
|
26156
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
26239
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path54.sep);
|
|
26157
26240
|
if (isSubdirectory) {
|
|
26158
26241
|
return {
|
|
26159
26242
|
success: false,
|
|
@@ -26176,7 +26259,7 @@ async function estimateFanOut(sourceFiles, cwd) {
|
|
|
26176
26259
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
26177
26260
|
const uniqueTestFiles = new Set;
|
|
26178
26261
|
for (const sourceFile of sourceFiles) {
|
|
26179
|
-
const resolvedPath =
|
|
26262
|
+
const resolvedPath = path55.resolve(cwd, sourceFile);
|
|
26180
26263
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
26181
26264
|
const testFiles = impactMap[normalizedPath];
|
|
26182
26265
|
if (testFiles) {
|
|
@@ -26261,19 +26344,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
26261
26344
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
26262
26345
|
}
|
|
26263
26346
|
function detectGoTest(cwd) {
|
|
26264
|
-
return
|
|
26347
|
+
return fs23.existsSync(path55.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
26265
26348
|
}
|
|
26266
26349
|
function detectJavaMaven(cwd) {
|
|
26267
|
-
return
|
|
26350
|
+
return fs23.existsSync(path55.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
26268
26351
|
}
|
|
26269
26352
|
function detectGradle(cwd) {
|
|
26270
|
-
const hasBuildFile =
|
|
26271
|
-
const hasGradlew =
|
|
26353
|
+
const hasBuildFile = fs23.existsSync(path55.join(cwd, "build.gradle")) || fs23.existsSync(path55.join(cwd, "build.gradle.kts"));
|
|
26354
|
+
const hasGradlew = fs23.existsSync(path55.join(cwd, "gradlew")) || fs23.existsSync(path55.join(cwd, "gradlew.bat"));
|
|
26272
26355
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
26273
26356
|
}
|
|
26274
26357
|
function detectDotnetTest(cwd) {
|
|
26275
26358
|
try {
|
|
26276
|
-
const files =
|
|
26359
|
+
const files = fs23.readdirSync(cwd);
|
|
26277
26360
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
26278
26361
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
26279
26362
|
} catch {
|
|
@@ -26281,25 +26364,25 @@ function detectDotnetTest(cwd) {
|
|
|
26281
26364
|
}
|
|
26282
26365
|
}
|
|
26283
26366
|
function detectCTest(cwd) {
|
|
26284
|
-
const hasSource =
|
|
26285
|
-
const hasBuildCache =
|
|
26367
|
+
const hasSource = fs23.existsSync(path55.join(cwd, "CMakeLists.txt"));
|
|
26368
|
+
const hasBuildCache = fs23.existsSync(path55.join(cwd, "CMakeCache.txt")) || fs23.existsSync(path55.join(cwd, "build", "CMakeCache.txt"));
|
|
26286
26369
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
26287
26370
|
}
|
|
26288
26371
|
function detectSwiftTest(cwd) {
|
|
26289
|
-
return
|
|
26372
|
+
return fs23.existsSync(path55.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
26290
26373
|
}
|
|
26291
26374
|
function detectDartTest(cwd) {
|
|
26292
|
-
return
|
|
26375
|
+
return fs23.existsSync(path55.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
26293
26376
|
}
|
|
26294
26377
|
function detectRSpec(cwd) {
|
|
26295
|
-
const hasRSpecFile =
|
|
26296
|
-
const hasGemfile =
|
|
26297
|
-
const hasSpecDir =
|
|
26378
|
+
const hasRSpecFile = fs23.existsSync(path55.join(cwd, ".rspec"));
|
|
26379
|
+
const hasGemfile = fs23.existsSync(path55.join(cwd, "Gemfile"));
|
|
26380
|
+
const hasSpecDir = fs23.existsSync(path55.join(cwd, "spec"));
|
|
26298
26381
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
26299
26382
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
26300
26383
|
}
|
|
26301
26384
|
function detectMinitest(cwd) {
|
|
26302
|
-
return
|
|
26385
|
+
return fs23.existsSync(path55.join(cwd, "test")) && (fs23.existsSync(path55.join(cwd, "Gemfile")) || fs23.existsSync(path55.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
26303
26386
|
}
|
|
26304
26387
|
var DISPATCH_FRAMEWORK_MAP = {
|
|
26305
26388
|
bun: "bun",
|
|
@@ -26384,9 +26467,9 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
26384
26467
|
async function detectTestFramework(cwd) {
|
|
26385
26468
|
const baseDir = cwd;
|
|
26386
26469
|
try {
|
|
26387
|
-
const packageJsonPath =
|
|
26388
|
-
if (
|
|
26389
|
-
const content =
|
|
26470
|
+
const packageJsonPath = path55.join(baseDir, "package.json");
|
|
26471
|
+
if (fs23.existsSync(packageJsonPath)) {
|
|
26472
|
+
const content = fs23.readFileSync(packageJsonPath, "utf-8");
|
|
26390
26473
|
const pkg = JSON.parse(content);
|
|
26391
26474
|
const _deps = pkg.dependencies || {};
|
|
26392
26475
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -26405,38 +26488,38 @@ async function detectTestFramework(cwd) {
|
|
|
26405
26488
|
return "jest";
|
|
26406
26489
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
26407
26490
|
return "mocha";
|
|
26408
|
-
if (
|
|
26491
|
+
if (fs23.existsSync(path55.join(baseDir, "bun.lockb")) || fs23.existsSync(path55.join(baseDir, "bun.lock"))) {
|
|
26409
26492
|
if (scripts.test?.includes("bun"))
|
|
26410
26493
|
return "bun";
|
|
26411
26494
|
}
|
|
26412
26495
|
}
|
|
26413
26496
|
} catch {}
|
|
26414
26497
|
try {
|
|
26415
|
-
const pyprojectTomlPath =
|
|
26416
|
-
const setupCfgPath =
|
|
26417
|
-
const requirementsTxtPath =
|
|
26418
|
-
if (
|
|
26419
|
-
const content =
|
|
26498
|
+
const pyprojectTomlPath = path55.join(baseDir, "pyproject.toml");
|
|
26499
|
+
const setupCfgPath = path55.join(baseDir, "setup.cfg");
|
|
26500
|
+
const requirementsTxtPath = path55.join(baseDir, "requirements.txt");
|
|
26501
|
+
if (fs23.existsSync(pyprojectTomlPath)) {
|
|
26502
|
+
const content = fs23.readFileSync(pyprojectTomlPath, "utf-8");
|
|
26420
26503
|
if (content.includes("[tool.pytest"))
|
|
26421
26504
|
return "pytest";
|
|
26422
26505
|
if (content.includes("pytest"))
|
|
26423
26506
|
return "pytest";
|
|
26424
26507
|
}
|
|
26425
|
-
if (
|
|
26426
|
-
const content =
|
|
26508
|
+
if (fs23.existsSync(setupCfgPath)) {
|
|
26509
|
+
const content = fs23.readFileSync(setupCfgPath, "utf-8");
|
|
26427
26510
|
if (content.includes("[pytest]"))
|
|
26428
26511
|
return "pytest";
|
|
26429
26512
|
}
|
|
26430
|
-
if (
|
|
26431
|
-
const content =
|
|
26513
|
+
if (fs23.existsSync(requirementsTxtPath)) {
|
|
26514
|
+
const content = fs23.readFileSync(requirementsTxtPath, "utf-8");
|
|
26432
26515
|
if (content.includes("pytest"))
|
|
26433
26516
|
return "pytest";
|
|
26434
26517
|
}
|
|
26435
26518
|
} catch {}
|
|
26436
26519
|
try {
|
|
26437
|
-
const cargoTomlPath =
|
|
26438
|
-
if (
|
|
26439
|
-
const content =
|
|
26520
|
+
const cargoTomlPath = path55.join(baseDir, "Cargo.toml");
|
|
26521
|
+
if (fs23.existsSync(cargoTomlPath)) {
|
|
26522
|
+
const content = fs23.readFileSync(cargoTomlPath, "utf-8");
|
|
26440
26523
|
if (content.includes("[dev-dependencies]")) {
|
|
26441
26524
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
26442
26525
|
return "cargo";
|
|
@@ -26445,10 +26528,10 @@ async function detectTestFramework(cwd) {
|
|
|
26445
26528
|
}
|
|
26446
26529
|
} catch {}
|
|
26447
26530
|
try {
|
|
26448
|
-
const pesterConfigPath =
|
|
26449
|
-
const pesterConfigJsonPath =
|
|
26450
|
-
const pesterPs1Path =
|
|
26451
|
-
if (
|
|
26531
|
+
const pesterConfigPath = path55.join(baseDir, "pester.config.ps1");
|
|
26532
|
+
const pesterConfigJsonPath = path55.join(baseDir, "pester.config.ps1.json");
|
|
26533
|
+
const pesterPs1Path = path55.join(baseDir, "tests.ps1");
|
|
26534
|
+
if (fs23.existsSync(pesterConfigPath) || fs23.existsSync(pesterConfigJsonPath) || fs23.existsSync(pesterPs1Path)) {
|
|
26452
26535
|
return "pester";
|
|
26453
26536
|
}
|
|
26454
26537
|
} catch {}
|
|
@@ -26490,12 +26573,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
26490
26573
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
26491
26574
|
}
|
|
26492
26575
|
function resolveWorkspacePath(file, workingDir) {
|
|
26493
|
-
return
|
|
26576
|
+
return path55.isAbsolute(file) ? path55.resolve(file) : path55.resolve(workingDir, file);
|
|
26494
26577
|
}
|
|
26495
26578
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
26496
26579
|
if (!preferRelative)
|
|
26497
26580
|
return absolutePath;
|
|
26498
|
-
return
|
|
26581
|
+
return path55.relative(workingDir, absolutePath);
|
|
26499
26582
|
}
|
|
26500
26583
|
function dedupePush(target, value) {
|
|
26501
26584
|
if (!target.includes(value)) {
|
|
@@ -26532,18 +26615,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
26532
26615
|
}
|
|
26533
26616
|
}
|
|
26534
26617
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
26535
|
-
const relativeDir =
|
|
26618
|
+
const relativeDir = path55.dirname(relativePath);
|
|
26536
26619
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
26537
26620
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
26538
|
-
const rootDir =
|
|
26539
|
-
return nestedRelativeDir ? [rootDir,
|
|
26621
|
+
const rootDir = path55.join(workingDir, dirName);
|
|
26622
|
+
return nestedRelativeDir ? [rootDir, path55.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
26540
26623
|
});
|
|
26541
26624
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
26542
26625
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
26543
|
-
directories.push(
|
|
26626
|
+
directories.push(path55.join(workingDir, "src/test/java", path55.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
26544
26627
|
}
|
|
26545
26628
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
26546
|
-
directories.push(
|
|
26629
|
+
directories.push(path55.join(workingDir, "src/test/kotlin", path55.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
26547
26630
|
}
|
|
26548
26631
|
return [...new Set(directories)];
|
|
26549
26632
|
}
|
|
@@ -26551,19 +26634,19 @@ function hasCompoundTestExtension(filename) {
|
|
|
26551
26634
|
const lower = filename.toLowerCase();
|
|
26552
26635
|
return COMPOUND_TEST_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
26553
26636
|
}
|
|
26554
|
-
function isLanguageSpecificTestFile(
|
|
26555
|
-
const lower =
|
|
26637
|
+
function isLanguageSpecificTestFile(basename11) {
|
|
26638
|
+
const lower = basename11.toLowerCase();
|
|
26556
26639
|
if (lower.endsWith("_test.go"))
|
|
26557
26640
|
return true;
|
|
26558
26641
|
if (lower.endsWith(".py") && (lower.startsWith("test_") || lower.endsWith("_test.py")))
|
|
26559
26642
|
return true;
|
|
26560
26643
|
if (lower.endsWith("_spec.rb"))
|
|
26561
26644
|
return true;
|
|
26562
|
-
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(
|
|
26645
|
+
if (lower.endsWith(".java") && (/^Test[A-Z]/.test(basename11) || basename11.endsWith("Test.java") || basename11.endsWith("Tests.java") || lower.endsWith("it.java")))
|
|
26563
26646
|
return true;
|
|
26564
26647
|
if (lower.endsWith(".cs") && (lower.endsWith("test.cs") || lower.endsWith("tests.cs")))
|
|
26565
26648
|
return true;
|
|
26566
|
-
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(
|
|
26649
|
+
if (lower.endsWith(".kt") && (/^Test[A-Z]/.test(basename11) || lower.endsWith("test.kt") || lower.endsWith("tests.kt")))
|
|
26567
26650
|
return true;
|
|
26568
26651
|
if (lower.endsWith(".tests.ps1"))
|
|
26569
26652
|
return true;
|
|
@@ -26571,23 +26654,23 @@ function isLanguageSpecificTestFile(basename10) {
|
|
|
26571
26654
|
}
|
|
26572
26655
|
function isConventionTestFilePath(filePath) {
|
|
26573
26656
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
26574
|
-
const
|
|
26575
|
-
return hasCompoundTestExtension(
|
|
26657
|
+
const basename11 = path55.basename(filePath);
|
|
26658
|
+
return hasCompoundTestExtension(basename11) || basename11.includes(".spec.") || basename11.includes(".test.") || isLanguageSpecificTestFile(basename11) || isTestDirectoryPath(normalizedPath);
|
|
26576
26659
|
}
|
|
26577
26660
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
26578
26661
|
const testFiles = [];
|
|
26579
26662
|
for (const file of sourceFiles) {
|
|
26580
26663
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
26581
|
-
const relativeFile =
|
|
26582
|
-
const
|
|
26583
|
-
const
|
|
26584
|
-
const preferRelativeOutput = !
|
|
26664
|
+
const relativeFile = path55.relative(workingDir, absoluteFile);
|
|
26665
|
+
const basename11 = path55.basename(absoluteFile);
|
|
26666
|
+
const dirname25 = path55.dirname(absoluteFile);
|
|
26667
|
+
const preferRelativeOutput = !path55.isAbsolute(file);
|
|
26585
26668
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
26586
26669
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
26587
26670
|
continue;
|
|
26588
26671
|
}
|
|
26589
|
-
const nameWithoutExt =
|
|
26590
|
-
const ext =
|
|
26672
|
+
const nameWithoutExt = basename11.replace(/\.[^.]+$/, "");
|
|
26673
|
+
const ext = path55.extname(basename11);
|
|
26591
26674
|
const genericTestNames = [
|
|
26592
26675
|
`${nameWithoutExt}.spec${ext}`,
|
|
26593
26676
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -26596,20 +26679,20 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
26596
26679
|
const colocatedCandidates = [
|
|
26597
26680
|
...genericTestNames,
|
|
26598
26681
|
...languageSpecificTestNames
|
|
26599
|
-
].map((candidateName) =>
|
|
26682
|
+
].map((candidateName) => path55.join(dirname25, candidateName));
|
|
26600
26683
|
const testDirectoryNames = [
|
|
26601
|
-
|
|
26684
|
+
basename11,
|
|
26602
26685
|
...genericTestNames,
|
|
26603
26686
|
...languageSpecificTestNames
|
|
26604
26687
|
];
|
|
26605
26688
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
26606
26689
|
const possibleTestFiles = [
|
|
26607
26690
|
...colocatedCandidates,
|
|
26608
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
26609
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
26691
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path55.join(dirname25, dirName, candidateName))),
|
|
26692
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path55.join(candidateDir, candidateName)))
|
|
26610
26693
|
];
|
|
26611
26694
|
for (const testFile of possibleTestFiles) {
|
|
26612
|
-
if (
|
|
26695
|
+
if (fs23.existsSync(testFile)) {
|
|
26613
26696
|
dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
|
|
26614
26697
|
}
|
|
26615
26698
|
}
|
|
@@ -26626,8 +26709,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26626
26709
|
for (const testFile of candidateTestFiles) {
|
|
26627
26710
|
try {
|
|
26628
26711
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
26629
|
-
const content =
|
|
26630
|
-
const testDir =
|
|
26712
|
+
const content = fs23.readFileSync(absoluteTestFile, "utf-8");
|
|
26713
|
+
const testDir = path55.dirname(absoluteTestFile);
|
|
26631
26714
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
26632
26715
|
let match;
|
|
26633
26716
|
match = importRegex.exec(content);
|
|
@@ -26635,8 +26718,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26635
26718
|
const importPath = match[1];
|
|
26636
26719
|
let resolvedImport;
|
|
26637
26720
|
if (importPath.startsWith(".")) {
|
|
26638
|
-
resolvedImport =
|
|
26639
|
-
const existingExt =
|
|
26721
|
+
resolvedImport = path55.resolve(testDir, importPath);
|
|
26722
|
+
const existingExt = path55.extname(resolvedImport);
|
|
26640
26723
|
if (!existingExt) {
|
|
26641
26724
|
for (const extToTry of [
|
|
26642
26725
|
".ts",
|
|
@@ -26647,7 +26730,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26647
26730
|
".cjs"
|
|
26648
26731
|
]) {
|
|
26649
26732
|
const withExt = resolvedImport + extToTry;
|
|
26650
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
26733
|
+
if (absoluteSourceFiles.includes(withExt) || fs23.existsSync(withExt)) {
|
|
26651
26734
|
resolvedImport = withExt;
|
|
26652
26735
|
break;
|
|
26653
26736
|
}
|
|
@@ -26656,12 +26739,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26656
26739
|
} else {
|
|
26657
26740
|
continue;
|
|
26658
26741
|
}
|
|
26659
|
-
const importBasename =
|
|
26660
|
-
const importDir =
|
|
26742
|
+
const importBasename = path55.basename(resolvedImport, path55.extname(resolvedImport));
|
|
26743
|
+
const importDir = path55.dirname(resolvedImport);
|
|
26661
26744
|
for (const sourceFile of absoluteSourceFiles) {
|
|
26662
|
-
const sourceDir =
|
|
26663
|
-
const sourceBasename =
|
|
26664
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
26745
|
+
const sourceDir = path55.dirname(sourceFile);
|
|
26746
|
+
const sourceBasename = path55.basename(sourceFile, path55.extname(sourceFile));
|
|
26747
|
+
const isRelatedDir = importDir === sourceDir || importDir === path55.join(sourceDir, "__tests__") || importDir === path55.join(sourceDir, "tests") || importDir === path55.join(sourceDir, "test") || importDir === path55.join(sourceDir, "spec");
|
|
26665
26748
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
26666
26749
|
dedupePush(testFiles, testFile);
|
|
26667
26750
|
break;
|
|
@@ -26674,8 +26757,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26674
26757
|
while (match !== null) {
|
|
26675
26758
|
const importPath = match[1];
|
|
26676
26759
|
if (importPath.startsWith(".")) {
|
|
26677
|
-
let resolvedImport =
|
|
26678
|
-
const existingExt =
|
|
26760
|
+
let resolvedImport = path55.resolve(testDir, importPath);
|
|
26761
|
+
const existingExt = path55.extname(resolvedImport);
|
|
26679
26762
|
if (!existingExt) {
|
|
26680
26763
|
for (const extToTry of [
|
|
26681
26764
|
".ts",
|
|
@@ -26686,18 +26769,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
26686
26769
|
".cjs"
|
|
26687
26770
|
]) {
|
|
26688
26771
|
const withExt = resolvedImport + extToTry;
|
|
26689
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
26772
|
+
if (absoluteSourceFiles.includes(withExt) || fs23.existsSync(withExt)) {
|
|
26690
26773
|
resolvedImport = withExt;
|
|
26691
26774
|
break;
|
|
26692
26775
|
}
|
|
26693
26776
|
}
|
|
26694
26777
|
}
|
|
26695
|
-
const importDir =
|
|
26696
|
-
const importBasename =
|
|
26778
|
+
const importDir = path55.dirname(resolvedImport);
|
|
26779
|
+
const importBasename = path55.basename(resolvedImport, path55.extname(resolvedImport));
|
|
26697
26780
|
for (const sourceFile of absoluteSourceFiles) {
|
|
26698
|
-
const sourceDir =
|
|
26699
|
-
const sourceBasename =
|
|
26700
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
26781
|
+
const sourceDir = path55.dirname(sourceFile);
|
|
26782
|
+
const sourceBasename = path55.basename(sourceFile, path55.extname(sourceFile));
|
|
26783
|
+
const isRelatedDir = importDir === sourceDir || importDir === path55.join(sourceDir, "__tests__") || importDir === path55.join(sourceDir, "tests") || importDir === path55.join(sourceDir, "test") || importDir === path55.join(sourceDir, "spec");
|
|
26701
26784
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
26702
26785
|
dedupePush(testFiles, testFile);
|
|
26703
26786
|
break;
|
|
@@ -26817,8 +26900,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
26817
26900
|
return ["mvn", "test"];
|
|
26818
26901
|
case "gradle": {
|
|
26819
26902
|
const isWindows = process.platform === "win32";
|
|
26820
|
-
const hasGradlewBat =
|
|
26821
|
-
const hasGradlew =
|
|
26903
|
+
const hasGradlewBat = fs23.existsSync(path55.join(baseDir, "gradlew.bat"));
|
|
26904
|
+
const hasGradlew = fs23.existsSync(path55.join(baseDir, "gradlew"));
|
|
26822
26905
|
if (hasGradlewBat && isWindows)
|
|
26823
26906
|
return ["gradlew.bat", "test"];
|
|
26824
26907
|
if (hasGradlew)
|
|
@@ -26835,7 +26918,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
26835
26918
|
"cmake-build-release",
|
|
26836
26919
|
"out"
|
|
26837
26920
|
];
|
|
26838
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
26921
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(path55.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
26839
26922
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
26840
26923
|
}
|
|
26841
26924
|
case "swift-test":
|
|
@@ -27269,13 +27352,13 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
27269
27352
|
};
|
|
27270
27353
|
}
|
|
27271
27354
|
const startTime = Date.now();
|
|
27272
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
27355
|
+
const vitestJsonOutputPath = framework === "vitest" ? path55.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
27273
27356
|
try {
|
|
27274
27357
|
if (vitestJsonOutputPath) {
|
|
27275
27358
|
try {
|
|
27276
|
-
|
|
27277
|
-
if (
|
|
27278
|
-
|
|
27359
|
+
fs23.mkdirSync(path55.dirname(vitestJsonOutputPath), { recursive: true });
|
|
27360
|
+
if (fs23.existsSync(vitestJsonOutputPath)) {
|
|
27361
|
+
fs23.unlinkSync(vitestJsonOutputPath);
|
|
27279
27362
|
}
|
|
27280
27363
|
} catch {}
|
|
27281
27364
|
}
|
|
@@ -27301,8 +27384,8 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
27301
27384
|
}
|
|
27302
27385
|
if (vitestJsonOutputPath) {
|
|
27303
27386
|
try {
|
|
27304
|
-
if (
|
|
27305
|
-
const vitestJsonOutput =
|
|
27387
|
+
if (fs23.existsSync(vitestJsonOutputPath)) {
|
|
27388
|
+
const vitestJsonOutput = fs23.readFileSync(vitestJsonOutputPath, "utf-8");
|
|
27306
27389
|
if (vitestJsonOutput.trim().length > 0) {
|
|
27307
27390
|
output += (output ? `
|
|
27308
27391
|
` : "") + vitestJsonOutput;
|
|
@@ -27441,10 +27524,10 @@ var SKIP_DIRECTORIES = new Set([
|
|
|
27441
27524
|
]);
|
|
27442
27525
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
27443
27526
|
const normalized = testFile.replace(/\\/g, "/");
|
|
27444
|
-
if (!
|
|
27527
|
+
if (!path55.isAbsolute(testFile))
|
|
27445
27528
|
return normalized;
|
|
27446
|
-
const relative7 =
|
|
27447
|
-
if (relative7.startsWith("..") ||
|
|
27529
|
+
const relative7 = path55.relative(workingDir, testFile);
|
|
27530
|
+
if (relative7.startsWith("..") || path55.isAbsolute(relative7)) {
|
|
27448
27531
|
return normalized;
|
|
27449
27532
|
}
|
|
27450
27533
|
return relative7.replace(/\\/g, "/");
|
|
@@ -27683,7 +27766,7 @@ var test_runner = createSwarmTool({
|
|
|
27683
27766
|
const sourceFiles = args.files.filter((file) => {
|
|
27684
27767
|
if (directTestFiles.includes(file))
|
|
27685
27768
|
return false;
|
|
27686
|
-
const ext =
|
|
27769
|
+
const ext = path55.extname(file).toLowerCase();
|
|
27687
27770
|
return SOURCE_EXTENSIONS.has(ext);
|
|
27688
27771
|
});
|
|
27689
27772
|
const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
|
|
@@ -27729,7 +27812,7 @@ var test_runner = createSwarmTool({
|
|
|
27729
27812
|
if (isConventionTestFilePath(f)) {
|
|
27730
27813
|
return false;
|
|
27731
27814
|
}
|
|
27732
|
-
const ext =
|
|
27815
|
+
const ext = path55.extname(f).toLowerCase();
|
|
27733
27816
|
return SOURCE_EXTENSIONS.has(ext);
|
|
27734
27817
|
});
|
|
27735
27818
|
if (sourceFiles.length === 0) {
|
|
@@ -27779,7 +27862,7 @@ var test_runner = createSwarmTool({
|
|
|
27779
27862
|
if (isConventionTestFilePath(f)) {
|
|
27780
27863
|
return false;
|
|
27781
27864
|
}
|
|
27782
|
-
const ext =
|
|
27865
|
+
const ext = path55.extname(f).toLowerCase();
|
|
27783
27866
|
return SOURCE_EXTENSIONS.has(ext);
|
|
27784
27867
|
});
|
|
27785
27868
|
if (sourceFiles.length === 0) {
|
|
@@ -27831,8 +27914,8 @@ var test_runner = createSwarmTool({
|
|
|
27831
27914
|
}
|
|
27832
27915
|
if (impactResult.impactedTests.length > 0) {
|
|
27833
27916
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
27834
|
-
const relativePath =
|
|
27835
|
-
return
|
|
27917
|
+
const relativePath = path55.relative(workingDir, absPath);
|
|
27918
|
+
return path55.isAbsolute(relativePath) ? absPath : relativePath;
|
|
27836
27919
|
});
|
|
27837
27920
|
} else {
|
|
27838
27921
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -27927,8 +28010,8 @@ function validateDirectoryPath(dir) {
|
|
|
27927
28010
|
if (dir.includes("..")) {
|
|
27928
28011
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
27929
28012
|
}
|
|
27930
|
-
const normalized =
|
|
27931
|
-
const absolutePath =
|
|
28013
|
+
const normalized = path56.normalize(dir);
|
|
28014
|
+
const absolutePath = path56.isAbsolute(normalized) ? normalized : path56.resolve(normalized);
|
|
27932
28015
|
return absolutePath;
|
|
27933
28016
|
}
|
|
27934
28017
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -27951,9 +28034,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
27951
28034
|
}
|
|
27952
28035
|
function getPackageVersion(dir) {
|
|
27953
28036
|
try {
|
|
27954
|
-
const packagePath =
|
|
27955
|
-
if (
|
|
27956
|
-
const content =
|
|
28037
|
+
const packagePath = path56.join(dir, "package.json");
|
|
28038
|
+
if (fs24.existsSync(packagePath)) {
|
|
28039
|
+
const content = fs24.readFileSync(packagePath, "utf-8");
|
|
27957
28040
|
const pkg = JSON.parse(content);
|
|
27958
28041
|
return pkg.version ?? null;
|
|
27959
28042
|
}
|
|
@@ -27962,9 +28045,9 @@ function getPackageVersion(dir) {
|
|
|
27962
28045
|
}
|
|
27963
28046
|
function getChangelogVersion(dir) {
|
|
27964
28047
|
try {
|
|
27965
|
-
const changelogPath =
|
|
27966
|
-
if (
|
|
27967
|
-
const content =
|
|
28048
|
+
const changelogPath = path56.join(dir, "CHANGELOG.md");
|
|
28049
|
+
if (fs24.existsSync(changelogPath)) {
|
|
28050
|
+
const content = fs24.readFileSync(changelogPath, "utf-8");
|
|
27968
28051
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
27969
28052
|
if (match) {
|
|
27970
28053
|
return match[1];
|
|
@@ -27976,10 +28059,10 @@ function getChangelogVersion(dir) {
|
|
|
27976
28059
|
function getVersionFileVersion(dir) {
|
|
27977
28060
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
27978
28061
|
for (const file of possibleFiles) {
|
|
27979
|
-
const filePath =
|
|
27980
|
-
if (
|
|
28062
|
+
const filePath = path56.join(dir, file);
|
|
28063
|
+
if (fs24.existsSync(filePath)) {
|
|
27981
28064
|
try {
|
|
27982
|
-
const content =
|
|
28065
|
+
const content = fs24.readFileSync(filePath, "utf-8").trim();
|
|
27983
28066
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
27984
28067
|
if (match) {
|
|
27985
28068
|
return match[1];
|
|
@@ -28713,8 +28796,8 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
28713
28796
|
}
|
|
28714
28797
|
|
|
28715
28798
|
// src/commands/reset.ts
|
|
28716
|
-
import * as
|
|
28717
|
-
import * as
|
|
28799
|
+
import * as fs25 from "fs";
|
|
28800
|
+
import * as path57 from "path";
|
|
28718
28801
|
|
|
28719
28802
|
// src/background/circuit-breaker.ts
|
|
28720
28803
|
class CircuitBreaker {
|
|
@@ -29421,8 +29504,8 @@ async function handleResetCommand(directory, args) {
|
|
|
29421
29504
|
for (const filename of filesToReset) {
|
|
29422
29505
|
try {
|
|
29423
29506
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
29424
|
-
if (
|
|
29425
|
-
|
|
29507
|
+
if (fs25.existsSync(resolvedPath)) {
|
|
29508
|
+
fs25.unlinkSync(resolvedPath);
|
|
29426
29509
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
29427
29510
|
} else {
|
|
29428
29511
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -29433,9 +29516,9 @@ async function handleResetCommand(directory, args) {
|
|
|
29433
29516
|
}
|
|
29434
29517
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
29435
29518
|
try {
|
|
29436
|
-
const rootPath =
|
|
29437
|
-
if (
|
|
29438
|
-
|
|
29519
|
+
const rootPath = path57.join(directory, filename);
|
|
29520
|
+
if (fs25.existsSync(rootPath)) {
|
|
29521
|
+
fs25.unlinkSync(rootPath);
|
|
29439
29522
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
29440
29523
|
}
|
|
29441
29524
|
} catch (err) {
|
|
@@ -29450,8 +29533,8 @@ async function handleResetCommand(directory, args) {
|
|
|
29450
29533
|
}
|
|
29451
29534
|
try {
|
|
29452
29535
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
29453
|
-
if (
|
|
29454
|
-
|
|
29536
|
+
if (fs25.existsSync(summariesPath)) {
|
|
29537
|
+
fs25.rmSync(summariesPath, { recursive: true, force: true });
|
|
29455
29538
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
29456
29539
|
} else {
|
|
29457
29540
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -29470,15 +29553,15 @@ async function handleResetCommand(directory, args) {
|
|
|
29470
29553
|
}
|
|
29471
29554
|
|
|
29472
29555
|
// src/commands/reset-session.ts
|
|
29473
|
-
import * as
|
|
29474
|
-
import * as
|
|
29556
|
+
import * as fs28 from "fs";
|
|
29557
|
+
import * as path60 from "path";
|
|
29475
29558
|
|
|
29476
29559
|
// src/prm/trajectory-store.ts
|
|
29477
|
-
import * as
|
|
29478
|
-
import * as
|
|
29560
|
+
import * as fs26 from "fs/promises";
|
|
29561
|
+
import * as path58 from "path";
|
|
29479
29562
|
var MAX_TRACKED_TRAJECTORY_SESSIONS = 500;
|
|
29480
29563
|
function getTrajectoryPath(sessionId, directory) {
|
|
29481
|
-
const relativePath =
|
|
29564
|
+
const relativePath = path58.join("trajectories", `${sessionId}.jsonl`);
|
|
29482
29565
|
return validateSwarmPath(directory, relativePath);
|
|
29483
29566
|
}
|
|
29484
29567
|
var _inMemoryTrajectoryCache = new Map;
|
|
@@ -29508,7 +29591,7 @@ function clearTrajectoryCache(sessionId) {
|
|
|
29508
29591
|
async function readTrajectory(sessionId, directory) {
|
|
29509
29592
|
try {
|
|
29510
29593
|
const trajectoryPath = getTrajectoryPath(sessionId, directory);
|
|
29511
|
-
const content = await
|
|
29594
|
+
const content = await fs26.readFile(trajectoryPath, "utf-8");
|
|
29512
29595
|
const lines = content.split(`
|
|
29513
29596
|
`).filter((line) => line.trim().length > 0);
|
|
29514
29597
|
const entries = [];
|
|
@@ -29533,15 +29616,15 @@ async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
|
|
|
29533
29616
|
for (const subdir of ["trajectories", "replays"]) {
|
|
29534
29617
|
try {
|
|
29535
29618
|
const dirPath = validateSwarmPath(directory, subdir);
|
|
29536
|
-
const entries = await
|
|
29619
|
+
const entries = await fs26.readdir(dirPath, { withFileTypes: true });
|
|
29537
29620
|
for (const entry of entries) {
|
|
29538
29621
|
if (!entry.isFile())
|
|
29539
29622
|
continue;
|
|
29540
|
-
const filePath =
|
|
29623
|
+
const filePath = path58.join(dirPath, entry.name);
|
|
29541
29624
|
try {
|
|
29542
|
-
const stat6 = await
|
|
29625
|
+
const stat6 = await fs26.stat(filePath);
|
|
29543
29626
|
if (now - stat6.mtimeMs > cutoffMs) {
|
|
29544
|
-
await
|
|
29627
|
+
await fs26.unlink(filePath);
|
|
29545
29628
|
}
|
|
29546
29629
|
} catch {}
|
|
29547
29630
|
}
|
|
@@ -29963,17 +30046,17 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
|
|
|
29963
30046
|
};
|
|
29964
30047
|
}
|
|
29965
30048
|
// src/prm/replay.ts
|
|
29966
|
-
import { promises as
|
|
29967
|
-
import
|
|
30049
|
+
import { promises as fs27 } from "fs";
|
|
30050
|
+
import path59 from "path";
|
|
29968
30051
|
function isPathSafe(targetPath, basePath) {
|
|
29969
|
-
const resolvedTarget =
|
|
29970
|
-
const resolvedBase =
|
|
29971
|
-
const rel =
|
|
29972
|
-
return !rel.startsWith("..") && !
|
|
30052
|
+
const resolvedTarget = path59.resolve(targetPath);
|
|
30053
|
+
const resolvedBase = path59.resolve(basePath);
|
|
30054
|
+
const rel = path59.relative(resolvedBase, resolvedTarget);
|
|
30055
|
+
return !rel.startsWith("..") && !path59.isAbsolute(rel);
|
|
29973
30056
|
}
|
|
29974
30057
|
function isWithinReplaysDir(targetPath) {
|
|
29975
|
-
const resolved =
|
|
29976
|
-
const parts = resolved.split(
|
|
30058
|
+
const resolved = path59.resolve(targetPath);
|
|
30059
|
+
const parts = resolved.split(path59.sep);
|
|
29977
30060
|
for (let i = 0;i < parts.length - 1; i++) {
|
|
29978
30061
|
if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
|
|
29979
30062
|
return true;
|
|
@@ -29986,15 +30069,15 @@ function sanitizeFilename(input) {
|
|
|
29986
30069
|
}
|
|
29987
30070
|
async function startReplayRecording(sessionID, directory) {
|
|
29988
30071
|
try {
|
|
29989
|
-
const replayDir =
|
|
30072
|
+
const replayDir = path59.join(directory, ".swarm", "replays");
|
|
29990
30073
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
29991
30074
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
29992
|
-
const filepath =
|
|
30075
|
+
const filepath = path59.join(replayDir, filename);
|
|
29993
30076
|
if (!isPathSafe(filepath, replayDir)) {
|
|
29994
30077
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
29995
30078
|
return null;
|
|
29996
30079
|
}
|
|
29997
|
-
await
|
|
30080
|
+
await fs27.mkdir(replayDir, { recursive: true });
|
|
29998
30081
|
return filepath;
|
|
29999
30082
|
} catch (err) {
|
|
30000
30083
|
console.warn(`[replay] Failed to start recording for session ${sessionID}: ${err}`);
|
|
@@ -30014,7 +30097,7 @@ async function recordReplayEntry(artifactPath, sessionID, entry) {
|
|
|
30014
30097
|
};
|
|
30015
30098
|
const line = `${JSON.stringify(fullEntry)}
|
|
30016
30099
|
`;
|
|
30017
|
-
await
|
|
30100
|
+
await fs27.appendFile(artifactPath, line, "utf-8");
|
|
30018
30101
|
} catch (err) {
|
|
30019
30102
|
console.warn(`[replay] Failed to record entry: ${err}`);
|
|
30020
30103
|
}
|
|
@@ -30059,10 +30142,11 @@ function errorMessage(err) {
|
|
|
30059
30142
|
}
|
|
30060
30143
|
async function handleResetSessionCommand(directory, _args) {
|
|
30061
30144
|
const results = [];
|
|
30145
|
+
let statePath;
|
|
30062
30146
|
try {
|
|
30063
|
-
|
|
30064
|
-
if (
|
|
30065
|
-
|
|
30147
|
+
statePath = validateSwarmPath(directory, "session/state.json");
|
|
30148
|
+
if (fs28.existsSync(statePath)) {
|
|
30149
|
+
fs28.unlinkSync(statePath);
|
|
30066
30150
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
30067
30151
|
} else {
|
|
30068
30152
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -30070,11 +30154,11 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30070
30154
|
} catch {
|
|
30071
30155
|
results.push("\u274C Failed to delete state.json");
|
|
30072
30156
|
}
|
|
30073
|
-
const sessionDir =
|
|
30157
|
+
const sessionDir = statePath ? path60.dirname(statePath) : undefined;
|
|
30074
30158
|
let sessionFiles = [];
|
|
30075
|
-
if (
|
|
30159
|
+
if (sessionDir && fs28.existsSync(sessionDir)) {
|
|
30076
30160
|
try {
|
|
30077
|
-
sessionFiles =
|
|
30161
|
+
sessionFiles = fs28.readdirSync(sessionDir);
|
|
30078
30162
|
} catch (err) {
|
|
30079
30163
|
results.push(`\u274C Failed to read session directory: ${errorMessage(err)}`);
|
|
30080
30164
|
}
|
|
@@ -30082,13 +30166,13 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30082
30166
|
for (const file of sessionFiles) {
|
|
30083
30167
|
if (file === "state.json")
|
|
30084
30168
|
continue;
|
|
30085
|
-
const filePath =
|
|
30169
|
+
const filePath = path60.join(sessionDir, file);
|
|
30086
30170
|
try {
|
|
30087
|
-
if (!
|
|
30171
|
+
if (!fs28.existsSync(filePath))
|
|
30088
30172
|
continue;
|
|
30089
|
-
if (!
|
|
30173
|
+
if (!fs28.lstatSync(filePath).isFile())
|
|
30090
30174
|
continue;
|
|
30091
|
-
|
|
30175
|
+
fs28.unlinkSync(filePath);
|
|
30092
30176
|
results.push(`\u2713 Deleted ${file}`);
|
|
30093
30177
|
} catch (err) {
|
|
30094
30178
|
results.push(`\u274C Failed to delete ${file}: ${errorMessage(err)}`);
|
|
@@ -30104,10 +30188,10 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30104
30188
|
const chainCount = swarmState.delegationChains.size;
|
|
30105
30189
|
swarmState.delegationChains.clear();
|
|
30106
30190
|
results.push(`\u2705 Cleared ${chainCount} delegation chain(s)`);
|
|
30107
|
-
const worktreesDir =
|
|
30191
|
+
const worktreesDir = path60.resolve(path60.dirname(directory), ".swarm-worktrees");
|
|
30108
30192
|
try {
|
|
30109
|
-
if (
|
|
30110
|
-
|
|
30193
|
+
if (fs28.existsSync(worktreesDir)) {
|
|
30194
|
+
fs28.rmSync(worktreesDir, { recursive: true, force: true });
|
|
30111
30195
|
results.push("\u2705 Removed .swarm-worktrees/ directory");
|
|
30112
30196
|
}
|
|
30113
30197
|
} catch (err) {
|
|
@@ -30137,7 +30221,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30137
30221
|
}
|
|
30138
30222
|
|
|
30139
30223
|
// src/summaries/manager.ts
|
|
30140
|
-
import * as
|
|
30224
|
+
import * as path61 from "path";
|
|
30141
30225
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
30142
30226
|
function sanitizeSummaryId(id) {
|
|
30143
30227
|
if (!id || id.length === 0) {
|
|
@@ -30161,7 +30245,7 @@ function sanitizeSummaryId(id) {
|
|
|
30161
30245
|
}
|
|
30162
30246
|
async function loadFullOutput(directory, id) {
|
|
30163
30247
|
const sanitizedId = sanitizeSummaryId(id);
|
|
30164
|
-
const relativePath =
|
|
30248
|
+
const relativePath = path61.join("summaries", `${sanitizedId}.json`);
|
|
30165
30249
|
validateSwarmPath(directory, relativePath);
|
|
30166
30250
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
30167
30251
|
if (content === null) {
|
|
@@ -30213,18 +30297,91 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
|
30213
30297
|
}
|
|
30214
30298
|
|
|
30215
30299
|
// src/commands/rollback.ts
|
|
30216
|
-
import * as
|
|
30217
|
-
import * as
|
|
30300
|
+
import * as fs29 from "fs";
|
|
30301
|
+
import * as path62 from "path";
|
|
30302
|
+
function safeParseToolJson(result) {
|
|
30303
|
+
try {
|
|
30304
|
+
const jsonStr = typeof result === "string" ? result : result.output;
|
|
30305
|
+
return JSON.parse(jsonStr);
|
|
30306
|
+
} catch {
|
|
30307
|
+
return null;
|
|
30308
|
+
}
|
|
30309
|
+
}
|
|
30310
|
+
async function listGitCheckpoints(directory) {
|
|
30311
|
+
try {
|
|
30312
|
+
const result = await checkpoint.execute({ action: "list" }, {
|
|
30313
|
+
directory
|
|
30314
|
+
});
|
|
30315
|
+
const parsed = safeParseToolJson(result);
|
|
30316
|
+
if (!parsed)
|
|
30317
|
+
return null;
|
|
30318
|
+
if (parsed.success !== true || !Array.isArray(parsed.checkpoints)) {
|
|
30319
|
+
return null;
|
|
30320
|
+
}
|
|
30321
|
+
return parsed.checkpoints;
|
|
30322
|
+
} catch {
|
|
30323
|
+
return null;
|
|
30324
|
+
}
|
|
30325
|
+
}
|
|
30326
|
+
function formatGitCheckpointList(checkpoints) {
|
|
30327
|
+
if (checkpoints.length === 0) {
|
|
30328
|
+
return "No checkpoints found. Create one with `/swarm checkpoint save <label>`";
|
|
30329
|
+
}
|
|
30330
|
+
return [
|
|
30331
|
+
"## Available Checkpoints",
|
|
30332
|
+
"",
|
|
30333
|
+
...checkpoints.map((c, index) => `- ${index + 1}. "${c.label}" - ${new Date(c.timestamp).toLocaleString()} (${c.sha.slice(0, 12)})`),
|
|
30334
|
+
"",
|
|
30335
|
+
"Run `/swarm rollback <label-or-number>` to restore to a checkpoint."
|
|
30336
|
+
].join(`
|
|
30337
|
+
`);
|
|
30338
|
+
}
|
|
30339
|
+
function resolveGitCheckpoint(checkpoints, selector) {
|
|
30340
|
+
const index = Number.parseInt(selector, 10);
|
|
30341
|
+
if (/^\d+$/.test(selector) && index >= 1 && index <= checkpoints.length) {
|
|
30342
|
+
return checkpoints[index - 1] ?? null;
|
|
30343
|
+
}
|
|
30344
|
+
return checkpoints.find((c) => c.label === selector) ?? null;
|
|
30345
|
+
}
|
|
30346
|
+
async function restoreGitCheckpoint(directory, selected) {
|
|
30347
|
+
const result = await checkpoint.execute({ action: "restore", label: selected.label }, { directory });
|
|
30348
|
+
const parsed = safeParseToolJson(result);
|
|
30349
|
+
if (!parsed) {
|
|
30350
|
+
return `Error: Failed to parse checkpoint response for "${selected.label}"`;
|
|
30351
|
+
}
|
|
30352
|
+
if (parsed.success !== true) {
|
|
30353
|
+
return `Error: ${parsed.error || `Failed to restore checkpoint "${selected.label}"`}`;
|
|
30354
|
+
}
|
|
30355
|
+
const eventsPath = validateSwarmPath(directory, "events.jsonl");
|
|
30356
|
+
const rollbackEvent = {
|
|
30357
|
+
type: "rollback",
|
|
30358
|
+
label: selected.label,
|
|
30359
|
+
sha: selected.sha,
|
|
30360
|
+
timestamp: new Date().toISOString(),
|
|
30361
|
+
source: "checkpoints.json"
|
|
30362
|
+
};
|
|
30363
|
+
try {
|
|
30364
|
+
fs29.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
30365
|
+
`);
|
|
30366
|
+
} catch (error2) {
|
|
30367
|
+
console.error("Failed to write rollback event:", error2 instanceof Error ? error2.message : String(error2));
|
|
30368
|
+
}
|
|
30369
|
+
return `Rolled back to checkpoint "${selected.label}" (${selected.sha.slice(0, 12)})`;
|
|
30370
|
+
}
|
|
30218
30371
|
async function handleRollbackCommand(directory, args) {
|
|
30219
30372
|
const phaseArg = args[0];
|
|
30220
30373
|
if (!phaseArg) {
|
|
30221
30374
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
30222
|
-
if (!
|
|
30223
|
-
|
|
30375
|
+
if (!fs29.existsSync(manifestPath2)) {
|
|
30376
|
+
const gitCheckpoints = await listGitCheckpoints(directory);
|
|
30377
|
+
if (gitCheckpoints) {
|
|
30378
|
+
return formatGitCheckpointList(gitCheckpoints);
|
|
30379
|
+
}
|
|
30380
|
+
return "No checkpoints found. Use `/swarm checkpoint save <label>` to create checkpoints.";
|
|
30224
30381
|
}
|
|
30225
30382
|
let manifest2;
|
|
30226
30383
|
try {
|
|
30227
|
-
manifest2 = JSON.parse(
|
|
30384
|
+
manifest2 = JSON.parse(fs29.readFileSync(manifestPath2, "utf-8"));
|
|
30228
30385
|
} catch {
|
|
30229
30386
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
30230
30387
|
}
|
|
@@ -30243,15 +30400,31 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30243
30400
|
}
|
|
30244
30401
|
const targetPhase = parseInt(phaseArg, 10);
|
|
30245
30402
|
if (Number.isNaN(targetPhase) || targetPhase < 1) {
|
|
30246
|
-
|
|
30403
|
+
const gitCheckpoints = await listGitCheckpoints(directory);
|
|
30404
|
+
if (!gitCheckpoints) {
|
|
30405
|
+
return "Error: Phase number must be a positive integer.";
|
|
30406
|
+
}
|
|
30407
|
+
const selected = resolveGitCheckpoint(gitCheckpoints, phaseArg);
|
|
30408
|
+
if (!selected) {
|
|
30409
|
+
return `Error: Checkpoint "${phaseArg}" not found. Available checkpoints: ${gitCheckpoints.map((c) => `"${c.label}"`).join(", ") || "none"}`;
|
|
30410
|
+
}
|
|
30411
|
+
return restoreGitCheckpoint(directory, selected);
|
|
30247
30412
|
}
|
|
30248
30413
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
30249
|
-
if (!
|
|
30250
|
-
|
|
30414
|
+
if (!fs29.existsSync(manifestPath)) {
|
|
30415
|
+
const gitCheckpoints = await listGitCheckpoints(directory);
|
|
30416
|
+
if (!gitCheckpoints) {
|
|
30417
|
+
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
30418
|
+
}
|
|
30419
|
+
const selected = resolveGitCheckpoint(gitCheckpoints, phaseArg);
|
|
30420
|
+
if (!selected) {
|
|
30421
|
+
return `Error: Checkpoint ${phaseArg} not found. Available checkpoints: ${gitCheckpoints.map((c, index) => `${index + 1}="${c.label}"`).join(", ") || "none"}`;
|
|
30422
|
+
}
|
|
30423
|
+
return restoreGitCheckpoint(directory, selected);
|
|
30251
30424
|
}
|
|
30252
30425
|
let manifest;
|
|
30253
30426
|
try {
|
|
30254
|
-
manifest = JSON.parse(
|
|
30427
|
+
manifest = JSON.parse(fs29.readFileSync(manifestPath, "utf-8"));
|
|
30255
30428
|
} catch {
|
|
30256
30429
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
30257
30430
|
}
|
|
@@ -30261,10 +30434,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30261
30434
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
30262
30435
|
}
|
|
30263
30436
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
30264
|
-
if (!
|
|
30437
|
+
if (!fs29.existsSync(checkpointDir)) {
|
|
30265
30438
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
30266
30439
|
}
|
|
30267
|
-
const checkpointFiles =
|
|
30440
|
+
const checkpointFiles = fs29.readdirSync(checkpointDir);
|
|
30268
30441
|
if (checkpointFiles.length === 0) {
|
|
30269
30442
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
30270
30443
|
}
|
|
@@ -30280,10 +30453,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30280
30453
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
30281
30454
|
continue;
|
|
30282
30455
|
}
|
|
30283
|
-
const src =
|
|
30284
|
-
const dest =
|
|
30456
|
+
const src = path62.join(checkpointDir, file);
|
|
30457
|
+
const dest = path62.join(swarmDir, file);
|
|
30285
30458
|
try {
|
|
30286
|
-
|
|
30459
|
+
fs29.cpSync(src, dest, { recursive: true, force: true });
|
|
30287
30460
|
successes.push(file);
|
|
30288
30461
|
} catch (error2) {
|
|
30289
30462
|
failures.push({ file, error: error2.message });
|
|
@@ -30300,11 +30473,11 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30300
30473
|
].join(`
|
|
30301
30474
|
`);
|
|
30302
30475
|
}
|
|
30303
|
-
const existingLedgerPath =
|
|
30476
|
+
const existingLedgerPath = path62.join(swarmDir, "plan-ledger.jsonl");
|
|
30304
30477
|
let ledgerDeletionFailed = false;
|
|
30305
|
-
if (
|
|
30478
|
+
if (fs29.existsSync(existingLedgerPath)) {
|
|
30306
30479
|
try {
|
|
30307
|
-
|
|
30480
|
+
fs29.unlinkSync(existingLedgerPath);
|
|
30308
30481
|
} catch (err) {
|
|
30309
30482
|
ledgerDeletionFailed = true;
|
|
30310
30483
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -30313,9 +30486,9 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30313
30486
|
}
|
|
30314
30487
|
if (!ledgerDeletionFailed) {
|
|
30315
30488
|
try {
|
|
30316
|
-
const planJsonPath =
|
|
30317
|
-
if (
|
|
30318
|
-
const planRaw =
|
|
30489
|
+
const planJsonPath = path62.join(swarmDir, "plan.json");
|
|
30490
|
+
if (fs29.existsSync(planJsonPath)) {
|
|
30491
|
+
const planRaw = fs29.readFileSync(planJsonPath, "utf-8");
|
|
30319
30492
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
30320
30493
|
const planId = derivePlanId(plan);
|
|
30321
30494
|
const planHash = computePlanHash(plan);
|
|
@@ -30343,7 +30516,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30343
30516
|
timestamp: new Date().toISOString()
|
|
30344
30517
|
};
|
|
30345
30518
|
try {
|
|
30346
|
-
|
|
30519
|
+
fs29.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
30347
30520
|
`);
|
|
30348
30521
|
} catch (error2) {
|
|
30349
30522
|
console.error("Failed to write rollback event:", error2 instanceof Error ? error2.message : String(error2));
|
|
@@ -30360,9 +30533,9 @@ async function handleRollbackCommand(directory, args) {
|
|
|
30360
30533
|
}
|
|
30361
30534
|
|
|
30362
30535
|
// src/commands/sdd.ts
|
|
30363
|
-
import * as
|
|
30364
|
-
import * as
|
|
30365
|
-
var SWARM_SPEC_REL =
|
|
30536
|
+
import * as fs30 from "fs";
|
|
30537
|
+
import * as path63 from "path";
|
|
30538
|
+
var SWARM_SPEC_REL = path63.join(".swarm", "spec.md");
|
|
30366
30539
|
var USAGE9 = `Usage:
|
|
30367
30540
|
/swarm sdd status [--json] [--source <provider>]
|
|
30368
30541
|
/swarm sdd validate [--json] [--change <id>] [--source <provider>] [--feature <id>]
|
|
@@ -30478,7 +30651,7 @@ ${USAGE9}`;
|
|
|
30478
30651
|
}
|
|
30479
30652
|
const speckitDetection = detectSpeckit(directory);
|
|
30480
30653
|
const speckitPresent = speckitDetection.features.length > 0;
|
|
30481
|
-
const nativeSpecExists =
|
|
30654
|
+
const nativeSpecExists = fs30.existsSync(path63.join(directory, SWARM_SPEC_REL));
|
|
30482
30655
|
if (speckitPresent && !parsed.source && !nativeSpecExists) {
|
|
30483
30656
|
const openspecProjection = buildOpenSpecProjectionSync(directory);
|
|
30484
30657
|
if (openspecProjection !== null) {
|
|
@@ -30548,7 +30721,7 @@ ${USAGE9}`;
|
|
|
30548
30721
|
${USAGE9}`;
|
|
30549
30722
|
}
|
|
30550
30723
|
let useSpeckit = false;
|
|
30551
|
-
const nativeSpecExists =
|
|
30724
|
+
const nativeSpecExists = fs30.existsSync(path63.join(directory, SWARM_SPEC_REL));
|
|
30552
30725
|
if (parsed.source === "speckit") {
|
|
30553
30726
|
useSpeckit = true;
|
|
30554
30727
|
} else if (!parsed.source && !nativeSpecExists) {
|
|
@@ -30859,13 +31032,13 @@ Ensure this is a git repository with commit history.`;
|
|
|
30859
31032
|
const report = reportLines.filter(Boolean).join(`
|
|
30860
31033
|
`);
|
|
30861
31034
|
try {
|
|
30862
|
-
const
|
|
30863
|
-
const
|
|
30864
|
-
const reportPath =
|
|
30865
|
-
await
|
|
30866
|
-
const reportTempPath =
|
|
31035
|
+
const fs31 = await import("fs/promises");
|
|
31036
|
+
const path64 = await import("path");
|
|
31037
|
+
const reportPath = path64.join(directory, ".swarm", "simulate-report.md");
|
|
31038
|
+
await fs31.mkdir(path64.dirname(reportPath), { recursive: true });
|
|
31039
|
+
const reportTempPath = path64.join(path64.dirname(reportPath), `${path64.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
30867
31040
|
try {
|
|
30868
|
-
await
|
|
31041
|
+
await fs31.writeFile(reportTempPath, report, "utf-8");
|
|
30869
31042
|
renameSync11(reportTempPath, reportPath);
|
|
30870
31043
|
} catch (err) {
|
|
30871
31044
|
try {
|
|
@@ -30891,8 +31064,8 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
30891
31064
|
|
|
30892
31065
|
// src/services/status-service.ts
|
|
30893
31066
|
import * as fsSync2 from "fs";
|
|
30894
|
-
import { readFile as
|
|
30895
|
-
import * as
|
|
31067
|
+
import { readFile as readFile17 } from "fs/promises";
|
|
31068
|
+
import * as path65 from "path";
|
|
30896
31069
|
|
|
30897
31070
|
// src/hooks/extractors.ts
|
|
30898
31071
|
function extractCurrentPhase(planContent) {
|
|
@@ -30936,16 +31109,16 @@ function extractCurrentPhaseFromPlan2(plan) {
|
|
|
30936
31109
|
|
|
30937
31110
|
// src/turbo/lean/state.ts
|
|
30938
31111
|
init_logger();
|
|
30939
|
-
import * as
|
|
30940
|
-
import * as
|
|
31112
|
+
import * as fs31 from "fs";
|
|
31113
|
+
import * as path64 from "path";
|
|
30941
31114
|
var STATE_FILE3 = "turbo-state.json";
|
|
30942
31115
|
function nowISO3() {
|
|
30943
31116
|
return new Date().toISOString();
|
|
30944
31117
|
}
|
|
30945
31118
|
function ensureSwarmDir2(directory) {
|
|
30946
|
-
const swarmDir =
|
|
30947
|
-
if (!
|
|
30948
|
-
|
|
31119
|
+
const swarmDir = path64.resolve(directory, ".swarm");
|
|
31120
|
+
if (!fs31.existsSync(swarmDir)) {
|
|
31121
|
+
fs31.mkdirSync(swarmDir, { recursive: true });
|
|
30949
31122
|
}
|
|
30950
31123
|
return swarmDir;
|
|
30951
31124
|
}
|
|
@@ -30988,17 +31161,17 @@ function markStateUnreadable2(directory, reason) {
|
|
|
30988
31161
|
}
|
|
30989
31162
|
function readPersisted2(directory) {
|
|
30990
31163
|
try {
|
|
30991
|
-
const filePath =
|
|
30992
|
-
if (!
|
|
31164
|
+
const filePath = path64.join(directory, ".swarm", STATE_FILE3);
|
|
31165
|
+
if (!fs31.existsSync(filePath)) {
|
|
30993
31166
|
const seed = emptyPersisted2();
|
|
30994
31167
|
try {
|
|
30995
31168
|
ensureSwarmDir2(directory);
|
|
30996
|
-
|
|
31169
|
+
fs31.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
|
|
30997
31170
|
`, "utf-8");
|
|
30998
31171
|
} catch {}
|
|
30999
31172
|
return seed;
|
|
31000
31173
|
}
|
|
31001
|
-
const raw =
|
|
31174
|
+
const raw = fs31.readFileSync(filePath, "utf-8");
|
|
31002
31175
|
const parsed = JSON.parse(raw);
|
|
31003
31176
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
|
|
31004
31177
|
markStateUnreadable2(directory, `malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
|
|
@@ -31024,7 +31197,7 @@ function writePersisted2(directory, persisted) {
|
|
|
31024
31197
|
let payload;
|
|
31025
31198
|
try {
|
|
31026
31199
|
ensureSwarmDir2(directory);
|
|
31027
|
-
filePath =
|
|
31200
|
+
filePath = path64.join(directory, ".swarm", STATE_FILE3);
|
|
31028
31201
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
31029
31202
|
persisted.updatedAt = nowISO3();
|
|
31030
31203
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -31035,14 +31208,14 @@ function writePersisted2(directory, persisted) {
|
|
|
31035
31208
|
throw new Error(`Lean Turbo state persistence prepare failed: ${msg}`);
|
|
31036
31209
|
}
|
|
31037
31210
|
try {
|
|
31038
|
-
|
|
31039
|
-
|
|
31211
|
+
fs31.writeFileSync(tmpPath, payload, "utf-8");
|
|
31212
|
+
fs31.renameSync(tmpPath, filePath);
|
|
31040
31213
|
} catch (error2) {
|
|
31041
31214
|
const msg = error2 instanceof Error ? error2.message : String(error2);
|
|
31042
31215
|
error(`[turbo/lean/state] Failed to persist ${STATE_FILE3} atomically: ${msg}`);
|
|
31043
31216
|
try {
|
|
31044
|
-
if (
|
|
31045
|
-
|
|
31217
|
+
if (fs31.existsSync(tmpPath)) {
|
|
31218
|
+
fs31.unlinkSync(tmpPath);
|
|
31046
31219
|
}
|
|
31047
31220
|
} catch {}
|
|
31048
31221
|
throw new Error(`Lean Turbo state persistence failed: ${msg}`);
|
|
@@ -31142,7 +31315,7 @@ var _internals47 = {
|
|
|
31142
31315
|
};
|
|
31143
31316
|
function readSpecStalenessSnapshot(directory) {
|
|
31144
31317
|
try {
|
|
31145
|
-
const p =
|
|
31318
|
+
const p = path65.join(directory, ".swarm", "spec-staleness.json");
|
|
31146
31319
|
if (!fsSync2.existsSync(p))
|
|
31147
31320
|
return { stale: false };
|
|
31148
31321
|
const raw = fsSync2.readFileSync(p, "utf-8");
|
|
@@ -31395,7 +31568,7 @@ async function safeLineCount(filePath) {
|
|
|
31395
31568
|
try {
|
|
31396
31569
|
if (!fsSync2.existsSync(filePath))
|
|
31397
31570
|
return 0;
|
|
31398
|
-
const content = await
|
|
31571
|
+
const content = await readFile17(filePath, "utf-8");
|
|
31399
31572
|
let n = 0;
|
|
31400
31573
|
for (const line of content.split(`
|
|
31401
31574
|
`)) {
|
|
@@ -31674,13 +31847,13 @@ function buildStatusMessage2(session, directory, sessionID) {
|
|
|
31674
31847
|
}
|
|
31675
31848
|
|
|
31676
31849
|
// src/commands/unlink.ts
|
|
31677
|
-
import { existsSync as
|
|
31678
|
-
import * as
|
|
31850
|
+
import { existsSync as existsSync40 } from "fs";
|
|
31851
|
+
import * as path66 from "path";
|
|
31679
31852
|
var DEDUP_THRESHOLD2 = 0.6;
|
|
31680
31853
|
async function copySharedKnowledgeToLocal(linkDir, localSwarmDir) {
|
|
31681
|
-
const sharedPath =
|
|
31682
|
-
const localPath =
|
|
31683
|
-
if (!
|
|
31854
|
+
const sharedPath = path66.join(linkDir, "knowledge.jsonl");
|
|
31855
|
+
const localPath = path66.join(localSwarmDir, "knowledge.jsonl");
|
|
31856
|
+
if (!existsSync40(sharedPath))
|
|
31684
31857
|
return 0;
|
|
31685
31858
|
const sharedEntries = await readKnowledge(sharedPath);
|
|
31686
31859
|
if (sharedEntries.length === 0)
|
|
@@ -31714,7 +31887,7 @@ async function handleUnlinkCommand(directory, args) {
|
|
|
31714
31887
|
let copied = 0;
|
|
31715
31888
|
if (copyBack) {
|
|
31716
31889
|
try {
|
|
31717
|
-
copied = await copySharedKnowledgeToLocal(linkDir,
|
|
31890
|
+
copied = await copySharedKnowledgeToLocal(linkDir, path66.join(directory, ".swarm"));
|
|
31718
31891
|
} catch (error2) {
|
|
31719
31892
|
return `\u274C Failed to copy shared knowledge back to local: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
31720
31893
|
}
|
|
@@ -31876,7 +32049,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
31876
32049
|
async function handleHelpCommand(ctx) {
|
|
31877
32050
|
const targetCommand = ctx.args.join(" ");
|
|
31878
32051
|
if (!targetCommand) {
|
|
31879
|
-
const { buildHelpText } = await import("./index-
|
|
32052
|
+
const { buildHelpText } = await import("./index-502f6np6.js");
|
|
31880
32053
|
return buildHelpText();
|
|
31881
32054
|
}
|
|
31882
32055
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -31885,7 +32058,7 @@ async function handleHelpCommand(ctx) {
|
|
|
31885
32058
|
return _internals49.buildDetailedHelp(resolved.key, resolved.entry);
|
|
31886
32059
|
}
|
|
31887
32060
|
const similar = _internals49.findSimilarCommands(targetCommand);
|
|
31888
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
32061
|
+
const { buildHelpText: fullHelp } = await import("./index-502f6np6.js");
|
|
31889
32062
|
if (similar.length > 0) {
|
|
31890
32063
|
return `Command '/swarm ${targetCommand}' not found.
|
|
31891
32064
|
|
|
@@ -32018,7 +32191,7 @@ var COMMAND_REGISTRY = {
|
|
|
32018
32191
|
},
|
|
32019
32192
|
"guardrail explain": {
|
|
32020
32193
|
handler: async (ctx) => {
|
|
32021
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
32194
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-etdrhd4d.js");
|
|
32022
32195
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
32023
32196
|
},
|
|
32024
32197
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -32028,7 +32201,7 @@ var COMMAND_REGISTRY = {
|
|
|
32028
32201
|
},
|
|
32029
32202
|
"guardrail-log": {
|
|
32030
32203
|
handler: async (ctx) => {
|
|
32031
|
-
const { handleGuardrailLog } = await import("./guardrail-log-
|
|
32204
|
+
const { handleGuardrailLog } = await import("./guardrail-log-2rns4g6d.js");
|
|
32032
32205
|
return handleGuardrailLog(ctx.directory, ctx.args);
|
|
32033
32206
|
},
|
|
32034
32207
|
description: "Read the guardrail decision log (use --blocks-only for blocks)",
|
|
@@ -32540,9 +32713,9 @@ Subcommands:
|
|
|
32540
32713
|
},
|
|
32541
32714
|
rollback: {
|
|
32542
32715
|
handler: (ctx) => handleRollbackCommand(ctx.directory, ctx.args),
|
|
32543
|
-
description: "Restore swarm state to a checkpoint
|
|
32544
|
-
details: "Restores .swarm/
|
|
32545
|
-
args: "<phase-number>",
|
|
32716
|
+
description: "Restore swarm state or project files to a checkpoint",
|
|
32717
|
+
details: "Restores legacy .swarm/ phase checkpoints from checkpoints/phase-<N> when present. Otherwise restores named git checkpoints from .swarm/checkpoints.json by label or list number. Writes rollback event to events.jsonl. Without an argument, lists available checkpoints.",
|
|
32718
|
+
args: "<phase-number|label|list-number>",
|
|
32546
32719
|
category: "utility",
|
|
32547
32720
|
toolPolicy: "restricted"
|
|
32548
32721
|
},
|
|
@@ -32555,7 +32728,7 @@ Subcommands:
|
|
|
32555
32728
|
toolPolicy: "agent"
|
|
32556
32729
|
},
|
|
32557
32730
|
handoff: {
|
|
32558
|
-
handler: (ctx) => handleHandoffCommand(ctx.directory, ctx.args),
|
|
32731
|
+
handler: (ctx) => handleHandoffCommand(ctx.directory, ctx.args, ctx.sessionID),
|
|
32559
32732
|
description: "Prepare state for clean model switch (new session)",
|
|
32560
32733
|
args: "",
|
|
32561
32734
|
details: "Generates handoff.md with full session state snapshot, including plan progress, recent decisions, and agent delegation history. Prepended to the next session prompt for seamless model switches.",
|
|
@@ -32781,7 +32954,7 @@ Subcommands:
|
|
|
32781
32954
|
checkpoint: {
|
|
32782
32955
|
handler: (ctx) => handleCheckpointCommand(ctx.directory, ctx.args),
|
|
32783
32956
|
description: "Manage project checkpoints [save|restore|delete|list] <label>",
|
|
32784
|
-
details: "save: creates named
|
|
32957
|
+
details: "save: creates named git checkpoint. restore: hard-resets tracked files to the checkpoint. delete: removes named checkpoint metadata. list: shows all checkpoints with timestamps. All subcommands require a label except list.",
|
|
32785
32958
|
args: "<save|restore|delete|list> <label>",
|
|
32786
32959
|
category: "utility",
|
|
32787
32960
|
clashesWithNativeCcCommand: "/checkpoint",
|
|
@@ -32801,24 +32974,24 @@ function validateAliases() {
|
|
|
32801
32974
|
continue;
|
|
32802
32975
|
}
|
|
32803
32976
|
const visited = new Set;
|
|
32804
|
-
const
|
|
32977
|
+
const path67 = [];
|
|
32805
32978
|
let current = target;
|
|
32806
32979
|
while (current) {
|
|
32807
32980
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
32808
32981
|
if (!currentEntry)
|
|
32809
32982
|
break;
|
|
32810
32983
|
if (visited.has(current)) {
|
|
32811
|
-
const cycleStart =
|
|
32984
|
+
const cycleStart = path67.indexOf(current);
|
|
32812
32985
|
const fullChain = [
|
|
32813
32986
|
name,
|
|
32814
|
-
...
|
|
32987
|
+
...path67.slice(0, cycleStart > 0 ? cycleStart : path67.length),
|
|
32815
32988
|
current
|
|
32816
32989
|
].join(" \u2192 ");
|
|
32817
32990
|
errors.push(`Circular alias detected: ${fullChain}`);
|
|
32818
32991
|
break;
|
|
32819
32992
|
}
|
|
32820
32993
|
visited.add(current);
|
|
32821
|
-
|
|
32994
|
+
path67.push(current);
|
|
32822
32995
|
current = currentEntry.aliasOf || "";
|
|
32823
32996
|
}
|
|
32824
32997
|
}
|
|
@@ -34157,7 +34330,7 @@ init_logger();
|
|
|
34157
34330
|
|
|
34158
34331
|
// src/hooks/guardrails/destructive-command.ts
|
|
34159
34332
|
import * as fsSync3 from "fs";
|
|
34160
|
-
import * as
|
|
34333
|
+
import * as path67 from "path";
|
|
34161
34334
|
var DC_MAX_UNWRAP_DEPTH = 5;
|
|
34162
34335
|
var DC_SAFE_TARGETS = new Set([
|
|
34163
34336
|
"node_modules",
|
|
@@ -34321,16 +34494,16 @@ function dcIsRemotePath(p) {
|
|
|
34321
34494
|
return DC_REMOTE_PREFIXES.some((pfx) => p.startsWith(pfx));
|
|
34322
34495
|
}
|
|
34323
34496
|
function dcLstatAncestorWalk(targetPath, cwd) {
|
|
34324
|
-
const normalizedTarget =
|
|
34325
|
-
const normalizedCwd =
|
|
34497
|
+
const normalizedTarget = path67.resolve(cwd, targetPath);
|
|
34498
|
+
const normalizedCwd = path67.resolve(cwd);
|
|
34326
34499
|
const ancestors = [];
|
|
34327
34500
|
let current = normalizedTarget;
|
|
34328
34501
|
while (true) {
|
|
34329
34502
|
ancestors.push(current);
|
|
34330
|
-
const parent =
|
|
34503
|
+
const parent = path67.dirname(current);
|
|
34331
34504
|
if (parent === current)
|
|
34332
34505
|
break;
|
|
34333
|
-
const rel =
|
|
34506
|
+
const rel = path67.relative(normalizedCwd, current);
|
|
34334
34507
|
if (rel === "" || rel.startsWith(".."))
|
|
34335
34508
|
break;
|
|
34336
34509
|
current = parent;
|
|
@@ -34369,14 +34542,14 @@ function dcValidateTargets(targets, cwd) {
|
|
|
34369
34542
|
const lstatBlock = dcLstatAncestorWalk(t, cwd);
|
|
34370
34543
|
if (lstatBlock)
|
|
34371
34544
|
return lstatBlock;
|
|
34372
|
-
const
|
|
34373
|
-
if (t ===
|
|
34545
|
+
const basename12 = path67.basename(t);
|
|
34546
|
+
if (t === basename12 && DC_SAFE_TARGETS.has(t)) {
|
|
34374
34547
|
continue;
|
|
34375
34548
|
}
|
|
34376
34549
|
if (DC_FS_ROOTS.has(t) || DC_FS_ROOTS.has(t.replace(/\//g, "\\"))) {
|
|
34377
34550
|
return `BLOCKED: Destructive command targets filesystem root "${t}"`;
|
|
34378
34551
|
}
|
|
34379
|
-
if (
|
|
34552
|
+
if (path67.isAbsolute(t) || /^[A-Za-z]:/.test(t)) {
|
|
34380
34553
|
for (const blocked of DC_BLOCKED_ABSOLUTE_PREFIXES) {
|
|
34381
34554
|
if (t.startsWith(blocked)) {
|
|
34382
34555
|
return `BLOCKED: Destructive command targets system path "${t}" which is under protected prefix "${blocked}"`;
|
|
@@ -34391,9 +34564,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
34391
34564
|
if (mklinkMatch) {
|
|
34392
34565
|
const target = mklinkMatch[2].trim();
|
|
34393
34566
|
if (!dcHasUnresolvableVars(target)) {
|
|
34394
|
-
const resolved =
|
|
34395
|
-
const rel =
|
|
34396
|
-
if (rel.startsWith("..") ||
|
|
34567
|
+
const resolved = path67.resolve(cwd, target);
|
|
34568
|
+
const rel = path67.relative(cwd, resolved);
|
|
34569
|
+
if (rel.startsWith("..") || path67.isAbsolute(rel)) {
|
|
34397
34570
|
return `BLOCKED: Junction/symlink creation targeting path outside working directory: mklink target "${target}" resolves to "${resolved}" which is outside "${cwd}". Creating junctions to external paths and then deleting them recursively can destroy data.`;
|
|
34398
34571
|
}
|
|
34399
34572
|
}
|
|
@@ -34405,9 +34578,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
34405
34578
|
if (newItemMatch) {
|
|
34406
34579
|
const target = newItemMatch[1].trim();
|
|
34407
34580
|
if (!dcHasUnresolvableVars(target)) {
|
|
34408
|
-
const resolved =
|
|
34409
|
-
const rel =
|
|
34410
|
-
if (rel.startsWith("..") ||
|
|
34581
|
+
const resolved = path67.resolve(cwd, target);
|
|
34582
|
+
const rel = path67.relative(cwd, resolved);
|
|
34583
|
+
if (rel.startsWith("..") || path67.isAbsolute(rel)) {
|
|
34411
34584
|
return `BLOCKED: Junction/symlink creation targeting path outside working directory: New-Item target "${target}" resolves to "${resolved}" which is outside "${cwd}". This pattern caused the K2.6 data-loss incident.`;
|
|
34412
34585
|
}
|
|
34413
34586
|
}
|
|
@@ -34417,9 +34590,9 @@ function dcCheckJunctionCreation(segment, cwd) {
|
|
|
34417
34590
|
if (lnMatch) {
|
|
34418
34591
|
const target = lnMatch[1].trim();
|
|
34419
34592
|
if (!dcHasUnresolvableVars(target)) {
|
|
34420
|
-
const resolved =
|
|
34421
|
-
const rel =
|
|
34422
|
-
if (rel.startsWith("..") ||
|
|
34593
|
+
const resolved = path67.resolve(cwd, target);
|
|
34594
|
+
const rel = path67.relative(cwd, resolved);
|
|
34595
|
+
if (rel.startsWith("..") || path67.isAbsolute(rel)) {
|
|
34423
34596
|
return `BLOCKED: Symlink creation targeting path outside working directory: ln -s target "${target}" resolves to "${resolved}" which is outside "${cwd}". Symlinks to external paths combined with recursive deletion can destroy data.`;
|
|
34424
34597
|
}
|
|
34425
34598
|
}
|
|
@@ -34790,10 +34963,10 @@ function classifySwarmCommandChatFallbackUse(resolved) {
|
|
|
34790
34963
|
init_executor();
|
|
34791
34964
|
|
|
34792
34965
|
// src/hooks/shell-write-detect.ts
|
|
34793
|
-
import * as
|
|
34966
|
+
import * as path68 from "path";
|
|
34794
34967
|
import parse from "bash-parser";
|
|
34795
|
-
function buildDedupeKey(category, operator,
|
|
34796
|
-
return `${category}|${operator}|${
|
|
34968
|
+
function buildDedupeKey(category, operator, path69) {
|
|
34969
|
+
return `${category}|${operator}|${path69 ?? "null"}`;
|
|
34797
34970
|
}
|
|
34798
34971
|
var REDIRECT_WRITE_TOKENS = new Set([
|
|
34799
34972
|
"GREAT",
|
|
@@ -34853,16 +35026,16 @@ function detectProcessSubstitutionWrites(command) {
|
|
|
34853
35026
|
results.push(builtinResult);
|
|
34854
35027
|
const appendMatch = stage.match(/^\s*(.*?)\s*>>(\s*)(\S+)\s*$/);
|
|
34855
35028
|
if (appendMatch) {
|
|
34856
|
-
const
|
|
34857
|
-
if (
|
|
34858
|
-
results.push({ category: "redirect", operator: ">>", path:
|
|
35029
|
+
const path69 = appendMatch[3];
|
|
35030
|
+
if (path69 && !isNullDevice(path69)) {
|
|
35031
|
+
results.push({ category: "redirect", operator: ">>", path: path69 });
|
|
34859
35032
|
}
|
|
34860
35033
|
} else {
|
|
34861
35034
|
const writeMatch = stage.match(/^\s*(.*?)\s*>(?!>)(\s*)(\S+)\s*$/);
|
|
34862
35035
|
if (writeMatch) {
|
|
34863
|
-
const
|
|
34864
|
-
if (
|
|
34865
|
-
results.push({ category: "redirect", operator: ">", path:
|
|
35036
|
+
const path69 = writeMatch[3];
|
|
35037
|
+
if (path69 && !isNullDevice(path69)) {
|
|
35038
|
+
results.push({ category: "redirect", operator: ">", path: path69 });
|
|
34866
35039
|
}
|
|
34867
35040
|
}
|
|
34868
35041
|
}
|
|
@@ -35036,8 +35209,8 @@ function extractRedirectPath(fileNode) {
|
|
|
35036
35209
|
return null;
|
|
35037
35210
|
return text;
|
|
35038
35211
|
}
|
|
35039
|
-
function isNullDevice(
|
|
35040
|
-
return
|
|
35212
|
+
function isNullDevice(path69) {
|
|
35213
|
+
return path69 === "/dev/null" || path69 === "/dev/zero" || path69 === "/dev/urandom";
|
|
35041
35214
|
}
|
|
35042
35215
|
function isNumeric(s) {
|
|
35043
35216
|
return /^\d+$/.test(s);
|
|
@@ -35057,12 +35230,12 @@ function detectRedirects(cmd) {
|
|
|
35057
35230
|
if (!opType || !REDIRECT_ALL_WRITE_TOKENS.has(opType))
|
|
35058
35231
|
continue;
|
|
35059
35232
|
const fileNode = r.file;
|
|
35060
|
-
const
|
|
35233
|
+
const path69 = extractRedirectPath(fileNode);
|
|
35061
35234
|
const opLabel = operatorLabel(opNode);
|
|
35062
35235
|
if (REDIRECT_WRITE_TOKENS.has(opType)) {
|
|
35063
|
-
results.push({ category: "redirect", operator: opLabel, path:
|
|
35236
|
+
results.push({ category: "redirect", operator: opLabel, path: path69 });
|
|
35064
35237
|
} else if (REDIRECT_HERE_TOKENS.has(opType)) {
|
|
35065
|
-
results.push({ category: "here_doc", operator: opLabel, path:
|
|
35238
|
+
results.push({ category: "here_doc", operator: opLabel, path: path69 });
|
|
35066
35239
|
}
|
|
35067
35240
|
}
|
|
35068
35241
|
return results;
|
|
@@ -35105,9 +35278,9 @@ function detectBuiltinWrites(cmd) {
|
|
|
35105
35278
|
const suffixWords2 = getSuffixWords(cmd);
|
|
35106
35279
|
for (const word of suffixWords2) {
|
|
35107
35280
|
if (word.startsWith("of=")) {
|
|
35108
|
-
const
|
|
35109
|
-
if (
|
|
35110
|
-
results.push({ category: "builtin_write", operator: "dd of=", path:
|
|
35281
|
+
const path69 = word.slice(3);
|
|
35282
|
+
if (path69 && !isNullDevice(path69)) {
|
|
35283
|
+
results.push({ category: "builtin_write", operator: "dd of=", path: path69 });
|
|
35111
35284
|
}
|
|
35112
35285
|
}
|
|
35113
35286
|
}
|
|
@@ -35226,12 +35399,12 @@ function detectNetworkDownloaders(cmd) {
|
|
|
35226
35399
|
for (let i = 0;i < suffixWords.length; i++) {
|
|
35227
35400
|
const word = suffixWords[i];
|
|
35228
35401
|
if (word === "-o" && i + 1 < suffixWords.length) {
|
|
35229
|
-
const
|
|
35230
|
-
if (!
|
|
35402
|
+
const path69 = suffixWords[i + 1];
|
|
35403
|
+
if (!path69.startsWith("-")) {
|
|
35231
35404
|
results.push({
|
|
35232
35405
|
category: "network_download",
|
|
35233
35406
|
operator: "curl -o",
|
|
35234
|
-
path:
|
|
35407
|
+
path: path69
|
|
35235
35408
|
});
|
|
35236
35409
|
}
|
|
35237
35410
|
} else if (word.startsWith("-o") && word.length > 2) {
|
|
@@ -35246,12 +35419,12 @@ function detectNetworkDownloaders(cmd) {
|
|
|
35246
35419
|
for (let i = 0;i < suffixWords.length; i++) {
|
|
35247
35420
|
const word = suffixWords[i];
|
|
35248
35421
|
if (word === "-O" && i + 1 < suffixWords.length) {
|
|
35249
|
-
const
|
|
35250
|
-
if (!
|
|
35422
|
+
const path69 = suffixWords[i + 1];
|
|
35423
|
+
if (!path69.startsWith("-")) {
|
|
35251
35424
|
results.push({
|
|
35252
35425
|
category: "network_download",
|
|
35253
35426
|
operator: "wget -O",
|
|
35254
|
-
path:
|
|
35427
|
+
path: path69
|
|
35255
35428
|
});
|
|
35256
35429
|
}
|
|
35257
35430
|
} else if (word.startsWith("-O") && word.length > 2) {
|
|
@@ -35360,9 +35533,9 @@ function detectGitDestructive(cmd) {
|
|
|
35360
35533
|
if (first === "checkout") {
|
|
35361
35534
|
const dashDashIdx = suffixWords.indexOf("--");
|
|
35362
35535
|
if (dashDashIdx !== -1 && dashDashIdx + 1 < suffixWords.length) {
|
|
35363
|
-
const
|
|
35364
|
-
const op =
|
|
35365
|
-
results.push({ category: "git_destructive", operator: op, path:
|
|
35536
|
+
const path69 = suffixWords[dashDashIdx + 1];
|
|
35537
|
+
const op = path69 === "." ? "git checkout -- ." : "git checkout --";
|
|
35538
|
+
results.push({ category: "git_destructive", operator: op, path: path69 });
|
|
35366
35539
|
}
|
|
35367
35540
|
} else if (first === "restore") {
|
|
35368
35541
|
const hasHard = suffixWords.some((w) => w === "--hard" || w === "-H" || w.startsWith("-") && w.includes("H"));
|
|
@@ -35482,10 +35655,10 @@ function detectPowerShellWrites(command) {
|
|
|
35482
35655
|
if (redirectMatch) {
|
|
35483
35656
|
const beforeRedirect = redirectMatch[1];
|
|
35484
35657
|
const op = redirectMatch[2];
|
|
35485
|
-
const
|
|
35658
|
+
const path69 = redirectMatch[3];
|
|
35486
35659
|
const fdRedirectPattern = /\d>\s*$|\s\d>&$/;
|
|
35487
35660
|
if (!fdRedirectPattern.test(`${beforeRedirect} ${op}`)) {
|
|
35488
|
-
results.push({ category: "redirect", operator: op, path:
|
|
35661
|
+
results.push({ category: "redirect", operator: op, path: path69 });
|
|
35489
35662
|
}
|
|
35490
35663
|
}
|
|
35491
35664
|
const leadingRedirect = innerCommand.match(/^((?:>){1,2})\s+(\S+)$/);
|
|
@@ -35498,12 +35671,12 @@ function detectPowerShellWrites(command) {
|
|
|
35498
35671
|
}
|
|
35499
35672
|
const iwrMatch = trimmed.match(/^(?:Invoke-WebRequest|curl)\s.*?(?:-OutFile\s+(\S+)|-o\s+(\S+))/i);
|
|
35500
35673
|
if (iwrMatch) {
|
|
35501
|
-
const
|
|
35502
|
-
if (
|
|
35674
|
+
const path69 = iwrMatch[1] || iwrMatch[2];
|
|
35675
|
+
if (path69) {
|
|
35503
35676
|
results.push({
|
|
35504
35677
|
category: "network_download",
|
|
35505
35678
|
operator: "Invoke-WebRequest -OutFile",
|
|
35506
|
-
path:
|
|
35679
|
+
path: path69
|
|
35507
35680
|
});
|
|
35508
35681
|
}
|
|
35509
35682
|
}
|
|
@@ -35515,15 +35688,15 @@ function detectPowerShellWrites(command) {
|
|
|
35515
35688
|
const rest = cmd.slice(cmdletMatch[0].length).trim();
|
|
35516
35689
|
const pathFlagMatch = rest.match(/(?:-Path|-FilePath|-LiteralPath)\s+("([^"]+)"|'([^']+)'|(\S+))/i);
|
|
35517
35690
|
if (pathFlagMatch) {
|
|
35518
|
-
const
|
|
35519
|
-
return { category: "redirect", operator: cmdletName, path:
|
|
35691
|
+
const path69 = pathFlagMatch[2] ?? pathFlagMatch[3] ?? pathFlagMatch[4] ?? "";
|
|
35692
|
+
return { category: "redirect", operator: cmdletName, path: path69 };
|
|
35520
35693
|
}
|
|
35521
35694
|
const tokens = rest.match(/(?:[^\s"-]+|"[^"]*"|'[^']*'|-[^\s]+)/g) ?? [];
|
|
35522
35695
|
for (const token of tokens) {
|
|
35523
35696
|
if (token.startsWith("-"))
|
|
35524
35697
|
continue;
|
|
35525
|
-
const
|
|
35526
|
-
return { category: "redirect", operator: cmdletName, path:
|
|
35698
|
+
const path69 = token.replace(/^["']|["']$/g, "");
|
|
35699
|
+
return { category: "redirect", operator: cmdletName, path: path69 };
|
|
35527
35700
|
}
|
|
35528
35701
|
return null;
|
|
35529
35702
|
}
|
|
@@ -35539,9 +35712,9 @@ function detectPowerShellWrites(command) {
|
|
|
35539
35712
|
for (const token of tokens) {
|
|
35540
35713
|
if (token.startsWith("-"))
|
|
35541
35714
|
continue;
|
|
35542
|
-
const
|
|
35543
|
-
if (
|
|
35544
|
-
results.push({ category: "redirect", operator: cmdletName, path:
|
|
35715
|
+
const path69 = token.replace(/^["']|["']$/g, "");
|
|
35716
|
+
if (path69) {
|
|
35717
|
+
results.push({ category: "redirect", operator: cmdletName, path: path69 });
|
|
35545
35718
|
break;
|
|
35546
35719
|
}
|
|
35547
35720
|
}
|
|
@@ -35554,8 +35727,8 @@ function detectPowerShellWrites(command) {
|
|
|
35554
35727
|
const rest = cmd.slice(opMatch[0].length).trim();
|
|
35555
35728
|
const destFlagMatch = rest.match(/-Destination\s+(\S+|"[^"]+"|'[^']+')/i);
|
|
35556
35729
|
if (destFlagMatch) {
|
|
35557
|
-
const
|
|
35558
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
35730
|
+
const path69 = destFlagMatch[1].replace(/^["']|["']$/g, "");
|
|
35731
|
+
return { category: "builtin_write", operator: cmdletName, path: path69 };
|
|
35559
35732
|
}
|
|
35560
35733
|
const tokens = [];
|
|
35561
35734
|
const flagTakingValue = new Set([
|
|
@@ -35594,11 +35767,11 @@ function detectPowerShellWrites(command) {
|
|
|
35594
35767
|
}
|
|
35595
35768
|
}
|
|
35596
35769
|
if (tokens.length >= 2) {
|
|
35597
|
-
const
|
|
35598
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
35770
|
+
const path69 = tokens[tokens.length - 1].replace(/^["']|["']$/g, "");
|
|
35771
|
+
return { category: "builtin_write", operator: cmdletName, path: path69 };
|
|
35599
35772
|
} else if (tokens.length === 1) {
|
|
35600
|
-
const
|
|
35601
|
-
return { category: "builtin_write", operator: cmdletName, path:
|
|
35773
|
+
const path69 = tokens[0].replace(/^["']|["']$/g, "");
|
|
35774
|
+
return { category: "builtin_write", operator: cmdletName, path: path69 };
|
|
35602
35775
|
}
|
|
35603
35776
|
return null;
|
|
35604
35777
|
}
|
|
@@ -35612,14 +35785,14 @@ function detectPowerShellWrites(command) {
|
|
|
35612
35785
|
const afterCmdlet = pipeFileOpMatch[2].trim();
|
|
35613
35786
|
const destFlagMatch = afterCmdlet.match(/-Destination\s+(\S+|"[^"]+"|'[^']+')/i);
|
|
35614
35787
|
if (destFlagMatch) {
|
|
35615
|
-
const
|
|
35616
|
-
results.push({ category: "builtin_write", operator: cmdletName, path:
|
|
35788
|
+
const path69 = destFlagMatch[1].replace(/^["']|["']$/g, "");
|
|
35789
|
+
results.push({ category: "builtin_write", operator: cmdletName, path: path69 });
|
|
35617
35790
|
} else {
|
|
35618
35791
|
const tokens = afterCmdlet.match(/(?:[^\s"-]+|"[^"]*"|'[^']*'|-[^\s]+)/g) ?? [];
|
|
35619
35792
|
const nonFlagTokens = tokens.filter((t) => !t.startsWith("-") && t.length > 0);
|
|
35620
35793
|
if (nonFlagTokens.length > 0) {
|
|
35621
|
-
const
|
|
35622
|
-
results.push({ category: "builtin_write", operator: cmdletName, path:
|
|
35794
|
+
const path69 = nonFlagTokens[nonFlagTokens.length - 1].replace(/^["']|["']$/g, "");
|
|
35795
|
+
results.push({ category: "builtin_write", operator: cmdletName, path: path69 });
|
|
35623
35796
|
}
|
|
35624
35797
|
}
|
|
35625
35798
|
}
|
|
@@ -35672,10 +35845,10 @@ function detectCmdWrites(command) {
|
|
|
35672
35845
|
if (redirectMatch) {
|
|
35673
35846
|
const beforeRedirect = redirectMatch[1];
|
|
35674
35847
|
const op = redirectMatch[2];
|
|
35675
|
-
const
|
|
35848
|
+
const path69 = redirectMatch[3];
|
|
35676
35849
|
const fdRedirectPattern = /\d>&?$/;
|
|
35677
35850
|
if (!fdRedirectPattern.test(beforeRedirect)) {
|
|
35678
|
-
results.push({ category: "redirect", operator: op, path:
|
|
35851
|
+
results.push({ category: "redirect", operator: op, path: path69 });
|
|
35679
35852
|
}
|
|
35680
35853
|
}
|
|
35681
35854
|
const leadingRedirect = innerCommand.match(/^((?:>){1,2})\s+(\S+)$/);
|
|
@@ -35733,8 +35906,8 @@ function detectCmdWrites(command) {
|
|
|
35733
35906
|
const rawTokens = rest.match(/(\/?[^\s]+|"[^"]*"|'[^']*')/g) ?? [];
|
|
35734
35907
|
const tokens = rawTokens.filter((t) => !t.startsWith("/"));
|
|
35735
35908
|
if (tokens.length > 0) {
|
|
35736
|
-
const
|
|
35737
|
-
return { category: "builtin_write", operator: "del", path:
|
|
35909
|
+
const path69 = tokens[0].replace(/^["']|["']$/g, "");
|
|
35910
|
+
return { category: "builtin_write", operator: "del", path: path69 };
|
|
35738
35911
|
}
|
|
35739
35912
|
return null;
|
|
35740
35913
|
}
|
|
@@ -35744,16 +35917,16 @@ function detectCmdWrites(command) {
|
|
|
35744
35917
|
}
|
|
35745
35918
|
const rdMatch = innerCommand.match(/^rd\s+(?:\/s\s+|\/q\s+)*(\S+)/i);
|
|
35746
35919
|
if (rdMatch) {
|
|
35747
|
-
const
|
|
35748
|
-
if (!
|
|
35749
|
-
results.push({ category: "builtin_write", operator: "rd", path:
|
|
35920
|
+
const path69 = rdMatch[1].replace(/^["']|["']$/g, "");
|
|
35921
|
+
if (!path69.startsWith("/")) {
|
|
35922
|
+
results.push({ category: "builtin_write", operator: "rd", path: path69 });
|
|
35750
35923
|
}
|
|
35751
35924
|
}
|
|
35752
35925
|
const mdMatch = trimmed.match(/^md\s+(\S+)/i);
|
|
35753
35926
|
if (mdMatch) {
|
|
35754
|
-
const
|
|
35755
|
-
if (!
|
|
35756
|
-
results.push({ category: "builtin_write", operator: "md", path:
|
|
35927
|
+
const path69 = mdMatch[1].replace(/^["']|["']$/g, "");
|
|
35928
|
+
if (!path69.startsWith("/")) {
|
|
35929
|
+
results.push({ category: "builtin_write", operator: "md", path: path69 });
|
|
35757
35930
|
}
|
|
35758
35931
|
}
|
|
35759
35932
|
const echoMatch = trimmed.match(/^echo\s+(\S+.*?)\s+((?:>){1,2})\s*(\S+)$/i);
|
|
@@ -35869,9 +36042,10 @@ function resolvePath(pathText, cwd) {
|
|
|
35869
36042
|
return null;
|
|
35870
36043
|
const isWindowsPath = /^[a-zA-Z]:[\\\\/]/.test(cwd) || cwd.includes("\\");
|
|
35871
36044
|
if (isWindowsPath) {
|
|
35872
|
-
return
|
|
36045
|
+
return path68.win32.resolve(cwd, pathText);
|
|
35873
36046
|
}
|
|
35874
|
-
|
|
36047
|
+
const normalizedRelativeWindowsPath = !path68.posix.isAbsolute(pathText) && !/^[a-zA-Z]:[\\/]/.test(pathText) ? pathText.replace(/\\/g, "/") : pathText;
|
|
36048
|
+
return path68.posix.resolve(cwd, normalizedRelativeWindowsPath);
|
|
35875
36049
|
}
|
|
35876
36050
|
function getCdTarget(cmd) {
|
|
35877
36051
|
if (!cmd || typeof cmd !== "object")
|
|
@@ -35938,7 +36112,7 @@ function collectWritesWithNodes(node, out, cwdStack) {
|
|
|
35938
36112
|
for (const cmd of node.commands) {
|
|
35939
36113
|
const cdTarget = getCdTarget(cmd);
|
|
35940
36114
|
if (cdTarget) {
|
|
35941
|
-
currentStack[0] =
|
|
36115
|
+
currentStack[0] = path68.posix.resolve(currentStack[0] ?? "/", cdTarget);
|
|
35942
36116
|
collectWritesWithNodes(cmd, out, currentStack);
|
|
35943
36117
|
} else {
|
|
35944
36118
|
collectWritesWithNodes(cmd, out, currentStack);
|
|
@@ -35984,7 +36158,7 @@ function collectWritesWithNodes(node, out, cwdStack) {
|
|
|
35984
36158
|
const effectiveCwd = cwdStack[0] ?? "/";
|
|
35985
36159
|
const cdTarget = getCdTarget(node);
|
|
35986
36160
|
if (cdTarget) {
|
|
35987
|
-
cwdStack[0] =
|
|
36161
|
+
cwdStack[0] = path68.posix.resolve(cwdStack[0] ?? "/", cdTarget);
|
|
35988
36162
|
return;
|
|
35989
36163
|
}
|
|
35990
36164
|
const writesFromRedirs = getWritesFromCommandRedirs(node, effectiveCwd);
|
|
@@ -36030,12 +36204,12 @@ function getWritesFromRedirectNode(redirect, _context) {
|
|
|
36030
36204
|
if (!opType || !REDIRECT_ALL_WRITE_TOKENS.has(opType))
|
|
36031
36205
|
return [];
|
|
36032
36206
|
const fileNode = r.file;
|
|
36033
|
-
const
|
|
36207
|
+
const path69 = extractRedirectPath(fileNode);
|
|
36034
36208
|
const opLabel = operatorLabel(opNode);
|
|
36035
36209
|
if (REDIRECT_WRITE_TOKENS.has(opType)) {
|
|
36036
|
-
return [{ category: "redirect", operator: opLabel, path:
|
|
36210
|
+
return [{ category: "redirect", operator: opLabel, path: path69 }];
|
|
36037
36211
|
} else if (REDIRECT_HERE_TOKENS.has(opType)) {
|
|
36038
|
-
return [{ category: "here_doc", operator: opLabel, path:
|
|
36212
|
+
return [{ category: "here_doc", operator: opLabel, path: path69 }];
|
|
36039
36213
|
}
|
|
36040
36214
|
return [];
|
|
36041
36215
|
}
|
|
@@ -36156,6 +36330,15 @@ var ACTIVE_PARALLEL_TASK_STATES = new Set([
|
|
|
36156
36330
|
"tests_run"
|
|
36157
36331
|
]);
|
|
36158
36332
|
|
|
36333
|
+
// src/hooks/realtime-learning-nudge.ts
|
|
36334
|
+
var realtimeLearningNudgeBySession = new Map;
|
|
36335
|
+
function resetRealtimeLearningNudgeState() {
|
|
36336
|
+
realtimeLearningNudgeBySession.clear();
|
|
36337
|
+
}
|
|
36338
|
+
function clearRealtimeLearningNudgeSession(sessionID) {
|
|
36339
|
+
realtimeLearningNudgeBySession.delete(sessionID);
|
|
36340
|
+
}
|
|
36341
|
+
|
|
36159
36342
|
// src/session/worktree-link-suggestion.ts
|
|
36160
36343
|
import { execFile as execFile3 } from "child_process";
|
|
36161
36344
|
var GIT_TIMEOUT_MS2 = 1500;
|
|
@@ -36298,6 +36481,7 @@ function resetSwarmState() {
|
|
|
36298
36481
|
swarmState.environmentProfiles.clear();
|
|
36299
36482
|
clearPendingCoderScope();
|
|
36300
36483
|
resetStandardWorktreeIsolationState();
|
|
36484
|
+
resetRealtimeLearningNudgeState();
|
|
36301
36485
|
_councilDisagreementWarned.clear();
|
|
36302
36486
|
}
|
|
36303
36487
|
function resetSwarmStatePreservingSingletons() {
|
|
@@ -36436,6 +36620,7 @@ function startAgentSession(sessionId, agentName, staleDurationMs = STALE_SESSION
|
|
|
36436
36620
|
}
|
|
36437
36621
|
function endAgentSession(sessionId) {
|
|
36438
36622
|
swarmState.agentSessions.delete(sessionId);
|
|
36623
|
+
clearRealtimeLearningNudgeSession(sessionId);
|
|
36439
36624
|
}
|
|
36440
36625
|
function getAgentSession(sessionId) {
|
|
36441
36626
|
return swarmState.agentSessions.get(sessionId);
|
|
@@ -36778,8 +36963,8 @@ function evidenceToWorkflowState(evidence) {
|
|
|
36778
36963
|
}
|
|
36779
36964
|
async function readPlanFromDisk(directory) {
|
|
36780
36965
|
try {
|
|
36781
|
-
const planPath =
|
|
36782
|
-
const content = await
|
|
36966
|
+
const planPath = path69.join(directory, ".swarm", "plan.json");
|
|
36967
|
+
const content = await fs32.readFile(planPath, "utf-8");
|
|
36783
36968
|
const parsed = JSON.parse(content);
|
|
36784
36969
|
return PlanSchema.parse(parsed);
|
|
36785
36970
|
} catch {
|
|
@@ -36789,8 +36974,8 @@ async function readPlanFromDisk(directory) {
|
|
|
36789
36974
|
async function readGateEvidenceFromDisk(directory) {
|
|
36790
36975
|
const evidenceMap = new Map;
|
|
36791
36976
|
try {
|
|
36792
|
-
const evidenceDir =
|
|
36793
|
-
const entries = await
|
|
36977
|
+
const evidenceDir = path69.join(directory, ".swarm", "evidence");
|
|
36978
|
+
const entries = await fs32.readdir(evidenceDir, { withFileTypes: true });
|
|
36794
36979
|
for (const entry of entries) {
|
|
36795
36980
|
if (!entry.isFile() || !entry.name.endsWith(".json")) {
|
|
36796
36981
|
continue;
|
|
@@ -36800,8 +36985,8 @@ async function readGateEvidenceFromDisk(directory) {
|
|
|
36800
36985
|
continue;
|
|
36801
36986
|
}
|
|
36802
36987
|
try {
|
|
36803
|
-
const filePath =
|
|
36804
|
-
const content = await
|
|
36988
|
+
const filePath = path69.join(evidenceDir, entry.name);
|
|
36989
|
+
const content = await fs32.readFile(filePath, "utf-8");
|
|
36805
36990
|
const parsed = JSON.parse(content);
|
|
36806
36991
|
if (parsed && typeof parsed.taskId === "string" && Array.isArray(parsed.required_gates)) {
|
|
36807
36992
|
evidenceMap.set(taskId, parsed);
|
|
@@ -36942,7 +37127,7 @@ function hasActiveEpicMode(sessionID) {
|
|
|
36942
37127
|
async function rehydratePrSubscriptions(sessionID, directory) {
|
|
36943
37128
|
const map = new Map;
|
|
36944
37129
|
try {
|
|
36945
|
-
const { listActive: listActive2 } = await import("./pr-subscriptions-
|
|
37130
|
+
const { listActive: listActive2 } = await import("./pr-subscriptions-0dpn4epk.js");
|
|
36946
37131
|
const records = await listActive2(directory);
|
|
36947
37132
|
for (const record of records) {
|
|
36948
37133
|
if (record.sessionID !== sessionID)
|