opencode-swarm 7.99.6 → 7.100.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{config-doctor-1j77p1jy.js → config-doctor-g29kxhek.js} +2 -2
- package/dist/cli/{evidence-summary-service-5ww1npaa.js → evidence-summary-service-ch74hb16.js} +2 -2
- package/dist/cli/{guardrail-explain-s4c2h8mv.js → guardrail-explain-q8pj9691.js} +8 -8
- package/dist/cli/{guardrail-log-ya49kpwn.js → guardrail-log-ywajkn46.js} +3 -3
- package/dist/cli/{index-h9ptj4b1.js → index-5bstvpct.js} +1 -1
- package/dist/cli/{index-94qwbx11.js → index-7ztmmqpt.js} +6 -0
- package/dist/cli/{index-s3esnz7m.js → index-e9n3xsk0.js} +1 -1
- package/dist/cli/{index-etssqrff.js → index-jg6m72g7.js} +9 -9
- package/dist/cli/{index-7hnwnw5g.js → index-m0qshbr6.js} +41 -1
- package/dist/cli/{index-xsswhy6k.js → index-pj3a5fbt.js} +1 -1
- package/dist/cli/{index-1kcp4q4y.js → index-q5cae5d7.js} +1064 -332
- package/dist/cli/{index-0d3pmjf9.js → index-rpb763g8.js} +1 -1
- package/dist/cli/{index-ksc4ftms.js → index-tj0jek4p.js} +2 -2
- package/dist/cli/{index-9twtnjkv.js → index-y3x3gvy6.js} +1 -1
- package/dist/cli/index.js +7 -7
- package/dist/cli/{pending-delegations-vh2nae3n.js → pending-delegations-dvprsdfy.js} +1 -1
- package/dist/cli/{pr-subscriptions-d57tq0c0.js → pr-subscriptions-zfxjtyzw.js} +2 -2
- package/dist/cli/{schema-nz638xc3.js → schema-n7pd65qq.js} +1 -1
- package/dist/config/schema.d.ts +40 -0
- package/dist/hooks/utils.d.ts +8 -3
- package/dist/index.js +2258 -1455
- package/dist/memory/config.d.ts +38 -0
- package/dist/memory/embeddings/cache.d.ts +25 -0
- package/dist/memory/embeddings/fusion.d.ts +56 -0
- package/dist/memory/embeddings/local-provider.d.ts +57 -0
- package/dist/memory/embeddings/reranker.d.ts +42 -0
- package/dist/memory/embeddings/types.d.ts +27 -0
- package/dist/memory/scoring.d.ts +1 -0
- package/dist/memory/sqlite-provider.d.ts +19 -0
- package/dist/services/version-check.d.ts +0 -4
- package/package.json +1 -1
- package/tests/fixtures/memory-recall/paraphrase-auth.json +64 -0
- package/tests/fixtures/memory-recall/paraphrase-concurrency.json +64 -0
- package/tests/fixtures/memory-recall/paraphrase-deployment.json +64 -0
|
@@ -57,7 +57,7 @@ import {
|
|
|
57
57
|
readDoctorArtifact,
|
|
58
58
|
removeStraySwarmDir,
|
|
59
59
|
runConfigDoctor
|
|
60
|
-
} from "./index-
|
|
60
|
+
} from "./index-rpb763g8.js";
|
|
61
61
|
import {
|
|
62
62
|
AGENT_TOOL_MAP,
|
|
63
63
|
ALL_SUBAGENT_NAMES,
|
|
@@ -70,7 +70,7 @@ import {
|
|
|
70
70
|
TOOL_NAME_SET,
|
|
71
71
|
resolveExternalSkillsConfig,
|
|
72
72
|
stripKnownSwarmPrefix
|
|
73
|
-
} from "./index-
|
|
73
|
+
} from "./index-m0qshbr6.js";
|
|
74
74
|
import {
|
|
75
75
|
MAX_TRANSIENT_RETRIES,
|
|
76
76
|
PlanSchema,
|
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
transientBackoff,
|
|
115
115
|
validateProjectRoot,
|
|
116
116
|
writeProjectedSpecSync
|
|
117
|
-
} from "./index-
|
|
117
|
+
} from "./index-y3x3gvy6.js";
|
|
118
118
|
import {
|
|
119
119
|
_internals as _internals2,
|
|
120
120
|
_internals1 as _internals3,
|
|
@@ -138,12 +138,12 @@ import {
|
|
|
138
138
|
listActive,
|
|
139
139
|
subscribe,
|
|
140
140
|
unsubscribe
|
|
141
|
-
} from "./index-
|
|
141
|
+
} from "./index-e9n3xsk0.js";
|
|
142
142
|
import {
|
|
143
143
|
readSwarmFileAsync,
|
|
144
144
|
safeHook,
|
|
145
145
|
validateSwarmPath
|
|
146
|
-
} from "./index-
|
|
146
|
+
} from "./index-7ztmmqpt.js";
|
|
147
147
|
import {
|
|
148
148
|
deepMerge
|
|
149
149
|
} from "./index-p0arc26j.js";
|
|
@@ -909,7 +909,7 @@ var init_executor = __esm(() => {
|
|
|
909
909
|
// package.json
|
|
910
910
|
var package_default = {
|
|
911
911
|
name: "opencode-swarm",
|
|
912
|
-
version: "7.
|
|
912
|
+
version: "7.100.0",
|
|
913
913
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
914
914
|
main: "dist/index.js",
|
|
915
915
|
types: "dist/index.d.ts",
|
|
@@ -6034,7 +6034,7 @@ function hasActiveEpicMode(sessionID) {
|
|
|
6034
6034
|
async function rehydratePrSubscriptions(sessionID, directory) {
|
|
6035
6035
|
const map = new Map;
|
|
6036
6036
|
try {
|
|
6037
|
-
const { listActive: listActive2 } = await import("./pr-subscriptions-
|
|
6037
|
+
const { listActive: listActive2 } = await import("./pr-subscriptions-zfxjtyzw.js");
|
|
6038
6038
|
const records = await listActive2(directory);
|
|
6039
6039
|
for (const record of records) {
|
|
6040
6040
|
if (record.sessionID !== sessionID)
|
|
@@ -13362,7 +13362,7 @@ async function runFinalizeStage(ctx) {
|
|
|
13362
13362
|
}
|
|
13363
13363
|
}
|
|
13364
13364
|
try {
|
|
13365
|
-
const { CuratorConfigSchema: CCS } = await import("./schema-
|
|
13365
|
+
const { CuratorConfigSchema: CCS } = await import("./schema-n7pd65qq.js");
|
|
13366
13366
|
const { config: pmLoadedConfig } = _internals20.loadPluginConfigWithMeta(ctx.directory);
|
|
13367
13367
|
const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
|
|
13368
13368
|
if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
|
|
@@ -15889,6 +15889,7 @@ import { existsSync as existsSync16, mkdirSync as mkdirSync9, readFileSync as re
|
|
|
15889
15889
|
import { homedir as homedir4 } from "os";
|
|
15890
15890
|
import { join as join27 } from "path";
|
|
15891
15891
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
15892
|
+
var SEMVER_REGEX = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/;
|
|
15892
15893
|
var MAX_RESPONSE_BYTES = 256 * 1024;
|
|
15893
15894
|
function cacheDir() {
|
|
15894
15895
|
const xdg = process.env.XDG_CACHE_HOME;
|
|
@@ -15913,26 +15914,39 @@ function readVersionCache() {
|
|
|
15913
15914
|
return null;
|
|
15914
15915
|
}
|
|
15915
15916
|
}
|
|
15917
|
+
function parseVersion(version) {
|
|
15918
|
+
const trimmed = version.trim();
|
|
15919
|
+
const match = SEMVER_REGEX.exec(trimmed);
|
|
15920
|
+
if (!match)
|
|
15921
|
+
return null;
|
|
15922
|
+
return {
|
|
15923
|
+
major: Number.parseInt(match[1], 10),
|
|
15924
|
+
minor: Number.parseInt(match[2], 10),
|
|
15925
|
+
patch: Number.parseInt(match[3], 10),
|
|
15926
|
+
prerelease: match[4] ?? null
|
|
15927
|
+
};
|
|
15928
|
+
}
|
|
15916
15929
|
function compareVersions(a, b) {
|
|
15917
|
-
const
|
|
15918
|
-
const
|
|
15919
|
-
|
|
15920
|
-
|
|
15921
|
-
|
|
15922
|
-
|
|
15923
|
-
|
|
15924
|
-
|
|
15925
|
-
|
|
15926
|
-
return 1;
|
|
15927
|
-
if (av < bv)
|
|
15928
|
-
return -1;
|
|
15930
|
+
const aParsed = parseVersion(a);
|
|
15931
|
+
const bParsed = parseVersion(b);
|
|
15932
|
+
if (!aParsed || !bParsed)
|
|
15933
|
+
return 0;
|
|
15934
|
+
if (aParsed.major !== bParsed.major) {
|
|
15935
|
+
return aParsed.major > bParsed.major ? 1 : -1;
|
|
15936
|
+
}
|
|
15937
|
+
if (aParsed.minor !== bParsed.minor) {
|
|
15938
|
+
return aParsed.minor > bParsed.minor ? 1 : -1;
|
|
15929
15939
|
}
|
|
15930
|
-
if (
|
|
15940
|
+
if (aParsed.patch !== bParsed.patch) {
|
|
15941
|
+
return aParsed.patch > bParsed.patch ? 1 : -1;
|
|
15942
|
+
}
|
|
15943
|
+
if (aParsed.prerelease && !bParsed.prerelease)
|
|
15931
15944
|
return -1;
|
|
15932
|
-
if (!
|
|
15945
|
+
if (!aParsed.prerelease && bParsed.prerelease)
|
|
15933
15946
|
return 1;
|
|
15934
|
-
if (
|
|
15935
|
-
return
|
|
15947
|
+
if (aParsed.prerelease && bParsed.prerelease) {
|
|
15948
|
+
return aParsed.prerelease < bParsed.prerelease ? -1 : aParsed.prerelease > bParsed.prerelease ? 1 : 0;
|
|
15949
|
+
}
|
|
15936
15950
|
return 0;
|
|
15937
15951
|
}
|
|
15938
15952
|
|
|
@@ -17140,7 +17154,7 @@ async function handleDoctorCommand(directory, args) {
|
|
|
17140
17154
|
const result = runConfigDoctor(config, directory);
|
|
17141
17155
|
let output;
|
|
17142
17156
|
if (enableAutoFix && result.hasAutoFixableIssues) {
|
|
17143
|
-
const { runConfigDoctorWithFixes } = await import("./config-doctor-
|
|
17157
|
+
const { runConfigDoctorWithFixes } = await import("./config-doctor-g29kxhek.js");
|
|
17144
17158
|
const fixResult = await runConfigDoctorWithFixes(directory, config, true);
|
|
17145
17159
|
output = formatDoctorMarkdown(fixResult.result);
|
|
17146
17160
|
} else {
|
|
@@ -17953,7 +17967,7 @@ async function handleEvidenceCommand(directory, args) {
|
|
|
17953
17967
|
return formatTaskEvidenceMarkdown(evidenceData);
|
|
17954
17968
|
}
|
|
17955
17969
|
async function handleEvidenceSummaryCommand(directory) {
|
|
17956
|
-
const { buildEvidenceSummary } = await import("./evidence-summary-service-
|
|
17970
|
+
const { buildEvidenceSummary } = await import("./evidence-summary-service-ch74hb16.js");
|
|
17957
17971
|
const artifact = await buildEvidenceSummary(directory);
|
|
17958
17972
|
if (!artifact) {
|
|
17959
17973
|
return "No plan found. Run `/swarm plan` to check plan status.";
|
|
@@ -20507,7 +20521,7 @@ ${USAGE7}`;
|
|
|
20507
20521
|
|
|
20508
20522
|
// src/commands/memory.ts
|
|
20509
20523
|
import { existsSync as existsSync27 } from "fs";
|
|
20510
|
-
import * as
|
|
20524
|
+
import * as path50 from "path";
|
|
20511
20525
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
20512
20526
|
|
|
20513
20527
|
// src/memory/config.ts
|
|
@@ -20542,6 +20556,24 @@ var DEFAULT_CONSOLIDATION_CONFIG = {
|
|
|
20542
20556
|
autoApplyMinConfidence: 0.6,
|
|
20543
20557
|
decayHalfLifeDays: { ...DEFAULT_DECAY_HALF_LIFE_DAYS }
|
|
20544
20558
|
};
|
|
20559
|
+
var DEFAULT_EMBEDDINGS_CONFIG = {
|
|
20560
|
+
enabled: false,
|
|
20561
|
+
model: "Xenova/all-MiniLM-L6-v2",
|
|
20562
|
+
dimension: 384,
|
|
20563
|
+
cacheSize: 256
|
|
20564
|
+
};
|
|
20565
|
+
var DEFAULT_RETRIEVAL_CONFIG = {
|
|
20566
|
+
rrfK: 60,
|
|
20567
|
+
weights: {
|
|
20568
|
+
lexical: 0.5,
|
|
20569
|
+
dense: 0.4,
|
|
20570
|
+
metadata: 0.1
|
|
20571
|
+
},
|
|
20572
|
+
rerank: {
|
|
20573
|
+
enabled: false
|
|
20574
|
+
},
|
|
20575
|
+
latencyBudgetMs: 250
|
|
20576
|
+
};
|
|
20545
20577
|
var DEFAULT_MEMORY_CONFIG = {
|
|
20546
20578
|
enabled: false,
|
|
20547
20579
|
provider: "sqlite",
|
|
@@ -20578,6 +20610,8 @@ var DEFAULT_MEMORY_CONFIG = {
|
|
|
20578
20610
|
...DEFAULT_CONSOLIDATION_CONFIG,
|
|
20579
20611
|
decayHalfLifeDays: { ...DEFAULT_DECAY_HALF_LIFE_DAYS }
|
|
20580
20612
|
},
|
|
20613
|
+
embeddings: { ...DEFAULT_EMBEDDINGS_CONFIG },
|
|
20614
|
+
retrieval: { ...DEFAULT_RETRIEVAL_CONFIG },
|
|
20581
20615
|
hardDelete: false
|
|
20582
20616
|
};
|
|
20583
20617
|
var DURABLE_MEMORY_KINDS = new Set([
|
|
@@ -20634,6 +20668,22 @@ function resolveMemoryConfig(input) {
|
|
|
20634
20668
|
...DEFAULT_MEMORY_CONFIG.consolidation.decayHalfLifeDays,
|
|
20635
20669
|
...input?.consolidation?.decayHalfLifeDays ?? {}
|
|
20636
20670
|
}
|
|
20671
|
+
},
|
|
20672
|
+
embeddings: {
|
|
20673
|
+
...DEFAULT_MEMORY_CONFIG.embeddings,
|
|
20674
|
+
...input?.embeddings ?? {}
|
|
20675
|
+
},
|
|
20676
|
+
retrieval: {
|
|
20677
|
+
...DEFAULT_MEMORY_CONFIG.retrieval,
|
|
20678
|
+
...input?.retrieval ?? {},
|
|
20679
|
+
weights: {
|
|
20680
|
+
...DEFAULT_MEMORY_CONFIG.retrieval.weights,
|
|
20681
|
+
...input?.retrieval?.weights ?? {}
|
|
20682
|
+
},
|
|
20683
|
+
rerank: {
|
|
20684
|
+
...DEFAULT_MEMORY_CONFIG.retrieval.rerank,
|
|
20685
|
+
...input?.retrieval?.rerank ?? {}
|
|
20686
|
+
}
|
|
20637
20687
|
}
|
|
20638
20688
|
};
|
|
20639
20689
|
}
|
|
@@ -20648,8 +20698,8 @@ class MemoryValidationError extends Error {
|
|
|
20648
20698
|
}
|
|
20649
20699
|
// src/memory/evaluation.ts
|
|
20650
20700
|
import * as fs19 from "fs/promises";
|
|
20651
|
-
import * as
|
|
20652
|
-
import * as
|
|
20701
|
+
import * as os12 from "os";
|
|
20702
|
+
import * as path48 from "path";
|
|
20653
20703
|
|
|
20654
20704
|
// src/memory/local-jsonl-provider.ts
|
|
20655
20705
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
@@ -21921,18 +21971,372 @@ async function writeJsonlAtomic(filePath, values) {
|
|
|
21921
21971
|
|
|
21922
21972
|
// src/memory/provider-pool.ts
|
|
21923
21973
|
import { realpathSync as realpathSync2 } from "fs";
|
|
21924
|
-
import * as
|
|
21974
|
+
import * as path47 from "path";
|
|
21925
21975
|
|
|
21926
21976
|
// src/memory/sqlite-provider.ts
|
|
21927
21977
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
21978
|
+
import { mkdirSync as mkdirSync17 } from "fs";
|
|
21979
|
+
import { createRequire as createRequire4 } from "module";
|
|
21980
|
+
import * as path46 from "path";
|
|
21981
|
+
|
|
21982
|
+
// src/memory/embeddings/cache.ts
|
|
21983
|
+
var DEFAULT_CACHE_SIZE = 256;
|
|
21984
|
+
function normalizeQuery(query) {
|
|
21985
|
+
return query.toLowerCase().trim();
|
|
21986
|
+
}
|
|
21987
|
+
function compositeKey(modelVersion, normalizedQuery) {
|
|
21988
|
+
return `${modelVersion}\x00${normalizedQuery}`;
|
|
21989
|
+
}
|
|
21990
|
+
|
|
21991
|
+
class EmbeddingCache {
|
|
21992
|
+
cache;
|
|
21993
|
+
maxSize;
|
|
21994
|
+
constructor(maxSize = DEFAULT_CACHE_SIZE) {
|
|
21995
|
+
this.maxSize = maxSize;
|
|
21996
|
+
this.cache = new Map;
|
|
21997
|
+
}
|
|
21998
|
+
get size() {
|
|
21999
|
+
return this.cache.size;
|
|
22000
|
+
}
|
|
22001
|
+
get(modelVersion, query) {
|
|
22002
|
+
const key = compositeKey(modelVersion, normalizeQuery(query));
|
|
22003
|
+
const entry = this.cache.get(key);
|
|
22004
|
+
if (entry !== undefined) {
|
|
22005
|
+
this.cache.delete(key);
|
|
22006
|
+
this.cache.set(key, entry);
|
|
22007
|
+
}
|
|
22008
|
+
return entry;
|
|
22009
|
+
}
|
|
22010
|
+
set(modelVersion, query, entry) {
|
|
22011
|
+
const key = compositeKey(modelVersion, normalizeQuery(query));
|
|
22012
|
+
if (this.cache.has(key)) {
|
|
22013
|
+
this.cache.delete(key);
|
|
22014
|
+
} else if (this.cache.size >= this.maxSize) {
|
|
22015
|
+
const oldestKey = this.cache.keys().next().value;
|
|
22016
|
+
if (oldestKey !== undefined) {
|
|
22017
|
+
this.cache.delete(oldestKey);
|
|
22018
|
+
}
|
|
22019
|
+
}
|
|
22020
|
+
if (this.cache.size < this.maxSize) {
|
|
22021
|
+
this.cache.set(key, entry);
|
|
22022
|
+
}
|
|
22023
|
+
}
|
|
22024
|
+
has(modelVersion, query) {
|
|
22025
|
+
const key = compositeKey(modelVersion, normalizeQuery(query));
|
|
22026
|
+
return this.cache.has(key);
|
|
22027
|
+
}
|
|
22028
|
+
clear() {
|
|
22029
|
+
this.cache.clear();
|
|
22030
|
+
}
|
|
22031
|
+
}
|
|
22032
|
+
|
|
22033
|
+
// src/memory/embeddings/fusion.ts
|
|
22034
|
+
function fuseRankings(lexicalRankedIds, denseRankedIds, metadataRankedIds, weights, rrfK) {
|
|
22035
|
+
const lexicalRanks = buildRankMap(lexicalRankedIds);
|
|
22036
|
+
const denseRanks = buildRankMap(denseRankedIds);
|
|
22037
|
+
const metadataRanks = buildRankMap(metadataRankedIds);
|
|
22038
|
+
const allIds = new Set;
|
|
22039
|
+
for (const id of lexicalRankedIds)
|
|
22040
|
+
allIds.add(id);
|
|
22041
|
+
for (const id of denseRankedIds)
|
|
22042
|
+
allIds.add(id);
|
|
22043
|
+
for (const id of metadataRankedIds)
|
|
22044
|
+
allIds.add(id);
|
|
22045
|
+
const candidates = [];
|
|
22046
|
+
for (const id of allIds) {
|
|
22047
|
+
const lexicalRank = lexicalRanks.get(id) ?? null;
|
|
22048
|
+
const denseRank = denseRanks.get(id) ?? null;
|
|
22049
|
+
const metadataRank = metadataRanks.get(id) ?? null;
|
|
22050
|
+
const rawScore = (lexicalRank !== null ? weights.lexical * rrfTerm(lexicalRank, rrfK) : 0) + (denseRank !== null ? weights.dense * rrfTerm(denseRank, rrfK) : 0) + (metadataRank !== null ? weights.metadata * rrfTerm(metadataRank, rrfK) : 0);
|
|
22051
|
+
candidates.push({
|
|
22052
|
+
id,
|
|
22053
|
+
fusedScore: rawScore,
|
|
22054
|
+
lexicalRank,
|
|
22055
|
+
denseRank,
|
|
22056
|
+
metadataRank
|
|
22057
|
+
});
|
|
22058
|
+
}
|
|
22059
|
+
return minMaxNormalise(candidates);
|
|
22060
|
+
}
|
|
22061
|
+
function buildRankMap(rankedIds) {
|
|
22062
|
+
const map = new Map;
|
|
22063
|
+
for (let i = 0;i < rankedIds.length; i++) {
|
|
22064
|
+
map.set(rankedIds[i], i + 1);
|
|
22065
|
+
}
|
|
22066
|
+
return map;
|
|
22067
|
+
}
|
|
22068
|
+
function rrfTerm(rank, rrfK) {
|
|
22069
|
+
return 1 / (rrfK + rank);
|
|
22070
|
+
}
|
|
22071
|
+
function minMaxNormalise(candidates) {
|
|
22072
|
+
if (candidates.length === 0)
|
|
22073
|
+
return candidates;
|
|
22074
|
+
let min = Infinity;
|
|
22075
|
+
let max = -Infinity;
|
|
22076
|
+
for (const c of candidates) {
|
|
22077
|
+
if (c.fusedScore < min)
|
|
22078
|
+
min = c.fusedScore;
|
|
22079
|
+
if (c.fusedScore > max)
|
|
22080
|
+
max = c.fusedScore;
|
|
22081
|
+
}
|
|
22082
|
+
const range = max - min;
|
|
22083
|
+
const normalised = [];
|
|
22084
|
+
for (const c of candidates) {
|
|
22085
|
+
const normalisedScore = range === 0 ? 1 : (c.fusedScore - min) / range;
|
|
22086
|
+
normalised.push({
|
|
22087
|
+
...c,
|
|
22088
|
+
fusedScore: normalisedScore
|
|
22089
|
+
});
|
|
22090
|
+
}
|
|
22091
|
+
normalised.sort((a, b) => b.fusedScore - a.fusedScore || a.id.localeCompare(b.id));
|
|
22092
|
+
return normalised;
|
|
22093
|
+
}
|
|
22094
|
+
|
|
22095
|
+
// src/memory/embeddings/local-provider.ts
|
|
21928
22096
|
import { mkdirSync as mkdirSync15 } from "fs";
|
|
21929
22097
|
import { createRequire as createRequire2 } from "module";
|
|
22098
|
+
import * as os10 from "os";
|
|
22099
|
+
import * as path43 from "path";
|
|
22100
|
+
|
|
22101
|
+
// src/memory/embeddings/types.ts
|
|
22102
|
+
class EmbeddingUnavailableError extends Error {
|
|
22103
|
+
constructor(message) {
|
|
22104
|
+
super(message ?? "Embedding provider is unavailable (dependency not installed or model failed to load)");
|
|
22105
|
+
this.name = "EmbeddingUnavailableError";
|
|
22106
|
+
}
|
|
22107
|
+
}
|
|
22108
|
+
|
|
22109
|
+
class EmbeddingVersionMismatchError extends Error {
|
|
22110
|
+
queryVersion;
|
|
22111
|
+
storedVersion;
|
|
22112
|
+
constructor(queryVersion, storedVersion) {
|
|
22113
|
+
super(`Embedding version mismatch: query uses ${queryVersion} but stored vectors are ${storedVersion}. Rebuild the index or pin the model version.`);
|
|
22114
|
+
this.name = "EmbeddingVersionMismatchError";
|
|
22115
|
+
this.queryVersion = queryVersion;
|
|
22116
|
+
this.storedVersion = storedVersion;
|
|
22117
|
+
}
|
|
22118
|
+
}
|
|
22119
|
+
|
|
22120
|
+
// src/memory/embeddings/local-provider.ts
|
|
22121
|
+
var _internals33 = {
|
|
22122
|
+
resolveEmbeddingCacheDir() {
|
|
22123
|
+
let base;
|
|
22124
|
+
if (process.platform === "win32") {
|
|
22125
|
+
base = process.env.LOCALAPPDATA || path43.join(os10.homedir(), "AppData", "Local");
|
|
22126
|
+
} else if (process.platform === "darwin") {
|
|
22127
|
+
base = path43.join(os10.homedir(), "Library", "Caches");
|
|
22128
|
+
} else {
|
|
22129
|
+
base = process.env.XDG_CACHE_HOME || path43.join(os10.homedir(), ".cache");
|
|
22130
|
+
}
|
|
22131
|
+
const resolved = path43.join(base, "opencode", "embeddings");
|
|
22132
|
+
const segments = resolved.split(path43.sep);
|
|
22133
|
+
if (segments.includes(".swarm")) {
|
|
22134
|
+
const safeDefault = process.platform === "win32" ? path43.join(os10.homedir(), "AppData", "Local", "opencode", "embeddings") : process.platform === "darwin" ? path43.join(os10.homedir(), "Library", "Caches", "opencode", "embeddings") : path43.join(os10.homedir(), ".cache", "opencode", "embeddings");
|
|
22135
|
+
warn("Embedding cache dir resolved under .swarm/ \u2014 falling back to safe default");
|
|
22136
|
+
return safeDefault;
|
|
22137
|
+
}
|
|
22138
|
+
return resolved;
|
|
22139
|
+
}
|
|
22140
|
+
};
|
|
22141
|
+
function resolveEmbeddingCacheDir() {
|
|
22142
|
+
return _internals33.resolveEmbeddingCacheDir();
|
|
22143
|
+
}
|
|
22144
|
+
|
|
22145
|
+
class LocalEmbeddingProvider {
|
|
22146
|
+
modelName;
|
|
22147
|
+
dimension;
|
|
22148
|
+
modelVersion;
|
|
22149
|
+
_available = false;
|
|
22150
|
+
loadFailed = false;
|
|
22151
|
+
pipeline = null;
|
|
22152
|
+
static downloadNoticePrinted = false;
|
|
22153
|
+
constructor(config) {
|
|
22154
|
+
this.modelName = config.model;
|
|
22155
|
+
this.dimension = config.dimension;
|
|
22156
|
+
this.modelVersion = config.version ?? `${config.model}:${config.dimension}`;
|
|
22157
|
+
}
|
|
22158
|
+
get available() {
|
|
22159
|
+
return this._available;
|
|
22160
|
+
}
|
|
22161
|
+
async ensurePipeline() {
|
|
22162
|
+
if (this.loadFailed) {
|
|
22163
|
+
return null;
|
|
22164
|
+
}
|
|
22165
|
+
if (this.pipeline)
|
|
22166
|
+
return this.pipeline;
|
|
22167
|
+
try {
|
|
22168
|
+
const req = createRequire2(import.meta.url);
|
|
22169
|
+
const transformers = req("@xenova/transformers");
|
|
22170
|
+
if (!LocalEmbeddingProvider.downloadNoticePrinted) {
|
|
22171
|
+
LocalEmbeddingProvider.downloadNoticePrinted = true;
|
|
22172
|
+
console.log(`[opencode-swarm] Downloading embedding model "${this.modelName}" (~25 MB) \u2014 this happens once per process.`);
|
|
22173
|
+
}
|
|
22174
|
+
const cacheDir2 = resolveEmbeddingCacheDir();
|
|
22175
|
+
mkdirSync15(cacheDir2, { recursive: true });
|
|
22176
|
+
this.pipeline = await transformers.pipeline("feature-extraction", this.modelName, { cache_dir: cacheDir2 });
|
|
22177
|
+
this._available = true;
|
|
22178
|
+
return this.pipeline;
|
|
22179
|
+
} catch (err) {
|
|
22180
|
+
this.loadFailed = true;
|
|
22181
|
+
this._available = false;
|
|
22182
|
+
warn("Local embedding provider unavailable \u2014 falling back to lexical-only", {
|
|
22183
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
22184
|
+
});
|
|
22185
|
+
return null;
|
|
22186
|
+
}
|
|
22187
|
+
}
|
|
22188
|
+
async embed(text) {
|
|
22189
|
+
const pipeline = await this.ensurePipeline();
|
|
22190
|
+
if (!pipeline) {
|
|
22191
|
+
throw new EmbeddingUnavailableError("Embedding provider is unavailable (dependency not installed or model failed to load)");
|
|
22192
|
+
}
|
|
22193
|
+
const result = await pipeline(text, {
|
|
22194
|
+
pooling: "mean",
|
|
22195
|
+
normalize: true
|
|
22196
|
+
});
|
|
22197
|
+
return this.tensorToFloat32Array(result);
|
|
22198
|
+
}
|
|
22199
|
+
async embedBatch(texts) {
|
|
22200
|
+
if (texts.length === 0)
|
|
22201
|
+
return [];
|
|
22202
|
+
const pipeline = await this.ensurePipeline();
|
|
22203
|
+
if (!pipeline) {
|
|
22204
|
+
throw new EmbeddingUnavailableError("Embedding provider is unavailable (dependency not installed or model failed to load)");
|
|
22205
|
+
}
|
|
22206
|
+
const result = await pipeline(texts, {
|
|
22207
|
+
pooling: "mean",
|
|
22208
|
+
normalize: true
|
|
22209
|
+
});
|
|
22210
|
+
if (Array.isArray(result)) {
|
|
22211
|
+
return result.map((t) => this.tensorToFloat32Array(t));
|
|
22212
|
+
}
|
|
22213
|
+
return this.tensorToFloat32ArrayBatch(result);
|
|
22214
|
+
}
|
|
22215
|
+
tensorToFloat32Array(tensor) {
|
|
22216
|
+
if (tensor instanceof Float32Array)
|
|
22217
|
+
return tensor;
|
|
22218
|
+
const obj = tensor;
|
|
22219
|
+
if (obj?.data && obj.data instanceof Float32Array) {
|
|
22220
|
+
return obj.data;
|
|
22221
|
+
}
|
|
22222
|
+
const entries = Object.entries(tensor);
|
|
22223
|
+
for (const [, value] of entries) {
|
|
22224
|
+
if (value instanceof Float32Array)
|
|
22225
|
+
return value;
|
|
22226
|
+
}
|
|
22227
|
+
throw new Error(`Unexpected embedding tensor shape: ${JSON.stringify(tensor)}`);
|
|
22228
|
+
}
|
|
22229
|
+
tensorToFloat32ArrayBatch(tensor) {
|
|
22230
|
+
const obj = tensor;
|
|
22231
|
+
if (obj?.data && obj.data instanceof Float32Array && obj.dims && obj.dims.length >= 2) {
|
|
22232
|
+
const batchSize = obj.dims[0];
|
|
22233
|
+
const dim = obj.dims[1];
|
|
22234
|
+
const result = [];
|
|
22235
|
+
for (let i = 0;i < batchSize; i++) {
|
|
22236
|
+
const offset = i * dim;
|
|
22237
|
+
result.push(obj.data.slice(offset, offset + dim));
|
|
22238
|
+
}
|
|
22239
|
+
return result;
|
|
22240
|
+
}
|
|
22241
|
+
if (Array.isArray(tensor)) {
|
|
22242
|
+
return tensor.map((t) => this.tensorToFloat32Array(t));
|
|
22243
|
+
}
|
|
22244
|
+
throw new Error(`Unexpected batch embedding tensor shape: ${JSON.stringify(tensor)}`);
|
|
22245
|
+
}
|
|
22246
|
+
}
|
|
22247
|
+
|
|
22248
|
+
// src/memory/embeddings/reranker.ts
|
|
22249
|
+
import { mkdirSync as mkdirSync16 } from "fs";
|
|
22250
|
+
import { createRequire as createRequire3 } from "module";
|
|
22251
|
+
import * as os11 from "os";
|
|
21930
22252
|
import * as path44 from "path";
|
|
22253
|
+
function shouldRerank(previousRecallElapsedMs, latencyBudgetMs) {
|
|
22254
|
+
return previousRecallElapsedMs <= latencyBudgetMs;
|
|
22255
|
+
}
|
|
22256
|
+
|
|
22257
|
+
class CrossEncoderReranker {
|
|
22258
|
+
options;
|
|
22259
|
+
loadFailed = false;
|
|
22260
|
+
_available = false;
|
|
22261
|
+
pipeline = null;
|
|
22262
|
+
constructor(options) {
|
|
22263
|
+
this.options = options;
|
|
22264
|
+
}
|
|
22265
|
+
get available() {
|
|
22266
|
+
return this._available;
|
|
22267
|
+
}
|
|
22268
|
+
async ensurePipeline() {
|
|
22269
|
+
if (this.loadFailed)
|
|
22270
|
+
return null;
|
|
22271
|
+
if (this.pipeline)
|
|
22272
|
+
return this.pipeline;
|
|
22273
|
+
try {
|
|
22274
|
+
const req = createRequire3(import.meta.url);
|
|
22275
|
+
const transformers = req("@xenova/transformers");
|
|
22276
|
+
const modelName = this.options.model ?? "Xenova/ms-marco-MiniLM-L-6-v2";
|
|
22277
|
+
const cacheDir2 = resolveRerankerCacheDir();
|
|
22278
|
+
mkdirSync16(cacheDir2, { recursive: true });
|
|
22279
|
+
this.pipeline = await transformers.pipeline("text-classification", modelName, { cache_dir: cacheDir2 });
|
|
22280
|
+
this._available = true;
|
|
22281
|
+
return this.pipeline;
|
|
22282
|
+
} catch (err) {
|
|
22283
|
+
this.loadFailed = true;
|
|
22284
|
+
this._available = false;
|
|
22285
|
+
warn("Cross-encoder reranker unavailable \u2014 skipping rerank", {
|
|
22286
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
22287
|
+
});
|
|
22288
|
+
return null;
|
|
22289
|
+
}
|
|
22290
|
+
}
|
|
22291
|
+
async rerank(candidates, query, topN) {
|
|
22292
|
+
if (candidates.length === 0)
|
|
22293
|
+
return candidates;
|
|
22294
|
+
const pipeline = await this.ensurePipeline();
|
|
22295
|
+
if (!pipeline)
|
|
22296
|
+
return candidates;
|
|
22297
|
+
try {
|
|
22298
|
+
const inputs = candidates.map((c) => [query, c.text]);
|
|
22299
|
+
const results = await pipeline(inputs, { truncation: true });
|
|
22300
|
+
const scored = candidates.map((c, idx) => ({
|
|
22301
|
+
...c,
|
|
22302
|
+
score: results[idx]?.score ?? 0
|
|
22303
|
+
}));
|
|
22304
|
+
scored.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
|
|
22305
|
+
if (typeof topN === "number" && topN > 0) {
|
|
22306
|
+
return scored.slice(0, topN);
|
|
22307
|
+
}
|
|
22308
|
+
return scored;
|
|
22309
|
+
} catch (err) {
|
|
22310
|
+
warn("Rerank scoring failed \u2014 returning original order", {
|
|
22311
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
22312
|
+
});
|
|
22313
|
+
return candidates;
|
|
22314
|
+
}
|
|
22315
|
+
}
|
|
22316
|
+
}
|
|
22317
|
+
function resolveRerankerCacheDir() {
|
|
22318
|
+
let base;
|
|
22319
|
+
if (process.platform === "win32") {
|
|
22320
|
+
base = process.env.LOCALAPPDATA || path44.join(os11.homedir(), "AppData", "Local");
|
|
22321
|
+
} else if (process.platform === "darwin") {
|
|
22322
|
+
base = path44.join(os11.homedir(), "Library", "Caches");
|
|
22323
|
+
} else {
|
|
22324
|
+
base = process.env.XDG_CACHE_HOME || path44.join(os11.homedir(), ".cache");
|
|
22325
|
+
}
|
|
22326
|
+
const resolved = path44.join(base, "opencode", "embeddings");
|
|
22327
|
+
const segments = resolved.split(path44.sep);
|
|
22328
|
+
if (segments.includes(".swarm")) {
|
|
22329
|
+
const safeDefault = process.platform === "win32" ? path44.join(os11.homedir(), "AppData", "Local", "opencode", "embeddings") : process.platform === "darwin" ? path44.join(os11.homedir(), "Library", "Caches", "opencode", "embeddings") : path44.join(os11.homedir(), ".cache", "opencode", "embeddings");
|
|
22330
|
+
warn("Reranker cache dir resolved under .swarm/ \u2014 falling back to safe default");
|
|
22331
|
+
return safeDefault;
|
|
22332
|
+
}
|
|
22333
|
+
return resolved;
|
|
22334
|
+
}
|
|
21931
22335
|
|
|
21932
22336
|
// src/memory/jsonl-migration.ts
|
|
21933
22337
|
import { existsSync as existsSync26, renameSync as renameSync10, unlinkSync as unlinkSync7 } from "fs";
|
|
21934
22338
|
import { copyFile as copyFile2, mkdir as mkdir11, readFile as readFile13, stat as stat5, writeFile as writeFile11 } from "fs/promises";
|
|
21935
|
-
import * as
|
|
22339
|
+
import * as path45 from "path";
|
|
21936
22340
|
var LEGACY_JSONL_MIGRATION_VERSION = 2;
|
|
21937
22341
|
var LEGACY_JSONL_MIGRATION_NAME = "legacy_jsonl_import_complete";
|
|
21938
22342
|
function resolveMemoryStorageDir(rootDirectory, config = {}) {
|
|
@@ -21948,8 +22352,8 @@ function resolveSqliteDatabasePath(rootDirectory, config = {}) {
|
|
|
21948
22352
|
async function readLegacyJsonl(rootDirectory, config = {}) {
|
|
21949
22353
|
const resolved = resolveConfig(config);
|
|
21950
22354
|
const storageDir = resolveMemoryStorageDir(rootDirectory, resolved);
|
|
21951
|
-
const memoryLoad = await readMemoryJsonl(
|
|
21952
|
-
const proposalLoad = await readProposalJsonl(
|
|
22355
|
+
const memoryLoad = await readMemoryJsonl(path45.join(storageDir, "memories.jsonl"), resolved);
|
|
22356
|
+
const proposalLoad = await readProposalJsonl(path45.join(storageDir, "proposals.jsonl"), resolved);
|
|
21953
22357
|
return {
|
|
21954
22358
|
memories: memoryLoad.records,
|
|
21955
22359
|
proposals: proposalLoad.records,
|
|
@@ -21959,14 +22363,14 @@ async function readLegacyJsonl(rootDirectory, config = {}) {
|
|
|
21959
22363
|
}
|
|
21960
22364
|
async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
21961
22365
|
const storageDir = resolveMemoryStorageDir(rootDirectory, config);
|
|
21962
|
-
const backupDir =
|
|
22366
|
+
const backupDir = path45.join(storageDir, "backups");
|
|
21963
22367
|
await mkdir11(backupDir, { recursive: true });
|
|
21964
22368
|
const results = [];
|
|
21965
22369
|
for (const filename of ["memories.jsonl", "proposals.jsonl"]) {
|
|
21966
|
-
const source =
|
|
22370
|
+
const source = path45.join(storageDir, filename);
|
|
21967
22371
|
if (!existsSync26(source))
|
|
21968
22372
|
continue;
|
|
21969
|
-
const backup =
|
|
22373
|
+
const backup = path45.join(backupDir, `${filename}.pre-sqlite-migration`);
|
|
21970
22374
|
if (existsSync26(backup)) {
|
|
21971
22375
|
results.push({ source, backup, created: false });
|
|
21972
22376
|
continue;
|
|
@@ -21977,11 +22381,11 @@ async function backupLegacyJsonl(rootDirectory, config = {}) {
|
|
|
21977
22381
|
return results;
|
|
21978
22382
|
}
|
|
21979
22383
|
async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
21980
|
-
const exportDir =
|
|
22384
|
+
const exportDir = path45.join(resolveMemoryStorageDir(rootDirectory, config), "export");
|
|
21981
22385
|
await mkdir11(exportDir, { recursive: true });
|
|
21982
|
-
const memoriesPath =
|
|
21983
|
-
const proposalsPath =
|
|
21984
|
-
const memoriesTempPath =
|
|
22386
|
+
const memoriesPath = path45.join(exportDir, "memories.jsonl");
|
|
22387
|
+
const proposalsPath = path45.join(exportDir, "proposals.jsonl");
|
|
22388
|
+
const memoriesTempPath = path45.join(path45.dirname(memoriesPath), `${path45.basename(memoriesPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
21985
22389
|
try {
|
|
21986
22390
|
await writeFile11(memoriesTempPath, toJsonl(memories), "utf-8");
|
|
21987
22391
|
renameSync10(memoriesTempPath, memoriesPath);
|
|
@@ -21991,7 +22395,7 @@ async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
|
21991
22395
|
} catch {}
|
|
21992
22396
|
throw err;
|
|
21993
22397
|
}
|
|
21994
|
-
const proposalsTempPath =
|
|
22398
|
+
const proposalsTempPath = path45.join(path45.dirname(proposalsPath), `${path45.basename(proposalsPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
21995
22399
|
try {
|
|
21996
22400
|
await writeFile11(proposalsTempPath, toJsonl(proposals), "utf-8");
|
|
21997
22401
|
renameSync10(proposalsTempPath, proposalsPath);
|
|
@@ -22004,9 +22408,9 @@ async function writeJsonlExport(rootDirectory, config, memories, proposals) {
|
|
|
22004
22408
|
return { directory: exportDir, memoriesPath, proposalsPath };
|
|
22005
22409
|
}
|
|
22006
22410
|
async function writeMigrationReport(rootDirectory, report, config = {}) {
|
|
22007
|
-
const reportPath =
|
|
22008
|
-
await mkdir11(
|
|
22009
|
-
const reportTempPath =
|
|
22411
|
+
const reportPath = path45.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
22412
|
+
await mkdir11(path45.dirname(reportPath), { recursive: true });
|
|
22413
|
+
const reportTempPath = path45.join(path45.dirname(reportPath), `${path45.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
22010
22414
|
try {
|
|
22011
22415
|
await writeFile11(reportTempPath, `${JSON.stringify(report, null, 2)}
|
|
22012
22416
|
`, "utf-8");
|
|
@@ -22020,7 +22424,7 @@ async function writeMigrationReport(rootDirectory, report, config = {}) {
|
|
|
22020
22424
|
return reportPath;
|
|
22021
22425
|
}
|
|
22022
22426
|
async function readMigrationReport(rootDirectory, config = {}) {
|
|
22023
|
-
const reportPath =
|
|
22427
|
+
const reportPath = path45.join(resolveMemoryStorageDir(rootDirectory, config), "migration-report.json");
|
|
22024
22428
|
if (!existsSync26(reportPath))
|
|
22025
22429
|
return null;
|
|
22026
22430
|
try {
|
|
@@ -22033,7 +22437,7 @@ async function getLegacyJsonlFileStatus(rootDirectory, config = {}) {
|
|
|
22033
22437
|
const storageDir = resolveMemoryStorageDir(rootDirectory, config);
|
|
22034
22438
|
const statuses = [];
|
|
22035
22439
|
for (const file of ["memories.jsonl", "proposals.jsonl"]) {
|
|
22036
|
-
const filePath =
|
|
22440
|
+
const filePath = path45.join(storageDir, file);
|
|
22037
22441
|
let sizeBytes = 0;
|
|
22038
22442
|
if (existsSync26(filePath)) {
|
|
22039
22443
|
sizeBytes = (await stat5(filePath)).size;
|
|
@@ -22157,7 +22561,7 @@ var _DatabaseCtor2 = null;
|
|
|
22157
22561
|
function loadDatabaseCtor2() {
|
|
22158
22562
|
if (_DatabaseCtor2)
|
|
22159
22563
|
return _DatabaseCtor2;
|
|
22160
|
-
const req =
|
|
22564
|
+
const req = createRequire4(import.meta.url);
|
|
22161
22565
|
_DatabaseCtor2 = req("bun:sqlite").Database;
|
|
22162
22566
|
return _DatabaseCtor2;
|
|
22163
22567
|
}
|
|
@@ -22277,6 +22681,16 @@ var MIGRATIONS2 = [
|
|
|
22277
22681
|
CREATE INDEX IF NOT EXISTS idx_memory_recall_usage_timestamp
|
|
22278
22682
|
ON memory_recall_usage(timestamp DESC);
|
|
22279
22683
|
`
|
|
22684
|
+
},
|
|
22685
|
+
{
|
|
22686
|
+
version: 6,
|
|
22687
|
+
name: "create_embedding_config_table",
|
|
22688
|
+
sql: `
|
|
22689
|
+
CREATE TABLE IF NOT EXISTS embedding_config (
|
|
22690
|
+
key TEXT PRIMARY KEY,
|
|
22691
|
+
value TEXT
|
|
22692
|
+
);
|
|
22693
|
+
`
|
|
22280
22694
|
}
|
|
22281
22695
|
];
|
|
22282
22696
|
|
|
@@ -22288,6 +22702,10 @@ class SQLiteMemoryProvider {
|
|
|
22288
22702
|
initPromise = null;
|
|
22289
22703
|
db = null;
|
|
22290
22704
|
ftsAvailable = false;
|
|
22705
|
+
vecAvailable = false;
|
|
22706
|
+
embeddingProvider = null;
|
|
22707
|
+
embeddingCache = null;
|
|
22708
|
+
reranker = null;
|
|
22291
22709
|
memories = new Map;
|
|
22292
22710
|
proposals = new Map;
|
|
22293
22711
|
lastAutomaticJsonlMigration = null;
|
|
@@ -22341,7 +22759,7 @@ class SQLiteMemoryProvider {
|
|
|
22341
22759
|
}
|
|
22342
22760
|
async doInitialize() {
|
|
22343
22761
|
const dbPath = this.databasePath();
|
|
22344
|
-
|
|
22762
|
+
mkdirSync17(path46.dirname(dbPath), { recursive: true });
|
|
22345
22763
|
const Db = loadDatabaseCtor2();
|
|
22346
22764
|
this.db = new Db(dbPath);
|
|
22347
22765
|
this.db.run("PRAGMA journal_mode = WAL;");
|
|
@@ -22352,6 +22770,29 @@ class SQLiteMemoryProvider {
|
|
|
22352
22770
|
this.runMigrations();
|
|
22353
22771
|
this.backfillScopeKeys();
|
|
22354
22772
|
this.ftsAvailable = this.initializeFtsIndex();
|
|
22773
|
+
this.initializeVecExtension();
|
|
22774
|
+
if (this.config.embeddings.enabled && !this.embeddingProvider) {
|
|
22775
|
+
try {
|
|
22776
|
+
this.embeddingProvider = new LocalEmbeddingProvider({
|
|
22777
|
+
model: this.config.embeddings.model,
|
|
22778
|
+
dimension: this.config.embeddings.dimension,
|
|
22779
|
+
version: this.config.embeddings.version
|
|
22780
|
+
});
|
|
22781
|
+
} catch (err) {
|
|
22782
|
+
this.embeddingProvider = null;
|
|
22783
|
+
warn("Failed to construct embedding provider \u2014 dense retrieval disabled", {
|
|
22784
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
22785
|
+
});
|
|
22786
|
+
}
|
|
22787
|
+
try {
|
|
22788
|
+
this.embeddingCache = new EmbeddingCache(this.config.embeddings.cacheSize);
|
|
22789
|
+
} catch (err) {
|
|
22790
|
+
this.embeddingCache = null;
|
|
22791
|
+
warn("Failed to construct embedding cache \u2014 recall works without cache", {
|
|
22792
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
22793
|
+
});
|
|
22794
|
+
}
|
|
22795
|
+
}
|
|
22355
22796
|
this.lastAutomaticJsonlMigration = null;
|
|
22356
22797
|
await this.migrateLegacyJsonlIfNeeded();
|
|
22357
22798
|
const memoryLoad = this.loadMemories();
|
|
@@ -22378,6 +22819,7 @@ class SQLiteMemoryProvider {
|
|
|
22378
22819
|
}, { rejectDurableSecrets: this.config.redaction.rejectDurableSecrets });
|
|
22379
22820
|
this.memories.set(next.id, next);
|
|
22380
22821
|
this.writeMemory(next);
|
|
22822
|
+
await this.writeMemoryVec(next);
|
|
22381
22823
|
await this.event("upsert", next.id);
|
|
22382
22824
|
return next;
|
|
22383
22825
|
}
|
|
@@ -22394,6 +22836,7 @@ class SQLiteMemoryProvider {
|
|
|
22394
22836
|
this.memories.delete(id);
|
|
22395
22837
|
this.requireDb().run("DELETE FROM memory_items WHERE id = ?", [id]);
|
|
22396
22838
|
this.deleteMemoryFts(id);
|
|
22839
|
+
this.deleteMemoryVec(id);
|
|
22397
22840
|
} else {
|
|
22398
22841
|
const tombstone = {
|
|
22399
22842
|
...existing,
|
|
@@ -22410,20 +22853,139 @@ class SQLiteMemoryProvider {
|
|
|
22410
22853
|
}
|
|
22411
22854
|
async recallWithDiagnostics(request) {
|
|
22412
22855
|
await this.initialize();
|
|
22856
|
+
if (!this.config.embeddings.enabled || !this.vecAvailable || !this.embeddingProvider) {
|
|
22857
|
+
const scopedRecords2 = await this.list({
|
|
22858
|
+
scopes: request.scopes,
|
|
22859
|
+
kinds: request.kinds,
|
|
22860
|
+
includeExpired: request.includeExpired,
|
|
22861
|
+
limit: RECALL_CANDIDATE_LIMIT
|
|
22862
|
+
});
|
|
22863
|
+
const candidates = this.selectRecallCandidates(request, scopedRecords2);
|
|
22864
|
+
const result = scoreMemoryRecordsWithDiagnostics(candidates.records, request);
|
|
22865
|
+
const reranked = candidates.ftsOrder ? rerankWithFts(result.items, candidates.ftsOrder) : result.items;
|
|
22866
|
+
return {
|
|
22867
|
+
items: reranked.slice(0, request.maxItems),
|
|
22868
|
+
diagnostics: {
|
|
22869
|
+
...result.diagnostics,
|
|
22870
|
+
returnedCount: Math.min(reranked.length, request.maxItems)
|
|
22871
|
+
}
|
|
22872
|
+
};
|
|
22873
|
+
}
|
|
22874
|
+
const recallElapsedStart = Date.now();
|
|
22413
22875
|
const scopedRecords = await this.list({
|
|
22414
22876
|
scopes: request.scopes,
|
|
22415
22877
|
kinds: request.kinds,
|
|
22416
22878
|
includeExpired: request.includeExpired,
|
|
22417
22879
|
limit: RECALL_CANDIDATE_LIMIT
|
|
22418
22880
|
});
|
|
22419
|
-
const
|
|
22420
|
-
const
|
|
22421
|
-
const
|
|
22881
|
+
const lexicalCandidates = this.selectRecallCandidates(request, scopedRecords);
|
|
22882
|
+
const lexicalResult = scoreMemoryRecordsWithDiagnostics(lexicalCandidates.records, request);
|
|
22883
|
+
const lexicalReranked = lexicalCandidates.ftsOrder ? rerankWithFts(lexicalResult.items, lexicalCandidates.ftsOrder) : lexicalResult.items;
|
|
22884
|
+
const lexicalIds = lexicalReranked.map((item) => item.record.id);
|
|
22885
|
+
let denseIds = [];
|
|
22886
|
+
try {
|
|
22887
|
+
const modelVersion = this.embeddingProvider.modelVersion;
|
|
22888
|
+
const normalizedQuery = normalizeMemoryText(request.query).toLowerCase();
|
|
22889
|
+
let queryEmbedding = this.embeddingCache?.get(modelVersion, normalizedQuery)?.vector ?? null;
|
|
22890
|
+
if (queryEmbedding === null) {
|
|
22891
|
+
queryEmbedding = await this.embeddingProvider.embed(normalizedQuery);
|
|
22892
|
+
this.embeddingCache?.set(modelVersion, normalizedQuery, {
|
|
22893
|
+
vector: queryEmbedding,
|
|
22894
|
+
modelVersion,
|
|
22895
|
+
queryHash: normalizedQuery
|
|
22896
|
+
});
|
|
22897
|
+
}
|
|
22898
|
+
const denseRecords = await this.selectDenseCandidates(request, queryEmbedding);
|
|
22899
|
+
denseIds = denseRecords.map((record) => record.id);
|
|
22900
|
+
} catch (err) {
|
|
22901
|
+
if (err instanceof EmbeddingVersionMismatchError || err instanceof EmbeddingUnavailableError) {
|
|
22902
|
+
warn("Dense retrieval failed \u2014 falling back to lexical-only", {
|
|
22903
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
22904
|
+
});
|
|
22905
|
+
} else {
|
|
22906
|
+
warn("Dense retrieval failed \u2014 falling back to lexical-only", {
|
|
22907
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
22908
|
+
});
|
|
22909
|
+
}
|
|
22910
|
+
return {
|
|
22911
|
+
items: lexicalReranked.slice(0, request.maxItems),
|
|
22912
|
+
diagnostics: {
|
|
22913
|
+
...lexicalResult.diagnostics,
|
|
22914
|
+
returnedCount: Math.min(lexicalReranked.length, request.maxItems)
|
|
22915
|
+
}
|
|
22916
|
+
};
|
|
22917
|
+
}
|
|
22918
|
+
const metadataIds = buildMetadataRankedIds(lexicalReranked, request);
|
|
22919
|
+
const weights = this.config.retrieval.weights;
|
|
22920
|
+
const rrfK = this.config.retrieval.rrfK;
|
|
22921
|
+
const fused = fuseRankings(lexicalIds, denseIds, metadataIds, weights, rrfK);
|
|
22922
|
+
const lexicalItemMap = new Map(lexicalReranked.map((item) => [item.record.id, item]));
|
|
22923
|
+
const minScore = request.minScore ?? this.config.recall.minScore;
|
|
22924
|
+
const fusedItems = [];
|
|
22925
|
+
for (const candidate of fused) {
|
|
22926
|
+
if (candidate.fusedScore < minScore)
|
|
22927
|
+
continue;
|
|
22928
|
+
const lexicalItem = lexicalItemMap.get(candidate.id);
|
|
22929
|
+
if (lexicalItem) {
|
|
22930
|
+
fusedItems.push({
|
|
22931
|
+
record: lexicalItem.record,
|
|
22932
|
+
score: candidate.fusedScore,
|
|
22933
|
+
reason: `${lexicalItem.reason}, rrf_fused=${candidate.fusedScore.toFixed(4)}`,
|
|
22934
|
+
signals: lexicalItem.signals
|
|
22935
|
+
});
|
|
22936
|
+
} else {
|
|
22937
|
+
const record = this.memories.get(candidate.id);
|
|
22938
|
+
if (record) {
|
|
22939
|
+
fusedItems.push({
|
|
22940
|
+
record,
|
|
22941
|
+
score: candidate.fusedScore,
|
|
22942
|
+
reason: `rrf_fused=${candidate.fusedScore.toFixed(4)}`,
|
|
22943
|
+
signals: {
|
|
22944
|
+
textOverlap: 0,
|
|
22945
|
+
tagOverlap: 0,
|
|
22946
|
+
fileOverlap: 0,
|
|
22947
|
+
symbolOverlap: 0,
|
|
22948
|
+
kindMatch: false,
|
|
22949
|
+
scopeMatch: false
|
|
22950
|
+
}
|
|
22951
|
+
});
|
|
22952
|
+
}
|
|
22953
|
+
}
|
|
22954
|
+
}
|
|
22955
|
+
const previousRecallElapsedMs = Date.now() - recallElapsedStart;
|
|
22956
|
+
let rerankedItems = fusedItems;
|
|
22957
|
+
if (this.config.retrieval.rerank.enabled && shouldRerank(previousRecallElapsedMs, this.config.retrieval.latencyBudgetMs)) {
|
|
22958
|
+
try {
|
|
22959
|
+
if (!this.reranker) {
|
|
22960
|
+
this.reranker = new CrossEncoderReranker({
|
|
22961
|
+
model: this.config.retrieval.rerank.model
|
|
22962
|
+
});
|
|
22963
|
+
}
|
|
22964
|
+
const topN = Math.min(20, fusedItems.length);
|
|
22965
|
+
const rerankCandidates = fusedItems.slice(0, topN).map((item) => ({
|
|
22966
|
+
id: item.record.id,
|
|
22967
|
+
text: item.record.text,
|
|
22968
|
+
score: item.score
|
|
22969
|
+
}));
|
|
22970
|
+
const rerankResult = await this.reranker.rerank(rerankCandidates, request.query, topN);
|
|
22971
|
+
const topNPrefix = fusedItems.slice(0, topN);
|
|
22972
|
+
const tail = fusedItems.slice(topN);
|
|
22973
|
+
const rerankOrder = new Map(rerankResult.map((c, idx) => [c.id, idx]));
|
|
22974
|
+
const reorderedTopN = [...topNPrefix].sort((a, b) => (rerankOrder.get(a.record.id) ?? 0) - (rerankOrder.get(b.record.id) ?? 0));
|
|
22975
|
+
rerankedItems = [...reorderedTopN, ...tail];
|
|
22976
|
+
} catch (err) {
|
|
22977
|
+
warn("Rerank failed \u2014 returning fused order", {
|
|
22978
|
+
reason: err instanceof Error ? err.message : String(err)
|
|
22979
|
+
});
|
|
22980
|
+
rerankedItems = fusedItems;
|
|
22981
|
+
}
|
|
22982
|
+
}
|
|
22422
22983
|
return {
|
|
22423
|
-
items:
|
|
22984
|
+
items: rerankedItems.slice(0, request.maxItems),
|
|
22424
22985
|
diagnostics: {
|
|
22425
|
-
...
|
|
22426
|
-
returnedCount: Math.min(
|
|
22986
|
+
...lexicalResult.diagnostics,
|
|
22987
|
+
returnedCount: Math.min(rerankedItems.length, request.maxItems),
|
|
22988
|
+
fusionActive: true
|
|
22427
22989
|
}
|
|
22428
22990
|
};
|
|
22429
22991
|
}
|
|
@@ -22580,6 +23142,11 @@ class SQLiteMemoryProvider {
|
|
|
22580
23142
|
for (const memory of result.memories) {
|
|
22581
23143
|
this.memories.set(memory.id, memory);
|
|
22582
23144
|
}
|
|
23145
|
+
for (const memory of result.memories) {
|
|
23146
|
+
if (memory.metadata.deleted !== true) {
|
|
23147
|
+
await this.writeMemoryVec(memory);
|
|
23148
|
+
}
|
|
23149
|
+
}
|
|
22583
23150
|
return result.change;
|
|
22584
23151
|
}
|
|
22585
23152
|
close() {
|
|
@@ -22592,6 +23159,46 @@ class SQLiteMemoryProvider {
|
|
|
22592
23159
|
this.initPromise = null;
|
|
22593
23160
|
this.lastAutomaticJsonlMigration = null;
|
|
22594
23161
|
}
|
|
23162
|
+
async rebuildEmbeddingIndex() {
|
|
23163
|
+
await this.initialize();
|
|
23164
|
+
if (!this.vecAvailable || !this.embeddingProvider) {
|
|
23165
|
+
warn("rebuildEmbeddingIndex skipped \u2014 sqlite-vec or embedding provider not available");
|
|
23166
|
+
return;
|
|
23167
|
+
}
|
|
23168
|
+
const currentVersion = this.embeddingProvider.modelVersion;
|
|
23169
|
+
const durableRecords = Array.from(this.memories.values()).filter((record) => DURABLE_MEMORY_KINDS.has(record.kind) && record.metadata.deleted !== true && record.supersededBy === undefined && record.stability !== "ephemeral");
|
|
23170
|
+
let successCount = 0;
|
|
23171
|
+
let failureCount = 0;
|
|
23172
|
+
const db = this.requireDb();
|
|
23173
|
+
for (const record of durableRecords) {
|
|
23174
|
+
try {
|
|
23175
|
+
const normalizedText = normalizeMemoryText(record.text).toLowerCase();
|
|
23176
|
+
if (normalizedText.length === 0)
|
|
23177
|
+
continue;
|
|
23178
|
+
const vector = await this.embeddingProvider.embed(normalizedText);
|
|
23179
|
+
db.run("INSERT OR REPLACE INTO memory_items_vec (id, embedding) VALUES (?, ?)", [record.id, vector]);
|
|
23180
|
+
successCount++;
|
|
23181
|
+
} catch (err) {
|
|
23182
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
23183
|
+
warn("rebuildEmbeddingIndex: failed to embed record", {
|
|
23184
|
+
id: record.id,
|
|
23185
|
+
reason
|
|
23186
|
+
});
|
|
23187
|
+
failureCount++;
|
|
23188
|
+
}
|
|
23189
|
+
}
|
|
23190
|
+
if (failureCount === 0) {
|
|
23191
|
+
db.run("INSERT OR REPLACE INTO embedding_config (key, value) VALUES (?, ?)", ["model_version", currentVersion]);
|
|
23192
|
+
}
|
|
23193
|
+
this.embeddingCache?.clear();
|
|
23194
|
+
if (failureCount > 0) {
|
|
23195
|
+
warn("rebuildEmbeddingIndex completed with failures", {
|
|
23196
|
+
successCount,
|
|
23197
|
+
failureCount,
|
|
23198
|
+
total: durableRecords.length
|
|
23199
|
+
});
|
|
23200
|
+
}
|
|
23201
|
+
}
|
|
22595
23202
|
async importJsonl() {
|
|
22596
23203
|
const wasInitialized = this.initialized;
|
|
22597
23204
|
await this.initialize();
|
|
@@ -22650,6 +23257,7 @@ class SQLiteMemoryProvider {
|
|
|
22650
23257
|
for (const id of removeIds) {
|
|
22651
23258
|
db.run("DELETE FROM memory_items WHERE id = ?", [id]);
|
|
22652
23259
|
this.deleteMemoryFts(id);
|
|
23260
|
+
this.deleteMemoryVec(id);
|
|
22653
23261
|
}
|
|
22654
23262
|
this.insertEvent("compact", "memory_items", "removed deleted, superseded, and expired scratch memories", JSON.stringify(result));
|
|
22655
23263
|
});
|
|
@@ -22696,6 +23304,52 @@ class SQLiteMemoryProvider {
|
|
|
22696
23304
|
return { records: scopedRecords, usedFts: false };
|
|
22697
23305
|
}
|
|
22698
23306
|
}
|
|
23307
|
+
getStoredModelVersion() {
|
|
23308
|
+
const row = this.requireDb().query(`SELECT value FROM embedding_config WHERE key = 'model_version' LIMIT 1`).get("model_version");
|
|
23309
|
+
return row?.value ?? null;
|
|
23310
|
+
}
|
|
23311
|
+
async selectDenseCandidates(request, queryEmbedding) {
|
|
23312
|
+
if (!this.config.embeddings.enabled || !this.vecAvailable || !this.embeddingProvider) {
|
|
23313
|
+
return [];
|
|
23314
|
+
}
|
|
23315
|
+
const storedVersion = this.getStoredModelVersion();
|
|
23316
|
+
const queryVersion = this.embeddingProvider.modelVersion;
|
|
23317
|
+
if (storedVersion !== null && storedVersion !== queryVersion) {
|
|
23318
|
+
throw new EmbeddingVersionMismatchError(queryVersion, storedVersion);
|
|
23319
|
+
}
|
|
23320
|
+
const k = Math.max(100, request.maxItems * 20);
|
|
23321
|
+
const rows = this.requireDb().query(`SELECT id, distance FROM memory_items_vec WHERE embedding MATCH ? ORDER BY distance LIMIT ?`).all(queryEmbedding, k);
|
|
23322
|
+
const scopeKeys = request.scopes?.map((s) => stableScopeKey(s)) ?? [];
|
|
23323
|
+
const kinds = request.kinds ?? [];
|
|
23324
|
+
const includeInactive = false;
|
|
23325
|
+
const includeExpired = request.includeExpired ?? false;
|
|
23326
|
+
const allowedIds = new Set;
|
|
23327
|
+
for (const record of this.memories.values()) {
|
|
23328
|
+
if (scopeKeys.length > 0 && !scopeKeys.includes(stableScopeKey(record.scope)))
|
|
23329
|
+
continue;
|
|
23330
|
+
if (kinds.length > 0 && !kinds.includes(record.kind))
|
|
23331
|
+
continue;
|
|
23332
|
+
if (!includeInactive && record.supersededBy)
|
|
23333
|
+
continue;
|
|
23334
|
+
if (!includeInactive && record.metadata.deleted === true)
|
|
23335
|
+
continue;
|
|
23336
|
+
if (!includeExpired && record.expiresAt) {
|
|
23337
|
+
const expires = Date.parse(record.expiresAt);
|
|
23338
|
+
if (Number.isFinite(expires) && expires <= Date.now())
|
|
23339
|
+
continue;
|
|
23340
|
+
}
|
|
23341
|
+
allowedIds.add(record.id);
|
|
23342
|
+
}
|
|
23343
|
+
const results = [];
|
|
23344
|
+
for (const row of rows) {
|
|
23345
|
+
if (!allowedIds.has(row.id))
|
|
23346
|
+
continue;
|
|
23347
|
+
const record = this.memories.get(row.id);
|
|
23348
|
+
if (record)
|
|
23349
|
+
results.push(record);
|
|
23350
|
+
}
|
|
23351
|
+
return results;
|
|
23352
|
+
}
|
|
22699
23353
|
runMigrations() {
|
|
22700
23354
|
const db = this.requireDb();
|
|
22701
23355
|
db.run(`CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -22768,6 +23422,26 @@ class SQLiteMemoryProvider {
|
|
|
22768
23422
|
return false;
|
|
22769
23423
|
}
|
|
22770
23424
|
}
|
|
23425
|
+
initializeVecExtension() {
|
|
23426
|
+
const db = this.requireDb();
|
|
23427
|
+
try {
|
|
23428
|
+
const dimension = Math.max(1, Math.trunc(this.config.embeddings.dimension ?? 384));
|
|
23429
|
+
const req = createRequire4(import.meta.url);
|
|
23430
|
+
const pkgDir = path46.dirname(req.resolve("@sqlite/sqlite-vec/package.json"));
|
|
23431
|
+
const ext = process.platform === "win32" ? ".dll" : process.platform === "darwin" ? ".dylib" : ".so";
|
|
23432
|
+
const vec0Path = path46.join(pkgDir, `vec0${ext}`);
|
|
23433
|
+
db.loadExtension(vec0Path);
|
|
23434
|
+
db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_items_vec USING vec0(
|
|
23435
|
+
id TEXT PRIMARY KEY, embedding FLOAT[${dimension}]
|
|
23436
|
+
)`);
|
|
23437
|
+
const modelVersion = this.config.embeddings.version ?? `${this.config.embeddings.model}:${dimension}`;
|
|
23438
|
+
db.run("INSERT OR IGNORE INTO embedding_config (key, value) VALUES (?, ?)", ["model_version", modelVersion]);
|
|
23439
|
+
this.vecAvailable = true;
|
|
23440
|
+
} catch (err) {
|
|
23441
|
+
this.vecAvailable = false;
|
|
23442
|
+
warn("sqlite-vec extension not available \u2014 dense retrieval disabled", err);
|
|
23443
|
+
}
|
|
23444
|
+
}
|
|
22771
23445
|
recreateFtsIndex() {
|
|
22772
23446
|
const db = this.requireDb();
|
|
22773
23447
|
const recreate = db.transaction(() => {
|
|
@@ -22879,6 +23553,34 @@ class SQLiteMemoryProvider {
|
|
|
22879
23553
|
this.ftsAvailable = false;
|
|
22880
23554
|
}
|
|
22881
23555
|
}
|
|
23556
|
+
async writeMemoryVec(record) {
|
|
23557
|
+
if (!this.config.embeddings.enabled)
|
|
23558
|
+
return;
|
|
23559
|
+
if (!this.vecAvailable)
|
|
23560
|
+
return;
|
|
23561
|
+
if (!this.embeddingProvider)
|
|
23562
|
+
return;
|
|
23563
|
+
if (!DURABLE_MEMORY_KINDS.has(record.kind))
|
|
23564
|
+
return;
|
|
23565
|
+
if (record.stability === "ephemeral")
|
|
23566
|
+
return;
|
|
23567
|
+
const normalizedText = normalizeMemoryText(record.text).toLowerCase();
|
|
23568
|
+
if (normalizedText.length === 0)
|
|
23569
|
+
return;
|
|
23570
|
+
try {
|
|
23571
|
+
const vector = await this.embeddingProvider.embed(normalizedText);
|
|
23572
|
+
this.requireDb().run("INSERT OR REPLACE INTO memory_items_vec (id, embedding) VALUES (?, ?)", [record.id, vector]);
|
|
23573
|
+
} catch (err) {
|
|
23574
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
23575
|
+
if (err instanceof EmbeddingUnavailableError) {
|
|
23576
|
+
warn("Embedding provider unavailable during write \u2014 skipping vector", {
|
|
23577
|
+
reason
|
|
23578
|
+
});
|
|
23579
|
+
} else {
|
|
23580
|
+
warn("Embedding computation failed \u2014 skipping vector", { reason });
|
|
23581
|
+
}
|
|
23582
|
+
}
|
|
23583
|
+
}
|
|
22882
23584
|
deleteMemoryFts(id) {
|
|
22883
23585
|
if (!this.ftsAvailable)
|
|
22884
23586
|
return;
|
|
@@ -22888,6 +23590,13 @@ class SQLiteMemoryProvider {
|
|
|
22888
23590
|
this.ftsAvailable = false;
|
|
22889
23591
|
}
|
|
22890
23592
|
}
|
|
23593
|
+
deleteMemoryVec(id) {
|
|
23594
|
+
if (!this.vecAvailable)
|
|
23595
|
+
return;
|
|
23596
|
+
try {
|
|
23597
|
+
this.requireDb().run("DELETE FROM memory_items_vec WHERE id = ?", [id]);
|
|
23598
|
+
} catch {}
|
|
23599
|
+
}
|
|
22891
23600
|
writeProposal(proposal) {
|
|
22892
23601
|
this.requireDb().run(`INSERT OR REPLACE INTO memory_proposals (
|
|
22893
23602
|
id,
|
|
@@ -23231,6 +23940,29 @@ function rerankWithFts(items, ftsOrder) {
|
|
|
23231
23940
|
};
|
|
23232
23941
|
}).sort((a, b) => b.score - a.score || a.record.id.localeCompare(b.record.id));
|
|
23233
23942
|
}
|
|
23943
|
+
function buildMetadataRankedIds(lexicalItems, request) {
|
|
23944
|
+
const scopeKeys = request.scopes?.map((s) => stableScopeKey(s)) ?? [];
|
|
23945
|
+
const kinds = new Set(request.kinds ?? []);
|
|
23946
|
+
const hasScopeFilter = scopeKeys.length > 0;
|
|
23947
|
+
const hasKindFilter = kinds.size > 0;
|
|
23948
|
+
const both = [];
|
|
23949
|
+
const scopeOnly = [];
|
|
23950
|
+
const kindOnly = [];
|
|
23951
|
+
const neither = [];
|
|
23952
|
+
for (const item of lexicalItems) {
|
|
23953
|
+
const scopeMatch = !hasScopeFilter || scopeKeys.includes(stableScopeKey(item.record.scope));
|
|
23954
|
+
const kindMatch = !hasKindFilter || kinds.has(item.record.kind);
|
|
23955
|
+
if (scopeMatch && kindMatch)
|
|
23956
|
+
both.push(item.record.id);
|
|
23957
|
+
else if (scopeMatch)
|
|
23958
|
+
scopeOnly.push(item.record.id);
|
|
23959
|
+
else if (kindMatch)
|
|
23960
|
+
kindOnly.push(item.record.id);
|
|
23961
|
+
else
|
|
23962
|
+
neither.push(item.record.id);
|
|
23963
|
+
}
|
|
23964
|
+
return [...both, ...scopeOnly, ...kindOnly, ...neither];
|
|
23965
|
+
}
|
|
23234
23966
|
|
|
23235
23967
|
// src/memory/provider-pool.ts
|
|
23236
23968
|
var MAX_POOL_SIZE = 16;
|
|
@@ -23370,7 +24102,7 @@ function resolvePoolKey(directory) {
|
|
|
23370
24102
|
try {
|
|
23371
24103
|
return realpathSync2(directory);
|
|
23372
24104
|
} catch {
|
|
23373
|
-
return
|
|
24105
|
+
return path47.resolve(directory);
|
|
23374
24106
|
}
|
|
23375
24107
|
}
|
|
23376
24108
|
|
|
@@ -23442,7 +24174,7 @@ var DEFAULT_MODES = [
|
|
|
23442
24174
|
];
|
|
23443
24175
|
var DEFAULT_TIMESTAMP = "2026-05-26T12:00:00.000Z";
|
|
23444
24176
|
async function evaluateMemoryRecallFixtures(options) {
|
|
23445
|
-
const fixtureDirectory =
|
|
24177
|
+
const fixtureDirectory = path48.resolve(options.fixtureDirectory);
|
|
23446
24178
|
const providers = options.providers ?? DEFAULT_PROVIDERS;
|
|
23447
24179
|
const modes = options.modes ?? DEFAULT_MODES;
|
|
23448
24180
|
const generatedAt = new Date().toISOString();
|
|
@@ -23451,7 +24183,7 @@ async function evaluateMemoryRecallFixtures(options) {
|
|
|
23451
24183
|
for (const fixture of fixtures) {
|
|
23452
24184
|
const materialized = materializeFixture(fixture);
|
|
23453
24185
|
for (const providerName of providers) {
|
|
23454
|
-
const tempRoot = await fs19.realpath(await fs19.mkdtemp(
|
|
24186
|
+
const tempRoot = await fs19.realpath(await fs19.mkdtemp(path48.join(os12.tmpdir(), "swarm-memory-eval-")));
|
|
23455
24187
|
const provider = createEvaluationProvider(providerName, tempRoot);
|
|
23456
24188
|
try {
|
|
23457
24189
|
await provider.initialize?.();
|
|
@@ -23495,7 +24227,7 @@ async function loadRecallEvaluationFixtures(fixtureDirectory) {
|
|
|
23495
24227
|
const files = entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name).sort((a, b) => a.localeCompare(b));
|
|
23496
24228
|
const fixtures = [];
|
|
23497
24229
|
for (const file of files) {
|
|
23498
|
-
const raw = await fs19.readFile(
|
|
24230
|
+
const raw = await fs19.readFile(path48.join(fixtureDirectory, file), "utf-8");
|
|
23499
24231
|
fixtures.push(validateFixture(JSON.parse(raw), file));
|
|
23500
24232
|
}
|
|
23501
24233
|
return fixtures;
|
|
@@ -23772,8 +24504,8 @@ var CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
|
23772
24504
|
}).passthrough();
|
|
23773
24505
|
// src/memory/consolidation-log.ts
|
|
23774
24506
|
import { appendFile as appendFile4, mkdir as mkdir12, readFile as readFile15 } from "fs/promises";
|
|
23775
|
-
import * as
|
|
23776
|
-
var LOG_RELATIVE_PATH =
|
|
24507
|
+
import * as path49 from "path";
|
|
24508
|
+
var LOG_RELATIVE_PATH = path49.join("memory", "consolidation-log.jsonl");
|
|
23777
24509
|
async function readConsolidationLog(directory) {
|
|
23778
24510
|
const filePath = validateSwarmPath(directory, LOG_RELATIVE_PATH);
|
|
23779
24511
|
let raw;
|
|
@@ -23796,7 +24528,7 @@ async function readConsolidationLog(directory) {
|
|
|
23796
24528
|
}
|
|
23797
24529
|
|
|
23798
24530
|
// src/commands/memory.ts
|
|
23799
|
-
var PACKAGE_ROOT =
|
|
24531
|
+
var PACKAGE_ROOT = path50.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
|
|
23800
24532
|
async function handleMemoryCommand(_directory, _args) {
|
|
23801
24533
|
return [
|
|
23802
24534
|
"## Swarm Memory",
|
|
@@ -24094,7 +24826,7 @@ function resolveCommandMemoryConfig(directory) {
|
|
|
24094
24826
|
}
|
|
24095
24827
|
function parseEvaluateArgs(directory, args) {
|
|
24096
24828
|
let json = false;
|
|
24097
|
-
let fixtureDirectory =
|
|
24829
|
+
let fixtureDirectory = path50.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
|
|
24098
24830
|
for (let i = 0;i < args.length; i++) {
|
|
24099
24831
|
const arg = args[i];
|
|
24100
24832
|
if (arg === "--json") {
|
|
@@ -24108,10 +24840,10 @@ function parseEvaluateArgs(directory, args) {
|
|
|
24108
24840
|
error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
|
|
24109
24841
|
};
|
|
24110
24842
|
}
|
|
24111
|
-
const resolvedFixtures =
|
|
24112
|
-
const canonical =
|
|
24113
|
-
const allowedRootA =
|
|
24114
|
-
const allowedRootB =
|
|
24843
|
+
const resolvedFixtures = path50.resolve(directory, next);
|
|
24844
|
+
const canonical = path50.normalize(resolvedFixtures) + path50.sep;
|
|
24845
|
+
const allowedRootA = path50.normalize(directory) + path50.sep;
|
|
24846
|
+
const allowedRootB = path50.normalize(path50.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path50.sep;
|
|
24115
24847
|
if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
|
|
24116
24848
|
return {
|
|
24117
24849
|
error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
|
|
@@ -24150,15 +24882,15 @@ function parseMaintenanceArgs(args, options) {
|
|
|
24150
24882
|
return { limit, confirm };
|
|
24151
24883
|
}
|
|
24152
24884
|
function resolvePackageRootFromModule(modulePath) {
|
|
24153
|
-
const moduleDir =
|
|
24154
|
-
const leaf =
|
|
24885
|
+
const moduleDir = path50.dirname(modulePath);
|
|
24886
|
+
const leaf = path50.basename(moduleDir);
|
|
24155
24887
|
if (leaf === "commands" || leaf === "cli") {
|
|
24156
|
-
return
|
|
24888
|
+
return path50.resolve(moduleDir, "..", "..");
|
|
24157
24889
|
}
|
|
24158
24890
|
if (leaf === "dist") {
|
|
24159
|
-
return
|
|
24891
|
+
return path50.resolve(moduleDir, "..");
|
|
24160
24892
|
}
|
|
24161
|
-
return
|
|
24893
|
+
return path50.resolve(moduleDir, "..");
|
|
24162
24894
|
}
|
|
24163
24895
|
function formatMigrationResult(label, report) {
|
|
24164
24896
|
if (!report) {
|
|
@@ -24275,15 +25007,15 @@ function truncate(value, maxLength) {
|
|
|
24275
25007
|
}
|
|
24276
25008
|
|
|
24277
25009
|
// src/services/plan-service.ts
|
|
24278
|
-
var
|
|
25010
|
+
var _internals34 = {
|
|
24279
25011
|
loadPlanJsonOnly,
|
|
24280
25012
|
derivePlanMarkdown,
|
|
24281
25013
|
readSwarmFileAsync
|
|
24282
25014
|
};
|
|
24283
25015
|
async function getPlanData(directory, phaseArg) {
|
|
24284
|
-
const plan = await
|
|
25016
|
+
const plan = await _internals34.loadPlanJsonOnly(directory);
|
|
24285
25017
|
if (plan) {
|
|
24286
|
-
const fullMarkdown =
|
|
25018
|
+
const fullMarkdown = _internals34.derivePlanMarkdown(plan);
|
|
24287
25019
|
if (phaseArg === undefined || phaseArg === null || phaseArg === "") {
|
|
24288
25020
|
return {
|
|
24289
25021
|
hasPlan: true,
|
|
@@ -24326,7 +25058,7 @@ async function getPlanData(directory, phaseArg) {
|
|
|
24326
25058
|
isLegacy: false
|
|
24327
25059
|
};
|
|
24328
25060
|
}
|
|
24329
|
-
const planContent = await
|
|
25061
|
+
const planContent = await _internals34.readSwarmFileAsync(directory, "plan.md");
|
|
24330
25062
|
if (!planContent) {
|
|
24331
25063
|
return {
|
|
24332
25064
|
hasPlan: false,
|
|
@@ -24423,7 +25155,7 @@ async function handlePlanCommand(directory, args) {
|
|
|
24423
25155
|
return formatPlanMarkdown(planData);
|
|
24424
25156
|
}
|
|
24425
25157
|
// src/commands/post-mortem.ts
|
|
24426
|
-
var
|
|
25158
|
+
var _internals35 = {
|
|
24427
25159
|
createCuratorLLMDelegate,
|
|
24428
25160
|
runCuratorPostMortem
|
|
24429
25161
|
};
|
|
@@ -24435,10 +25167,10 @@ async function handlePostMortemCommand(directory, args, options) {
|
|
|
24435
25167
|
};
|
|
24436
25168
|
if (options?.sessionID) {
|
|
24437
25169
|
try {
|
|
24438
|
-
pmOptions.llmDelegate =
|
|
25170
|
+
pmOptions.llmDelegate = _internals35.createCuratorLLMDelegate(directory, "postmortem", options.sessionID);
|
|
24439
25171
|
} catch {}
|
|
24440
25172
|
}
|
|
24441
|
-
const result = await
|
|
25173
|
+
const result = await _internals35.runCuratorPostMortem(directory, pmOptions);
|
|
24442
25174
|
const lines = [];
|
|
24443
25175
|
if (result.success) {
|
|
24444
25176
|
lines.push("## Post-Mortem Report Generated");
|
|
@@ -24593,12 +25325,12 @@ function formatRelativeTime(epochMs) {
|
|
|
24593
25325
|
const diffDays = Math.floor(diffHours / 24);
|
|
24594
25326
|
return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
|
|
24595
25327
|
}
|
|
24596
|
-
var
|
|
25328
|
+
var _internals36 = {
|
|
24597
25329
|
formatRelativeTime,
|
|
24598
25330
|
listActive
|
|
24599
25331
|
};
|
|
24600
25332
|
async function handlePrMonitorStatusCommand(directory, _args, sessionID, source) {
|
|
24601
|
-
const allActive = await
|
|
25333
|
+
const allActive = await _internals36.listActive(directory);
|
|
24602
25334
|
const allSessions = source === "cli";
|
|
24603
25335
|
const subs = allSessions ? allActive : allActive.filter((record) => record.sessionID === sessionID);
|
|
24604
25336
|
if (subs.length === 0) {
|
|
@@ -24736,7 +25468,7 @@ async function handlePrSubscribeCommand(directory, args, sessionID) {
|
|
|
24736
25468
|
const repoFullName = `${prInfo.owner}/${prInfo.repo}`;
|
|
24737
25469
|
const prUrl = `https://github.com/${prInfo.owner}/${prInfo.repo}/pull/${prInfo.number}`;
|
|
24738
25470
|
try {
|
|
24739
|
-
const config =
|
|
25471
|
+
const config = _internals37.loadPluginConfig(directory);
|
|
24740
25472
|
const prMonitorConfig = config.pr_monitor;
|
|
24741
25473
|
if (!prMonitorConfig?.enabled) {
|
|
24742
25474
|
return [
|
|
@@ -24746,7 +25478,7 @@ async function handlePrSubscribeCommand(directory, args, sessionID) {
|
|
|
24746
25478
|
].join(`
|
|
24747
25479
|
`);
|
|
24748
25480
|
}
|
|
24749
|
-
await
|
|
25481
|
+
await _internals37.subscribe(directory, {
|
|
24750
25482
|
sessionID,
|
|
24751
25483
|
prNumber: prInfo.number,
|
|
24752
25484
|
repoFullName,
|
|
@@ -24770,7 +25502,7 @@ async function handlePrSubscribeCommand(directory, args, sessionID) {
|
|
|
24770
25502
|
`);
|
|
24771
25503
|
}
|
|
24772
25504
|
}
|
|
24773
|
-
var
|
|
25505
|
+
var _internals37 = {
|
|
24774
25506
|
loadPluginConfig,
|
|
24775
25507
|
subscribe
|
|
24776
25508
|
};
|
|
@@ -24793,9 +25525,9 @@ async function handlePrUnsubscribeCommand(directory, args, sessionID) {
|
|
|
24793
25525
|
`);
|
|
24794
25526
|
}
|
|
24795
25527
|
const refToken = rest[0];
|
|
24796
|
-
const prInfo =
|
|
25528
|
+
const prInfo = _internals38.parsePrRef(refToken, directory);
|
|
24797
25529
|
if (!prInfo) {
|
|
24798
|
-
if (
|
|
25530
|
+
if (_internals38.looksLikePrRef(refToken)) {
|
|
24799
25531
|
return [
|
|
24800
25532
|
`Error: Could not resolve PR reference from "${refToken}".`,
|
|
24801
25533
|
"",
|
|
@@ -24816,8 +25548,8 @@ async function handlePrUnsubscribeCommand(directory, args, sessionID) {
|
|
|
24816
25548
|
const repoFullName = `${prInfo.owner}/${prInfo.repo}`;
|
|
24817
25549
|
const prUrl = `https://github.com/${prInfo.owner}/${prInfo.repo}/pull/${prInfo.number}`;
|
|
24818
25550
|
try {
|
|
24819
|
-
const correlationId =
|
|
24820
|
-
const result = await
|
|
25551
|
+
const correlationId = _internals38.buildCorrelationId(sessionID, repoFullName, prInfo.number);
|
|
25552
|
+
const result = await _internals38.unsubscribe(directory, correlationId);
|
|
24821
25553
|
if (!result) {
|
|
24822
25554
|
return [
|
|
24823
25555
|
`Not subscribed to ${prUrl}`,
|
|
@@ -24844,7 +25576,7 @@ async function handlePrUnsubscribeCommand(directory, args, sessionID) {
|
|
|
24844
25576
|
`);
|
|
24845
25577
|
}
|
|
24846
25578
|
}
|
|
24847
|
-
var
|
|
25579
|
+
var _internals38 = {
|
|
24848
25580
|
unsubscribe,
|
|
24849
25581
|
buildCorrelationId,
|
|
24850
25582
|
parsePrRef,
|
|
@@ -24853,11 +25585,11 @@ var _internals37 = {
|
|
|
24853
25585
|
|
|
24854
25586
|
// src/services/preflight-service.ts
|
|
24855
25587
|
import * as fs26 from "fs";
|
|
24856
|
-
import * as
|
|
25588
|
+
import * as path57 from "path";
|
|
24857
25589
|
|
|
24858
25590
|
// src/tools/lint.ts
|
|
24859
25591
|
import * as fs20 from "fs";
|
|
24860
|
-
import * as
|
|
25592
|
+
import * as path51 from "path";
|
|
24861
25593
|
|
|
24862
25594
|
// src/utils/path-security.ts
|
|
24863
25595
|
function containsPathTraversal(str) {
|
|
@@ -24913,9 +25645,9 @@ function validateArgs(args) {
|
|
|
24913
25645
|
}
|
|
24914
25646
|
function getLinterCommand(linter, mode, projectDir) {
|
|
24915
25647
|
const isWindows = process.platform === "win32";
|
|
24916
|
-
const binDir =
|
|
24917
|
-
const biomeBin = isWindows ?
|
|
24918
|
-
const eslintBin = isWindows ?
|
|
25648
|
+
const binDir = path51.join(projectDir, "node_modules", ".bin");
|
|
25649
|
+
const biomeBin = isWindows ? path51.join(binDir, "biome.EXE") : path51.join(binDir, "biome");
|
|
25650
|
+
const eslintBin = isWindows ? path51.join(binDir, "eslint.cmd") : path51.join(binDir, "eslint");
|
|
24919
25651
|
switch (linter) {
|
|
24920
25652
|
case "biome":
|
|
24921
25653
|
if (mode === "fix") {
|
|
@@ -24931,7 +25663,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
24931
25663
|
}
|
|
24932
25664
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
24933
25665
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
24934
|
-
const gradlew = fs20.existsSync(
|
|
25666
|
+
const gradlew = fs20.existsSync(path51.join(cwd, gradlewName)) ? path51.join(cwd, gradlewName) : null;
|
|
24935
25667
|
switch (linter) {
|
|
24936
25668
|
case "ruff":
|
|
24937
25669
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -24965,10 +25697,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
24965
25697
|
}
|
|
24966
25698
|
}
|
|
24967
25699
|
function detectRuff(cwd) {
|
|
24968
|
-
if (fs20.existsSync(
|
|
25700
|
+
if (fs20.existsSync(path51.join(cwd, "ruff.toml")))
|
|
24969
25701
|
return isCommandAvailable("ruff");
|
|
24970
25702
|
try {
|
|
24971
|
-
const pyproject =
|
|
25703
|
+
const pyproject = path51.join(cwd, "pyproject.toml");
|
|
24972
25704
|
if (fs20.existsSync(pyproject)) {
|
|
24973
25705
|
const content = fs20.readFileSync(pyproject, "utf-8");
|
|
24974
25706
|
if (content.includes("[tool.ruff]"))
|
|
@@ -24978,19 +25710,19 @@ function detectRuff(cwd) {
|
|
|
24978
25710
|
return false;
|
|
24979
25711
|
}
|
|
24980
25712
|
function detectClippy(cwd) {
|
|
24981
|
-
return fs20.existsSync(
|
|
25713
|
+
return fs20.existsSync(path51.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
24982
25714
|
}
|
|
24983
25715
|
function detectGolangciLint(cwd) {
|
|
24984
|
-
return fs20.existsSync(
|
|
25716
|
+
return fs20.existsSync(path51.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
24985
25717
|
}
|
|
24986
25718
|
function detectCheckstyle(cwd) {
|
|
24987
|
-
const hasMaven = fs20.existsSync(
|
|
24988
|
-
const hasGradle = fs20.existsSync(
|
|
24989
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs20.existsSync(
|
|
25719
|
+
const hasMaven = fs20.existsSync(path51.join(cwd, "pom.xml"));
|
|
25720
|
+
const hasGradle = fs20.existsSync(path51.join(cwd, "build.gradle")) || fs20.existsSync(path51.join(cwd, "build.gradle.kts"));
|
|
25721
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs20.existsSync(path51.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
24990
25722
|
return (hasMaven || hasGradle) && hasBinary;
|
|
24991
25723
|
}
|
|
24992
25724
|
function detectKtlint(cwd) {
|
|
24993
|
-
const hasKotlin = fs20.existsSync(
|
|
25725
|
+
const hasKotlin = fs20.existsSync(path51.join(cwd, "build.gradle.kts")) || fs20.existsSync(path51.join(cwd, "build.gradle")) || (() => {
|
|
24994
25726
|
try {
|
|
24995
25727
|
return fs20.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
24996
25728
|
} catch {
|
|
@@ -25009,11 +25741,11 @@ function detectDotnetFormat(cwd) {
|
|
|
25009
25741
|
}
|
|
25010
25742
|
}
|
|
25011
25743
|
function detectCppcheck(cwd) {
|
|
25012
|
-
if (fs20.existsSync(
|
|
25744
|
+
if (fs20.existsSync(path51.join(cwd, "CMakeLists.txt"))) {
|
|
25013
25745
|
return isCommandAvailable("cppcheck");
|
|
25014
25746
|
}
|
|
25015
25747
|
try {
|
|
25016
|
-
const dirsToCheck = [cwd,
|
|
25748
|
+
const dirsToCheck = [cwd, path51.join(cwd, "src")];
|
|
25017
25749
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
25018
25750
|
try {
|
|
25019
25751
|
return fs20.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -25027,13 +25759,13 @@ function detectCppcheck(cwd) {
|
|
|
25027
25759
|
}
|
|
25028
25760
|
}
|
|
25029
25761
|
function detectSwiftlint(cwd) {
|
|
25030
|
-
return fs20.existsSync(
|
|
25762
|
+
return fs20.existsSync(path51.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
25031
25763
|
}
|
|
25032
25764
|
function detectDartAnalyze(cwd) {
|
|
25033
|
-
return fs20.existsSync(
|
|
25765
|
+
return fs20.existsSync(path51.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
25034
25766
|
}
|
|
25035
25767
|
function detectRubocop(cwd) {
|
|
25036
|
-
return (fs20.existsSync(
|
|
25768
|
+
return (fs20.existsSync(path51.join(cwd, "Gemfile")) || fs20.existsSync(path51.join(cwd, "gems.rb")) || fs20.existsSync(path51.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
25037
25769
|
}
|
|
25038
25770
|
function detectAdditionalLinter(cwd) {
|
|
25039
25771
|
if (detectRuff(cwd))
|
|
@@ -25061,10 +25793,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
25061
25793
|
function findBinInAncestors(startDir, binName) {
|
|
25062
25794
|
let dir = startDir;
|
|
25063
25795
|
while (true) {
|
|
25064
|
-
const candidate =
|
|
25796
|
+
const candidate = path51.join(dir, "node_modules", ".bin", binName);
|
|
25065
25797
|
if (fs20.existsSync(candidate))
|
|
25066
25798
|
return candidate;
|
|
25067
|
-
const parent =
|
|
25799
|
+
const parent = path51.dirname(dir);
|
|
25068
25800
|
if (parent === dir)
|
|
25069
25801
|
break;
|
|
25070
25802
|
dir = parent;
|
|
@@ -25073,10 +25805,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
25073
25805
|
}
|
|
25074
25806
|
function findBinInEnvPath(binName) {
|
|
25075
25807
|
const searchPath = process.env.PATH ?? "";
|
|
25076
|
-
for (const dir of searchPath.split(
|
|
25808
|
+
for (const dir of searchPath.split(path51.delimiter)) {
|
|
25077
25809
|
if (!dir)
|
|
25078
25810
|
continue;
|
|
25079
|
-
const candidate =
|
|
25811
|
+
const candidate = path51.join(dir, binName);
|
|
25080
25812
|
if (fs20.existsSync(candidate))
|
|
25081
25813
|
return candidate;
|
|
25082
25814
|
}
|
|
@@ -25089,13 +25821,13 @@ async function detectAvailableLinter(directory) {
|
|
|
25089
25821
|
return null;
|
|
25090
25822
|
const projectDir = directory;
|
|
25091
25823
|
const isWindows = process.platform === "win32";
|
|
25092
|
-
const biomeBin = isWindows ?
|
|
25093
|
-
const eslintBin = isWindows ?
|
|
25824
|
+
const biomeBin = isWindows ? path51.join(projectDir, "node_modules", ".bin", "biome.EXE") : path51.join(projectDir, "node_modules", ".bin", "biome");
|
|
25825
|
+
const eslintBin = isWindows ? path51.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path51.join(projectDir, "node_modules", ".bin", "eslint");
|
|
25094
25826
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
25095
25827
|
if (localResult)
|
|
25096
25828
|
return localResult;
|
|
25097
|
-
const biomeAncestor = findBinInAncestors(
|
|
25098
|
-
const eslintAncestor = findBinInAncestors(
|
|
25829
|
+
const biomeAncestor = findBinInAncestors(path51.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
25830
|
+
const eslintAncestor = findBinInAncestors(path51.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
25099
25831
|
if (biomeAncestor || eslintAncestor) {
|
|
25100
25832
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
25101
25833
|
}
|
|
@@ -25278,15 +26010,15 @@ var lint = createSwarmTool({
|
|
|
25278
26010
|
}
|
|
25279
26011
|
const { mode } = args;
|
|
25280
26012
|
const cwd = directory;
|
|
25281
|
-
const linter = await
|
|
26013
|
+
const linter = await _internals39.detectAvailableLinter(directory);
|
|
25282
26014
|
if (linter) {
|
|
25283
|
-
const result = await
|
|
26015
|
+
const result = await _internals39.runLint(linter, mode, directory);
|
|
25284
26016
|
return JSON.stringify(result, null, 2);
|
|
25285
26017
|
}
|
|
25286
|
-
const additionalLinter =
|
|
26018
|
+
const additionalLinter = _internals39.detectAdditionalLinter(cwd);
|
|
25287
26019
|
if (additionalLinter) {
|
|
25288
26020
|
warn(`[lint] Using ${additionalLinter} linter for this project`);
|
|
25289
|
-
const result = await
|
|
26021
|
+
const result = await _internals39.runAdditionalLint(additionalLinter, mode, cwd);
|
|
25290
26022
|
return JSON.stringify(result, null, 2);
|
|
25291
26023
|
}
|
|
25292
26024
|
const errorResult = {
|
|
@@ -25300,7 +26032,7 @@ For Rust: rustup component add clippy`
|
|
|
25300
26032
|
return JSON.stringify(errorResult, null, 2);
|
|
25301
26033
|
}
|
|
25302
26034
|
});
|
|
25303
|
-
var
|
|
26035
|
+
var _internals39 = {
|
|
25304
26036
|
detectAvailableLinter,
|
|
25305
26037
|
runLint,
|
|
25306
26038
|
detectAdditionalLinter,
|
|
@@ -25309,7 +26041,7 @@ var _internals38 = {
|
|
|
25309
26041
|
|
|
25310
26042
|
// src/tools/secretscan.ts
|
|
25311
26043
|
import * as fs21 from "fs";
|
|
25312
|
-
import * as
|
|
26044
|
+
import * as path52 from "path";
|
|
25313
26045
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
25314
26046
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
25315
26047
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -25536,7 +26268,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
25536
26268
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
25537
26269
|
}
|
|
25538
26270
|
function loadSecretScanIgnore(scanDir) {
|
|
25539
|
-
const ignorePath =
|
|
26271
|
+
const ignorePath = path52.join(scanDir, ".secretscanignore");
|
|
25540
26272
|
try {
|
|
25541
26273
|
if (!fs21.existsSync(ignorePath))
|
|
25542
26274
|
return [];
|
|
@@ -25559,7 +26291,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
25559
26291
|
if (exactNames.has(entry))
|
|
25560
26292
|
return true;
|
|
25561
26293
|
for (const pattern of globPatterns) {
|
|
25562
|
-
if (
|
|
26294
|
+
if (path52.matchesGlob(relPath, pattern))
|
|
25563
26295
|
return true;
|
|
25564
26296
|
}
|
|
25565
26297
|
return false;
|
|
@@ -25580,7 +26312,7 @@ function validateDirectoryInput(dir) {
|
|
|
25580
26312
|
return null;
|
|
25581
26313
|
}
|
|
25582
26314
|
function isBinaryFile(filePath, buffer) {
|
|
25583
|
-
const ext =
|
|
26315
|
+
const ext = path52.extname(filePath).toLowerCase();
|
|
25584
26316
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
25585
26317
|
return true;
|
|
25586
26318
|
}
|
|
@@ -25717,9 +26449,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
25717
26449
|
return false;
|
|
25718
26450
|
}
|
|
25719
26451
|
function isPathWithinScope(realPath, scanDir) {
|
|
25720
|
-
const resolvedScanDir =
|
|
25721
|
-
const resolvedRealPath =
|
|
25722
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
26452
|
+
const resolvedScanDir = path52.resolve(scanDir);
|
|
26453
|
+
const resolvedRealPath = path52.resolve(realPath);
|
|
26454
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path52.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
25723
26455
|
}
|
|
25724
26456
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
25725
26457
|
skippedDirs: 0,
|
|
@@ -25745,8 +26477,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
25745
26477
|
return a.localeCompare(b);
|
|
25746
26478
|
});
|
|
25747
26479
|
for (const entry of entries) {
|
|
25748
|
-
const fullPath =
|
|
25749
|
-
const relPath =
|
|
26480
|
+
const fullPath = path52.join(dir, entry);
|
|
26481
|
+
const relPath = path52.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
25750
26482
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
25751
26483
|
stats.skippedDirs++;
|
|
25752
26484
|
continue;
|
|
@@ -25781,7 +26513,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
25781
26513
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
25782
26514
|
files.push(...subFiles);
|
|
25783
26515
|
} else if (lstat2.isFile()) {
|
|
25784
|
-
const ext =
|
|
26516
|
+
const ext = path52.extname(fullPath).toLowerCase();
|
|
25785
26517
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
25786
26518
|
files.push(fullPath);
|
|
25787
26519
|
} else {
|
|
@@ -25847,7 +26579,7 @@ var secretscan = createSwarmTool({
|
|
|
25847
26579
|
}
|
|
25848
26580
|
}
|
|
25849
26581
|
try {
|
|
25850
|
-
const _scanDirRaw =
|
|
26582
|
+
const _scanDirRaw = path52.resolve(directory);
|
|
25851
26583
|
const scanDir = (() => {
|
|
25852
26584
|
try {
|
|
25853
26585
|
return fs21.realpathSync(_scanDirRaw);
|
|
@@ -25988,7 +26720,7 @@ var secretscan = createSwarmTool({
|
|
|
25988
26720
|
});
|
|
25989
26721
|
async function runSecretscan(directory) {
|
|
25990
26722
|
try {
|
|
25991
|
-
const result = await
|
|
26723
|
+
const result = await _internals40.secretscan.execute({ directory }, {});
|
|
25992
26724
|
const jsonStr = typeof result === "string" ? result : result.output;
|
|
25993
26725
|
return JSON.parse(jsonStr);
|
|
25994
26726
|
} catch (e) {
|
|
@@ -26003,18 +26735,18 @@ async function runSecretscan(directory) {
|
|
|
26003
26735
|
return errorResult;
|
|
26004
26736
|
}
|
|
26005
26737
|
}
|
|
26006
|
-
var
|
|
26738
|
+
var _internals40 = {
|
|
26007
26739
|
secretscan,
|
|
26008
26740
|
runSecretscan
|
|
26009
26741
|
};
|
|
26010
26742
|
|
|
26011
26743
|
// src/tools/test-runner.ts
|
|
26012
26744
|
import * as fs25 from "fs";
|
|
26013
|
-
import * as
|
|
26745
|
+
import * as path56 from "path";
|
|
26014
26746
|
|
|
26015
26747
|
// src/test-impact/analyzer.ts
|
|
26016
26748
|
import fs22 from "fs";
|
|
26017
|
-
import
|
|
26749
|
+
import path53 from "path";
|
|
26018
26750
|
var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
26019
26751
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
26020
26752
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -26055,8 +26787,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
26055
26787
|
if (!importPath.startsWith(".")) {
|
|
26056
26788
|
return null;
|
|
26057
26789
|
}
|
|
26058
|
-
const resolved =
|
|
26059
|
-
if (
|
|
26790
|
+
const resolved = path53.resolve(fromDir, importPath);
|
|
26791
|
+
if (path53.extname(resolved)) {
|
|
26060
26792
|
if (fs22.existsSync(resolved) && fs22.statSync(resolved).isFile()) {
|
|
26061
26793
|
return normalizePath2(resolved);
|
|
26062
26794
|
}
|
|
@@ -26076,20 +26808,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
26076
26808
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
26077
26809
|
let baseDir = fromDir;
|
|
26078
26810
|
for (let i = 1;i < leadingDots; i++) {
|
|
26079
|
-
baseDir =
|
|
26811
|
+
baseDir = path53.dirname(baseDir);
|
|
26080
26812
|
}
|
|
26081
26813
|
const rest = module.slice(leadingDots);
|
|
26082
26814
|
if (rest.length === 0) {
|
|
26083
|
-
const initPath =
|
|
26815
|
+
const initPath = path53.join(baseDir, "__init__.py");
|
|
26084
26816
|
if (fs22.existsSync(initPath) && fs22.statSync(initPath).isFile()) {
|
|
26085
26817
|
return normalizePath2(initPath);
|
|
26086
26818
|
}
|
|
26087
26819
|
return null;
|
|
26088
26820
|
}
|
|
26089
|
-
const subpath = rest.replace(/\./g,
|
|
26821
|
+
const subpath = rest.replace(/\./g, path53.sep);
|
|
26090
26822
|
const candidates = [
|
|
26091
|
-
`${
|
|
26092
|
-
|
|
26823
|
+
`${path53.join(baseDir, subpath)}.py`,
|
|
26824
|
+
path53.join(baseDir, subpath, "__init__.py")
|
|
26093
26825
|
];
|
|
26094
26826
|
for (const c of candidates) {
|
|
26095
26827
|
if (fs22.existsSync(c) && fs22.statSync(c).isFile())
|
|
@@ -26099,7 +26831,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
26099
26831
|
}
|
|
26100
26832
|
var goModuleCache = new Map;
|
|
26101
26833
|
function findGoModule(fromDir) {
|
|
26102
|
-
const resolved =
|
|
26834
|
+
const resolved = path53.resolve(fromDir);
|
|
26103
26835
|
let cur = resolved;
|
|
26104
26836
|
const walked = [];
|
|
26105
26837
|
for (let i = 0;i < 16; i++) {
|
|
@@ -26111,7 +26843,7 @@ function findGoModule(fromDir) {
|
|
|
26111
26843
|
}
|
|
26112
26844
|
walked.push(cur);
|
|
26113
26845
|
try {
|
|
26114
|
-
const goMod =
|
|
26846
|
+
const goMod = path53.join(cur, "go.mod");
|
|
26115
26847
|
const content = fs22.readFileSync(goMod, "utf-8");
|
|
26116
26848
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
26117
26849
|
if (moduleMatch) {
|
|
@@ -26122,10 +26854,10 @@ function findGoModule(fromDir) {
|
|
|
26122
26854
|
}
|
|
26123
26855
|
} catch {}
|
|
26124
26856
|
try {
|
|
26125
|
-
fs22.accessSync(
|
|
26857
|
+
fs22.accessSync(path53.join(cur, ".git"));
|
|
26126
26858
|
break;
|
|
26127
26859
|
} catch {}
|
|
26128
|
-
const parent =
|
|
26860
|
+
const parent = path53.dirname(cur);
|
|
26129
26861
|
if (parent === cur)
|
|
26130
26862
|
break;
|
|
26131
26863
|
cur = parent;
|
|
@@ -26137,12 +26869,12 @@ function findGoModule(fromDir) {
|
|
|
26137
26869
|
function resolveGoImport(fromDir, importPath) {
|
|
26138
26870
|
let dir = null;
|
|
26139
26871
|
if (importPath.startsWith(".")) {
|
|
26140
|
-
dir =
|
|
26872
|
+
dir = path53.resolve(fromDir, importPath);
|
|
26141
26873
|
} else {
|
|
26142
26874
|
const mod = findGoModule(fromDir);
|
|
26143
26875
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
26144
26876
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
26145
|
-
dir =
|
|
26877
|
+
dir = path53.join(mod.moduleRoot, subpath);
|
|
26146
26878
|
}
|
|
26147
26879
|
}
|
|
26148
26880
|
if (dir === null)
|
|
@@ -26150,7 +26882,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
26150
26882
|
if (!fs22.existsSync(dir) || !fs22.statSync(dir).isDirectory())
|
|
26151
26883
|
return [];
|
|
26152
26884
|
try {
|
|
26153
|
-
return fs22.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(
|
|
26885
|
+
return fs22.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path53.join(dir, f)));
|
|
26154
26886
|
} catch {
|
|
26155
26887
|
return [];
|
|
26156
26888
|
}
|
|
@@ -26189,15 +26921,15 @@ function findTestFilesSync(cwd) {
|
|
|
26189
26921
|
for (const entry of entries) {
|
|
26190
26922
|
if (entry.isDirectory()) {
|
|
26191
26923
|
if (!skipDirs.has(entry.name)) {
|
|
26192
|
-
walk(
|
|
26924
|
+
walk(path53.join(dir, entry.name), visitedInodes);
|
|
26193
26925
|
}
|
|
26194
26926
|
} else if (entry.isFile()) {
|
|
26195
26927
|
const name = entry.name;
|
|
26196
26928
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
26197
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
26929
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path53.sep}tests${path53.sep}`) && name.endsWith(".py");
|
|
26198
26930
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
26199
26931
|
if (isTsTest || isPyTest || isGoTest) {
|
|
26200
|
-
testFiles.push(normalizePath2(
|
|
26932
|
+
testFiles.push(normalizePath2(path53.join(dir, entry.name)));
|
|
26201
26933
|
}
|
|
26202
26934
|
}
|
|
26203
26935
|
}
|
|
@@ -26222,8 +26954,8 @@ function extractImports(content) {
|
|
|
26222
26954
|
];
|
|
26223
26955
|
}
|
|
26224
26956
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
26225
|
-
const ext =
|
|
26226
|
-
const testDir =
|
|
26957
|
+
const ext = path53.extname(testFile).toLowerCase();
|
|
26958
|
+
const testDir = path53.dirname(testFile);
|
|
26227
26959
|
function addEdge(source) {
|
|
26228
26960
|
if (!impactMap[source])
|
|
26229
26961
|
impactMap[source] = [];
|
|
@@ -26276,7 +27008,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
26276
27008
|
}
|
|
26277
27009
|
return impactMap;
|
|
26278
27010
|
}
|
|
26279
|
-
var
|
|
27011
|
+
var _internals41 = {
|
|
26280
27012
|
validateProjectRoot,
|
|
26281
27013
|
normalizePath: normalizePath2,
|
|
26282
27014
|
isCacheStale,
|
|
@@ -26291,12 +27023,12 @@ var _internals40 = {
|
|
|
26291
27023
|
_clearGoModuleCache
|
|
26292
27024
|
};
|
|
26293
27025
|
async function buildImpactMap(cwd) {
|
|
26294
|
-
const impactMap = await
|
|
26295
|
-
await
|
|
27026
|
+
const impactMap = await _internals41.buildImpactMapInternal(cwd);
|
|
27027
|
+
await _internals41.saveImpactMap(cwd, impactMap);
|
|
26296
27028
|
return impactMap;
|
|
26297
27029
|
}
|
|
26298
27030
|
async function loadImpactMap(cwd, options) {
|
|
26299
|
-
const cachePath =
|
|
27031
|
+
const cachePath = path53.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
26300
27032
|
if (fs22.existsSync(cachePath)) {
|
|
26301
27033
|
try {
|
|
26302
27034
|
const content = fs22.readFileSync(cachePath, "utf-8");
|
|
@@ -26306,7 +27038,7 @@ async function loadImpactMap(cwd, options) {
|
|
|
26306
27038
|
const hasValidValues = Object.values(map).every((v) => Array.isArray(v) && v.every((item) => typeof item === "string"));
|
|
26307
27039
|
if (hasValidValues) {
|
|
26308
27040
|
const generatedAt = new Date(data.generatedAt).getTime();
|
|
26309
|
-
if (!
|
|
27041
|
+
if (!_internals41.isCacheStale(map, generatedAt)) {
|
|
26310
27042
|
return map;
|
|
26311
27043
|
}
|
|
26312
27044
|
if (options?.skipRebuild) {
|
|
@@ -26326,15 +27058,15 @@ async function loadImpactMap(cwd, options) {
|
|
|
26326
27058
|
if (options?.skipRebuild) {
|
|
26327
27059
|
return {};
|
|
26328
27060
|
}
|
|
26329
|
-
return
|
|
27061
|
+
return _internals41.buildImpactMap(cwd);
|
|
26330
27062
|
}
|
|
26331
27063
|
async function saveImpactMap(cwd, impactMap) {
|
|
26332
|
-
if (!
|
|
27064
|
+
if (!path53.isAbsolute(cwd)) {
|
|
26333
27065
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
26334
27066
|
}
|
|
26335
|
-
|
|
26336
|
-
const cacheDir2 =
|
|
26337
|
-
const cachePath =
|
|
27067
|
+
_internals41.validateProjectRoot(cwd);
|
|
27068
|
+
const cacheDir2 = path53.join(cwd, ".swarm", "cache");
|
|
27069
|
+
const cachePath = path53.join(cacheDir2, "impact-map.json");
|
|
26338
27070
|
if (!fs22.existsSync(cacheDir2)) {
|
|
26339
27071
|
fs22.mkdirSync(cacheDir2, { recursive: true });
|
|
26340
27072
|
}
|
|
@@ -26356,7 +27088,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
26356
27088
|
};
|
|
26357
27089
|
}
|
|
26358
27090
|
const validFiles = changedFiles.filter((f) => typeof f === "string" && f.length > 0 && !f.includes("\x00"));
|
|
26359
|
-
const impactMap = await
|
|
27091
|
+
const impactMap = await _internals41.loadImpactMap(cwd);
|
|
26360
27092
|
const impactedTestsSet = new Set;
|
|
26361
27093
|
const untestedFiles = [];
|
|
26362
27094
|
let visitedCount = 0;
|
|
@@ -26366,7 +27098,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
26366
27098
|
budgetExceeded = true;
|
|
26367
27099
|
break;
|
|
26368
27100
|
}
|
|
26369
|
-
const normalizedChanged = normalizePath2(
|
|
27101
|
+
const normalizedChanged = normalizePath2(path53.resolve(changedFile));
|
|
26370
27102
|
const tests = impactMap[normalizedChanged];
|
|
26371
27103
|
if (tests && tests.length > 0) {
|
|
26372
27104
|
for (const test of tests) {
|
|
@@ -26380,13 +27112,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
26380
27112
|
if (budgetExceeded)
|
|
26381
27113
|
break;
|
|
26382
27114
|
} else {
|
|
26383
|
-
const changedDir = normalizePath2(
|
|
26384
|
-
const changedInputDir = normalizePath2(
|
|
27115
|
+
const changedDir = normalizePath2(path53.dirname(normalizedChanged));
|
|
27116
|
+
const changedInputDir = normalizePath2(path53.dirname(changedFile));
|
|
26385
27117
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
26386
27118
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
26387
27119
|
}).sort(([sourceA], [sourceB]) => {
|
|
26388
|
-
const sourceDirA = normalizePath2(
|
|
26389
|
-
const sourceDirB = normalizePath2(
|
|
27120
|
+
const sourceDirA = normalizePath2(path53.dirname(sourceA));
|
|
27121
|
+
const sourceDirB = normalizePath2(path53.dirname(sourceB));
|
|
26390
27122
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
26391
27123
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
26392
27124
|
if (exactA !== exactB)
|
|
@@ -26713,7 +27445,7 @@ function detectFlakyTests(allHistory) {
|
|
|
26713
27445
|
|
|
26714
27446
|
// src/test-impact/history-store.ts
|
|
26715
27447
|
import fs23 from "fs";
|
|
26716
|
-
import
|
|
27448
|
+
import path54 from "path";
|
|
26717
27449
|
var MAX_HISTORY_PER_TEST = 20;
|
|
26718
27450
|
var MAX_ERROR_LENGTH = 500;
|
|
26719
27451
|
var MAX_STACK_LENGTH = 200;
|
|
@@ -26725,10 +27457,10 @@ function getHistoryPath(workingDir) {
|
|
|
26725
27457
|
if (!workingDir) {
|
|
26726
27458
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
26727
27459
|
}
|
|
26728
|
-
if (!
|
|
27460
|
+
if (!path54.isAbsolute(workingDir)) {
|
|
26729
27461
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
26730
27462
|
}
|
|
26731
|
-
return
|
|
27463
|
+
return path54.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
26732
27464
|
}
|
|
26733
27465
|
function sanitizeErrorMessage(errorMessage) {
|
|
26734
27466
|
if (errorMessage === undefined) {
|
|
@@ -26820,8 +27552,8 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
26820
27552
|
}
|
|
26821
27553
|
}
|
|
26822
27554
|
const historyPath = getHistoryPath(workingDir);
|
|
26823
|
-
const historyDir =
|
|
26824
|
-
|
|
27555
|
+
const historyDir = path54.dirname(historyPath);
|
|
27556
|
+
_internals42.validateProjectRoot(workingDir);
|
|
26825
27557
|
if (!fs23.existsSync(historyDir)) {
|
|
26826
27558
|
fs23.mkdirSync(historyDir, { recursive: true });
|
|
26827
27559
|
}
|
|
@@ -26944,13 +27676,13 @@ function getAllHistory(workingDir) {
|
|
|
26944
27676
|
records.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
26945
27677
|
return records;
|
|
26946
27678
|
}
|
|
26947
|
-
var
|
|
27679
|
+
var _internals42 = {
|
|
26948
27680
|
validateProjectRoot
|
|
26949
27681
|
};
|
|
26950
27682
|
|
|
26951
27683
|
// src/tools/resolve-working-directory.ts
|
|
26952
27684
|
import * as fs24 from "fs";
|
|
26953
|
-
import * as
|
|
27685
|
+
import * as path55 from "path";
|
|
26954
27686
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
26955
27687
|
if (workingDirectory == null || workingDirectory === "") {
|
|
26956
27688
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -26989,8 +27721,8 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
26989
27721
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
26990
27722
|
};
|
|
26991
27723
|
}
|
|
26992
|
-
const normalizedDir =
|
|
26993
|
-
const resolvedDir =
|
|
27724
|
+
const normalizedDir = path55.normalize(workingDirectory);
|
|
27725
|
+
const resolvedDir = path55.resolve(normalizedDir);
|
|
26994
27726
|
let statResult;
|
|
26995
27727
|
try {
|
|
26996
27728
|
statResult = fs24.statSync(resolvedDir);
|
|
@@ -27009,7 +27741,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
27009
27741
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
27010
27742
|
return { success: true, directory: resolvedDir };
|
|
27011
27743
|
}
|
|
27012
|
-
const resolvedFallback =
|
|
27744
|
+
const resolvedFallback = path55.resolve(fallbackDirectory);
|
|
27013
27745
|
let fallbackExists = false;
|
|
27014
27746
|
try {
|
|
27015
27747
|
fs24.statSync(resolvedFallback);
|
|
@@ -27018,7 +27750,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
27018
27750
|
fallbackExists = false;
|
|
27019
27751
|
}
|
|
27020
27752
|
if (fallbackExists) {
|
|
27021
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
27753
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path55.sep);
|
|
27022
27754
|
if (isSubdirectory) {
|
|
27023
27755
|
return {
|
|
27024
27756
|
success: false,
|
|
@@ -27041,7 +27773,7 @@ async function estimateFanOut(sourceFiles, cwd) {
|
|
|
27041
27773
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
27042
27774
|
const uniqueTestFiles = new Set;
|
|
27043
27775
|
for (const sourceFile of sourceFiles) {
|
|
27044
|
-
const resolvedPath =
|
|
27776
|
+
const resolvedPath = path56.resolve(cwd, sourceFile);
|
|
27045
27777
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
27046
27778
|
const testFiles = impactMap[normalizedPath];
|
|
27047
27779
|
if (testFiles) {
|
|
@@ -27126,14 +27858,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
27126
27858
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
27127
27859
|
}
|
|
27128
27860
|
function detectGoTest(cwd) {
|
|
27129
|
-
return fs25.existsSync(
|
|
27861
|
+
return fs25.existsSync(path56.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
27130
27862
|
}
|
|
27131
27863
|
function detectJavaMaven(cwd) {
|
|
27132
|
-
return fs25.existsSync(
|
|
27864
|
+
return fs25.existsSync(path56.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
27133
27865
|
}
|
|
27134
27866
|
function detectGradle(cwd) {
|
|
27135
|
-
const hasBuildFile = fs25.existsSync(
|
|
27136
|
-
const hasGradlew = fs25.existsSync(
|
|
27867
|
+
const hasBuildFile = fs25.existsSync(path56.join(cwd, "build.gradle")) || fs25.existsSync(path56.join(cwd, "build.gradle.kts"));
|
|
27868
|
+
const hasGradlew = fs25.existsSync(path56.join(cwd, "gradlew")) || fs25.existsSync(path56.join(cwd, "gradlew.bat"));
|
|
27137
27869
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
27138
27870
|
}
|
|
27139
27871
|
function detectDotnetTest(cwd) {
|
|
@@ -27146,25 +27878,25 @@ function detectDotnetTest(cwd) {
|
|
|
27146
27878
|
}
|
|
27147
27879
|
}
|
|
27148
27880
|
function detectCTest(cwd) {
|
|
27149
|
-
const hasSource = fs25.existsSync(
|
|
27150
|
-
const hasBuildCache = fs25.existsSync(
|
|
27881
|
+
const hasSource = fs25.existsSync(path56.join(cwd, "CMakeLists.txt"));
|
|
27882
|
+
const hasBuildCache = fs25.existsSync(path56.join(cwd, "CMakeCache.txt")) || fs25.existsSync(path56.join(cwd, "build", "CMakeCache.txt"));
|
|
27151
27883
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
27152
27884
|
}
|
|
27153
27885
|
function detectSwiftTest(cwd) {
|
|
27154
|
-
return fs25.existsSync(
|
|
27886
|
+
return fs25.existsSync(path56.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
27155
27887
|
}
|
|
27156
27888
|
function detectDartTest(cwd) {
|
|
27157
|
-
return fs25.existsSync(
|
|
27889
|
+
return fs25.existsSync(path56.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
27158
27890
|
}
|
|
27159
27891
|
function detectRSpec(cwd) {
|
|
27160
|
-
const hasRSpecFile = fs25.existsSync(
|
|
27161
|
-
const hasGemfile = fs25.existsSync(
|
|
27162
|
-
const hasSpecDir = fs25.existsSync(
|
|
27892
|
+
const hasRSpecFile = fs25.existsSync(path56.join(cwd, ".rspec"));
|
|
27893
|
+
const hasGemfile = fs25.existsSync(path56.join(cwd, "Gemfile"));
|
|
27894
|
+
const hasSpecDir = fs25.existsSync(path56.join(cwd, "spec"));
|
|
27163
27895
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
27164
27896
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
27165
27897
|
}
|
|
27166
27898
|
function detectMinitest(cwd) {
|
|
27167
|
-
return fs25.existsSync(
|
|
27899
|
+
return fs25.existsSync(path56.join(cwd, "test")) && (fs25.existsSync(path56.join(cwd, "Gemfile")) || fs25.existsSync(path56.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
27168
27900
|
}
|
|
27169
27901
|
var DISPATCH_FRAMEWORK_MAP = {
|
|
27170
27902
|
bun: "bun",
|
|
@@ -27249,7 +27981,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
27249
27981
|
async function detectTestFramework(cwd) {
|
|
27250
27982
|
const baseDir = cwd;
|
|
27251
27983
|
try {
|
|
27252
|
-
const packageJsonPath =
|
|
27984
|
+
const packageJsonPath = path56.join(baseDir, "package.json");
|
|
27253
27985
|
if (fs25.existsSync(packageJsonPath)) {
|
|
27254
27986
|
const content = fs25.readFileSync(packageJsonPath, "utf-8");
|
|
27255
27987
|
const pkg = JSON.parse(content);
|
|
@@ -27270,16 +28002,16 @@ async function detectTestFramework(cwd) {
|
|
|
27270
28002
|
return "jest";
|
|
27271
28003
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
27272
28004
|
return "mocha";
|
|
27273
|
-
if (fs25.existsSync(
|
|
28005
|
+
if (fs25.existsSync(path56.join(baseDir, "bun.lockb")) || fs25.existsSync(path56.join(baseDir, "bun.lock"))) {
|
|
27274
28006
|
if (scripts.test?.includes("bun"))
|
|
27275
28007
|
return "bun";
|
|
27276
28008
|
}
|
|
27277
28009
|
}
|
|
27278
28010
|
} catch {}
|
|
27279
28011
|
try {
|
|
27280
|
-
const pyprojectTomlPath =
|
|
27281
|
-
const setupCfgPath =
|
|
27282
|
-
const requirementsTxtPath =
|
|
28012
|
+
const pyprojectTomlPath = path56.join(baseDir, "pyproject.toml");
|
|
28013
|
+
const setupCfgPath = path56.join(baseDir, "setup.cfg");
|
|
28014
|
+
const requirementsTxtPath = path56.join(baseDir, "requirements.txt");
|
|
27283
28015
|
if (fs25.existsSync(pyprojectTomlPath)) {
|
|
27284
28016
|
const content = fs25.readFileSync(pyprojectTomlPath, "utf-8");
|
|
27285
28017
|
if (content.includes("[tool.pytest"))
|
|
@@ -27299,7 +28031,7 @@ async function detectTestFramework(cwd) {
|
|
|
27299
28031
|
}
|
|
27300
28032
|
} catch {}
|
|
27301
28033
|
try {
|
|
27302
|
-
const cargoTomlPath =
|
|
28034
|
+
const cargoTomlPath = path56.join(baseDir, "Cargo.toml");
|
|
27303
28035
|
if (fs25.existsSync(cargoTomlPath)) {
|
|
27304
28036
|
const content = fs25.readFileSync(cargoTomlPath, "utf-8");
|
|
27305
28037
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -27310,9 +28042,9 @@ async function detectTestFramework(cwd) {
|
|
|
27310
28042
|
}
|
|
27311
28043
|
} catch {}
|
|
27312
28044
|
try {
|
|
27313
|
-
const pesterConfigPath =
|
|
27314
|
-
const pesterConfigJsonPath =
|
|
27315
|
-
const pesterPs1Path =
|
|
28045
|
+
const pesterConfigPath = path56.join(baseDir, "pester.config.ps1");
|
|
28046
|
+
const pesterConfigJsonPath = path56.join(baseDir, "pester.config.ps1.json");
|
|
28047
|
+
const pesterPs1Path = path56.join(baseDir, "tests.ps1");
|
|
27316
28048
|
if (fs25.existsSync(pesterConfigPath) || fs25.existsSync(pesterConfigJsonPath) || fs25.existsSync(pesterPs1Path)) {
|
|
27317
28049
|
return "pester";
|
|
27318
28050
|
}
|
|
@@ -27355,12 +28087,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
27355
28087
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
27356
28088
|
}
|
|
27357
28089
|
function resolveWorkspacePath(file, workingDir) {
|
|
27358
|
-
return
|
|
28090
|
+
return path56.isAbsolute(file) ? path56.resolve(file) : path56.resolve(workingDir, file);
|
|
27359
28091
|
}
|
|
27360
28092
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
27361
28093
|
if (!preferRelative)
|
|
27362
28094
|
return absolutePath;
|
|
27363
|
-
return
|
|
28095
|
+
return path56.relative(workingDir, absolutePath);
|
|
27364
28096
|
}
|
|
27365
28097
|
function dedupePush(target, value) {
|
|
27366
28098
|
if (!target.includes(value)) {
|
|
@@ -27397,18 +28129,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
27397
28129
|
}
|
|
27398
28130
|
}
|
|
27399
28131
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
27400
|
-
const relativeDir =
|
|
28132
|
+
const relativeDir = path56.dirname(relativePath);
|
|
27401
28133
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
27402
28134
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
27403
|
-
const rootDir =
|
|
27404
|
-
return nestedRelativeDir ? [rootDir,
|
|
28135
|
+
const rootDir = path56.join(workingDir, dirName);
|
|
28136
|
+
return nestedRelativeDir ? [rootDir, path56.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
27405
28137
|
});
|
|
27406
28138
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
27407
28139
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
27408
|
-
directories.push(
|
|
28140
|
+
directories.push(path56.join(workingDir, "src/test/java", path56.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
27409
28141
|
}
|
|
27410
28142
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
27411
|
-
directories.push(
|
|
28143
|
+
directories.push(path56.join(workingDir, "src/test/kotlin", path56.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
27412
28144
|
}
|
|
27413
28145
|
return [...new Set(directories)];
|
|
27414
28146
|
}
|
|
@@ -27436,23 +28168,23 @@ function isLanguageSpecificTestFile(basename10) {
|
|
|
27436
28168
|
}
|
|
27437
28169
|
function isConventionTestFilePath(filePath) {
|
|
27438
28170
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
27439
|
-
const basename10 =
|
|
28171
|
+
const basename10 = path56.basename(filePath);
|
|
27440
28172
|
return hasCompoundTestExtension(basename10) || basename10.includes(".spec.") || basename10.includes(".test.") || isLanguageSpecificTestFile(basename10) || isTestDirectoryPath(normalizedPath);
|
|
27441
28173
|
}
|
|
27442
28174
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
27443
28175
|
const testFiles = [];
|
|
27444
28176
|
for (const file of sourceFiles) {
|
|
27445
28177
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
27446
|
-
const relativeFile =
|
|
27447
|
-
const basename10 =
|
|
27448
|
-
const dirname25 =
|
|
27449
|
-
const preferRelativeOutput = !
|
|
28178
|
+
const relativeFile = path56.relative(workingDir, absoluteFile);
|
|
28179
|
+
const basename10 = path56.basename(absoluteFile);
|
|
28180
|
+
const dirname25 = path56.dirname(absoluteFile);
|
|
28181
|
+
const preferRelativeOutput = !path56.isAbsolute(file);
|
|
27450
28182
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
27451
28183
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
27452
28184
|
continue;
|
|
27453
28185
|
}
|
|
27454
28186
|
const nameWithoutExt = basename10.replace(/\.[^.]+$/, "");
|
|
27455
|
-
const ext =
|
|
28187
|
+
const ext = path56.extname(basename10);
|
|
27456
28188
|
const genericTestNames = [
|
|
27457
28189
|
`${nameWithoutExt}.spec${ext}`,
|
|
27458
28190
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -27461,7 +28193,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
27461
28193
|
const colocatedCandidates = [
|
|
27462
28194
|
...genericTestNames,
|
|
27463
28195
|
...languageSpecificTestNames
|
|
27464
|
-
].map((candidateName) =>
|
|
28196
|
+
].map((candidateName) => path56.join(dirname25, candidateName));
|
|
27465
28197
|
const testDirectoryNames = [
|
|
27466
28198
|
basename10,
|
|
27467
28199
|
...genericTestNames,
|
|
@@ -27470,8 +28202,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
27470
28202
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
27471
28203
|
const possibleTestFiles = [
|
|
27472
28204
|
...colocatedCandidates,
|
|
27473
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
27474
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
28205
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path56.join(dirname25, dirName, candidateName))),
|
|
28206
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path56.join(candidateDir, candidateName)))
|
|
27475
28207
|
];
|
|
27476
28208
|
for (const testFile of possibleTestFiles) {
|
|
27477
28209
|
if (fs25.existsSync(testFile)) {
|
|
@@ -27492,7 +28224,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27492
28224
|
try {
|
|
27493
28225
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
27494
28226
|
const content = fs25.readFileSync(absoluteTestFile, "utf-8");
|
|
27495
|
-
const testDir =
|
|
28227
|
+
const testDir = path56.dirname(absoluteTestFile);
|
|
27496
28228
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
27497
28229
|
let match;
|
|
27498
28230
|
match = importRegex.exec(content);
|
|
@@ -27500,8 +28232,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27500
28232
|
const importPath = match[1];
|
|
27501
28233
|
let resolvedImport;
|
|
27502
28234
|
if (importPath.startsWith(".")) {
|
|
27503
|
-
resolvedImport =
|
|
27504
|
-
const existingExt =
|
|
28235
|
+
resolvedImport = path56.resolve(testDir, importPath);
|
|
28236
|
+
const existingExt = path56.extname(resolvedImport);
|
|
27505
28237
|
if (!existingExt) {
|
|
27506
28238
|
for (const extToTry of [
|
|
27507
28239
|
".ts",
|
|
@@ -27521,12 +28253,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27521
28253
|
} else {
|
|
27522
28254
|
continue;
|
|
27523
28255
|
}
|
|
27524
|
-
const importBasename =
|
|
27525
|
-
const importDir =
|
|
28256
|
+
const importBasename = path56.basename(resolvedImport, path56.extname(resolvedImport));
|
|
28257
|
+
const importDir = path56.dirname(resolvedImport);
|
|
27526
28258
|
for (const sourceFile of absoluteSourceFiles) {
|
|
27527
|
-
const sourceDir =
|
|
27528
|
-
const sourceBasename =
|
|
27529
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
28259
|
+
const sourceDir = path56.dirname(sourceFile);
|
|
28260
|
+
const sourceBasename = path56.basename(sourceFile, path56.extname(sourceFile));
|
|
28261
|
+
const isRelatedDir = importDir === sourceDir || importDir === path56.join(sourceDir, "__tests__") || importDir === path56.join(sourceDir, "tests") || importDir === path56.join(sourceDir, "test") || importDir === path56.join(sourceDir, "spec");
|
|
27530
28262
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
27531
28263
|
dedupePush(testFiles, testFile);
|
|
27532
28264
|
break;
|
|
@@ -27539,8 +28271,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27539
28271
|
while (match !== null) {
|
|
27540
28272
|
const importPath = match[1];
|
|
27541
28273
|
if (importPath.startsWith(".")) {
|
|
27542
|
-
let resolvedImport =
|
|
27543
|
-
const existingExt =
|
|
28274
|
+
let resolvedImport = path56.resolve(testDir, importPath);
|
|
28275
|
+
const existingExt = path56.extname(resolvedImport);
|
|
27544
28276
|
if (!existingExt) {
|
|
27545
28277
|
for (const extToTry of [
|
|
27546
28278
|
".ts",
|
|
@@ -27557,12 +28289,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
27557
28289
|
}
|
|
27558
28290
|
}
|
|
27559
28291
|
}
|
|
27560
|
-
const importDir =
|
|
27561
|
-
const importBasename =
|
|
28292
|
+
const importDir = path56.dirname(resolvedImport);
|
|
28293
|
+
const importBasename = path56.basename(resolvedImport, path56.extname(resolvedImport));
|
|
27562
28294
|
for (const sourceFile of absoluteSourceFiles) {
|
|
27563
|
-
const sourceDir =
|
|
27564
|
-
const sourceBasename =
|
|
27565
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
28295
|
+
const sourceDir = path56.dirname(sourceFile);
|
|
28296
|
+
const sourceBasename = path56.basename(sourceFile, path56.extname(sourceFile));
|
|
28297
|
+
const isRelatedDir = importDir === sourceDir || importDir === path56.join(sourceDir, "__tests__") || importDir === path56.join(sourceDir, "tests") || importDir === path56.join(sourceDir, "test") || importDir === path56.join(sourceDir, "spec");
|
|
27566
28298
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
27567
28299
|
dedupePush(testFiles, testFile);
|
|
27568
28300
|
break;
|
|
@@ -27682,8 +28414,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
27682
28414
|
return ["mvn", "test"];
|
|
27683
28415
|
case "gradle": {
|
|
27684
28416
|
const isWindows = process.platform === "win32";
|
|
27685
|
-
const hasGradlewBat = fs25.existsSync(
|
|
27686
|
-
const hasGradlew = fs25.existsSync(
|
|
28417
|
+
const hasGradlewBat = fs25.existsSync(path56.join(baseDir, "gradlew.bat"));
|
|
28418
|
+
const hasGradlew = fs25.existsSync(path56.join(baseDir, "gradlew"));
|
|
27687
28419
|
if (hasGradlewBat && isWindows)
|
|
27688
28420
|
return ["gradlew.bat", "test"];
|
|
27689
28421
|
if (hasGradlew)
|
|
@@ -27700,7 +28432,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
27700
28432
|
"cmake-build-release",
|
|
27701
28433
|
"out"
|
|
27702
28434
|
];
|
|
27703
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs25.existsSync(
|
|
28435
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs25.existsSync(path56.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
27704
28436
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
27705
28437
|
}
|
|
27706
28438
|
case "swift-test":
|
|
@@ -28134,11 +28866,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
28134
28866
|
};
|
|
28135
28867
|
}
|
|
28136
28868
|
const startTime = Date.now();
|
|
28137
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
28869
|
+
const vitestJsonOutputPath = framework === "vitest" ? path56.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
28138
28870
|
try {
|
|
28139
28871
|
if (vitestJsonOutputPath) {
|
|
28140
28872
|
try {
|
|
28141
|
-
fs25.mkdirSync(
|
|
28873
|
+
fs25.mkdirSync(path56.dirname(vitestJsonOutputPath), { recursive: true });
|
|
28142
28874
|
if (fs25.existsSync(vitestJsonOutputPath)) {
|
|
28143
28875
|
fs25.unlinkSync(vitestJsonOutputPath);
|
|
28144
28876
|
}
|
|
@@ -28306,10 +29038,10 @@ var SKIP_DIRECTORIES = new Set([
|
|
|
28306
29038
|
]);
|
|
28307
29039
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
28308
29040
|
const normalized = testFile.replace(/\\/g, "/");
|
|
28309
|
-
if (!
|
|
29041
|
+
if (!path56.isAbsolute(testFile))
|
|
28310
29042
|
return normalized;
|
|
28311
|
-
const relative8 =
|
|
28312
|
-
if (relative8.startsWith("..") ||
|
|
29043
|
+
const relative8 = path56.relative(workingDir, testFile);
|
|
29044
|
+
if (relative8.startsWith("..") || path56.isAbsolute(relative8)) {
|
|
28313
29045
|
return normalized;
|
|
28314
29046
|
}
|
|
28315
29047
|
return relative8.replace(/\\/g, "/");
|
|
@@ -28548,7 +29280,7 @@ var test_runner = createSwarmTool({
|
|
|
28548
29280
|
const sourceFiles = args.files.filter((file) => {
|
|
28549
29281
|
if (directTestFiles.includes(file))
|
|
28550
29282
|
return false;
|
|
28551
|
-
const ext =
|
|
29283
|
+
const ext = path56.extname(file).toLowerCase();
|
|
28552
29284
|
return SOURCE_EXTENSIONS.has(ext);
|
|
28553
29285
|
});
|
|
28554
29286
|
const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
|
|
@@ -28594,7 +29326,7 @@ var test_runner = createSwarmTool({
|
|
|
28594
29326
|
if (isConventionTestFilePath(f)) {
|
|
28595
29327
|
return false;
|
|
28596
29328
|
}
|
|
28597
|
-
const ext =
|
|
29329
|
+
const ext = path56.extname(f).toLowerCase();
|
|
28598
29330
|
return SOURCE_EXTENSIONS.has(ext);
|
|
28599
29331
|
});
|
|
28600
29332
|
if (sourceFiles.length === 0) {
|
|
@@ -28644,7 +29376,7 @@ var test_runner = createSwarmTool({
|
|
|
28644
29376
|
if (isConventionTestFilePath(f)) {
|
|
28645
29377
|
return false;
|
|
28646
29378
|
}
|
|
28647
|
-
const ext =
|
|
29379
|
+
const ext = path56.extname(f).toLowerCase();
|
|
28648
29380
|
return SOURCE_EXTENSIONS.has(ext);
|
|
28649
29381
|
});
|
|
28650
29382
|
if (sourceFiles.length === 0) {
|
|
@@ -28696,8 +29428,8 @@ var test_runner = createSwarmTool({
|
|
|
28696
29428
|
}
|
|
28697
29429
|
if (impactResult.impactedTests.length > 0) {
|
|
28698
29430
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
28699
|
-
const relativePath =
|
|
28700
|
-
return
|
|
29431
|
+
const relativePath = path56.relative(workingDir, absPath);
|
|
29432
|
+
return path56.isAbsolute(relativePath) ? absPath : relativePath;
|
|
28701
29433
|
});
|
|
28702
29434
|
} else {
|
|
28703
29435
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -28792,8 +29524,8 @@ function validateDirectoryPath(dir) {
|
|
|
28792
29524
|
if (dir.includes("..")) {
|
|
28793
29525
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
28794
29526
|
}
|
|
28795
|
-
const normalized =
|
|
28796
|
-
const absolutePath =
|
|
29527
|
+
const normalized = path57.normalize(dir);
|
|
29528
|
+
const absolutePath = path57.isAbsolute(normalized) ? normalized : path57.resolve(normalized);
|
|
28797
29529
|
return absolutePath;
|
|
28798
29530
|
}
|
|
28799
29531
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -28816,7 +29548,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
28816
29548
|
}
|
|
28817
29549
|
function getPackageVersion(dir) {
|
|
28818
29550
|
try {
|
|
28819
|
-
const packagePath =
|
|
29551
|
+
const packagePath = path57.join(dir, "package.json");
|
|
28820
29552
|
if (fs26.existsSync(packagePath)) {
|
|
28821
29553
|
const content = fs26.readFileSync(packagePath, "utf-8");
|
|
28822
29554
|
const pkg = JSON.parse(content);
|
|
@@ -28827,7 +29559,7 @@ function getPackageVersion(dir) {
|
|
|
28827
29559
|
}
|
|
28828
29560
|
function getChangelogVersion(dir) {
|
|
28829
29561
|
try {
|
|
28830
|
-
const changelogPath =
|
|
29562
|
+
const changelogPath = path57.join(dir, "CHANGELOG.md");
|
|
28831
29563
|
if (fs26.existsSync(changelogPath)) {
|
|
28832
29564
|
const content = fs26.readFileSync(changelogPath, "utf-8");
|
|
28833
29565
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -28841,7 +29573,7 @@ function getChangelogVersion(dir) {
|
|
|
28841
29573
|
function getVersionFileVersion(dir) {
|
|
28842
29574
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
28843
29575
|
for (const file of possibleFiles) {
|
|
28844
|
-
const filePath =
|
|
29576
|
+
const filePath = path57.join(dir, file);
|
|
28845
29577
|
if (fs26.existsSync(filePath)) {
|
|
28846
29578
|
try {
|
|
28847
29579
|
const content = fs26.readFileSync(filePath, "utf-8").trim();
|
|
@@ -28857,9 +29589,9 @@ function getVersionFileVersion(dir) {
|
|
|
28857
29589
|
async function runVersionCheck(dir, _timeoutMs) {
|
|
28858
29590
|
const startTime = Date.now();
|
|
28859
29591
|
try {
|
|
28860
|
-
const packageVersion =
|
|
28861
|
-
const changelogVersion =
|
|
28862
|
-
const versionFileVersion =
|
|
29592
|
+
const packageVersion = _internals43.getPackageVersion(dir);
|
|
29593
|
+
const changelogVersion = _internals43.getChangelogVersion(dir);
|
|
29594
|
+
const versionFileVersion = _internals43.getVersionFileVersion(dir);
|
|
28863
29595
|
const versions = [];
|
|
28864
29596
|
if (packageVersion)
|
|
28865
29597
|
versions.push(`package.json: ${packageVersion}`);
|
|
@@ -29223,7 +29955,7 @@ async function runPreflight(dir, phase, config) {
|
|
|
29223
29955
|
const reportId = `preflight-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
29224
29956
|
let validatedDir;
|
|
29225
29957
|
try {
|
|
29226
|
-
validatedDir =
|
|
29958
|
+
validatedDir = _internals43.validateDirectoryPath(dir);
|
|
29227
29959
|
} catch (error2) {
|
|
29228
29960
|
return {
|
|
29229
29961
|
id: reportId,
|
|
@@ -29243,7 +29975,7 @@ async function runPreflight(dir, phase, config) {
|
|
|
29243
29975
|
}
|
|
29244
29976
|
let validatedTimeout;
|
|
29245
29977
|
try {
|
|
29246
|
-
validatedTimeout =
|
|
29978
|
+
validatedTimeout = _internals43.validateTimeout(config?.checkTimeoutMs, DEFAULT_CONFIG.checkTimeoutMs);
|
|
29247
29979
|
} catch (error2) {
|
|
29248
29980
|
return {
|
|
29249
29981
|
id: reportId,
|
|
@@ -29284,12 +30016,12 @@ async function runPreflight(dir, phase, config) {
|
|
|
29284
30016
|
});
|
|
29285
30017
|
const checks = [];
|
|
29286
30018
|
log("[Preflight] Running lint check...");
|
|
29287
|
-
const lintResult = await
|
|
30019
|
+
const lintResult = await _internals43.runLintCheck(validatedDir, cfg.linter, cfg.checkTimeoutMs);
|
|
29288
30020
|
checks.push(lintResult);
|
|
29289
30021
|
log(`[Preflight] Lint check: ${lintResult.status} ${lintResult.message}`);
|
|
29290
30022
|
if (!cfg.skipTests) {
|
|
29291
30023
|
log("[Preflight] Running tests check...");
|
|
29292
|
-
const testsResult = await
|
|
30024
|
+
const testsResult = await _internals43.runTestsCheck(validatedDir, cfg.testScope, cfg.checkTimeoutMs);
|
|
29293
30025
|
checks.push(testsResult);
|
|
29294
30026
|
log(`[Preflight] Tests check: ${testsResult.status} ${testsResult.message}`);
|
|
29295
30027
|
} else {
|
|
@@ -29301,7 +30033,7 @@ async function runPreflight(dir, phase, config) {
|
|
|
29301
30033
|
}
|
|
29302
30034
|
if (!cfg.skipSecrets) {
|
|
29303
30035
|
log("[Preflight] Running secrets check...");
|
|
29304
|
-
const secretsResult = await
|
|
30036
|
+
const secretsResult = await _internals43.runSecretsCheck(validatedDir, cfg.checkTimeoutMs);
|
|
29305
30037
|
checks.push(secretsResult);
|
|
29306
30038
|
log(`[Preflight] Secrets check: ${secretsResult.status} ${secretsResult.message}`);
|
|
29307
30039
|
} else {
|
|
@@ -29313,7 +30045,7 @@ async function runPreflight(dir, phase, config) {
|
|
|
29313
30045
|
}
|
|
29314
30046
|
if (!cfg.skipEvidence) {
|
|
29315
30047
|
log("[Preflight] Running evidence check...");
|
|
29316
|
-
const evidenceResult = await
|
|
30048
|
+
const evidenceResult = await _internals43.runEvidenceCheck(validatedDir);
|
|
29317
30049
|
checks.push(evidenceResult);
|
|
29318
30050
|
log(`[Preflight] Evidence check: ${evidenceResult.status} ${evidenceResult.message}`);
|
|
29319
30051
|
} else {
|
|
@@ -29324,12 +30056,12 @@ async function runPreflight(dir, phase, config) {
|
|
|
29324
30056
|
});
|
|
29325
30057
|
}
|
|
29326
30058
|
log("[Preflight] Running requirement coverage check...");
|
|
29327
|
-
const reqCoverageResult = await
|
|
30059
|
+
const reqCoverageResult = await _internals43.runRequirementCoverageCheck(validatedDir, phase);
|
|
29328
30060
|
checks.push(reqCoverageResult);
|
|
29329
30061
|
log(`[Preflight] Requirement coverage check: ${reqCoverageResult.status} ${reqCoverageResult.message}`);
|
|
29330
30062
|
if (!cfg.skipVersion) {
|
|
29331
30063
|
log("[Preflight] Running version check...");
|
|
29332
|
-
const versionResult = await
|
|
30064
|
+
const versionResult = await _internals43.runVersionCheck(validatedDir, cfg.checkTimeoutMs);
|
|
29333
30065
|
checks.push(versionResult);
|
|
29334
30066
|
log(`[Preflight] Version check: ${versionResult.status} ${versionResult.message}`);
|
|
29335
30067
|
} else {
|
|
@@ -29392,10 +30124,10 @@ function formatPreflightMarkdown(report) {
|
|
|
29392
30124
|
async function handlePreflightCommand(directory, _args) {
|
|
29393
30125
|
const plan = await loadPlan(directory);
|
|
29394
30126
|
const phase = plan?.current_phase ?? 1;
|
|
29395
|
-
const report = await
|
|
29396
|
-
return
|
|
30127
|
+
const report = await _internals43.runPreflight(directory, phase);
|
|
30128
|
+
return _internals43.formatPreflightMarkdown(report);
|
|
29397
30129
|
}
|
|
29398
|
-
var
|
|
30130
|
+
var _internals43 = {
|
|
29399
30131
|
runPreflight,
|
|
29400
30132
|
formatPreflightMarkdown,
|
|
29401
30133
|
handlePreflightCommand,
|
|
@@ -29579,7 +30311,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
29579
30311
|
|
|
29580
30312
|
// src/commands/reset.ts
|
|
29581
30313
|
import * as fs27 from "fs";
|
|
29582
|
-
import * as
|
|
30314
|
+
import * as path58 from "path";
|
|
29583
30315
|
|
|
29584
30316
|
// src/background/circuit-breaker.ts
|
|
29585
30317
|
class CircuitBreaker {
|
|
@@ -30298,7 +31030,7 @@ async function handleResetCommand(directory, args) {
|
|
|
30298
31030
|
}
|
|
30299
31031
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
30300
31032
|
try {
|
|
30301
|
-
const rootPath =
|
|
31033
|
+
const rootPath = path58.join(directory, filename);
|
|
30302
31034
|
if (fs27.existsSync(rootPath)) {
|
|
30303
31035
|
fs27.unlinkSync(rootPath);
|
|
30304
31036
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -30336,7 +31068,7 @@ async function handleResetCommand(directory, args) {
|
|
|
30336
31068
|
|
|
30337
31069
|
// src/commands/reset-session.ts
|
|
30338
31070
|
import * as fs29 from "fs";
|
|
30339
|
-
import * as
|
|
31071
|
+
import * as path60 from "path";
|
|
30340
31072
|
|
|
30341
31073
|
// src/hooks/trajectory-logger.ts
|
|
30342
31074
|
var callStartTimes = new Map;
|
|
@@ -30743,16 +31475,16 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
|
|
|
30743
31475
|
}
|
|
30744
31476
|
// src/prm/replay.ts
|
|
30745
31477
|
import { promises as fs28 } from "fs";
|
|
30746
|
-
import
|
|
31478
|
+
import path59 from "path";
|
|
30747
31479
|
function isPathSafe(targetPath, basePath) {
|
|
30748
|
-
const resolvedTarget =
|
|
30749
|
-
const resolvedBase =
|
|
30750
|
-
const rel =
|
|
30751
|
-
return !rel.startsWith("..") && !
|
|
31480
|
+
const resolvedTarget = path59.resolve(targetPath);
|
|
31481
|
+
const resolvedBase = path59.resolve(basePath);
|
|
31482
|
+
const rel = path59.relative(resolvedBase, resolvedTarget);
|
|
31483
|
+
return !rel.startsWith("..") && !path59.isAbsolute(rel);
|
|
30752
31484
|
}
|
|
30753
31485
|
function isWithinReplaysDir(targetPath) {
|
|
30754
|
-
const resolved =
|
|
30755
|
-
const parts = resolved.split(
|
|
31486
|
+
const resolved = path59.resolve(targetPath);
|
|
31487
|
+
const parts = resolved.split(path59.sep);
|
|
30756
31488
|
for (let i = 0;i < parts.length - 1; i++) {
|
|
30757
31489
|
if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
|
|
30758
31490
|
return true;
|
|
@@ -30765,10 +31497,10 @@ function sanitizeFilename(input) {
|
|
|
30765
31497
|
}
|
|
30766
31498
|
async function startReplayRecording(sessionID, directory) {
|
|
30767
31499
|
try {
|
|
30768
|
-
const replayDir =
|
|
31500
|
+
const replayDir = path59.join(directory, ".swarm", "replays");
|
|
30769
31501
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
30770
31502
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
30771
|
-
const filepath =
|
|
31503
|
+
const filepath = path59.join(replayDir, filename);
|
|
30772
31504
|
if (!isPathSafe(filepath, replayDir)) {
|
|
30773
31505
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
30774
31506
|
return null;
|
|
@@ -30800,7 +31532,7 @@ async function recordReplayEntry(artifactPath, sessionID, entry) {
|
|
|
30800
31532
|
}
|
|
30801
31533
|
|
|
30802
31534
|
// src/prm/index.ts
|
|
30803
|
-
var
|
|
31535
|
+
var _internals44 = {
|
|
30804
31536
|
getAgentSession,
|
|
30805
31537
|
readTrajectory,
|
|
30806
31538
|
getInMemoryTrajectory,
|
|
@@ -30823,7 +31555,7 @@ function resetPrmSessionState(session, sessionId) {
|
|
|
30823
31555
|
session.prmTrajectoryStep = 0;
|
|
30824
31556
|
session.replayArtifactPath = null;
|
|
30825
31557
|
if (sessionId) {
|
|
30826
|
-
|
|
31558
|
+
_internals44.clearTrajectoryCache(sessionId);
|
|
30827
31559
|
}
|
|
30828
31560
|
}
|
|
30829
31561
|
|
|
@@ -30846,7 +31578,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30846
31578
|
} catch {
|
|
30847
31579
|
results.push("\u274C Failed to delete state.json");
|
|
30848
31580
|
}
|
|
30849
|
-
const sessionDir =
|
|
31581
|
+
const sessionDir = path60.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
30850
31582
|
let sessionFiles = [];
|
|
30851
31583
|
if (fs29.existsSync(sessionDir)) {
|
|
30852
31584
|
try {
|
|
@@ -30858,7 +31590,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30858
31590
|
for (const file of sessionFiles) {
|
|
30859
31591
|
if (file === "state.json")
|
|
30860
31592
|
continue;
|
|
30861
|
-
const filePath =
|
|
31593
|
+
const filePath = path60.join(sessionDir, file);
|
|
30862
31594
|
try {
|
|
30863
31595
|
if (!fs29.existsSync(filePath))
|
|
30864
31596
|
continue;
|
|
@@ -30893,7 +31625,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
30893
31625
|
}
|
|
30894
31626
|
|
|
30895
31627
|
// src/summaries/manager.ts
|
|
30896
|
-
import * as
|
|
31628
|
+
import * as path61 from "path";
|
|
30897
31629
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
30898
31630
|
function sanitizeSummaryId(id) {
|
|
30899
31631
|
if (!id || id.length === 0) {
|
|
@@ -30917,7 +31649,7 @@ function sanitizeSummaryId(id) {
|
|
|
30917
31649
|
}
|
|
30918
31650
|
async function loadFullOutput(directory, id) {
|
|
30919
31651
|
const sanitizedId = sanitizeSummaryId(id);
|
|
30920
|
-
const relativePath =
|
|
31652
|
+
const relativePath = path61.join("summaries", `${sanitizedId}.json`);
|
|
30921
31653
|
validateSwarmPath(directory, relativePath);
|
|
30922
31654
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
30923
31655
|
if (content === null) {
|
|
@@ -30970,7 +31702,7 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
|
30970
31702
|
|
|
30971
31703
|
// src/commands/rollback.ts
|
|
30972
31704
|
import * as fs30 from "fs";
|
|
30973
|
-
import * as
|
|
31705
|
+
import * as path62 from "path";
|
|
30974
31706
|
async function handleRollbackCommand(directory, args) {
|
|
30975
31707
|
const phaseArg = args[0];
|
|
30976
31708
|
if (!phaseArg) {
|
|
@@ -31036,8 +31768,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
31036
31768
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
31037
31769
|
continue;
|
|
31038
31770
|
}
|
|
31039
|
-
const src =
|
|
31040
|
-
const dest =
|
|
31771
|
+
const src = path62.join(checkpointDir, file);
|
|
31772
|
+
const dest = path62.join(swarmDir, file);
|
|
31041
31773
|
try {
|
|
31042
31774
|
fs30.cpSync(src, dest, { recursive: true, force: true });
|
|
31043
31775
|
successes.push(file);
|
|
@@ -31056,7 +31788,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
31056
31788
|
].join(`
|
|
31057
31789
|
`);
|
|
31058
31790
|
}
|
|
31059
|
-
const existingLedgerPath =
|
|
31791
|
+
const existingLedgerPath = path62.join(swarmDir, "plan-ledger.jsonl");
|
|
31060
31792
|
let ledgerDeletionFailed = false;
|
|
31061
31793
|
if (fs30.existsSync(existingLedgerPath)) {
|
|
31062
31794
|
try {
|
|
@@ -31069,7 +31801,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
31069
31801
|
}
|
|
31070
31802
|
if (!ledgerDeletionFailed) {
|
|
31071
31803
|
try {
|
|
31072
|
-
const planJsonPath =
|
|
31804
|
+
const planJsonPath = path62.join(swarmDir, "plan.json");
|
|
31073
31805
|
if (fs30.existsSync(planJsonPath)) {
|
|
31074
31806
|
const planRaw = fs30.readFileSync(planJsonPath, "utf-8");
|
|
31075
31807
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -31330,10 +32062,10 @@ Ensure this is a git repository with commit history.`;
|
|
|
31330
32062
|
`);
|
|
31331
32063
|
try {
|
|
31332
32064
|
const fs31 = await import("fs/promises");
|
|
31333
|
-
const
|
|
31334
|
-
const reportPath =
|
|
31335
|
-
await fs31.mkdir(
|
|
31336
|
-
const reportTempPath =
|
|
32065
|
+
const path63 = await import("path");
|
|
32066
|
+
const reportPath = path63.join(directory, ".swarm", "simulate-report.md");
|
|
32067
|
+
await fs31.mkdir(path63.dirname(reportPath), { recursive: true });
|
|
32068
|
+
const reportTempPath = path63.join(path63.dirname(reportPath), `${path63.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
31337
32069
|
try {
|
|
31338
32070
|
await fs31.writeFile(reportTempPath, report, "utf-8");
|
|
31339
32071
|
renameSync11(reportTempPath, reportPath);
|
|
@@ -31362,18 +32094,18 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
31362
32094
|
// src/services/status-service.ts
|
|
31363
32095
|
import * as fsSync3 from "fs";
|
|
31364
32096
|
import { readFile as readFile16 } from "fs/promises";
|
|
31365
|
-
import * as
|
|
32097
|
+
import * as path64 from "path";
|
|
31366
32098
|
|
|
31367
32099
|
// src/turbo/lean/state.ts
|
|
31368
32100
|
init_logger();
|
|
31369
32101
|
import * as fs31 from "fs";
|
|
31370
|
-
import * as
|
|
32102
|
+
import * as path63 from "path";
|
|
31371
32103
|
var STATE_FILE3 = "turbo-state.json";
|
|
31372
32104
|
function nowISO3() {
|
|
31373
32105
|
return new Date().toISOString();
|
|
31374
32106
|
}
|
|
31375
32107
|
function ensureSwarmDir2(directory) {
|
|
31376
|
-
const swarmDir =
|
|
32108
|
+
const swarmDir = path63.resolve(directory, ".swarm");
|
|
31377
32109
|
if (!fs31.existsSync(swarmDir)) {
|
|
31378
32110
|
fs31.mkdirSync(swarmDir, { recursive: true });
|
|
31379
32111
|
}
|
|
@@ -31418,7 +32150,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
31418
32150
|
}
|
|
31419
32151
|
function readPersisted2(directory) {
|
|
31420
32152
|
try {
|
|
31421
|
-
const filePath =
|
|
32153
|
+
const filePath = path63.join(directory, ".swarm", STATE_FILE3);
|
|
31422
32154
|
if (!fs31.existsSync(filePath)) {
|
|
31423
32155
|
const seed = emptyPersisted2();
|
|
31424
32156
|
try {
|
|
@@ -31454,7 +32186,7 @@ function writePersisted2(directory, persisted) {
|
|
|
31454
32186
|
let payload;
|
|
31455
32187
|
try {
|
|
31456
32188
|
ensureSwarmDir2(directory);
|
|
31457
|
-
filePath =
|
|
32189
|
+
filePath = path63.join(directory, ".swarm", STATE_FILE3);
|
|
31458
32190
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
31459
32191
|
persisted.updatedAt = nowISO3();
|
|
31460
32192
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -31565,14 +32297,14 @@ var DEFAULT_CONTEXT_BUDGET_CONFIG = {
|
|
|
31565
32297
|
};
|
|
31566
32298
|
|
|
31567
32299
|
// src/services/status-service.ts
|
|
31568
|
-
var
|
|
32300
|
+
var _internals45 = {
|
|
31569
32301
|
loadLeanTurboRunState,
|
|
31570
32302
|
hasActiveLeanTurbo,
|
|
31571
32303
|
hasActiveFullAuto
|
|
31572
32304
|
};
|
|
31573
32305
|
function readSpecStalenessSnapshot(directory) {
|
|
31574
32306
|
try {
|
|
31575
|
-
const p =
|
|
32307
|
+
const p = path64.join(directory, ".swarm", "spec-staleness.json");
|
|
31576
32308
|
if (!fsSync3.existsSync(p))
|
|
31577
32309
|
return { stale: false };
|
|
31578
32310
|
const raw = fsSync3.readFileSync(p, "utf-8");
|
|
@@ -31670,7 +32402,7 @@ async function getStatusData(directory, agents) {
|
|
|
31670
32402
|
}
|
|
31671
32403
|
function enrichWithLeanTurbo(status, directory) {
|
|
31672
32404
|
const turboMode = hasActiveTurboMode();
|
|
31673
|
-
const leanActive =
|
|
32405
|
+
const leanActive = _internals45.hasActiveLeanTurbo();
|
|
31674
32406
|
let turboStrategy = "off";
|
|
31675
32407
|
if (leanActive) {
|
|
31676
32408
|
turboStrategy = "lean";
|
|
@@ -31689,7 +32421,7 @@ function enrichWithLeanTurbo(status, directory) {
|
|
|
31689
32421
|
}
|
|
31690
32422
|
}
|
|
31691
32423
|
if (leanSessionID) {
|
|
31692
|
-
const runState =
|
|
32424
|
+
const runState = _internals45.loadLeanTurboRunState(directory, leanSessionID);
|
|
31693
32425
|
if (runState) {
|
|
31694
32426
|
status.leanTurboPhase = runState.phase;
|
|
31695
32427
|
status.leanMaxParallelCoders = runState.maxParallelCoders;
|
|
@@ -31721,7 +32453,7 @@ function enrichWithLeanTurbo(status, directory) {
|
|
|
31721
32453
|
}
|
|
31722
32454
|
}
|
|
31723
32455
|
}
|
|
31724
|
-
status.fullAutoActive =
|
|
32456
|
+
status.fullAutoActive = _internals45.hasActiveFullAuto();
|
|
31725
32457
|
return status;
|
|
31726
32458
|
}
|
|
31727
32459
|
function formatStatusMarkdown(status) {
|
|
@@ -31875,7 +32607,7 @@ No active swarm plan found. Nothing to sync.`;
|
|
|
31875
32607
|
|
|
31876
32608
|
// src/commands/turbo.ts
|
|
31877
32609
|
init_logger();
|
|
31878
|
-
var
|
|
32610
|
+
var _internals46 = {
|
|
31879
32611
|
loadPluginConfigWithMeta
|
|
31880
32612
|
};
|
|
31881
32613
|
async function handleTurboCommand(directory, args, sessionID) {
|
|
@@ -31935,7 +32667,7 @@ async function handleTurboCommand(directory, args, sessionID) {
|
|
|
31935
32667
|
if (arg0 === "on") {
|
|
31936
32668
|
let strategy = "standard";
|
|
31937
32669
|
try {
|
|
31938
|
-
const { config } =
|
|
32670
|
+
const { config } = _internals46.loadPluginConfigWithMeta(directory);
|
|
31939
32671
|
if (config.turbo?.strategy === "lean") {
|
|
31940
32672
|
strategy = "lean";
|
|
31941
32673
|
}
|
|
@@ -32032,7 +32764,7 @@ function enableLeanTurbo(session, directory, sessionID) {
|
|
|
32032
32764
|
let maxParallelCoders = 4;
|
|
32033
32765
|
let conflictPolicy = "serialize";
|
|
32034
32766
|
try {
|
|
32035
|
-
const { config } =
|
|
32767
|
+
const { config } = _internals46.loadPluginConfigWithMeta(directory);
|
|
32036
32768
|
const leanConfig = config.turbo?.lean;
|
|
32037
32769
|
if (leanConfig) {
|
|
32038
32770
|
maxParallelCoders = leanConfig.max_parallel_coders ?? 4;
|
|
@@ -32105,11 +32837,11 @@ function buildStatusMessage2(session, directory, sessionID) {
|
|
|
32105
32837
|
|
|
32106
32838
|
// src/commands/unlink.ts
|
|
32107
32839
|
import { existsSync as existsSync37 } from "fs";
|
|
32108
|
-
import * as
|
|
32840
|
+
import * as path65 from "path";
|
|
32109
32841
|
var DEDUP_THRESHOLD2 = 0.6;
|
|
32110
32842
|
async function copySharedKnowledgeToLocal(linkDir, localSwarmDir) {
|
|
32111
|
-
const sharedPath =
|
|
32112
|
-
const localPath =
|
|
32843
|
+
const sharedPath = path65.join(linkDir, "knowledge.jsonl");
|
|
32844
|
+
const localPath = path65.join(localSwarmDir, "knowledge.jsonl");
|
|
32113
32845
|
if (!existsSync37(sharedPath))
|
|
32114
32846
|
return 0;
|
|
32115
32847
|
const sharedEntries = await readKnowledge(sharedPath);
|
|
@@ -32144,7 +32876,7 @@ async function handleUnlinkCommand(directory, args) {
|
|
|
32144
32876
|
let copied = 0;
|
|
32145
32877
|
if (copyBack) {
|
|
32146
32878
|
try {
|
|
32147
|
-
copied = await copySharedKnowledgeToLocal(linkDir,
|
|
32879
|
+
copied = await copySharedKnowledgeToLocal(linkDir, path65.join(directory, ".swarm"));
|
|
32148
32880
|
} catch (error2) {
|
|
32149
32881
|
return `\u274C Failed to copy shared knowledge back to local: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
32150
32882
|
}
|
|
@@ -32248,7 +32980,7 @@ function findSimilarCommands(query) {
|
|
|
32248
32980
|
}
|
|
32249
32981
|
const scored = VALID_COMMANDS.map((cmd) => {
|
|
32250
32982
|
const cmdLower = cmd.toLowerCase();
|
|
32251
|
-
const fullScore =
|
|
32983
|
+
const fullScore = _internals47.levenshteinDistance(q, cmdLower);
|
|
32252
32984
|
let tokenScore = Infinity;
|
|
32253
32985
|
if (cmd.includes(" ") || cmd.includes("-")) {
|
|
32254
32986
|
const qTokens = q.split(/[\s-]+/);
|
|
@@ -32261,7 +32993,7 @@ function findSimilarCommands(query) {
|
|
|
32261
32993
|
for (const ct of cmdTokens) {
|
|
32262
32994
|
if (ct.length === 0)
|
|
32263
32995
|
continue;
|
|
32264
|
-
const dist =
|
|
32996
|
+
const dist = _internals47.levenshteinDistance(qt, ct);
|
|
32265
32997
|
if (dist < minDist)
|
|
32266
32998
|
minDist = dist;
|
|
32267
32999
|
}
|
|
@@ -32271,7 +33003,7 @@ function findSimilarCommands(query) {
|
|
|
32271
33003
|
}
|
|
32272
33004
|
const dashStrippedQ = q.replace(/-/g, "");
|
|
32273
33005
|
const dashStrippedCmd = cmdLower.replace(/-/g, "");
|
|
32274
|
-
const dashScore =
|
|
33006
|
+
const dashScore = _internals47.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
|
|
32275
33007
|
const score = Math.min(fullScore, tokenScore, dashScore);
|
|
32276
33008
|
return { cmd, score };
|
|
32277
33009
|
});
|
|
@@ -32306,16 +33038,16 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
32306
33038
|
async function handleHelpCommand(ctx) {
|
|
32307
33039
|
const targetCommand = ctx.args.join(" ");
|
|
32308
33040
|
if (!targetCommand) {
|
|
32309
|
-
const { buildHelpText } = await import("./index-
|
|
33041
|
+
const { buildHelpText } = await import("./index-jg6m72g7.js");
|
|
32310
33042
|
return buildHelpText();
|
|
32311
33043
|
}
|
|
32312
33044
|
const tokens = targetCommand.split(/\s+/);
|
|
32313
|
-
const resolved =
|
|
33045
|
+
const resolved = _internals47.resolveCommand(tokens);
|
|
32314
33046
|
if (resolved) {
|
|
32315
|
-
return
|
|
33047
|
+
return _internals47.buildDetailedHelp(resolved.key, resolved.entry);
|
|
32316
33048
|
}
|
|
32317
|
-
const similar =
|
|
32318
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
33049
|
+
const similar = _internals47.findSimilarCommands(targetCommand);
|
|
33050
|
+
const { buildHelpText: fullHelp } = await import("./index-jg6m72g7.js");
|
|
32319
33051
|
if (similar.length > 0) {
|
|
32320
33052
|
return `Command '/swarm ${targetCommand}' not found.
|
|
32321
33053
|
|
|
@@ -32379,7 +33111,7 @@ var COMMAND_REGISTRY = {
|
|
|
32379
33111
|
toolNoArgs: true
|
|
32380
33112
|
},
|
|
32381
33113
|
help: {
|
|
32382
|
-
handler: (ctx) =>
|
|
33114
|
+
handler: (ctx) => _internals47.handleHelpCommand(ctx),
|
|
32383
33115
|
description: "Show help for swarm commands",
|
|
32384
33116
|
category: "core",
|
|
32385
33117
|
args: "[command]",
|
|
@@ -32448,7 +33180,7 @@ var COMMAND_REGISTRY = {
|
|
|
32448
33180
|
},
|
|
32449
33181
|
"guardrail explain": {
|
|
32450
33182
|
handler: async (ctx) => {
|
|
32451
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
33183
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-q8pj9691.js");
|
|
32452
33184
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
32453
33185
|
},
|
|
32454
33186
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -32458,7 +33190,7 @@ var COMMAND_REGISTRY = {
|
|
|
32458
33190
|
},
|
|
32459
33191
|
"guardrail-log": {
|
|
32460
33192
|
handler: async (ctx) => {
|
|
32461
|
-
const { handleGuardrailLog } = await import("./guardrail-log-
|
|
33193
|
+
const { handleGuardrailLog } = await import("./guardrail-log-ywajkn46.js");
|
|
32462
33194
|
return handleGuardrailLog(ctx.directory, ctx.args);
|
|
32463
33195
|
},
|
|
32464
33196
|
description: "Read the guardrail decision log (use --blocks-only for blocks)",
|
|
@@ -33221,24 +33953,24 @@ function validateAliases() {
|
|
|
33221
33953
|
continue;
|
|
33222
33954
|
}
|
|
33223
33955
|
const visited = new Set;
|
|
33224
|
-
const
|
|
33956
|
+
const path66 = [];
|
|
33225
33957
|
let current = target;
|
|
33226
33958
|
while (current) {
|
|
33227
33959
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
33228
33960
|
if (!currentEntry)
|
|
33229
33961
|
break;
|
|
33230
33962
|
if (visited.has(current)) {
|
|
33231
|
-
const cycleStart =
|
|
33963
|
+
const cycleStart = path66.indexOf(current);
|
|
33232
33964
|
const fullChain = [
|
|
33233
33965
|
name,
|
|
33234
|
-
...
|
|
33966
|
+
...path66.slice(0, cycleStart > 0 ? cycleStart : path66.length),
|
|
33235
33967
|
current
|
|
33236
33968
|
].join(" \u2192 ");
|
|
33237
33969
|
errors.push(`Circular alias detected: ${fullChain}`);
|
|
33238
33970
|
break;
|
|
33239
33971
|
}
|
|
33240
33972
|
visited.add(current);
|
|
33241
|
-
|
|
33973
|
+
path66.push(current);
|
|
33242
33974
|
current = currentEntry.aliasOf || "";
|
|
33243
33975
|
}
|
|
33244
33976
|
}
|
|
@@ -33257,7 +33989,7 @@ function validateToolPolicy() {
|
|
|
33257
33989
|
}
|
|
33258
33990
|
return { valid: warnings.length === 0, warnings };
|
|
33259
33991
|
}
|
|
33260
|
-
var
|
|
33992
|
+
var _internals47 = {
|
|
33261
33993
|
handleHelpCommand,
|
|
33262
33994
|
validateAliases,
|
|
33263
33995
|
validateToolPolicy,
|
|
@@ -33267,16 +33999,16 @@ var _internals46 = {
|
|
|
33267
33999
|
findSimilarCommands,
|
|
33268
34000
|
buildDetailedHelp
|
|
33269
34001
|
};
|
|
33270
|
-
var validation =
|
|
34002
|
+
var validation = _internals47.validateAliases();
|
|
33271
34003
|
if (!validation.valid) {
|
|
33272
34004
|
throw new Error(`COMMAND_REGISTRY alias validation failed:
|
|
33273
34005
|
${validation.errors.join(`
|
|
33274
34006
|
`)}`);
|
|
33275
34007
|
}
|
|
33276
|
-
|
|
34008
|
+
_internals47.emitValidationWarnings("COMMAND_REGISTRY alias warnings", validation.warnings);
|
|
33277
34009
|
try {
|
|
33278
|
-
const toolPolicyValidation =
|
|
33279
|
-
|
|
34010
|
+
const toolPolicyValidation = _internals47.validateToolPolicy();
|
|
34011
|
+
_internals47.emitValidationWarnings("COMMAND_REGISTRY toolPolicy warnings", toolPolicyValidation.warnings);
|
|
33280
34012
|
} catch (e) {
|
|
33281
34013
|
warn(`COMMAND_REGISTRY toolPolicy validation failed (non-fatal): ${e.message}`);
|
|
33282
34014
|
}
|
|
@@ -33335,7 +34067,7 @@ function formatCommandNotFound(tokens) {
|
|
|
33335
34067
|
const attemptedCommand = tokens[0] || "";
|
|
33336
34068
|
const MAX_DISPLAY = 100;
|
|
33337
34069
|
const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
|
|
33338
|
-
const similar =
|
|
34070
|
+
const similar = _internals47.findSimilarCommands(attemptedCommand);
|
|
33339
34071
|
const header = `Command \`/swarm ${displayCommand}\` not found.`;
|
|
33340
34072
|
const suggestions = similar.length > 0 ? `Did you mean:
|
|
33341
34073
|
${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
|
|
@@ -33392,4 +34124,4 @@ ${text}`;
|
|
|
33392
34124
|
};
|
|
33393
34125
|
}
|
|
33394
34126
|
|
|
33395
|
-
export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCostsCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS,
|
|
34127
|
+
export { package_default, handleAcknowledgeSpecDriftCommand, handleAgentsCommand, handleAnalyzeCommand, handleArchiveCommand, DC_SAFE_TARGETS, dcNormalizeCommand, dcUnwrapWrappers, dcSplitSegments, dcValidateTargets, dcCheckJunctionCreation, dcExtractWindowsCmdTargets, dcExtractPowerShellTargets, normalizeSwarmCommandInput, canonicalCommandKey, formatCommandNotFound, executeSwarmCommand, SWARM_COMMAND_TOOL_COMMANDS, SWARM_COMMAND_TOOL_ALLOWLIST, HUMAN_ONLY_SWARM_COMMANDS, classifySwarmCommandToolUse, classifySwarmCommandChatFallbackUse, detectPosixWrites, detectWindowsWrites, resolveWriteTargets, handleAutoProceedCommand, handleBenchmarkCommand, handleBrainstormCommand, handleCheckpointCommand, handleClarifyCommand, handleCloseCommand, handleCodebaseReviewCommand, handleConcurrencyCommand, handleConfigCommand, handleConsolidateCommand, handleCostsCommand, handleCouncilCommand, handleCurateCommand, handleDarkMatterCommand, handleDeepDiveCommand, handleDeepResearchCommand, getPluginConfigDir, getPluginCachePaths, getPluginLockFilePaths, handleDiagnoseCommand, handleDoctorCommand, handleEvidenceCommand, handleEvidenceSummaryCommand, handleExportCommand, handleFullAutoCommand, handleHandoffCommand, handleHistoryCommand, handleKnowledgeQuarantineCommand, handleKnowledgeRestoreCommand, handleKnowledgeMigrateCommand, handleKnowledgeListCommand, handleKnowledgeUnactionableCommand, handleKnowledgeRetryHardeningCommand, handleLearningCommand, handleLinkCommand, handleMemoryCommand, handleMemoryStatusCommand, handleMemoryMigrateCommand, handleMemoryImportCommand, handleMemoryExportCommand, handlePlanCommand, handlePreflightCommand, handlePromoteCommand, handleQaGatesCommand, handleResetCommand, handleResetSessionCommand, handleRetrieveCommand, handleRollbackCommand, handleSddStatusCommand, handleSddValidateCommand, handleSddProjectCommand, handleSddCommand, handleSimulateCommand, handleSpecifyCommand, handleStatusCommand, handleSyncPlanCommand, handleTurboCommand, handleUnlinkCommand, handleWriteRetroCommand, handleHelpCommand, COMMAND_REGISTRY, VALID_COMMANDS, _internals47 as _internals, resolveCommand };
|