opencode-swarm 7.88.3 → 7.88.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/agent-output-schema.d.ts +1 -1
- package/dist/agents/curator-agent.d.ts +1 -1
- package/dist/agents/explorer.d.ts +1 -0
- package/dist/cli/{config-doctor-jzbgpbdh.js → config-doctor-g04wdz19.js} +2 -2
- package/dist/cli/{explorer-gz70sm9b.js → explorer-h2fnj343.js} +4 -2
- package/dist/cli/{guardrail-explain-eqypvw60.js → guardrail-explain-xe0wjnxz.js} +7 -7
- package/dist/cli/{guardrail-log-c7egm5km.js → guardrail-log-m3285thy.js} +3 -3
- package/dist/cli/{index-0asbrmdx.js → index-123s7kjc.js} +88 -2
- package/dist/cli/{index-0rt5aamg.js → index-5p1gvn98.js} +8 -8
- package/dist/cli/{index-g00qm2gf.js → index-6tnmt41c.js} +1 -1
- package/dist/cli/{index-yhsmmv2z.js → index-bm4f0nme.js} +25 -1
- package/dist/cli/{index-819xp49y.js → index-bywt2171.js} +1 -1
- package/dist/cli/{index-ds057q5k.js → index-d4hpgf63.js} +2 -2
- package/dist/cli/{index-vjsr9bqt.js → index-gg589mfw.js} +1 -1
- package/dist/cli/{index-g6f4tt38.js → index-hs2knbfq.js} +520 -375
- package/dist/cli/{index-32axfg6h.js → index-rh53rrpt.js} +82 -12
- package/dist/cli/index.js +6 -6
- package/dist/cli/{schema-vb6jkxgg.js → schema-t9th7frq.js} +1 -1
- package/dist/cli/{skill-generator-kz4q8e49.js → skill-generator-s0spm65v.js} +1 -1
- package/dist/commands/memory.d.ts +1 -0
- package/dist/commands/registry.d.ts +8 -0
- package/dist/config/agent-names.d.ts +2 -2
- package/dist/config/schema.d.ts +60 -0
- package/dist/hooks/curator-llm-factory.d.ts +1 -1
- package/dist/index.js +1971 -1077
- package/dist/memory/config.d.ts +35 -0
- package/dist/memory/consolidation-log.d.ts +29 -0
- package/dist/memory/consolidation.d.ts +124 -0
- package/dist/memory/decay.d.ts +24 -0
- package/dist/memory/gateway.d.ts +14 -2
- package/dist/memory/maintenance.d.ts +18 -0
- package/dist/memory/run-log.d.ts +8 -1
- package/dist/memory/schema.d.ts +3 -3
- package/dist/memory/scoring.d.ts +45 -0
- package/dist/memory/sentinel.d.ts +15 -0
- package/dist/services/memory-consolidation.d.ts +32 -0
- package/dist/services/skill-generator.d.ts +8 -1
- package/dist/state.d.ts +4 -2
- package/package.json +1 -1
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
validateActionability,
|
|
21
21
|
validateActionableFields,
|
|
22
22
|
validateLesson
|
|
23
|
-
} from "./index-
|
|
23
|
+
} from "./index-rh53rrpt.js";
|
|
24
24
|
import {
|
|
25
25
|
appendKnowledge,
|
|
26
26
|
appendRejectedLesson,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
readDoctorArtifact,
|
|
48
48
|
removeStraySwarmDir,
|
|
49
49
|
runConfigDoctor
|
|
50
|
-
} from "./index-
|
|
50
|
+
} from "./index-bywt2171.js";
|
|
51
51
|
import {
|
|
52
52
|
AGENT_TOOL_MAP,
|
|
53
53
|
ALL_SUBAGENT_NAMES,
|
|
@@ -60,7 +60,7 @@ import {
|
|
|
60
60
|
TOOL_NAME_SET,
|
|
61
61
|
resolveExternalSkillsConfig,
|
|
62
62
|
stripKnownSwarmPrefix
|
|
63
|
-
} from "./index-
|
|
63
|
+
} from "./index-123s7kjc.js";
|
|
64
64
|
import {
|
|
65
65
|
MAX_TRANSIENT_RETRIES,
|
|
66
66
|
PlanSchema,
|
|
@@ -899,7 +899,7 @@ var init_executor = __esm(() => {
|
|
|
899
899
|
// package.json
|
|
900
900
|
var package_default = {
|
|
901
901
|
name: "opencode-swarm",
|
|
902
|
-
version: "7.88.
|
|
902
|
+
version: "7.88.4",
|
|
903
903
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
904
904
|
main: "dist/index.js",
|
|
905
905
|
types: "dist/index.d.ts",
|
|
@@ -4119,6 +4119,7 @@ var swarmState = {
|
|
|
4119
4119
|
curatorInitAgentNames: [],
|
|
4120
4120
|
curatorPhaseAgentNames: [],
|
|
4121
4121
|
curatorPostmortemAgentNames: [],
|
|
4122
|
+
curatorConsolidationAgentNames: [],
|
|
4122
4123
|
skillImproverAgentNames: [],
|
|
4123
4124
|
specWriterAgentNames: [],
|
|
4124
4125
|
currentCriticalShownIds: new Map,
|
|
@@ -4145,6 +4146,7 @@ function resetSwarmState() {
|
|
|
4145
4146
|
swarmState.curatorInitAgentNames = [];
|
|
4146
4147
|
swarmState.curatorPhaseAgentNames = [];
|
|
4147
4148
|
swarmState.curatorPostmortemAgentNames = [];
|
|
4149
|
+
swarmState.curatorConsolidationAgentNames = [];
|
|
4148
4150
|
swarmState.skillImproverAgentNames = [];
|
|
4149
4151
|
swarmState.specWriterAgentNames = [];
|
|
4150
4152
|
swarmState.currentCriticalShownIds.clear();
|
|
@@ -4163,6 +4165,7 @@ function resetSwarmStatePreservingSingletons() {
|
|
|
4163
4165
|
const preservedCuratorInitAgentNames = swarmState.curatorInitAgentNames;
|
|
4164
4166
|
const preservedCuratorPhaseAgentNames = swarmState.curatorPhaseAgentNames;
|
|
4165
4167
|
const preservedCuratorPostmortemAgentNames = swarmState.curatorPostmortemAgentNames;
|
|
4168
|
+
const preservedCuratorConsolidationAgentNames = swarmState.curatorConsolidationAgentNames;
|
|
4166
4169
|
const preservedSkillImproverAgentNames = swarmState.skillImproverAgentNames;
|
|
4167
4170
|
const preservedSpecWriterAgentNames = swarmState.specWriterAgentNames;
|
|
4168
4171
|
const preservedGeneratedAgentNames = swarmState.generatedAgentNames;
|
|
@@ -4172,6 +4175,7 @@ function resetSwarmStatePreservingSingletons() {
|
|
|
4172
4175
|
swarmState.curatorInitAgentNames = preservedCuratorInitAgentNames;
|
|
4173
4176
|
swarmState.curatorPhaseAgentNames = preservedCuratorPhaseAgentNames;
|
|
4174
4177
|
swarmState.curatorPostmortemAgentNames = preservedCuratorPostmortemAgentNames;
|
|
4178
|
+
swarmState.curatorConsolidationAgentNames = preservedCuratorConsolidationAgentNames;
|
|
4175
4179
|
swarmState.skillImproverAgentNames = preservedSkillImproverAgentNames;
|
|
4176
4180
|
swarmState.specWriterAgentNames = preservedSpecWriterAgentNames;
|
|
4177
4181
|
swarmState.generatedAgentNames = preservedGeneratedAgentNames;
|
|
@@ -5720,13 +5724,15 @@ function resolveCuratorAgentName(mode, sessionId) {
|
|
|
5720
5724
|
const suffixMap = {
|
|
5721
5725
|
init: "curator_init",
|
|
5722
5726
|
phase: "curator_phase",
|
|
5723
|
-
postmortem: "curator_postmortem"
|
|
5727
|
+
postmortem: "curator_postmortem",
|
|
5728
|
+
consolidation: "curator_consolidation"
|
|
5724
5729
|
};
|
|
5725
5730
|
const suffix = suffixMap[mode];
|
|
5726
5731
|
const registeredNamesMap = {
|
|
5727
5732
|
init: swarmState.curatorInitAgentNames,
|
|
5728
5733
|
phase: swarmState.curatorPhaseAgentNames,
|
|
5729
|
-
postmortem: swarmState.curatorPostmortemAgentNames
|
|
5734
|
+
postmortem: swarmState.curatorPostmortemAgentNames,
|
|
5735
|
+
consolidation: swarmState.curatorConsolidationAgentNames
|
|
5730
5736
|
};
|
|
5731
5737
|
const registeredNames = registeredNamesMap[mode];
|
|
5732
5738
|
if (registeredNames.length === 1)
|
|
@@ -6190,7 +6196,7 @@ async function runCuratorPostMortem(directory, options = {}) {
|
|
|
6190
6196
|
let reportContent;
|
|
6191
6197
|
if (options.llmDelegate) {
|
|
6192
6198
|
try {
|
|
6193
|
-
const { CURATOR_POSTMORTEM_PROMPT: CURATOR_POSTMORTEM_PROMPT2 } = await import("./explorer-
|
|
6199
|
+
const { CURATOR_POSTMORTEM_PROMPT: CURATOR_POSTMORTEM_PROMPT2 } = await import("./explorer-h2fnj343.js");
|
|
6194
6200
|
const userInput = assembleLLMInput(effectivePlanId, planSummary, knowledgeSummary, curatorDigest, proposals, unactionable, retrospectives, driftReports);
|
|
6195
6201
|
const ac = new AbortController;
|
|
6196
6202
|
const timer = setTimeout(() => ac.abort(), 300000);
|
|
@@ -11539,7 +11545,7 @@ async function runFinalizeStage(ctx) {
|
|
|
11539
11545
|
}
|
|
11540
11546
|
}
|
|
11541
11547
|
try {
|
|
11542
|
-
const { CuratorConfigSchema: CCS } = await import("./schema-
|
|
11548
|
+
const { CuratorConfigSchema: CCS } = await import("./schema-t9th7frq.js");
|
|
11543
11549
|
const { config: pmLoadedConfig } = _internals20.loadPluginConfigWithMeta(ctx.directory);
|
|
11544
11550
|
const curatorCfg = CCS.parse(pmLoadedConfig.curator ?? {});
|
|
11545
11551
|
if (curatorCfg.enabled && curatorCfg.postmortem_enabled) {
|
|
@@ -15220,7 +15226,7 @@ async function handleDoctorCommand(directory, args) {
|
|
|
15220
15226
|
const result = runConfigDoctor(config, directory);
|
|
15221
15227
|
let output;
|
|
15222
15228
|
if (enableAutoFix && result.hasAutoFixableIssues) {
|
|
15223
|
-
const { runConfigDoctorWithFixes } = await import("./config-doctor-
|
|
15229
|
+
const { runConfigDoctorWithFixes } = await import("./config-doctor-g04wdz19.js");
|
|
15224
15230
|
const fixResult = await runConfigDoctorWithFixes(directory, config, true);
|
|
15225
15231
|
output = formatDoctorMarkdown(fixResult.result);
|
|
15226
15232
|
} else {
|
|
@@ -18335,10 +18341,41 @@ ${USAGE7}`;
|
|
|
18335
18341
|
|
|
18336
18342
|
// src/commands/memory.ts
|
|
18337
18343
|
import { existsSync as existsSync25 } from "fs";
|
|
18338
|
-
import * as
|
|
18344
|
+
import * as path44 from "path";
|
|
18339
18345
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18340
18346
|
|
|
18341
18347
|
// src/memory/config.ts
|
|
18348
|
+
var DEFAULT_DECAY_HALF_LIFE_DAYS = {
|
|
18349
|
+
scratch: 7,
|
|
18350
|
+
todo: 30,
|
|
18351
|
+
code_pattern: 90,
|
|
18352
|
+
test_pattern: 90,
|
|
18353
|
+
failure_pattern: 90,
|
|
18354
|
+
api_finding: 180,
|
|
18355
|
+
evidence: 180,
|
|
18356
|
+
architecture_decision: 0,
|
|
18357
|
+
repo_convention: 0,
|
|
18358
|
+
project_fact: 0,
|
|
18359
|
+
security_note: 0,
|
|
18360
|
+
user_preference: 0
|
|
18361
|
+
};
|
|
18362
|
+
var DEFAULT_IMPORTANCE_CONFIG = {
|
|
18363
|
+
wRecency: 0.2,
|
|
18364
|
+
wFrequency: 0.2,
|
|
18365
|
+
wFreshness: 0.15,
|
|
18366
|
+
wConfidence: 0.25,
|
|
18367
|
+
lambda: 0.05,
|
|
18368
|
+
mu: 0.01,
|
|
18369
|
+
n: 50,
|
|
18370
|
+
threshold: 0.2
|
|
18371
|
+
};
|
|
18372
|
+
var DEFAULT_CONSOLIDATION_CONFIG = {
|
|
18373
|
+
enabled: false,
|
|
18374
|
+
maxClustersPerPass: 10,
|
|
18375
|
+
jaccardThreshold: 0.3,
|
|
18376
|
+
autoApplyMinConfidence: 0.6,
|
|
18377
|
+
decayHalfLifeDays: { ...DEFAULT_DECAY_HALF_LIFE_DAYS }
|
|
18378
|
+
};
|
|
18342
18379
|
var DEFAULT_MEMORY_CONFIG = {
|
|
18343
18380
|
enabled: false,
|
|
18344
18381
|
provider: "sqlite",
|
|
@@ -18368,7 +18405,12 @@ var DEFAULT_MEMORY_CONFIG = {
|
|
|
18368
18405
|
maintenance: {
|
|
18369
18406
|
lowUtilityMaxConfidence: 0.45,
|
|
18370
18407
|
lowUtilityMinAgeDays: 30,
|
|
18371
|
-
autoCompactEveryNRecalls: 50
|
|
18408
|
+
autoCompactEveryNRecalls: 50,
|
|
18409
|
+
importance: { ...DEFAULT_IMPORTANCE_CONFIG }
|
|
18410
|
+
},
|
|
18411
|
+
consolidation: {
|
|
18412
|
+
...DEFAULT_CONSOLIDATION_CONFIG,
|
|
18413
|
+
decayHalfLifeDays: { ...DEFAULT_DECAY_HALF_LIFE_DAYS }
|
|
18372
18414
|
},
|
|
18373
18415
|
hardDelete: false
|
|
18374
18416
|
};
|
|
@@ -18413,7 +18455,19 @@ function resolveMemoryConfig(input) {
|
|
|
18413
18455
|
},
|
|
18414
18456
|
maintenance: {
|
|
18415
18457
|
...DEFAULT_MEMORY_CONFIG.maintenance,
|
|
18416
|
-
...input?.maintenance ?? {}
|
|
18458
|
+
...input?.maintenance ?? {},
|
|
18459
|
+
importance: {
|
|
18460
|
+
...DEFAULT_MEMORY_CONFIG.maintenance.importance,
|
|
18461
|
+
...input?.maintenance?.importance ?? {}
|
|
18462
|
+
}
|
|
18463
|
+
},
|
|
18464
|
+
consolidation: {
|
|
18465
|
+
...DEFAULT_MEMORY_CONFIG.consolidation,
|
|
18466
|
+
...input?.consolidation ?? {},
|
|
18467
|
+
decayHalfLifeDays: {
|
|
18468
|
+
...DEFAULT_MEMORY_CONFIG.consolidation.decayHalfLifeDays,
|
|
18469
|
+
...input?.consolidation?.decayHalfLifeDays ?? {}
|
|
18470
|
+
}
|
|
18417
18471
|
}
|
|
18418
18472
|
};
|
|
18419
18473
|
}
|
|
@@ -18501,6 +18555,9 @@ function containsSecret(text) {
|
|
|
18501
18555
|
return findSecrets(text).length > 0;
|
|
18502
18556
|
}
|
|
18503
18557
|
|
|
18558
|
+
// src/memory/sentinel.ts
|
|
18559
|
+
var MEMORY_RECALL_SENTINEL = "## Retrieved Swarm Memory";
|
|
18560
|
+
|
|
18504
18561
|
// src/memory/schema.ts
|
|
18505
18562
|
var MemoryScopeTypeSchema = exports_external.enum([
|
|
18506
18563
|
"global_user",
|
|
@@ -18702,6 +18759,9 @@ function hasEvidenceSource(record) {
|
|
|
18702
18759
|
}
|
|
18703
18760
|
function validateMemoryRecordRules(record, options) {
|
|
18704
18761
|
const parsed = MemoryRecordSchema.parse(record);
|
|
18762
|
+
if (parsed.text.includes(MEMORY_RECALL_SENTINEL)) {
|
|
18763
|
+
throw new MemoryValidationError("memory text cannot contain the recall sentinel header");
|
|
18764
|
+
}
|
|
18705
18765
|
const expectedHash = computeMemoryContentHash(parsed);
|
|
18706
18766
|
const expectedId = createMemoryId(parsed);
|
|
18707
18767
|
if (parsed.contentHash !== expectedHash) {
|
|
@@ -18813,165 +18873,6 @@ function normalizeTags(tags) {
|
|
|
18813
18873
|
return Array.from(new Set(tags.map((tag) => tag.toLowerCase().replace(/[^\w-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "")).filter(Boolean))).slice(0, 32);
|
|
18814
18874
|
}
|
|
18815
18875
|
|
|
18816
|
-
// src/memory/maintenance.ts
|
|
18817
|
-
var DEFAULT_LOW_UTILITY_MAX_CONFIDENCE = 0.45;
|
|
18818
|
-
var DEFAULT_LOW_UTILITY_MIN_AGE_DAYS = 30;
|
|
18819
|
-
async function buildMemoryMaintenanceReport(provider, options = {}) {
|
|
18820
|
-
const now = options.now ?? new Date;
|
|
18821
|
-
const limit = Math.max(1, Math.trunc(options.limit ?? 20));
|
|
18822
|
-
const memories = await provider.list({
|
|
18823
|
-
includeExpired: true,
|
|
18824
|
-
includeInactive: true
|
|
18825
|
-
});
|
|
18826
|
-
const proposals = await loadMaintenanceProposals(provider, limit);
|
|
18827
|
-
const recallUsage = provider.listRecallUsage ? await provider.listRecallUsage() : [];
|
|
18828
|
-
const usageByMemory = summarizeRecallByMemory(recallUsage);
|
|
18829
|
-
const usageByRole = summarizeRecallByRole(recallUsage);
|
|
18830
|
-
const activeMemories = memories.filter((memory) => isActiveMemory(memory, now));
|
|
18831
|
-
const deletedMemories = memories.filter((memory) => memory.metadata.deleted === true);
|
|
18832
|
-
const expiredScratchMemories = memories.filter((memory) => memory.kind === "scratch" && isExpired(memory, now));
|
|
18833
|
-
const supersededMemories = memories.filter((memory) => Boolean(memory.supersededBy));
|
|
18834
|
-
const lowUtilityMemories = activeMemories.filter((memory) => isLowUtility(memory, usageByMemory, now, {
|
|
18835
|
-
maxConfidence: options.lowUtilityMaxConfidence ?? DEFAULT_LOW_UTILITY_MAX_CONFIDENCE,
|
|
18836
|
-
minAgeDays: options.lowUtilityMinAgeDays ?? DEFAULT_LOW_UTILITY_MIN_AGE_DAYS
|
|
18837
|
-
})).sort(memorySort);
|
|
18838
|
-
const neverRecalledMemories = activeMemories.filter((memory) => !usageByMemory.has(memory.id)).sort(memorySort);
|
|
18839
|
-
const rejectedProposalReasons = proposals.filter((proposal) => proposal.status === "rejected").sort(proposalSort);
|
|
18840
|
-
const pendingProposals = proposals.filter((proposal) => proposal.status === "pending").sort(proposalSort);
|
|
18841
|
-
return {
|
|
18842
|
-
generatedAt: now.toISOString(),
|
|
18843
|
-
totalMemories: memories.length,
|
|
18844
|
-
activeMemories: activeMemories.length,
|
|
18845
|
-
deletedMemories: deletedMemories.slice(0, limit),
|
|
18846
|
-
expiredScratchMemories: expiredScratchMemories.slice(0, limit),
|
|
18847
|
-
supersededMemories: supersededMemories.slice(0, limit),
|
|
18848
|
-
supersededChains: buildSupersededChains(memories).slice(0, limit),
|
|
18849
|
-
lowUtilityMemories: lowUtilityMemories.slice(0, limit),
|
|
18850
|
-
neverRecalledMemories: neverRecalledMemories.slice(0, limit),
|
|
18851
|
-
mostRecalledMemories: Array.from(usageByMemory.values()).sort((a, b) => b.count - a.count || b.lastRecalledAt.localeCompare(a.lastRecalledAt) || a.memoryId.localeCompare(b.memoryId)).slice(0, limit),
|
|
18852
|
-
recallByAgentRole: Array.from(usageByRole.values()).sort((a, b) => b.count - a.count || a.agentRole.localeCompare(b.agentRole)).slice(0, limit),
|
|
18853
|
-
rejectedProposalReasons: rejectedProposalReasons.slice(0, limit),
|
|
18854
|
-
pendingProposals: pendingProposals.slice(0, limit),
|
|
18855
|
-
recallEventCount: recallUsage.length
|
|
18856
|
-
};
|
|
18857
|
-
}
|
|
18858
|
-
function shouldCompactMemory(memory, now = new Date) {
|
|
18859
|
-
if (memory.metadata.deleted === true)
|
|
18860
|
-
return "deleted";
|
|
18861
|
-
if (memory.supersededBy)
|
|
18862
|
-
return "superseded";
|
|
18863
|
-
if (memory.kind === "scratch" && isExpired(memory, now)) {
|
|
18864
|
-
return "expired_scratch";
|
|
18865
|
-
}
|
|
18866
|
-
return null;
|
|
18867
|
-
}
|
|
18868
|
-
function isActiveMemory(memory, now) {
|
|
18869
|
-
return memory.metadata.deleted !== true && !memory.supersededBy && !isExpired(memory, now);
|
|
18870
|
-
}
|
|
18871
|
-
function isLowUtility(memory, usageByMemory, now, options) {
|
|
18872
|
-
if (usageByMemory.has(memory.id))
|
|
18873
|
-
return false;
|
|
18874
|
-
const updated = Date.parse(memory.updatedAt);
|
|
18875
|
-
const ageDays = Number.isFinite(updated) ? (now.getTime() - updated) / (24 * 60 * 60 * 1000) : 0;
|
|
18876
|
-
return memory.confidence <= options.maxConfidence || ageDays >= options.minAgeDays;
|
|
18877
|
-
}
|
|
18878
|
-
function summarizeRecallByMemory(usageEvents) {
|
|
18879
|
-
const byMemory = new Map;
|
|
18880
|
-
for (const event of usageEvents) {
|
|
18881
|
-
event.memoryIds.forEach((memoryId, index) => {
|
|
18882
|
-
const role = event.agentRole ?? "unknown";
|
|
18883
|
-
const existing = byMemory.get(memoryId) ?? {
|
|
18884
|
-
memoryId,
|
|
18885
|
-
count: 0,
|
|
18886
|
-
lastRecalledAt: event.timestamp,
|
|
18887
|
-
agentRoles: {},
|
|
18888
|
-
averageScore: 0,
|
|
18889
|
-
scoreTotal: 0,
|
|
18890
|
-
scoreCount: 0
|
|
18891
|
-
};
|
|
18892
|
-
existing.count++;
|
|
18893
|
-
existing.lastRecalledAt = event.timestamp > existing.lastRecalledAt ? event.timestamp : existing.lastRecalledAt;
|
|
18894
|
-
existing.agentRoles[role] = (existing.agentRoles[role] ?? 0) + 1;
|
|
18895
|
-
const score = event.scores[index];
|
|
18896
|
-
if (typeof score === "number" && Number.isFinite(score)) {
|
|
18897
|
-
existing.scoreTotal += score;
|
|
18898
|
-
existing.scoreCount++;
|
|
18899
|
-
existing.averageScore = existing.scoreTotal / existing.scoreCount;
|
|
18900
|
-
}
|
|
18901
|
-
byMemory.set(memoryId, existing);
|
|
18902
|
-
});
|
|
18903
|
-
}
|
|
18904
|
-
return new Map(Array.from(byMemory, ([memoryId, value]) => [
|
|
18905
|
-
memoryId,
|
|
18906
|
-
{
|
|
18907
|
-
memoryId,
|
|
18908
|
-
count: value.count,
|
|
18909
|
-
lastRecalledAt: value.lastRecalledAt,
|
|
18910
|
-
agentRoles: value.agentRoles,
|
|
18911
|
-
averageScore: value.averageScore
|
|
18912
|
-
}
|
|
18913
|
-
]));
|
|
18914
|
-
}
|
|
18915
|
-
async function loadMaintenanceProposals(provider, limit) {
|
|
18916
|
-
if (!provider.listProposals)
|
|
18917
|
-
return [];
|
|
18918
|
-
const [pending, rejected, recent] = await Promise.all([
|
|
18919
|
-
provider.listProposals({ status: "pending", limit }),
|
|
18920
|
-
provider.listProposals({ status: "rejected", limit }),
|
|
18921
|
-
provider.listProposals({ limit: Math.max(limit * 4, 100) })
|
|
18922
|
-
]);
|
|
18923
|
-
const byId = new Map;
|
|
18924
|
-
for (const proposal of [...pending, ...rejected, ...recent]) {
|
|
18925
|
-
byId.set(proposal.id, proposal);
|
|
18926
|
-
}
|
|
18927
|
-
return Array.from(byId.values());
|
|
18928
|
-
}
|
|
18929
|
-
function summarizeRecallByRole(usageEvents) {
|
|
18930
|
-
const byRole = new Map;
|
|
18931
|
-
for (const event of usageEvents) {
|
|
18932
|
-
const role = event.agentRole ?? "unknown";
|
|
18933
|
-
const existing = byRole.get(role) ?? {
|
|
18934
|
-
agentRole: role,
|
|
18935
|
-
count: 0,
|
|
18936
|
-
memoryIds: {}
|
|
18937
|
-
};
|
|
18938
|
-
existing.count++;
|
|
18939
|
-
for (const memoryId of event.memoryIds) {
|
|
18940
|
-
existing.memoryIds[memoryId] = (existing.memoryIds[memoryId] ?? 0) + 1;
|
|
18941
|
-
}
|
|
18942
|
-
byRole.set(role, existing);
|
|
18943
|
-
}
|
|
18944
|
-
return byRole;
|
|
18945
|
-
}
|
|
18946
|
-
function buildSupersededChains(memories) {
|
|
18947
|
-
const byId = new Map(memories.map((memory) => [memory.id, memory]));
|
|
18948
|
-
const supersededIds = new Set(memories.filter((memory) => memory.supersededBy).map((memory) => memory.id));
|
|
18949
|
-
const roots = memories.filter((memory) => memory.supersededBy && !(memory.supersedes ?? []).some((id) => supersededIds.has(id)));
|
|
18950
|
-
return roots.map((root) => {
|
|
18951
|
-
const chain = [root.id];
|
|
18952
|
-
const seen = new Set(chain);
|
|
18953
|
-
let cursor = root;
|
|
18954
|
-
while (cursor?.supersededBy && !seen.has(cursor.supersededBy)) {
|
|
18955
|
-
chain.push(cursor.supersededBy);
|
|
18956
|
-
seen.add(cursor.supersededBy);
|
|
18957
|
-
cursor = byId.get(cursor.supersededBy);
|
|
18958
|
-
}
|
|
18959
|
-
return {
|
|
18960
|
-
rootId: root.id,
|
|
18961
|
-
chain,
|
|
18962
|
-
reason: typeof root.metadata.supersedeReason === "string" ? root.metadata.supersedeReason : undefined
|
|
18963
|
-
};
|
|
18964
|
-
});
|
|
18965
|
-
}
|
|
18966
|
-
function memorySort(a, b) {
|
|
18967
|
-
return b.updatedAt.localeCompare(a.updatedAt) || a.id.localeCompare(b.id);
|
|
18968
|
-
}
|
|
18969
|
-
function proposalSort(a, b) {
|
|
18970
|
-
const aTime = a.reviewedAt ?? a.createdAt;
|
|
18971
|
-
const bTime = b.reviewedAt ?? b.createdAt;
|
|
18972
|
-
return bTime.localeCompare(aTime) || a.id.localeCompare(b.id);
|
|
18973
|
-
}
|
|
18974
|
-
|
|
18975
18876
|
// src/memory/role-profiles.ts
|
|
18976
18877
|
var MEMORY_RECALL_PROFILES = {
|
|
18977
18878
|
architect: {
|
|
@@ -19079,6 +18980,14 @@ var SCORING_WEIGHTS = {
|
|
|
19079
18980
|
function tokenize(text) {
|
|
19080
18981
|
return new Set(text.toLowerCase().replace(/[^\w\s-]/g, " ").split(/\s+/).map((token) => token.trim()).filter(Boolean));
|
|
19081
18982
|
}
|
|
18983
|
+
function importanceScore(input, weights) {
|
|
18984
|
+
const recency = input.daysSinceLastRecall === null ? 0 : Math.exp(-weights.lambda * Math.max(0, input.daysSinceLastRecall));
|
|
18985
|
+
const denom = Math.log1p(Math.max(1, weights.n));
|
|
18986
|
+
const frequency = denom === 0 ? 0 : Math.log1p(Math.max(0, input.retrievalCount)) / denom;
|
|
18987
|
+
const freshness = Math.exp(-weights.mu * Math.max(0, input.daysSinceCreated));
|
|
18988
|
+
const confidence = Math.min(1, Math.max(0, input.confidence));
|
|
18989
|
+
return weights.wRecency * recency + weights.wFrequency * frequency + weights.wFreshness * freshness + weights.wConfidence * confidence;
|
|
18990
|
+
}
|
|
19082
18991
|
function normalizeKindText(kind) {
|
|
19083
18992
|
return kind.replace(/_/g, " ");
|
|
19084
18993
|
}
|
|
@@ -19258,6 +19167,180 @@ function unionTokens(...sets) {
|
|
|
19258
19167
|
return union;
|
|
19259
19168
|
}
|
|
19260
19169
|
|
|
19170
|
+
// src/memory/maintenance.ts
|
|
19171
|
+
var DEFAULT_IMPORTANCE_WEIGHTS = {
|
|
19172
|
+
wRecency: 0.2,
|
|
19173
|
+
wFrequency: 0.2,
|
|
19174
|
+
wFreshness: 0.15,
|
|
19175
|
+
wConfidence: 0.25,
|
|
19176
|
+
lambda: 0.05,
|
|
19177
|
+
mu: 0.01,
|
|
19178
|
+
n: 50
|
|
19179
|
+
};
|
|
19180
|
+
var DEFAULT_IMPORTANCE_THRESHOLD = 0.2;
|
|
19181
|
+
var MS_PER_DAY2 = 24 * 60 * 60 * 1000;
|
|
19182
|
+
async function buildMemoryMaintenanceReport(provider, options = {}) {
|
|
19183
|
+
const now = options.now ?? new Date;
|
|
19184
|
+
const limit = Math.max(1, Math.trunc(options.limit ?? 20));
|
|
19185
|
+
const memories = await provider.list({
|
|
19186
|
+
includeExpired: true,
|
|
19187
|
+
includeInactive: true
|
|
19188
|
+
});
|
|
19189
|
+
const proposals = await loadMaintenanceProposals(provider, limit);
|
|
19190
|
+
const recallUsage = provider.listRecallUsage ? await provider.listRecallUsage() : [];
|
|
19191
|
+
const usageByMemory = summarizeRecallByMemory(recallUsage);
|
|
19192
|
+
const usageByRole = summarizeRecallByRole(recallUsage);
|
|
19193
|
+
const activeMemories = memories.filter((memory) => isActiveMemory(memory, now));
|
|
19194
|
+
const deletedMemories = memories.filter((memory) => memory.metadata.deleted === true);
|
|
19195
|
+
const expiredScratchMemories = memories.filter((memory) => memory.kind === "scratch" && isExpired(memory, now));
|
|
19196
|
+
const supersededMemories = memories.filter((memory) => Boolean(memory.supersededBy));
|
|
19197
|
+
const lowUtilityMemories = activeMemories.filter((memory) => isLowUtility(memory, usageByMemory, now, {
|
|
19198
|
+
weights: options.importanceWeights ?? DEFAULT_IMPORTANCE_WEIGHTS,
|
|
19199
|
+
threshold: options.importanceThreshold ?? DEFAULT_IMPORTANCE_THRESHOLD
|
|
19200
|
+
})).sort(memorySort);
|
|
19201
|
+
const neverRecalledMemories = activeMemories.filter((memory) => !usageByMemory.has(memory.id)).sort(memorySort);
|
|
19202
|
+
const rejectedProposalReasons = proposals.filter((proposal) => proposal.status === "rejected").sort(proposalSort);
|
|
19203
|
+
const pendingProposals = proposals.filter((proposal) => proposal.status === "pending").sort(proposalSort);
|
|
19204
|
+
return {
|
|
19205
|
+
generatedAt: now.toISOString(),
|
|
19206
|
+
totalMemories: memories.length,
|
|
19207
|
+
activeMemories: activeMemories.length,
|
|
19208
|
+
deletedMemories: deletedMemories.slice(0, limit),
|
|
19209
|
+
expiredScratchMemories: expiredScratchMemories.slice(0, limit),
|
|
19210
|
+
supersededMemories: supersededMemories.slice(0, limit),
|
|
19211
|
+
supersededChains: buildSupersededChains(memories).slice(0, limit),
|
|
19212
|
+
lowUtilityMemories: lowUtilityMemories.slice(0, limit),
|
|
19213
|
+
neverRecalledMemories: neverRecalledMemories.slice(0, limit),
|
|
19214
|
+
mostRecalledMemories: Array.from(usageByMemory.values()).sort((a, b) => b.count - a.count || b.lastRecalledAt.localeCompare(a.lastRecalledAt) || a.memoryId.localeCompare(b.memoryId)).slice(0, limit),
|
|
19215
|
+
recallByAgentRole: Array.from(usageByRole.values()).sort((a, b) => b.count - a.count || a.agentRole.localeCompare(b.agentRole)).slice(0, limit),
|
|
19216
|
+
rejectedProposalReasons: rejectedProposalReasons.slice(0, limit),
|
|
19217
|
+
pendingProposals: pendingProposals.slice(0, limit),
|
|
19218
|
+
recallEventCount: recallUsage.length
|
|
19219
|
+
};
|
|
19220
|
+
}
|
|
19221
|
+
function shouldCompactMemory(memory, now = new Date) {
|
|
19222
|
+
if (memory.metadata.deleted === true)
|
|
19223
|
+
return "deleted";
|
|
19224
|
+
if (memory.supersededBy)
|
|
19225
|
+
return "superseded";
|
|
19226
|
+
if (memory.kind === "scratch" && isExpired(memory, now)) {
|
|
19227
|
+
return "expired_scratch";
|
|
19228
|
+
}
|
|
19229
|
+
return null;
|
|
19230
|
+
}
|
|
19231
|
+
function isActiveMemory(memory, now) {
|
|
19232
|
+
return memory.metadata.deleted !== true && !memory.supersededBy && !isExpired(memory, now);
|
|
19233
|
+
}
|
|
19234
|
+
function isLowUtility(memory, usageByMemory, now, options) {
|
|
19235
|
+
if (usageByMemory.has(memory.id))
|
|
19236
|
+
return false;
|
|
19237
|
+
const created = Date.parse(memory.createdAt);
|
|
19238
|
+
const daysSinceCreated = Number.isFinite(created) ? Math.max(0, (now.getTime() - created) / MS_PER_DAY2) : 0;
|
|
19239
|
+
const importance = importanceScore({
|
|
19240
|
+
confidence: memory.confidence,
|
|
19241
|
+
retrievalCount: 0,
|
|
19242
|
+
daysSinceLastRecall: null,
|
|
19243
|
+
daysSinceCreated
|
|
19244
|
+
}, options.weights);
|
|
19245
|
+
return importance < options.threshold;
|
|
19246
|
+
}
|
|
19247
|
+
function summarizeRecallByMemory(usageEvents) {
|
|
19248
|
+
const byMemory = new Map;
|
|
19249
|
+
for (const event of usageEvents) {
|
|
19250
|
+
event.memoryIds.forEach((memoryId, index) => {
|
|
19251
|
+
const role = event.agentRole ?? "unknown";
|
|
19252
|
+
const existing = byMemory.get(memoryId) ?? {
|
|
19253
|
+
memoryId,
|
|
19254
|
+
count: 0,
|
|
19255
|
+
lastRecalledAt: event.timestamp,
|
|
19256
|
+
agentRoles: {},
|
|
19257
|
+
averageScore: 0,
|
|
19258
|
+
scoreTotal: 0,
|
|
19259
|
+
scoreCount: 0
|
|
19260
|
+
};
|
|
19261
|
+
existing.count++;
|
|
19262
|
+
existing.lastRecalledAt = event.timestamp > existing.lastRecalledAt ? event.timestamp : existing.lastRecalledAt;
|
|
19263
|
+
existing.agentRoles[role] = (existing.agentRoles[role] ?? 0) + 1;
|
|
19264
|
+
const score = event.scores[index];
|
|
19265
|
+
if (typeof score === "number" && Number.isFinite(score)) {
|
|
19266
|
+
existing.scoreTotal += score;
|
|
19267
|
+
existing.scoreCount++;
|
|
19268
|
+
existing.averageScore = existing.scoreTotal / existing.scoreCount;
|
|
19269
|
+
}
|
|
19270
|
+
byMemory.set(memoryId, existing);
|
|
19271
|
+
});
|
|
19272
|
+
}
|
|
19273
|
+
return new Map(Array.from(byMemory, ([memoryId, value]) => [
|
|
19274
|
+
memoryId,
|
|
19275
|
+
{
|
|
19276
|
+
memoryId,
|
|
19277
|
+
count: value.count,
|
|
19278
|
+
lastRecalledAt: value.lastRecalledAt,
|
|
19279
|
+
agentRoles: value.agentRoles,
|
|
19280
|
+
averageScore: value.averageScore
|
|
19281
|
+
}
|
|
19282
|
+
]));
|
|
19283
|
+
}
|
|
19284
|
+
async function loadMaintenanceProposals(provider, limit) {
|
|
19285
|
+
if (!provider.listProposals)
|
|
19286
|
+
return [];
|
|
19287
|
+
const [pending, rejected, recent] = await Promise.all([
|
|
19288
|
+
provider.listProposals({ status: "pending", limit }),
|
|
19289
|
+
provider.listProposals({ status: "rejected", limit }),
|
|
19290
|
+
provider.listProposals({ limit: Math.max(limit * 4, 100) })
|
|
19291
|
+
]);
|
|
19292
|
+
const byId = new Map;
|
|
19293
|
+
for (const proposal of [...pending, ...rejected, ...recent]) {
|
|
19294
|
+
byId.set(proposal.id, proposal);
|
|
19295
|
+
}
|
|
19296
|
+
return Array.from(byId.values());
|
|
19297
|
+
}
|
|
19298
|
+
function summarizeRecallByRole(usageEvents) {
|
|
19299
|
+
const byRole = new Map;
|
|
19300
|
+
for (const event of usageEvents) {
|
|
19301
|
+
const role = event.agentRole ?? "unknown";
|
|
19302
|
+
const existing = byRole.get(role) ?? {
|
|
19303
|
+
agentRole: role,
|
|
19304
|
+
count: 0,
|
|
19305
|
+
memoryIds: {}
|
|
19306
|
+
};
|
|
19307
|
+
existing.count++;
|
|
19308
|
+
for (const memoryId of event.memoryIds) {
|
|
19309
|
+
existing.memoryIds[memoryId] = (existing.memoryIds[memoryId] ?? 0) + 1;
|
|
19310
|
+
}
|
|
19311
|
+
byRole.set(role, existing);
|
|
19312
|
+
}
|
|
19313
|
+
return byRole;
|
|
19314
|
+
}
|
|
19315
|
+
function buildSupersededChains(memories) {
|
|
19316
|
+
const byId = new Map(memories.map((memory) => [memory.id, memory]));
|
|
19317
|
+
const supersededIds = new Set(memories.filter((memory) => memory.supersededBy).map((memory) => memory.id));
|
|
19318
|
+
const roots = memories.filter((memory) => memory.supersededBy && !(memory.supersedes ?? []).some((id) => supersededIds.has(id)));
|
|
19319
|
+
return roots.map((root) => {
|
|
19320
|
+
const chain = [root.id];
|
|
19321
|
+
const seen = new Set(chain);
|
|
19322
|
+
let cursor = root;
|
|
19323
|
+
while (cursor?.supersededBy && !seen.has(cursor.supersededBy)) {
|
|
19324
|
+
chain.push(cursor.supersededBy);
|
|
19325
|
+
seen.add(cursor.supersededBy);
|
|
19326
|
+
cursor = byId.get(cursor.supersededBy);
|
|
19327
|
+
}
|
|
19328
|
+
return {
|
|
19329
|
+
rootId: root.id,
|
|
19330
|
+
chain,
|
|
19331
|
+
reason: typeof root.metadata.supersedeReason === "string" ? root.metadata.supersedeReason : undefined
|
|
19332
|
+
};
|
|
19333
|
+
});
|
|
19334
|
+
}
|
|
19335
|
+
function memorySort(a, b) {
|
|
19336
|
+
return b.updatedAt.localeCompare(a.updatedAt) || a.id.localeCompare(b.id);
|
|
19337
|
+
}
|
|
19338
|
+
function proposalSort(a, b) {
|
|
19339
|
+
const aTime = a.reviewedAt ?? a.createdAt;
|
|
19340
|
+
const bTime = b.reviewedAt ?? b.createdAt;
|
|
19341
|
+
return bTime.localeCompare(aTime) || a.id.localeCompare(b.id);
|
|
19342
|
+
}
|
|
19343
|
+
|
|
19261
19344
|
// src/memory/local-jsonl-provider.ts
|
|
19262
19345
|
class LocalJsonlMemoryProvider {
|
|
19263
19346
|
name = "local-jsonl";
|
|
@@ -21521,8 +21604,33 @@ var AgentOutputMemorySchema = exports_external.object({
|
|
|
21521
21604
|
var CuratorOutputMemoryDecisionSchema = exports_external.object({
|
|
21522
21605
|
curatorMemoryDecisions: exports_external.array(CuratorMemoryDecisionSchema).max(20).optional()
|
|
21523
21606
|
}).passthrough();
|
|
21607
|
+
// src/memory/consolidation-log.ts
|
|
21608
|
+
import { appendFile as appendFile4, mkdir as mkdir12, readFile as readFile15 } from "fs/promises";
|
|
21609
|
+
import * as path43 from "path";
|
|
21610
|
+
var LOG_RELATIVE_PATH = path43.join("memory", "consolidation-log.jsonl");
|
|
21611
|
+
async function readConsolidationLog(directory) {
|
|
21612
|
+
const filePath = validateSwarmPath(directory, LOG_RELATIVE_PATH);
|
|
21613
|
+
let raw;
|
|
21614
|
+
try {
|
|
21615
|
+
raw = await readFile15(filePath, "utf-8");
|
|
21616
|
+
} catch {
|
|
21617
|
+
return [];
|
|
21618
|
+
}
|
|
21619
|
+
const records = [];
|
|
21620
|
+
for (const line of raw.split(`
|
|
21621
|
+
`)) {
|
|
21622
|
+
const trimmed = line.trim();
|
|
21623
|
+
if (!trimmed)
|
|
21624
|
+
continue;
|
|
21625
|
+
try {
|
|
21626
|
+
records.push(JSON.parse(trimmed));
|
|
21627
|
+
} catch {}
|
|
21628
|
+
}
|
|
21629
|
+
return records;
|
|
21630
|
+
}
|
|
21631
|
+
|
|
21524
21632
|
// src/commands/memory.ts
|
|
21525
|
-
var PACKAGE_ROOT =
|
|
21633
|
+
var PACKAGE_ROOT = path44.resolve(resolvePackageRootFromModule(fileURLToPath2(import.meta.url)));
|
|
21526
21634
|
async function handleMemoryCommand(_directory, _args) {
|
|
21527
21635
|
return [
|
|
21528
21636
|
"## Swarm Memory",
|
|
@@ -21535,10 +21643,38 @@ async function handleMemoryCommand(_directory, _args) {
|
|
|
21535
21643
|
"- `/swarm memory export` - export current memory and proposals to `.swarm/memory/export/*.jsonl`",
|
|
21536
21644
|
"- `/swarm memory import` - import `.swarm/memory/{memories,proposals}.jsonl` into SQLite",
|
|
21537
21645
|
"- `/swarm memory migrate` - run the one-time legacy JSONL to SQLite migration",
|
|
21538
|
-
"- `/swarm memory evaluate --json` - run the golden recall evaluation fixtures and emit a JSON report"
|
|
21646
|
+
"- `/swarm memory evaluate --json` - run the golden recall evaluation fixtures and emit a JSON report",
|
|
21647
|
+
"- `/swarm memory consolidation-log [--limit <n>]` - summarize recent episodic\u2192semantic consolidation passes (max 50 per query)"
|
|
21539
21648
|
].join(`
|
|
21540
21649
|
`);
|
|
21541
21650
|
}
|
|
21651
|
+
async function handleMemoryConsolidationLogCommand(directory, args) {
|
|
21652
|
+
const parsed = parseMaintenanceArgs(args, {
|
|
21653
|
+
usage: "Usage: /swarm memory consolidation-log [--limit <n>] (max 50 records per query)",
|
|
21654
|
+
allowConfirm: false
|
|
21655
|
+
});
|
|
21656
|
+
if ("error" in parsed)
|
|
21657
|
+
return parsed.error;
|
|
21658
|
+
const limit = Math.min(parsed.limit, 50);
|
|
21659
|
+
const records = await readConsolidationLog(directory);
|
|
21660
|
+
const recent = records.slice(-limit).reverse();
|
|
21661
|
+
const lines = [
|
|
21662
|
+
"## Swarm Memory Consolidation Log",
|
|
21663
|
+
"",
|
|
21664
|
+
`- Total recorded passes: \`${records.length}\``,
|
|
21665
|
+
`- Showing: \`${recent.length}\``
|
|
21666
|
+
];
|
|
21667
|
+
if (recent.length === 0) {
|
|
21668
|
+
lines.push("", "No consolidation passes have been recorded yet.");
|
|
21669
|
+
return lines.join(`
|
|
21670
|
+
`);
|
|
21671
|
+
}
|
|
21672
|
+
for (const record of recent) {
|
|
21673
|
+
lines.push("", `### Phase ${record.phaseNumber} \u2014 ${record.completedAt}`, `- Run: \`${record.runId ?? "unknown"}\``, `- Clusters: \`${record.clusterCount}\` (deferred \`${record.clustersDeferred}\`)`, `- Decisions applied: \`${record.decisionsEmitted}\` (added \`${record.added}\`, superseded \`${record.superseded}\`)`, `- Contradictions: \`${record.contradictionsDetected}\` | Deduped: \`${record.deduped}\` | Proposed: \`${record.proposed}\``, `- Memories decayed: \`${record.memoriesDecayed}\` | Errored: \`${record.errored}\``, `- Processed proposals: \`${record.processedProposalIds.length}\``);
|
|
21674
|
+
}
|
|
21675
|
+
return lines.join(`
|
|
21676
|
+
`);
|
|
21677
|
+
}
|
|
21542
21678
|
async function handleMemoryStatusCommand(directory, _args) {
|
|
21543
21679
|
const config = resolveCommandMemoryConfig(directory);
|
|
21544
21680
|
const storageDir = resolveMemoryStorageDir(directory, config);
|
|
@@ -21751,10 +21887,11 @@ function createMaintenanceProvider(directory, config) {
|
|
|
21751
21887
|
return createConfiguredMemoryProvider(directory, config);
|
|
21752
21888
|
}
|
|
21753
21889
|
function maintenanceReportOptions(config, limit) {
|
|
21890
|
+
const { threshold, ...weights } = config.maintenance.importance;
|
|
21754
21891
|
return {
|
|
21755
21892
|
limit,
|
|
21756
|
-
|
|
21757
|
-
|
|
21893
|
+
importanceWeights: weights,
|
|
21894
|
+
importanceThreshold: threshold
|
|
21758
21895
|
};
|
|
21759
21896
|
}
|
|
21760
21897
|
async function handleMemoryEvaluateCommand(directory, args) {
|
|
@@ -21791,7 +21928,7 @@ function resolveCommandMemoryConfig(directory) {
|
|
|
21791
21928
|
}
|
|
21792
21929
|
function parseEvaluateArgs(directory, args) {
|
|
21793
21930
|
let json = false;
|
|
21794
|
-
let fixtureDirectory =
|
|
21931
|
+
let fixtureDirectory = path44.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall");
|
|
21795
21932
|
for (let i = 0;i < args.length; i++) {
|
|
21796
21933
|
const arg = args[i];
|
|
21797
21934
|
if (arg === "--json") {
|
|
@@ -21805,10 +21942,10 @@ function parseEvaluateArgs(directory, args) {
|
|
|
21805
21942
|
error: "Usage: /swarm memory evaluate [--json] [--fixtures <directory>]"
|
|
21806
21943
|
};
|
|
21807
21944
|
}
|
|
21808
|
-
const resolvedFixtures =
|
|
21809
|
-
const canonical =
|
|
21810
|
-
const allowedRootA =
|
|
21811
|
-
const allowedRootB =
|
|
21945
|
+
const resolvedFixtures = path44.resolve(directory, next);
|
|
21946
|
+
const canonical = path44.normalize(resolvedFixtures) + path44.sep;
|
|
21947
|
+
const allowedRootA = path44.normalize(directory) + path44.sep;
|
|
21948
|
+
const allowedRootB = path44.normalize(path44.join(PACKAGE_ROOT, "tests", "fixtures", "memory-recall")) + path44.sep;
|
|
21812
21949
|
if (!canonical.startsWith(allowedRootA) && !canonical.startsWith(allowedRootB)) {
|
|
21813
21950
|
return {
|
|
21814
21951
|
error: "--fixtures <directory> must resolve under the project directory or the bundled tests/fixtures/memory-recall directory"
|
|
@@ -21847,15 +21984,15 @@ function parseMaintenanceArgs(args, options) {
|
|
|
21847
21984
|
return { limit, confirm };
|
|
21848
21985
|
}
|
|
21849
21986
|
function resolvePackageRootFromModule(modulePath) {
|
|
21850
|
-
const moduleDir =
|
|
21851
|
-
const leaf =
|
|
21987
|
+
const moduleDir = path44.dirname(modulePath);
|
|
21988
|
+
const leaf = path44.basename(moduleDir);
|
|
21852
21989
|
if (leaf === "commands" || leaf === "cli") {
|
|
21853
|
-
return
|
|
21990
|
+
return path44.resolve(moduleDir, "..", "..");
|
|
21854
21991
|
}
|
|
21855
21992
|
if (leaf === "dist") {
|
|
21856
|
-
return
|
|
21993
|
+
return path44.resolve(moduleDir, "..");
|
|
21857
21994
|
}
|
|
21858
|
-
return
|
|
21995
|
+
return path44.resolve(moduleDir, "..");
|
|
21859
21996
|
}
|
|
21860
21997
|
function formatMigrationResult(label, report) {
|
|
21861
21998
|
if (!report) {
|
|
@@ -22550,11 +22687,11 @@ var _internals36 = {
|
|
|
22550
22687
|
|
|
22551
22688
|
// src/services/preflight-service.ts
|
|
22552
22689
|
import * as fs24 from "fs";
|
|
22553
|
-
import * as
|
|
22690
|
+
import * as path51 from "path";
|
|
22554
22691
|
|
|
22555
22692
|
// src/tools/lint.ts
|
|
22556
22693
|
import * as fs18 from "fs";
|
|
22557
|
-
import * as
|
|
22694
|
+
import * as path45 from "path";
|
|
22558
22695
|
|
|
22559
22696
|
// src/utils/path-security.ts
|
|
22560
22697
|
function containsPathTraversal(str) {
|
|
@@ -22610,9 +22747,9 @@ function validateArgs(args) {
|
|
|
22610
22747
|
}
|
|
22611
22748
|
function getLinterCommand(linter, mode, projectDir) {
|
|
22612
22749
|
const isWindows = process.platform === "win32";
|
|
22613
|
-
const binDir =
|
|
22614
|
-
const biomeBin = isWindows ?
|
|
22615
|
-
const eslintBin = isWindows ?
|
|
22750
|
+
const binDir = path45.join(projectDir, "node_modules", ".bin");
|
|
22751
|
+
const biomeBin = isWindows ? path45.join(binDir, "biome.EXE") : path45.join(binDir, "biome");
|
|
22752
|
+
const eslintBin = isWindows ? path45.join(binDir, "eslint.cmd") : path45.join(binDir, "eslint");
|
|
22616
22753
|
switch (linter) {
|
|
22617
22754
|
case "biome":
|
|
22618
22755
|
if (mode === "fix") {
|
|
@@ -22628,7 +22765,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
22628
22765
|
}
|
|
22629
22766
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
22630
22767
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
22631
|
-
const gradlew = fs18.existsSync(
|
|
22768
|
+
const gradlew = fs18.existsSync(path45.join(cwd, gradlewName)) ? path45.join(cwd, gradlewName) : null;
|
|
22632
22769
|
switch (linter) {
|
|
22633
22770
|
case "ruff":
|
|
22634
22771
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -22662,10 +22799,10 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
22662
22799
|
}
|
|
22663
22800
|
}
|
|
22664
22801
|
function detectRuff(cwd) {
|
|
22665
|
-
if (fs18.existsSync(
|
|
22802
|
+
if (fs18.existsSync(path45.join(cwd, "ruff.toml")))
|
|
22666
22803
|
return isCommandAvailable("ruff");
|
|
22667
22804
|
try {
|
|
22668
|
-
const pyproject =
|
|
22805
|
+
const pyproject = path45.join(cwd, "pyproject.toml");
|
|
22669
22806
|
if (fs18.existsSync(pyproject)) {
|
|
22670
22807
|
const content = fs18.readFileSync(pyproject, "utf-8");
|
|
22671
22808
|
if (content.includes("[tool.ruff]"))
|
|
@@ -22675,19 +22812,19 @@ function detectRuff(cwd) {
|
|
|
22675
22812
|
return false;
|
|
22676
22813
|
}
|
|
22677
22814
|
function detectClippy(cwd) {
|
|
22678
|
-
return fs18.existsSync(
|
|
22815
|
+
return fs18.existsSync(path45.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
22679
22816
|
}
|
|
22680
22817
|
function detectGolangciLint(cwd) {
|
|
22681
|
-
return fs18.existsSync(
|
|
22818
|
+
return fs18.existsSync(path45.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
22682
22819
|
}
|
|
22683
22820
|
function detectCheckstyle(cwd) {
|
|
22684
|
-
const hasMaven = fs18.existsSync(
|
|
22685
|
-
const hasGradle = fs18.existsSync(
|
|
22686
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(
|
|
22821
|
+
const hasMaven = fs18.existsSync(path45.join(cwd, "pom.xml"));
|
|
22822
|
+
const hasGradle = fs18.existsSync(path45.join(cwd, "build.gradle")) || fs18.existsSync(path45.join(cwd, "build.gradle.kts"));
|
|
22823
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(path45.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
22687
22824
|
return (hasMaven || hasGradle) && hasBinary;
|
|
22688
22825
|
}
|
|
22689
22826
|
function detectKtlint(cwd) {
|
|
22690
|
-
const hasKotlin = fs18.existsSync(
|
|
22827
|
+
const hasKotlin = fs18.existsSync(path45.join(cwd, "build.gradle.kts")) || fs18.existsSync(path45.join(cwd, "build.gradle")) || (() => {
|
|
22691
22828
|
try {
|
|
22692
22829
|
return fs18.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
22693
22830
|
} catch {
|
|
@@ -22706,11 +22843,11 @@ function detectDotnetFormat(cwd) {
|
|
|
22706
22843
|
}
|
|
22707
22844
|
}
|
|
22708
22845
|
function detectCppcheck(cwd) {
|
|
22709
|
-
if (fs18.existsSync(
|
|
22846
|
+
if (fs18.existsSync(path45.join(cwd, "CMakeLists.txt"))) {
|
|
22710
22847
|
return isCommandAvailable("cppcheck");
|
|
22711
22848
|
}
|
|
22712
22849
|
try {
|
|
22713
|
-
const dirsToCheck = [cwd,
|
|
22850
|
+
const dirsToCheck = [cwd, path45.join(cwd, "src")];
|
|
22714
22851
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
22715
22852
|
try {
|
|
22716
22853
|
return fs18.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
@@ -22724,13 +22861,13 @@ function detectCppcheck(cwd) {
|
|
|
22724
22861
|
}
|
|
22725
22862
|
}
|
|
22726
22863
|
function detectSwiftlint(cwd) {
|
|
22727
|
-
return fs18.existsSync(
|
|
22864
|
+
return fs18.existsSync(path45.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
22728
22865
|
}
|
|
22729
22866
|
function detectDartAnalyze(cwd) {
|
|
22730
|
-
return fs18.existsSync(
|
|
22867
|
+
return fs18.existsSync(path45.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
22731
22868
|
}
|
|
22732
22869
|
function detectRubocop(cwd) {
|
|
22733
|
-
return (fs18.existsSync(
|
|
22870
|
+
return (fs18.existsSync(path45.join(cwd, "Gemfile")) || fs18.existsSync(path45.join(cwd, "gems.rb")) || fs18.existsSync(path45.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
22734
22871
|
}
|
|
22735
22872
|
function detectAdditionalLinter(cwd) {
|
|
22736
22873
|
if (detectRuff(cwd))
|
|
@@ -22758,10 +22895,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
22758
22895
|
function findBinInAncestors(startDir, binName) {
|
|
22759
22896
|
let dir = startDir;
|
|
22760
22897
|
while (true) {
|
|
22761
|
-
const candidate =
|
|
22898
|
+
const candidate = path45.join(dir, "node_modules", ".bin", binName);
|
|
22762
22899
|
if (fs18.existsSync(candidate))
|
|
22763
22900
|
return candidate;
|
|
22764
|
-
const parent =
|
|
22901
|
+
const parent = path45.dirname(dir);
|
|
22765
22902
|
if (parent === dir)
|
|
22766
22903
|
break;
|
|
22767
22904
|
dir = parent;
|
|
@@ -22770,10 +22907,10 @@ function findBinInAncestors(startDir, binName) {
|
|
|
22770
22907
|
}
|
|
22771
22908
|
function findBinInEnvPath(binName) {
|
|
22772
22909
|
const searchPath = process.env.PATH ?? "";
|
|
22773
|
-
for (const dir of searchPath.split(
|
|
22910
|
+
for (const dir of searchPath.split(path45.delimiter)) {
|
|
22774
22911
|
if (!dir)
|
|
22775
22912
|
continue;
|
|
22776
|
-
const candidate =
|
|
22913
|
+
const candidate = path45.join(dir, binName);
|
|
22777
22914
|
if (fs18.existsSync(candidate))
|
|
22778
22915
|
return candidate;
|
|
22779
22916
|
}
|
|
@@ -22786,13 +22923,13 @@ async function detectAvailableLinter(directory) {
|
|
|
22786
22923
|
return null;
|
|
22787
22924
|
const projectDir = directory;
|
|
22788
22925
|
const isWindows = process.platform === "win32";
|
|
22789
|
-
const biomeBin = isWindows ?
|
|
22790
|
-
const eslintBin = isWindows ?
|
|
22926
|
+
const biomeBin = isWindows ? path45.join(projectDir, "node_modules", ".bin", "biome.EXE") : path45.join(projectDir, "node_modules", ".bin", "biome");
|
|
22927
|
+
const eslintBin = isWindows ? path45.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path45.join(projectDir, "node_modules", ".bin", "eslint");
|
|
22791
22928
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
22792
22929
|
if (localResult)
|
|
22793
22930
|
return localResult;
|
|
22794
|
-
const biomeAncestor = findBinInAncestors(
|
|
22795
|
-
const eslintAncestor = findBinInAncestors(
|
|
22931
|
+
const biomeAncestor = findBinInAncestors(path45.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
22932
|
+
const eslintAncestor = findBinInAncestors(path45.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
22796
22933
|
if (biomeAncestor || eslintAncestor) {
|
|
22797
22934
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
22798
22935
|
}
|
|
@@ -23006,7 +23143,7 @@ var _internals37 = {
|
|
|
23006
23143
|
|
|
23007
23144
|
// src/tools/secretscan.ts
|
|
23008
23145
|
import * as fs19 from "fs";
|
|
23009
|
-
import * as
|
|
23146
|
+
import * as path46 from "path";
|
|
23010
23147
|
var MAX_FILE_PATH_LENGTH = 500;
|
|
23011
23148
|
var MAX_FILE_SIZE_BYTES = 512 * 1024;
|
|
23012
23149
|
var MAX_FILES_SCANNED = 1000;
|
|
@@ -23233,7 +23370,7 @@ function isGlobOrPathPattern(pattern) {
|
|
|
23233
23370
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
23234
23371
|
}
|
|
23235
23372
|
function loadSecretScanIgnore(scanDir) {
|
|
23236
|
-
const ignorePath =
|
|
23373
|
+
const ignorePath = path46.join(scanDir, ".secretscanignore");
|
|
23237
23374
|
try {
|
|
23238
23375
|
if (!fs19.existsSync(ignorePath))
|
|
23239
23376
|
return [];
|
|
@@ -23256,7 +23393,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
23256
23393
|
if (exactNames.has(entry))
|
|
23257
23394
|
return true;
|
|
23258
23395
|
for (const pattern of globPatterns) {
|
|
23259
|
-
if (
|
|
23396
|
+
if (path46.matchesGlob(relPath, pattern))
|
|
23260
23397
|
return true;
|
|
23261
23398
|
}
|
|
23262
23399
|
return false;
|
|
@@ -23277,7 +23414,7 @@ function validateDirectoryInput(dir) {
|
|
|
23277
23414
|
return null;
|
|
23278
23415
|
}
|
|
23279
23416
|
function isBinaryFile(filePath, buffer) {
|
|
23280
|
-
const ext =
|
|
23417
|
+
const ext = path46.extname(filePath).toLowerCase();
|
|
23281
23418
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
23282
23419
|
return true;
|
|
23283
23420
|
}
|
|
@@ -23414,9 +23551,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
23414
23551
|
return false;
|
|
23415
23552
|
}
|
|
23416
23553
|
function isPathWithinScope(realPath, scanDir) {
|
|
23417
|
-
const resolvedScanDir =
|
|
23418
|
-
const resolvedRealPath =
|
|
23419
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
23554
|
+
const resolvedScanDir = path46.resolve(scanDir);
|
|
23555
|
+
const resolvedRealPath = path46.resolve(realPath);
|
|
23556
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path46.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
23420
23557
|
}
|
|
23421
23558
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
23422
23559
|
skippedDirs: 0,
|
|
@@ -23442,8 +23579,8 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
23442
23579
|
return a.localeCompare(b);
|
|
23443
23580
|
});
|
|
23444
23581
|
for (const entry of entries) {
|
|
23445
|
-
const fullPath =
|
|
23446
|
-
const relPath =
|
|
23582
|
+
const fullPath = path46.join(dir, entry);
|
|
23583
|
+
const relPath = path46.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
23447
23584
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
23448
23585
|
stats.skippedDirs++;
|
|
23449
23586
|
continue;
|
|
@@ -23478,7 +23615,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
23478
23615
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
23479
23616
|
files.push(...subFiles);
|
|
23480
23617
|
} else if (lstat2.isFile()) {
|
|
23481
|
-
const ext =
|
|
23618
|
+
const ext = path46.extname(fullPath).toLowerCase();
|
|
23482
23619
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
23483
23620
|
files.push(fullPath);
|
|
23484
23621
|
} else {
|
|
@@ -23544,7 +23681,7 @@ var secretscan = createSwarmTool({
|
|
|
23544
23681
|
}
|
|
23545
23682
|
}
|
|
23546
23683
|
try {
|
|
23547
|
-
const _scanDirRaw =
|
|
23684
|
+
const _scanDirRaw = path46.resolve(directory);
|
|
23548
23685
|
const scanDir = (() => {
|
|
23549
23686
|
try {
|
|
23550
23687
|
return fs19.realpathSync(_scanDirRaw);
|
|
@@ -23707,11 +23844,11 @@ var _internals38 = {
|
|
|
23707
23844
|
|
|
23708
23845
|
// src/tools/test-runner.ts
|
|
23709
23846
|
import * as fs23 from "fs";
|
|
23710
|
-
import * as
|
|
23847
|
+
import * as path50 from "path";
|
|
23711
23848
|
|
|
23712
23849
|
// src/test-impact/analyzer.ts
|
|
23713
23850
|
import fs20 from "fs";
|
|
23714
|
-
import
|
|
23851
|
+
import path47 from "path";
|
|
23715
23852
|
var IMPORT_REGEX_ES = /import\s+[\s\S]*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
23716
23853
|
var IMPORT_REGEX_REQUIRE = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
23717
23854
|
var IMPORT_REGEX_REEXPORT = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
@@ -23752,8 +23889,8 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
23752
23889
|
if (!importPath.startsWith(".")) {
|
|
23753
23890
|
return null;
|
|
23754
23891
|
}
|
|
23755
|
-
const resolved =
|
|
23756
|
-
if (
|
|
23892
|
+
const resolved = path47.resolve(fromDir, importPath);
|
|
23893
|
+
if (path47.extname(resolved)) {
|
|
23757
23894
|
if (fs20.existsSync(resolved) && fs20.statSync(resolved).isFile()) {
|
|
23758
23895
|
return normalizePath2(resolved);
|
|
23759
23896
|
}
|
|
@@ -23773,20 +23910,20 @@ function resolvePythonImport(fromDir, module) {
|
|
|
23773
23910
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
23774
23911
|
let baseDir = fromDir;
|
|
23775
23912
|
for (let i = 1;i < leadingDots; i++) {
|
|
23776
|
-
baseDir =
|
|
23913
|
+
baseDir = path47.dirname(baseDir);
|
|
23777
23914
|
}
|
|
23778
23915
|
const rest = module.slice(leadingDots);
|
|
23779
23916
|
if (rest.length === 0) {
|
|
23780
|
-
const initPath =
|
|
23917
|
+
const initPath = path47.join(baseDir, "__init__.py");
|
|
23781
23918
|
if (fs20.existsSync(initPath) && fs20.statSync(initPath).isFile()) {
|
|
23782
23919
|
return normalizePath2(initPath);
|
|
23783
23920
|
}
|
|
23784
23921
|
return null;
|
|
23785
23922
|
}
|
|
23786
|
-
const subpath = rest.replace(/\./g,
|
|
23923
|
+
const subpath = rest.replace(/\./g, path47.sep);
|
|
23787
23924
|
const candidates = [
|
|
23788
|
-
`${
|
|
23789
|
-
|
|
23925
|
+
`${path47.join(baseDir, subpath)}.py`,
|
|
23926
|
+
path47.join(baseDir, subpath, "__init__.py")
|
|
23790
23927
|
];
|
|
23791
23928
|
for (const c of candidates) {
|
|
23792
23929
|
if (fs20.existsSync(c) && fs20.statSync(c).isFile())
|
|
@@ -23796,7 +23933,7 @@ function resolvePythonImport(fromDir, module) {
|
|
|
23796
23933
|
}
|
|
23797
23934
|
var goModuleCache = new Map;
|
|
23798
23935
|
function findGoModule(fromDir) {
|
|
23799
|
-
const resolved =
|
|
23936
|
+
const resolved = path47.resolve(fromDir);
|
|
23800
23937
|
let cur = resolved;
|
|
23801
23938
|
const walked = [];
|
|
23802
23939
|
for (let i = 0;i < 16; i++) {
|
|
@@ -23808,7 +23945,7 @@ function findGoModule(fromDir) {
|
|
|
23808
23945
|
}
|
|
23809
23946
|
walked.push(cur);
|
|
23810
23947
|
try {
|
|
23811
|
-
const goMod =
|
|
23948
|
+
const goMod = path47.join(cur, "go.mod");
|
|
23812
23949
|
const content = fs20.readFileSync(goMod, "utf-8");
|
|
23813
23950
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
23814
23951
|
if (moduleMatch) {
|
|
@@ -23819,10 +23956,10 @@ function findGoModule(fromDir) {
|
|
|
23819
23956
|
}
|
|
23820
23957
|
} catch {}
|
|
23821
23958
|
try {
|
|
23822
|
-
fs20.accessSync(
|
|
23959
|
+
fs20.accessSync(path47.join(cur, ".git"));
|
|
23823
23960
|
break;
|
|
23824
23961
|
} catch {}
|
|
23825
|
-
const parent =
|
|
23962
|
+
const parent = path47.dirname(cur);
|
|
23826
23963
|
if (parent === cur)
|
|
23827
23964
|
break;
|
|
23828
23965
|
cur = parent;
|
|
@@ -23834,12 +23971,12 @@ function findGoModule(fromDir) {
|
|
|
23834
23971
|
function resolveGoImport(fromDir, importPath) {
|
|
23835
23972
|
let dir = null;
|
|
23836
23973
|
if (importPath.startsWith(".")) {
|
|
23837
|
-
dir =
|
|
23974
|
+
dir = path47.resolve(fromDir, importPath);
|
|
23838
23975
|
} else {
|
|
23839
23976
|
const mod = findGoModule(fromDir);
|
|
23840
23977
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
23841
23978
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
23842
|
-
dir =
|
|
23979
|
+
dir = path47.join(mod.moduleRoot, subpath);
|
|
23843
23980
|
}
|
|
23844
23981
|
}
|
|
23845
23982
|
if (dir === null)
|
|
@@ -23847,7 +23984,7 @@ function resolveGoImport(fromDir, importPath) {
|
|
|
23847
23984
|
if (!fs20.existsSync(dir) || !fs20.statSync(dir).isDirectory())
|
|
23848
23985
|
return [];
|
|
23849
23986
|
try {
|
|
23850
|
-
return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(
|
|
23987
|
+
return fs20.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath2(path47.join(dir, f)));
|
|
23851
23988
|
} catch {
|
|
23852
23989
|
return [];
|
|
23853
23990
|
}
|
|
@@ -23886,15 +24023,15 @@ function findTestFilesSync(cwd) {
|
|
|
23886
24023
|
for (const entry of entries) {
|
|
23887
24024
|
if (entry.isDirectory()) {
|
|
23888
24025
|
if (!skipDirs.has(entry.name)) {
|
|
23889
|
-
walk(
|
|
24026
|
+
walk(path47.join(dir, entry.name), visitedInodes);
|
|
23890
24027
|
}
|
|
23891
24028
|
} else if (entry.isFile()) {
|
|
23892
24029
|
const name = entry.name;
|
|
23893
24030
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
23894
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
24031
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path47.sep}tests${path47.sep}`) && name.endsWith(".py");
|
|
23895
24032
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
23896
24033
|
if (isTsTest || isPyTest || isGoTest) {
|
|
23897
|
-
testFiles.push(normalizePath2(
|
|
24034
|
+
testFiles.push(normalizePath2(path47.join(dir, entry.name)));
|
|
23898
24035
|
}
|
|
23899
24036
|
}
|
|
23900
24037
|
}
|
|
@@ -23919,8 +24056,8 @@ function extractImports(content) {
|
|
|
23919
24056
|
];
|
|
23920
24057
|
}
|
|
23921
24058
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
23922
|
-
const ext =
|
|
23923
|
-
const testDir =
|
|
24059
|
+
const ext = path47.extname(testFile).toLowerCase();
|
|
24060
|
+
const testDir = path47.dirname(testFile);
|
|
23924
24061
|
function addEdge(source) {
|
|
23925
24062
|
if (!impactMap[source])
|
|
23926
24063
|
impactMap[source] = [];
|
|
@@ -23993,7 +24130,7 @@ async function buildImpactMap(cwd) {
|
|
|
23993
24130
|
return impactMap;
|
|
23994
24131
|
}
|
|
23995
24132
|
async function loadImpactMap(cwd, options) {
|
|
23996
|
-
const cachePath =
|
|
24133
|
+
const cachePath = path47.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
23997
24134
|
if (fs20.existsSync(cachePath)) {
|
|
23998
24135
|
try {
|
|
23999
24136
|
const content = fs20.readFileSync(cachePath, "utf-8");
|
|
@@ -24026,12 +24163,12 @@ async function loadImpactMap(cwd, options) {
|
|
|
24026
24163
|
return _internals39.buildImpactMap(cwd);
|
|
24027
24164
|
}
|
|
24028
24165
|
async function saveImpactMap(cwd, impactMap) {
|
|
24029
|
-
if (!
|
|
24166
|
+
if (!path47.isAbsolute(cwd)) {
|
|
24030
24167
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
24031
24168
|
}
|
|
24032
24169
|
_internals39.validateProjectRoot(cwd);
|
|
24033
|
-
const cacheDir2 =
|
|
24034
|
-
const cachePath =
|
|
24170
|
+
const cacheDir2 = path47.join(cwd, ".swarm", "cache");
|
|
24171
|
+
const cachePath = path47.join(cacheDir2, "impact-map.json");
|
|
24035
24172
|
if (!fs20.existsSync(cacheDir2)) {
|
|
24036
24173
|
fs20.mkdirSync(cacheDir2, { recursive: true });
|
|
24037
24174
|
}
|
|
@@ -24063,7 +24200,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
24063
24200
|
budgetExceeded = true;
|
|
24064
24201
|
break;
|
|
24065
24202
|
}
|
|
24066
|
-
const normalizedChanged = normalizePath2(
|
|
24203
|
+
const normalizedChanged = normalizePath2(path47.resolve(changedFile));
|
|
24067
24204
|
const tests = impactMap[normalizedChanged];
|
|
24068
24205
|
if (tests && tests.length > 0) {
|
|
24069
24206
|
for (const test of tests) {
|
|
@@ -24077,13 +24214,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
24077
24214
|
if (budgetExceeded)
|
|
24078
24215
|
break;
|
|
24079
24216
|
} else {
|
|
24080
|
-
const changedDir = normalizePath2(
|
|
24081
|
-
const changedInputDir = normalizePath2(
|
|
24217
|
+
const changedDir = normalizePath2(path47.dirname(normalizedChanged));
|
|
24218
|
+
const changedInputDir = normalizePath2(path47.dirname(changedFile));
|
|
24082
24219
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
24083
24220
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
24084
24221
|
}).sort(([sourceA], [sourceB]) => {
|
|
24085
|
-
const sourceDirA = normalizePath2(
|
|
24086
|
-
const sourceDirB = normalizePath2(
|
|
24222
|
+
const sourceDirA = normalizePath2(path47.dirname(sourceA));
|
|
24223
|
+
const sourceDirB = normalizePath2(path47.dirname(sourceB));
|
|
24087
24224
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
24088
24225
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
24089
24226
|
if (exactA !== exactB)
|
|
@@ -24410,7 +24547,7 @@ function detectFlakyTests(allHistory) {
|
|
|
24410
24547
|
|
|
24411
24548
|
// src/test-impact/history-store.ts
|
|
24412
24549
|
import fs21 from "fs";
|
|
24413
|
-
import
|
|
24550
|
+
import path48 from "path";
|
|
24414
24551
|
var MAX_HISTORY_PER_TEST = 20;
|
|
24415
24552
|
var MAX_ERROR_LENGTH = 500;
|
|
24416
24553
|
var MAX_STACK_LENGTH = 200;
|
|
@@ -24422,10 +24559,10 @@ function getHistoryPath(workingDir) {
|
|
|
24422
24559
|
if (!workingDir) {
|
|
24423
24560
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
24424
24561
|
}
|
|
24425
|
-
if (!
|
|
24562
|
+
if (!path48.isAbsolute(workingDir)) {
|
|
24426
24563
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
24427
24564
|
}
|
|
24428
|
-
return
|
|
24565
|
+
return path48.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
24429
24566
|
}
|
|
24430
24567
|
function sanitizeErrorMessage(errorMessage) {
|
|
24431
24568
|
if (errorMessage === undefined) {
|
|
@@ -24517,7 +24654,7 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
24517
24654
|
}
|
|
24518
24655
|
}
|
|
24519
24656
|
const historyPath = getHistoryPath(workingDir);
|
|
24520
|
-
const historyDir =
|
|
24657
|
+
const historyDir = path48.dirname(historyPath);
|
|
24521
24658
|
_internals40.validateProjectRoot(workingDir);
|
|
24522
24659
|
if (!fs21.existsSync(historyDir)) {
|
|
24523
24660
|
fs21.mkdirSync(historyDir, { recursive: true });
|
|
@@ -24647,7 +24784,7 @@ var _internals40 = {
|
|
|
24647
24784
|
|
|
24648
24785
|
// src/tools/resolve-working-directory.ts
|
|
24649
24786
|
import * as fs22 from "fs";
|
|
24650
|
-
import * as
|
|
24787
|
+
import * as path49 from "path";
|
|
24651
24788
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
24652
24789
|
if (workingDirectory == null || workingDirectory === "") {
|
|
24653
24790
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -24679,15 +24816,15 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24679
24816
|
};
|
|
24680
24817
|
}
|
|
24681
24818
|
}
|
|
24682
|
-
const rawPathParts = workingDirectory.split(
|
|
24819
|
+
const rawPathParts = workingDirectory.split(path49.sep);
|
|
24683
24820
|
if (rawPathParts.includes("..")) {
|
|
24684
24821
|
return {
|
|
24685
24822
|
success: false,
|
|
24686
24823
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
24687
24824
|
};
|
|
24688
24825
|
}
|
|
24689
|
-
const normalizedDir =
|
|
24690
|
-
const resolvedDir =
|
|
24826
|
+
const normalizedDir = path49.normalize(workingDirectory);
|
|
24827
|
+
const resolvedDir = path49.resolve(normalizedDir);
|
|
24691
24828
|
let statResult;
|
|
24692
24829
|
try {
|
|
24693
24830
|
statResult = fs22.statSync(resolvedDir);
|
|
@@ -24706,7 +24843,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24706
24843
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
24707
24844
|
return { success: true, directory: resolvedDir };
|
|
24708
24845
|
}
|
|
24709
|
-
const resolvedFallback =
|
|
24846
|
+
const resolvedFallback = path49.resolve(fallbackDirectory);
|
|
24710
24847
|
let fallbackExists = false;
|
|
24711
24848
|
try {
|
|
24712
24849
|
fs22.statSync(resolvedFallback);
|
|
@@ -24715,7 +24852,7 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
24715
24852
|
fallbackExists = false;
|
|
24716
24853
|
}
|
|
24717
24854
|
if (fallbackExists) {
|
|
24718
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
24855
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path49.sep);
|
|
24719
24856
|
if (isSubdirectory) {
|
|
24720
24857
|
return {
|
|
24721
24858
|
success: false,
|
|
@@ -24738,7 +24875,7 @@ async function estimateFanOut(sourceFiles, cwd) {
|
|
|
24738
24875
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
24739
24876
|
const uniqueTestFiles = new Set;
|
|
24740
24877
|
for (const sourceFile of sourceFiles) {
|
|
24741
|
-
const resolvedPath =
|
|
24878
|
+
const resolvedPath = path50.resolve(cwd, sourceFile);
|
|
24742
24879
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
24743
24880
|
const testFiles = impactMap[normalizedPath];
|
|
24744
24881
|
if (testFiles) {
|
|
@@ -24823,14 +24960,14 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
24823
24960
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
24824
24961
|
}
|
|
24825
24962
|
function detectGoTest(cwd) {
|
|
24826
|
-
return fs23.existsSync(
|
|
24963
|
+
return fs23.existsSync(path50.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
24827
24964
|
}
|
|
24828
24965
|
function detectJavaMaven(cwd) {
|
|
24829
|
-
return fs23.existsSync(
|
|
24966
|
+
return fs23.existsSync(path50.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
24830
24967
|
}
|
|
24831
24968
|
function detectGradle(cwd) {
|
|
24832
|
-
const hasBuildFile = fs23.existsSync(
|
|
24833
|
-
const hasGradlew = fs23.existsSync(
|
|
24969
|
+
const hasBuildFile = fs23.existsSync(path50.join(cwd, "build.gradle")) || fs23.existsSync(path50.join(cwd, "build.gradle.kts"));
|
|
24970
|
+
const hasGradlew = fs23.existsSync(path50.join(cwd, "gradlew")) || fs23.existsSync(path50.join(cwd, "gradlew.bat"));
|
|
24834
24971
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
24835
24972
|
}
|
|
24836
24973
|
function detectDotnetTest(cwd) {
|
|
@@ -24843,25 +24980,25 @@ function detectDotnetTest(cwd) {
|
|
|
24843
24980
|
}
|
|
24844
24981
|
}
|
|
24845
24982
|
function detectCTest(cwd) {
|
|
24846
|
-
const hasSource = fs23.existsSync(
|
|
24847
|
-
const hasBuildCache = fs23.existsSync(
|
|
24983
|
+
const hasSource = fs23.existsSync(path50.join(cwd, "CMakeLists.txt"));
|
|
24984
|
+
const hasBuildCache = fs23.existsSync(path50.join(cwd, "CMakeCache.txt")) || fs23.existsSync(path50.join(cwd, "build", "CMakeCache.txt"));
|
|
24848
24985
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
24849
24986
|
}
|
|
24850
24987
|
function detectSwiftTest(cwd) {
|
|
24851
|
-
return fs23.existsSync(
|
|
24988
|
+
return fs23.existsSync(path50.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
24852
24989
|
}
|
|
24853
24990
|
function detectDartTest(cwd) {
|
|
24854
|
-
return fs23.existsSync(
|
|
24991
|
+
return fs23.existsSync(path50.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
24855
24992
|
}
|
|
24856
24993
|
function detectRSpec(cwd) {
|
|
24857
|
-
const hasRSpecFile = fs23.existsSync(
|
|
24858
|
-
const hasGemfile = fs23.existsSync(
|
|
24859
|
-
const hasSpecDir = fs23.existsSync(
|
|
24994
|
+
const hasRSpecFile = fs23.existsSync(path50.join(cwd, ".rspec"));
|
|
24995
|
+
const hasGemfile = fs23.existsSync(path50.join(cwd, "Gemfile"));
|
|
24996
|
+
const hasSpecDir = fs23.existsSync(path50.join(cwd, "spec"));
|
|
24860
24997
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
24861
24998
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
24862
24999
|
}
|
|
24863
25000
|
function detectMinitest(cwd) {
|
|
24864
|
-
return fs23.existsSync(
|
|
25001
|
+
return fs23.existsSync(path50.join(cwd, "test")) && (fs23.existsSync(path50.join(cwd, "Gemfile")) || fs23.existsSync(path50.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
24865
25002
|
}
|
|
24866
25003
|
var DISPATCH_FRAMEWORK_MAP = {
|
|
24867
25004
|
bun: "bun",
|
|
@@ -24946,7 +25083,7 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
24946
25083
|
async function detectTestFramework(cwd) {
|
|
24947
25084
|
const baseDir = cwd;
|
|
24948
25085
|
try {
|
|
24949
|
-
const packageJsonPath =
|
|
25086
|
+
const packageJsonPath = path50.join(baseDir, "package.json");
|
|
24950
25087
|
if (fs23.existsSync(packageJsonPath)) {
|
|
24951
25088
|
const content = fs23.readFileSync(packageJsonPath, "utf-8");
|
|
24952
25089
|
const pkg = JSON.parse(content);
|
|
@@ -24967,16 +25104,16 @@ async function detectTestFramework(cwd) {
|
|
|
24967
25104
|
return "jest";
|
|
24968
25105
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
24969
25106
|
return "mocha";
|
|
24970
|
-
if (fs23.existsSync(
|
|
25107
|
+
if (fs23.existsSync(path50.join(baseDir, "bun.lockb")) || fs23.existsSync(path50.join(baseDir, "bun.lock"))) {
|
|
24971
25108
|
if (scripts.test?.includes("bun"))
|
|
24972
25109
|
return "bun";
|
|
24973
25110
|
}
|
|
24974
25111
|
}
|
|
24975
25112
|
} catch {}
|
|
24976
25113
|
try {
|
|
24977
|
-
const pyprojectTomlPath =
|
|
24978
|
-
const setupCfgPath =
|
|
24979
|
-
const requirementsTxtPath =
|
|
25114
|
+
const pyprojectTomlPath = path50.join(baseDir, "pyproject.toml");
|
|
25115
|
+
const setupCfgPath = path50.join(baseDir, "setup.cfg");
|
|
25116
|
+
const requirementsTxtPath = path50.join(baseDir, "requirements.txt");
|
|
24980
25117
|
if (fs23.existsSync(pyprojectTomlPath)) {
|
|
24981
25118
|
const content = fs23.readFileSync(pyprojectTomlPath, "utf-8");
|
|
24982
25119
|
if (content.includes("[tool.pytest"))
|
|
@@ -24996,7 +25133,7 @@ async function detectTestFramework(cwd) {
|
|
|
24996
25133
|
}
|
|
24997
25134
|
} catch {}
|
|
24998
25135
|
try {
|
|
24999
|
-
const cargoTomlPath =
|
|
25136
|
+
const cargoTomlPath = path50.join(baseDir, "Cargo.toml");
|
|
25000
25137
|
if (fs23.existsSync(cargoTomlPath)) {
|
|
25001
25138
|
const content = fs23.readFileSync(cargoTomlPath, "utf-8");
|
|
25002
25139
|
if (content.includes("[dev-dependencies]")) {
|
|
@@ -25007,9 +25144,9 @@ async function detectTestFramework(cwd) {
|
|
|
25007
25144
|
}
|
|
25008
25145
|
} catch {}
|
|
25009
25146
|
try {
|
|
25010
|
-
const pesterConfigPath =
|
|
25011
|
-
const pesterConfigJsonPath =
|
|
25012
|
-
const pesterPs1Path =
|
|
25147
|
+
const pesterConfigPath = path50.join(baseDir, "pester.config.ps1");
|
|
25148
|
+
const pesterConfigJsonPath = path50.join(baseDir, "pester.config.ps1.json");
|
|
25149
|
+
const pesterPs1Path = path50.join(baseDir, "tests.ps1");
|
|
25013
25150
|
if (fs23.existsSync(pesterConfigPath) || fs23.existsSync(pesterConfigJsonPath) || fs23.existsSync(pesterPs1Path)) {
|
|
25014
25151
|
return "pester";
|
|
25015
25152
|
}
|
|
@@ -25052,12 +25189,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
25052
25189
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
25053
25190
|
}
|
|
25054
25191
|
function resolveWorkspacePath(file, workingDir) {
|
|
25055
|
-
return
|
|
25192
|
+
return path50.isAbsolute(file) ? path50.resolve(file) : path50.resolve(workingDir, file);
|
|
25056
25193
|
}
|
|
25057
25194
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
25058
25195
|
if (!preferRelative)
|
|
25059
25196
|
return absolutePath;
|
|
25060
|
-
return
|
|
25197
|
+
return path50.relative(workingDir, absolutePath);
|
|
25061
25198
|
}
|
|
25062
25199
|
function dedupePush(target, value) {
|
|
25063
25200
|
if (!target.includes(value)) {
|
|
@@ -25094,18 +25231,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
25094
25231
|
}
|
|
25095
25232
|
}
|
|
25096
25233
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
25097
|
-
const relativeDir =
|
|
25234
|
+
const relativeDir = path50.dirname(relativePath);
|
|
25098
25235
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
25099
25236
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
25100
|
-
const rootDir =
|
|
25101
|
-
return nestedRelativeDir ? [rootDir,
|
|
25237
|
+
const rootDir = path50.join(workingDir, dirName);
|
|
25238
|
+
return nestedRelativeDir ? [rootDir, path50.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
25102
25239
|
});
|
|
25103
25240
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
25104
25241
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
25105
|
-
directories.push(
|
|
25242
|
+
directories.push(path50.join(workingDir, "src/test/java", path50.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
25106
25243
|
}
|
|
25107
25244
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
25108
|
-
directories.push(
|
|
25245
|
+
directories.push(path50.join(workingDir, "src/test/kotlin", path50.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
25109
25246
|
}
|
|
25110
25247
|
return [...new Set(directories)];
|
|
25111
25248
|
}
|
|
@@ -25133,23 +25270,23 @@ function isLanguageSpecificTestFile(basename9) {
|
|
|
25133
25270
|
}
|
|
25134
25271
|
function isConventionTestFilePath(filePath) {
|
|
25135
25272
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
25136
|
-
const basename9 =
|
|
25273
|
+
const basename9 = path50.basename(filePath);
|
|
25137
25274
|
return hasCompoundTestExtension(basename9) || basename9.includes(".spec.") || basename9.includes(".test.") || isLanguageSpecificTestFile(basename9) || isTestDirectoryPath(normalizedPath);
|
|
25138
25275
|
}
|
|
25139
25276
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
25140
25277
|
const testFiles = [];
|
|
25141
25278
|
for (const file of sourceFiles) {
|
|
25142
25279
|
const absoluteFile = resolveWorkspacePath(file, workingDir);
|
|
25143
|
-
const relativeFile =
|
|
25144
|
-
const basename9 =
|
|
25145
|
-
const
|
|
25146
|
-
const preferRelativeOutput = !
|
|
25280
|
+
const relativeFile = path50.relative(workingDir, absoluteFile);
|
|
25281
|
+
const basename9 = path50.basename(absoluteFile);
|
|
25282
|
+
const dirname24 = path50.dirname(absoluteFile);
|
|
25283
|
+
const preferRelativeOutput = !path50.isAbsolute(file);
|
|
25147
25284
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file)) {
|
|
25148
25285
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
25149
25286
|
continue;
|
|
25150
25287
|
}
|
|
25151
25288
|
const nameWithoutExt = basename9.replace(/\.[^.]+$/, "");
|
|
25152
|
-
const ext =
|
|
25289
|
+
const ext = path50.extname(basename9);
|
|
25153
25290
|
const genericTestNames = [
|
|
25154
25291
|
`${nameWithoutExt}.spec${ext}`,
|
|
25155
25292
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -25158,7 +25295,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
25158
25295
|
const colocatedCandidates = [
|
|
25159
25296
|
...genericTestNames,
|
|
25160
25297
|
...languageSpecificTestNames
|
|
25161
|
-
].map((candidateName) =>
|
|
25298
|
+
].map((candidateName) => path50.join(dirname24, candidateName));
|
|
25162
25299
|
const testDirectoryNames = [
|
|
25163
25300
|
basename9,
|
|
25164
25301
|
...genericTestNames,
|
|
@@ -25167,8 +25304,8 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
25167
25304
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
25168
25305
|
const possibleTestFiles = [
|
|
25169
25306
|
...colocatedCandidates,
|
|
25170
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
25171
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
25307
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path50.join(dirname24, dirName, candidateName))),
|
|
25308
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path50.join(candidateDir, candidateName)))
|
|
25172
25309
|
];
|
|
25173
25310
|
for (const testFile of possibleTestFiles) {
|
|
25174
25311
|
if (fs23.existsSync(testFile)) {
|
|
@@ -25189,7 +25326,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25189
25326
|
try {
|
|
25190
25327
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
25191
25328
|
const content = fs23.readFileSync(absoluteTestFile, "utf-8");
|
|
25192
|
-
const testDir =
|
|
25329
|
+
const testDir = path50.dirname(absoluteTestFile);
|
|
25193
25330
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
25194
25331
|
let match;
|
|
25195
25332
|
match = importRegex.exec(content);
|
|
@@ -25197,8 +25334,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25197
25334
|
const importPath = match[1];
|
|
25198
25335
|
let resolvedImport;
|
|
25199
25336
|
if (importPath.startsWith(".")) {
|
|
25200
|
-
resolvedImport =
|
|
25201
|
-
const existingExt =
|
|
25337
|
+
resolvedImport = path50.resolve(testDir, importPath);
|
|
25338
|
+
const existingExt = path50.extname(resolvedImport);
|
|
25202
25339
|
if (!existingExt) {
|
|
25203
25340
|
for (const extToTry of [
|
|
25204
25341
|
".ts",
|
|
@@ -25218,12 +25355,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25218
25355
|
} else {
|
|
25219
25356
|
continue;
|
|
25220
25357
|
}
|
|
25221
|
-
const importBasename =
|
|
25222
|
-
const importDir =
|
|
25358
|
+
const importBasename = path50.basename(resolvedImport, path50.extname(resolvedImport));
|
|
25359
|
+
const importDir = path50.dirname(resolvedImport);
|
|
25223
25360
|
for (const sourceFile of absoluteSourceFiles) {
|
|
25224
|
-
const sourceDir =
|
|
25225
|
-
const sourceBasename =
|
|
25226
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
25361
|
+
const sourceDir = path50.dirname(sourceFile);
|
|
25362
|
+
const sourceBasename = path50.basename(sourceFile, path50.extname(sourceFile));
|
|
25363
|
+
const isRelatedDir = importDir === sourceDir || importDir === path50.join(sourceDir, "__tests__") || importDir === path50.join(sourceDir, "tests") || importDir === path50.join(sourceDir, "test") || importDir === path50.join(sourceDir, "spec");
|
|
25227
25364
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
25228
25365
|
dedupePush(testFiles, testFile);
|
|
25229
25366
|
break;
|
|
@@ -25236,8 +25373,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25236
25373
|
while (match !== null) {
|
|
25237
25374
|
const importPath = match[1];
|
|
25238
25375
|
if (importPath.startsWith(".")) {
|
|
25239
|
-
let resolvedImport =
|
|
25240
|
-
const existingExt =
|
|
25376
|
+
let resolvedImport = path50.resolve(testDir, importPath);
|
|
25377
|
+
const existingExt = path50.extname(resolvedImport);
|
|
25241
25378
|
if (!existingExt) {
|
|
25242
25379
|
for (const extToTry of [
|
|
25243
25380
|
".ts",
|
|
@@ -25254,12 +25391,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
25254
25391
|
}
|
|
25255
25392
|
}
|
|
25256
25393
|
}
|
|
25257
|
-
const importDir =
|
|
25258
|
-
const importBasename =
|
|
25394
|
+
const importDir = path50.dirname(resolvedImport);
|
|
25395
|
+
const importBasename = path50.basename(resolvedImport, path50.extname(resolvedImport));
|
|
25259
25396
|
for (const sourceFile of absoluteSourceFiles) {
|
|
25260
|
-
const sourceDir =
|
|
25261
|
-
const sourceBasename =
|
|
25262
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
25397
|
+
const sourceDir = path50.dirname(sourceFile);
|
|
25398
|
+
const sourceBasename = path50.basename(sourceFile, path50.extname(sourceFile));
|
|
25399
|
+
const isRelatedDir = importDir === sourceDir || importDir === path50.join(sourceDir, "__tests__") || importDir === path50.join(sourceDir, "tests") || importDir === path50.join(sourceDir, "test") || importDir === path50.join(sourceDir, "spec");
|
|
25263
25400
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
25264
25401
|
dedupePush(testFiles, testFile);
|
|
25265
25402
|
break;
|
|
@@ -25379,8 +25516,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
25379
25516
|
return ["mvn", "test"];
|
|
25380
25517
|
case "gradle": {
|
|
25381
25518
|
const isWindows = process.platform === "win32";
|
|
25382
|
-
const hasGradlewBat = fs23.existsSync(
|
|
25383
|
-
const hasGradlew = fs23.existsSync(
|
|
25519
|
+
const hasGradlewBat = fs23.existsSync(path50.join(baseDir, "gradlew.bat"));
|
|
25520
|
+
const hasGradlew = fs23.existsSync(path50.join(baseDir, "gradlew"));
|
|
25384
25521
|
if (hasGradlewBat && isWindows)
|
|
25385
25522
|
return ["gradlew.bat", "test"];
|
|
25386
25523
|
if (hasGradlew)
|
|
@@ -25397,7 +25534,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir, bail) {
|
|
|
25397
25534
|
"cmake-build-release",
|
|
25398
25535
|
"out"
|
|
25399
25536
|
];
|
|
25400
|
-
const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(
|
|
25537
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(path50.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
25401
25538
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
25402
25539
|
}
|
|
25403
25540
|
case "swift-test":
|
|
@@ -25831,11 +25968,11 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
25831
25968
|
};
|
|
25832
25969
|
}
|
|
25833
25970
|
const startTime = Date.now();
|
|
25834
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
25971
|
+
const vitestJsonOutputPath = framework === "vitest" ? path50.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
25835
25972
|
try {
|
|
25836
25973
|
if (vitestJsonOutputPath) {
|
|
25837
25974
|
try {
|
|
25838
|
-
fs23.mkdirSync(
|
|
25975
|
+
fs23.mkdirSync(path50.dirname(vitestJsonOutputPath), { recursive: true });
|
|
25839
25976
|
if (fs23.existsSync(vitestJsonOutputPath)) {
|
|
25840
25977
|
fs23.unlinkSync(vitestJsonOutputPath);
|
|
25841
25978
|
}
|
|
@@ -26003,10 +26140,10 @@ var SKIP_DIRECTORIES = new Set([
|
|
|
26003
26140
|
]);
|
|
26004
26141
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
26005
26142
|
const normalized = testFile.replace(/\\/g, "/");
|
|
26006
|
-
if (!
|
|
26143
|
+
if (!path50.isAbsolute(testFile))
|
|
26007
26144
|
return normalized;
|
|
26008
|
-
const relative8 =
|
|
26009
|
-
if (relative8.startsWith("..") ||
|
|
26145
|
+
const relative8 = path50.relative(workingDir, testFile);
|
|
26146
|
+
if (relative8.startsWith("..") || path50.isAbsolute(relative8)) {
|
|
26010
26147
|
return normalized;
|
|
26011
26148
|
}
|
|
26012
26149
|
return relative8.replace(/\\/g, "/");
|
|
@@ -26245,7 +26382,7 @@ var test_runner = createSwarmTool({
|
|
|
26245
26382
|
const sourceFiles = args.files.filter((file) => {
|
|
26246
26383
|
if (directTestFiles.includes(file))
|
|
26247
26384
|
return false;
|
|
26248
|
-
const ext =
|
|
26385
|
+
const ext = path50.extname(file).toLowerCase();
|
|
26249
26386
|
return SOURCE_EXTENSIONS.has(ext);
|
|
26250
26387
|
});
|
|
26251
26388
|
const invalidFiles = args.files.filter((file) => !directTestFiles.includes(file) && !sourceFiles.includes(file));
|
|
@@ -26291,7 +26428,7 @@ var test_runner = createSwarmTool({
|
|
|
26291
26428
|
if (isConventionTestFilePath(f)) {
|
|
26292
26429
|
return false;
|
|
26293
26430
|
}
|
|
26294
|
-
const ext =
|
|
26431
|
+
const ext = path50.extname(f).toLowerCase();
|
|
26295
26432
|
return SOURCE_EXTENSIONS.has(ext);
|
|
26296
26433
|
});
|
|
26297
26434
|
if (sourceFiles.length === 0) {
|
|
@@ -26341,7 +26478,7 @@ var test_runner = createSwarmTool({
|
|
|
26341
26478
|
if (isConventionTestFilePath(f)) {
|
|
26342
26479
|
return false;
|
|
26343
26480
|
}
|
|
26344
|
-
const ext =
|
|
26481
|
+
const ext = path50.extname(f).toLowerCase();
|
|
26345
26482
|
return SOURCE_EXTENSIONS.has(ext);
|
|
26346
26483
|
});
|
|
26347
26484
|
if (sourceFiles.length === 0) {
|
|
@@ -26393,8 +26530,8 @@ var test_runner = createSwarmTool({
|
|
|
26393
26530
|
}
|
|
26394
26531
|
if (impactResult.impactedTests.length > 0) {
|
|
26395
26532
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
26396
|
-
const relativePath =
|
|
26397
|
-
return
|
|
26533
|
+
const relativePath = path50.relative(workingDir, absPath);
|
|
26534
|
+
return path50.isAbsolute(relativePath) ? absPath : relativePath;
|
|
26398
26535
|
});
|
|
26399
26536
|
} else {
|
|
26400
26537
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -26489,8 +26626,8 @@ function validateDirectoryPath(dir) {
|
|
|
26489
26626
|
if (dir.includes("..")) {
|
|
26490
26627
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
26491
26628
|
}
|
|
26492
|
-
const normalized =
|
|
26493
|
-
const absolutePath =
|
|
26629
|
+
const normalized = path51.normalize(dir);
|
|
26630
|
+
const absolutePath = path51.isAbsolute(normalized) ? normalized : path51.resolve(normalized);
|
|
26494
26631
|
return absolutePath;
|
|
26495
26632
|
}
|
|
26496
26633
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -26513,7 +26650,7 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
26513
26650
|
}
|
|
26514
26651
|
function getPackageVersion(dir) {
|
|
26515
26652
|
try {
|
|
26516
|
-
const packagePath =
|
|
26653
|
+
const packagePath = path51.join(dir, "package.json");
|
|
26517
26654
|
if (fs24.existsSync(packagePath)) {
|
|
26518
26655
|
const content = fs24.readFileSync(packagePath, "utf-8");
|
|
26519
26656
|
const pkg = JSON.parse(content);
|
|
@@ -26524,7 +26661,7 @@ function getPackageVersion(dir) {
|
|
|
26524
26661
|
}
|
|
26525
26662
|
function getChangelogVersion(dir) {
|
|
26526
26663
|
try {
|
|
26527
|
-
const changelogPath =
|
|
26664
|
+
const changelogPath = path51.join(dir, "CHANGELOG.md");
|
|
26528
26665
|
if (fs24.existsSync(changelogPath)) {
|
|
26529
26666
|
const content = fs24.readFileSync(changelogPath, "utf-8");
|
|
26530
26667
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
@@ -26538,7 +26675,7 @@ function getChangelogVersion(dir) {
|
|
|
26538
26675
|
function getVersionFileVersion(dir) {
|
|
26539
26676
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
26540
26677
|
for (const file of possibleFiles) {
|
|
26541
|
-
const filePath =
|
|
26678
|
+
const filePath = path51.join(dir, file);
|
|
26542
26679
|
if (fs24.existsSync(filePath)) {
|
|
26543
26680
|
try {
|
|
26544
26681
|
const content = fs24.readFileSync(filePath, "utf-8").trim();
|
|
@@ -27276,7 +27413,7 @@ async function handleQaGatesCommand(directory, args, sessionID) {
|
|
|
27276
27413
|
|
|
27277
27414
|
// src/commands/reset.ts
|
|
27278
27415
|
import * as fs25 from "fs";
|
|
27279
|
-
import * as
|
|
27416
|
+
import * as path52 from "path";
|
|
27280
27417
|
|
|
27281
27418
|
// src/background/circuit-breaker.ts
|
|
27282
27419
|
class CircuitBreaker {
|
|
@@ -27993,7 +28130,7 @@ async function handleResetCommand(directory, args) {
|
|
|
27993
28130
|
}
|
|
27994
28131
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
27995
28132
|
try {
|
|
27996
|
-
const rootPath =
|
|
28133
|
+
const rootPath = path52.join(directory, filename);
|
|
27997
28134
|
if (fs25.existsSync(rootPath)) {
|
|
27998
28135
|
fs25.unlinkSync(rootPath);
|
|
27999
28136
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
@@ -28031,7 +28168,7 @@ async function handleResetCommand(directory, args) {
|
|
|
28031
28168
|
|
|
28032
28169
|
// src/commands/reset-session.ts
|
|
28033
28170
|
import * as fs27 from "fs";
|
|
28034
|
-
import * as
|
|
28171
|
+
import * as path54 from "path";
|
|
28035
28172
|
|
|
28036
28173
|
// src/hooks/trajectory-logger.ts
|
|
28037
28174
|
var callStartTimes = new Map;
|
|
@@ -28438,16 +28575,16 @@ function detectPatterns(trajectory, config, lastProcessedStep = 0) {
|
|
|
28438
28575
|
}
|
|
28439
28576
|
// src/prm/replay.ts
|
|
28440
28577
|
import { promises as fs26 } from "fs";
|
|
28441
|
-
import
|
|
28578
|
+
import path53 from "path";
|
|
28442
28579
|
function isPathSafe(targetPath, basePath) {
|
|
28443
|
-
const resolvedTarget =
|
|
28444
|
-
const resolvedBase =
|
|
28445
|
-
const rel =
|
|
28446
|
-
return !rel.startsWith("..") && !
|
|
28580
|
+
const resolvedTarget = path53.resolve(targetPath);
|
|
28581
|
+
const resolvedBase = path53.resolve(basePath);
|
|
28582
|
+
const rel = path53.relative(resolvedBase, resolvedTarget);
|
|
28583
|
+
return !rel.startsWith("..") && !path53.isAbsolute(rel);
|
|
28447
28584
|
}
|
|
28448
28585
|
function isWithinReplaysDir(targetPath) {
|
|
28449
|
-
const resolved =
|
|
28450
|
-
const parts = resolved.split(
|
|
28586
|
+
const resolved = path53.resolve(targetPath);
|
|
28587
|
+
const parts = resolved.split(path53.sep);
|
|
28451
28588
|
for (let i = 0;i < parts.length - 1; i++) {
|
|
28452
28589
|
if (parts[i] === ".swarm" && parts[i + 1] === "replays") {
|
|
28453
28590
|
return true;
|
|
@@ -28460,10 +28597,10 @@ function sanitizeFilename(input) {
|
|
|
28460
28597
|
}
|
|
28461
28598
|
async function startReplayRecording(sessionID, directory) {
|
|
28462
28599
|
try {
|
|
28463
|
-
const replayDir =
|
|
28600
|
+
const replayDir = path53.join(directory, ".swarm", "replays");
|
|
28464
28601
|
const safeSessionID = sanitizeFilename(sessionID);
|
|
28465
28602
|
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
28466
|
-
const filepath =
|
|
28603
|
+
const filepath = path53.join(replayDir, filename);
|
|
28467
28604
|
if (!isPathSafe(filepath, replayDir)) {
|
|
28468
28605
|
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
28469
28606
|
return null;
|
|
@@ -28541,7 +28678,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28541
28678
|
} catch {
|
|
28542
28679
|
results.push("\u274C Failed to delete state.json");
|
|
28543
28680
|
}
|
|
28544
|
-
const sessionDir =
|
|
28681
|
+
const sessionDir = path54.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
28545
28682
|
let sessionFiles = [];
|
|
28546
28683
|
if (fs27.existsSync(sessionDir)) {
|
|
28547
28684
|
try {
|
|
@@ -28553,7 +28690,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28553
28690
|
for (const file of sessionFiles) {
|
|
28554
28691
|
if (file === "state.json")
|
|
28555
28692
|
continue;
|
|
28556
|
-
const filePath =
|
|
28693
|
+
const filePath = path54.join(sessionDir, file);
|
|
28557
28694
|
try {
|
|
28558
28695
|
if (!fs27.existsSync(filePath))
|
|
28559
28696
|
continue;
|
|
@@ -28588,7 +28725,7 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
28588
28725
|
}
|
|
28589
28726
|
|
|
28590
28727
|
// src/summaries/manager.ts
|
|
28591
|
-
import * as
|
|
28728
|
+
import * as path55 from "path";
|
|
28592
28729
|
var SUMMARY_ID_REGEX = /^S\d+$/;
|
|
28593
28730
|
function sanitizeSummaryId(id) {
|
|
28594
28731
|
if (!id || id.length === 0) {
|
|
@@ -28612,7 +28749,7 @@ function sanitizeSummaryId(id) {
|
|
|
28612
28749
|
}
|
|
28613
28750
|
async function loadFullOutput(directory, id) {
|
|
28614
28751
|
const sanitizedId = sanitizeSummaryId(id);
|
|
28615
|
-
const relativePath =
|
|
28752
|
+
const relativePath = path55.join("summaries", `${sanitizedId}.json`);
|
|
28616
28753
|
validateSwarmPath(directory, relativePath);
|
|
28617
28754
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
28618
28755
|
if (content === null) {
|
|
@@ -28665,7 +28802,7 @@ ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
|
28665
28802
|
|
|
28666
28803
|
// src/commands/rollback.ts
|
|
28667
28804
|
import * as fs28 from "fs";
|
|
28668
|
-
import * as
|
|
28805
|
+
import * as path56 from "path";
|
|
28669
28806
|
async function handleRollbackCommand(directory, args) {
|
|
28670
28807
|
const phaseArg = args[0];
|
|
28671
28808
|
if (!phaseArg) {
|
|
@@ -28731,8 +28868,8 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28731
28868
|
if (EXCLUDE_FILES.has(file) || file.startsWith("plan-ledger.archived-")) {
|
|
28732
28869
|
continue;
|
|
28733
28870
|
}
|
|
28734
|
-
const src =
|
|
28735
|
-
const dest =
|
|
28871
|
+
const src = path56.join(checkpointDir, file);
|
|
28872
|
+
const dest = path56.join(swarmDir, file);
|
|
28736
28873
|
try {
|
|
28737
28874
|
fs28.cpSync(src, dest, { recursive: true, force: true });
|
|
28738
28875
|
successes.push(file);
|
|
@@ -28751,7 +28888,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28751
28888
|
].join(`
|
|
28752
28889
|
`);
|
|
28753
28890
|
}
|
|
28754
|
-
const existingLedgerPath =
|
|
28891
|
+
const existingLedgerPath = path56.join(swarmDir, "plan-ledger.jsonl");
|
|
28755
28892
|
let ledgerDeletionFailed = false;
|
|
28756
28893
|
if (fs28.existsSync(existingLedgerPath)) {
|
|
28757
28894
|
try {
|
|
@@ -28764,7 +28901,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
28764
28901
|
}
|
|
28765
28902
|
if (!ledgerDeletionFailed) {
|
|
28766
28903
|
try {
|
|
28767
|
-
const planJsonPath =
|
|
28904
|
+
const planJsonPath = path56.join(swarmDir, "plan.json");
|
|
28768
28905
|
if (fs28.existsSync(planJsonPath)) {
|
|
28769
28906
|
const planRaw = fs28.readFileSync(planJsonPath, "utf-8");
|
|
28770
28907
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
@@ -29025,10 +29162,10 @@ Ensure this is a git repository with commit history.`;
|
|
|
29025
29162
|
`);
|
|
29026
29163
|
try {
|
|
29027
29164
|
const fs29 = await import("fs/promises");
|
|
29028
|
-
const
|
|
29029
|
-
const reportPath =
|
|
29030
|
-
await fs29.mkdir(
|
|
29031
|
-
const reportTempPath =
|
|
29165
|
+
const path57 = await import("path");
|
|
29166
|
+
const reportPath = path57.join(directory, ".swarm", "simulate-report.md");
|
|
29167
|
+
await fs29.mkdir(path57.dirname(reportPath), { recursive: true });
|
|
29168
|
+
const reportTempPath = path57.join(path57.dirname(reportPath), `${path57.basename(reportPath)}.tmp.${Date.now()}.${Math.floor(Math.random() * 1e9)}`);
|
|
29032
29169
|
try {
|
|
29033
29170
|
await fs29.writeFile(reportTempPath, report, "utf-8");
|
|
29034
29171
|
renameSync11(reportTempPath, reportPath);
|
|
@@ -29056,19 +29193,19 @@ async function handleSpecifyCommand(_directory, args) {
|
|
|
29056
29193
|
|
|
29057
29194
|
// src/services/status-service.ts
|
|
29058
29195
|
import * as fsSync3 from "fs";
|
|
29059
|
-
import { readFile as
|
|
29060
|
-
import * as
|
|
29196
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
29197
|
+
import * as path58 from "path";
|
|
29061
29198
|
|
|
29062
29199
|
// src/turbo/lean/state.ts
|
|
29063
29200
|
init_logger();
|
|
29064
29201
|
import * as fs29 from "fs";
|
|
29065
|
-
import * as
|
|
29202
|
+
import * as path57 from "path";
|
|
29066
29203
|
var STATE_FILE3 = "turbo-state.json";
|
|
29067
29204
|
function nowISO3() {
|
|
29068
29205
|
return new Date().toISOString();
|
|
29069
29206
|
}
|
|
29070
29207
|
function ensureSwarmDir2(directory) {
|
|
29071
|
-
const swarmDir =
|
|
29208
|
+
const swarmDir = path57.resolve(directory, ".swarm");
|
|
29072
29209
|
if (!fs29.existsSync(swarmDir)) {
|
|
29073
29210
|
fs29.mkdirSync(swarmDir, { recursive: true });
|
|
29074
29211
|
}
|
|
@@ -29113,7 +29250,7 @@ function markStateUnreadable2(directory, reason) {
|
|
|
29113
29250
|
}
|
|
29114
29251
|
function readPersisted2(directory) {
|
|
29115
29252
|
try {
|
|
29116
|
-
const filePath =
|
|
29253
|
+
const filePath = path57.join(directory, ".swarm", STATE_FILE3);
|
|
29117
29254
|
if (!fs29.existsSync(filePath)) {
|
|
29118
29255
|
const seed = emptyPersisted2();
|
|
29119
29256
|
try {
|
|
@@ -29149,7 +29286,7 @@ function writePersisted2(directory, persisted) {
|
|
|
29149
29286
|
let payload;
|
|
29150
29287
|
try {
|
|
29151
29288
|
ensureSwarmDir2(directory);
|
|
29152
|
-
filePath =
|
|
29289
|
+
filePath = path57.join(directory, ".swarm", STATE_FILE3);
|
|
29153
29290
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
29154
29291
|
persisted.updatedAt = nowISO3();
|
|
29155
29292
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -29267,7 +29404,7 @@ var _internals43 = {
|
|
|
29267
29404
|
};
|
|
29268
29405
|
function readSpecStalenessSnapshot(directory) {
|
|
29269
29406
|
try {
|
|
29270
|
-
const p =
|
|
29407
|
+
const p = path58.join(directory, ".swarm", "spec-staleness.json");
|
|
29271
29408
|
if (!fsSync3.existsSync(p))
|
|
29272
29409
|
return { stale: false };
|
|
29273
29410
|
const raw = fsSync3.readFileSync(p, "utf-8");
|
|
@@ -29520,7 +29657,7 @@ async function safeLineCount(filePath) {
|
|
|
29520
29657
|
try {
|
|
29521
29658
|
if (!fsSync3.existsSync(filePath))
|
|
29522
29659
|
return 0;
|
|
29523
|
-
const content = await
|
|
29660
|
+
const content = await readFile16(filePath, "utf-8");
|
|
29524
29661
|
let n = 0;
|
|
29525
29662
|
for (const line of content.split(`
|
|
29526
29663
|
`)) {
|
|
@@ -29934,7 +30071,7 @@ function buildDetailedHelp(commandName, entry) {
|
|
|
29934
30071
|
async function handleHelpCommand(ctx) {
|
|
29935
30072
|
const targetCommand = ctx.args.join(" ");
|
|
29936
30073
|
if (!targetCommand) {
|
|
29937
|
-
const { buildHelpText } = await import("./index-
|
|
30074
|
+
const { buildHelpText } = await import("./index-5p1gvn98.js");
|
|
29938
30075
|
return buildHelpText();
|
|
29939
30076
|
}
|
|
29940
30077
|
const tokens = targetCommand.split(/\s+/);
|
|
@@ -29943,7 +30080,7 @@ async function handleHelpCommand(ctx) {
|
|
|
29943
30080
|
return _internals45.buildDetailedHelp(resolved.key, resolved.entry);
|
|
29944
30081
|
}
|
|
29945
30082
|
const similar = _internals45.findSimilarCommands(targetCommand);
|
|
29946
|
-
const { buildHelpText: fullHelp } = await import("./index-
|
|
30083
|
+
const { buildHelpText: fullHelp } = await import("./index-5p1gvn98.js");
|
|
29947
30084
|
if (similar.length > 0) {
|
|
29948
30085
|
return `Command '/swarm ${targetCommand}' not found.
|
|
29949
30086
|
|
|
@@ -30076,7 +30213,7 @@ var COMMAND_REGISTRY = {
|
|
|
30076
30213
|
},
|
|
30077
30214
|
"guardrail explain": {
|
|
30078
30215
|
handler: async (ctx) => {
|
|
30079
|
-
const { handleGuardrailExplain } = await import("./guardrail-explain-
|
|
30216
|
+
const { handleGuardrailExplain } = await import("./guardrail-explain-xe0wjnxz.js");
|
|
30080
30217
|
return handleGuardrailExplain(ctx.directory, ctx.args);
|
|
30081
30218
|
},
|
|
30082
30219
|
description: "Dry-run: show what the guardrails would do to a command or write target (executes nothing)",
|
|
@@ -30086,7 +30223,7 @@ var COMMAND_REGISTRY = {
|
|
|
30086
30223
|
},
|
|
30087
30224
|
"guardrail-log": {
|
|
30088
30225
|
handler: async (ctx) => {
|
|
30089
|
-
const { handleGuardrailLog } = await import("./guardrail-log-
|
|
30226
|
+
const { handleGuardrailLog } = await import("./guardrail-log-m3285thy.js");
|
|
30090
30227
|
return handleGuardrailLog(ctx.directory, ctx.args);
|
|
30091
30228
|
},
|
|
30092
30229
|
description: "Read the guardrail decision log (use --blocks-only for blocks)",
|
|
@@ -30764,6 +30901,14 @@ Subcommands:
|
|
|
30764
30901
|
category: "utility",
|
|
30765
30902
|
toolPolicy: "human-only"
|
|
30766
30903
|
},
|
|
30904
|
+
"memory consolidation-log": {
|
|
30905
|
+
handler: (ctx) => handleMemoryConsolidationLogCommand(ctx.directory, ctx.args),
|
|
30906
|
+
description: "Summarize recent memory consolidation passes and metrics",
|
|
30907
|
+
subcommandOf: "memory",
|
|
30908
|
+
args: "--limit <n>",
|
|
30909
|
+
category: "diagnostics",
|
|
30910
|
+
toolPolicy: "agent"
|
|
30911
|
+
},
|
|
30767
30912
|
"memory-status": {
|
|
30768
30913
|
handler: (ctx) => handleMemoryStatusCommand(ctx.directory, ctx.args),
|
|
30769
30914
|
description: "Show Swarm memory provider, JSONL, and migration status",
|
|
@@ -30816,24 +30961,24 @@ function validateAliases() {
|
|
|
30816
30961
|
}
|
|
30817
30962
|
aliasTargets.get(target).push(name);
|
|
30818
30963
|
const visited = new Set;
|
|
30819
|
-
const
|
|
30964
|
+
const path59 = [];
|
|
30820
30965
|
let current = target;
|
|
30821
30966
|
while (current) {
|
|
30822
30967
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
30823
30968
|
if (!currentEntry)
|
|
30824
30969
|
break;
|
|
30825
30970
|
if (visited.has(current)) {
|
|
30826
|
-
const cycleStart =
|
|
30971
|
+
const cycleStart = path59.indexOf(current);
|
|
30827
30972
|
const fullChain = [
|
|
30828
30973
|
name,
|
|
30829
|
-
...
|
|
30974
|
+
...path59.slice(0, cycleStart > 0 ? cycleStart : path59.length),
|
|
30830
30975
|
current
|
|
30831
30976
|
].join(" \u2192 ");
|
|
30832
30977
|
errors.push(`Circular alias detected: ${fullChain}`);
|
|
30833
30978
|
break;
|
|
30834
30979
|
}
|
|
30835
30980
|
visited.add(current);
|
|
30836
|
-
|
|
30981
|
+
path59.push(current);
|
|
30837
30982
|
current = currentEntry.aliasOf || "";
|
|
30838
30983
|
}
|
|
30839
30984
|
}
|