opencode-swarm 6.80.2 → 6.81.1
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/README.md +168 -1457
- package/dist/cli/index.js +34 -6
- package/dist/config/schema.d.ts +27 -0
- package/dist/hooks/trajectory-logger.d.ts +14 -2
- package/dist/index.js +1527 -438
- package/dist/prm/__tests__/course-correction.test.d.ts +1 -0
- package/dist/prm/__tests__/escalation-queue-drain.test.d.ts +1 -0
- package/dist/prm/__tests__/escalation.test.d.ts +1 -0
- package/dist/prm/__tests__/index.test.d.ts +1 -0
- package/dist/prm/__tests__/integration.test.d.ts +1 -0
- package/dist/prm/__tests__/pattern-detector.test.d.ts +5 -0
- package/dist/prm/__tests__/replay.test.d.ts +1 -0
- package/dist/prm/__tests__/trajectory-store.test.d.ts +7 -0
- package/dist/prm/course-correction.d.ts +20 -0
- package/dist/prm/escalation.d.ts +73 -0
- package/dist/prm/index.d.ts +58 -0
- package/dist/prm/pattern-detector.d.ts +71 -0
- package/dist/prm/replay.d.ts +44 -0
- package/dist/prm/trajectory-store.d.ts +66 -0
- package/dist/prm/types.d.ts +120 -0
- package/dist/state.d.ts +14 -0
- package/dist/telemetry.d.ts +5 -1
- package/dist/types/events.d.ts +33 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14685,7 +14685,7 @@ function resolveGuardrailsConfig(config2, agentName) {
|
|
|
14685
14685
|
};
|
|
14686
14686
|
return resolved;
|
|
14687
14687
|
}
|
|
14688
|
-
var KNOWN_SWARM_PREFIXES, SEPARATORS, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, CuratorConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, PluginConfigSchema;
|
|
14688
|
+
var KNOWN_SWARM_PREFIXES, SEPARATORS, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, CuratorConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PrmConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, PluginConfigSchema;
|
|
14689
14689
|
var init_schema = __esm(() => {
|
|
14690
14690
|
init_zod();
|
|
14691
14691
|
init_constants();
|
|
@@ -15168,6 +15168,25 @@ var init_schema = __esm(() => {
|
|
|
15168
15168
|
emergencyThreshold: exports_external.number().min(1).max(99).default(80),
|
|
15169
15169
|
preserveLastNTurns: exports_external.number().int().min(1).default(5)
|
|
15170
15170
|
});
|
|
15171
|
+
PrmConfigSchema = exports_external.object({
|
|
15172
|
+
enabled: exports_external.boolean().default(true),
|
|
15173
|
+
pattern_thresholds: exports_external.object({
|
|
15174
|
+
repetition_loop: exports_external.number().min(1).default(2),
|
|
15175
|
+
ping_pong: exports_external.number().min(1).default(2),
|
|
15176
|
+
expansion_drift: exports_external.number().min(1).default(3),
|
|
15177
|
+
stuck_on_test: exports_external.number().min(1).default(3),
|
|
15178
|
+
context_thrash: exports_external.number().min(1).default(3)
|
|
15179
|
+
}).default(() => ({
|
|
15180
|
+
repetition_loop: 2,
|
|
15181
|
+
ping_pong: 2,
|
|
15182
|
+
expansion_drift: 3,
|
|
15183
|
+
stuck_on_test: 3,
|
|
15184
|
+
context_thrash: 3
|
|
15185
|
+
})),
|
|
15186
|
+
max_trajectory_lines: exports_external.number().min(10).default(1000),
|
|
15187
|
+
escalation_enabled: exports_external.boolean().default(true),
|
|
15188
|
+
detection_timeout_ms: exports_external.number().min(10).default(100)
|
|
15189
|
+
});
|
|
15171
15190
|
AgentAuthorityRuleSchema = exports_external.object({
|
|
15172
15191
|
readOnly: exports_external.boolean().optional(),
|
|
15173
15192
|
blockedExact: exports_external.array(exports_external.string()).optional(),
|
|
@@ -15248,6 +15267,7 @@ var init_schema = __esm(() => {
|
|
|
15248
15267
|
}).optional(),
|
|
15249
15268
|
incremental_verify: IncrementalVerifyConfigSchema.optional(),
|
|
15250
15269
|
compaction_service: CompactionConfigSchema.optional(),
|
|
15270
|
+
prm: PrmConfigSchema.optional(),
|
|
15251
15271
|
council: CouncilConfigSchema.optional(),
|
|
15252
15272
|
parallelization: ParallelizationConfigSchema.optional(),
|
|
15253
15273
|
turbo_mode: exports_external.boolean().default(false).optional(),
|
|
@@ -15921,6 +15941,29 @@ var init_telemetry = __esm(() => {
|
|
|
15921
15941
|
shellFamily,
|
|
15922
15942
|
executionMode
|
|
15923
15943
|
});
|
|
15944
|
+
},
|
|
15945
|
+
prmPatternDetected(sessionId, pattern, severity, category, stepRange) {
|
|
15946
|
+
emit("prm_pattern_detected", {
|
|
15947
|
+
sessionId,
|
|
15948
|
+
pattern,
|
|
15949
|
+
severity,
|
|
15950
|
+
category,
|
|
15951
|
+
stepRange
|
|
15952
|
+
});
|
|
15953
|
+
},
|
|
15954
|
+
prmCourseCorrectionInjected(sessionId, pattern, level) {
|
|
15955
|
+
emit("prm_course_correction_injected", { sessionId, pattern, level });
|
|
15956
|
+
},
|
|
15957
|
+
prmEscalationTriggered(sessionId, pattern, level, occurrenceCount) {
|
|
15958
|
+
emit("prm_escalation_triggered", {
|
|
15959
|
+
sessionId,
|
|
15960
|
+
pattern,
|
|
15961
|
+
level,
|
|
15962
|
+
occurrenceCount
|
|
15963
|
+
});
|
|
15964
|
+
},
|
|
15965
|
+
prmHardStop(sessionId, pattern, level, occurrenceCount) {
|
|
15966
|
+
emit("prm_hard_stop", { sessionId, pattern, level, occurrenceCount });
|
|
15924
15967
|
}
|
|
15925
15968
|
};
|
|
15926
15969
|
});
|
|
@@ -23676,6 +23719,12 @@ function createGuardrailsHooks(directory, directoryOrConfig, config2, authorityC
|
|
|
23676
23719
|
}
|
|
23677
23720
|
}
|
|
23678
23721
|
}
|
|
23722
|
+
{
|
|
23723
|
+
const prmSession = swarmState.agentSessions.get(input.sessionID);
|
|
23724
|
+
if (prmSession?.prmHardStopPending) {
|
|
23725
|
+
throw new Error("\uD83D\uDED1 PRM HARD STOP: Pattern escalation maximum reached. Stop tool calls and return progress summary.");
|
|
23726
|
+
}
|
|
23727
|
+
}
|
|
23679
23728
|
const resolved = resolveSessionAndWindow(input.sessionID);
|
|
23680
23729
|
if (!resolved)
|
|
23681
23730
|
return;
|
|
@@ -23989,6 +24038,22 @@ ${textPart2.text}`;
|
|
|
23989
24038
|
} else if (!isArchitectSession && session && (session.pendingAdvisoryMessages?.length ?? 0) > 0) {
|
|
23990
24039
|
session.pendingAdvisoryMessages = [];
|
|
23991
24040
|
}
|
|
24041
|
+
if (isArchitectSession && session?.prmHardStopPending) {
|
|
24042
|
+
session.prmHardStopPending = false;
|
|
24043
|
+
const lastPattern = session.prmLastPatternDetected;
|
|
24044
|
+
const patternType = lastPattern?.pattern ?? "unknown";
|
|
24045
|
+
const occurrenceCount = session.prmPatternCounts.get(patternType) ?? 0;
|
|
24046
|
+
telemetry.prmHardStop(_input.sessionID, patternType, session.prmEscalationLevel, occurrenceCount);
|
|
24047
|
+
const hardStopMsg = systemMessages[0];
|
|
24048
|
+
if (hardStopMsg) {
|
|
24049
|
+
const hardStopTextPart = (hardStopMsg.parts ?? []).find((part) => part.type === "text" && typeof part.text === "string");
|
|
24050
|
+
if (hardStopTextPart && !hardStopTextPart.text.includes("[HARD STOP]")) {
|
|
24051
|
+
hardStopTextPart.text = `[HARD STOP] PRM has detected repeated pattern violations. STOP all tool calls and return a summary of your progress. [/HARD STOP]
|
|
24052
|
+
|
|
24053
|
+
` + hardStopTextPart.text;
|
|
24054
|
+
}
|
|
24055
|
+
}
|
|
24056
|
+
}
|
|
23992
24057
|
if (isArchitectSession && session && session.architectWriteCount > session.selfCodingWarnedAtCount) {
|
|
23993
24058
|
let targetSystemMessage = systemMessages[0];
|
|
23994
24059
|
if (!targetSystemMessage) {
|
|
@@ -25512,7 +25577,12 @@ function startAgentSession(sessionId, agentName, staleDurationMs = 7200000, dire
|
|
|
25512
25577
|
revisionLimitHit: false,
|
|
25513
25578
|
loopDetectionWindow: [],
|
|
25514
25579
|
pendingAdvisoryMessages: [],
|
|
25515
|
-
sessionRehydratedAt: 0
|
|
25580
|
+
sessionRehydratedAt: 0,
|
|
25581
|
+
prmPatternCounts: new Map,
|
|
25582
|
+
prmEscalationLevel: 0,
|
|
25583
|
+
prmLastPatternDetected: null,
|
|
25584
|
+
prmTrajectoryStep: 0,
|
|
25585
|
+
prmHardStopPending: false
|
|
25516
25586
|
};
|
|
25517
25587
|
swarmState.agentSessions.set(sessionId, sessionState);
|
|
25518
25588
|
telemetry.sessionStarted(sessionId, agentName);
|
|
@@ -25657,6 +25727,21 @@ function ensureAgentSession(sessionId, agentName, directory) {
|
|
|
25657
25727
|
if (session.sessionRehydratedAt === undefined) {
|
|
25658
25728
|
session.sessionRehydratedAt = 0;
|
|
25659
25729
|
}
|
|
25730
|
+
if (session.prmPatternCounts === undefined) {
|
|
25731
|
+
session.prmPatternCounts = new Map;
|
|
25732
|
+
}
|
|
25733
|
+
if (session.prmEscalationLevel === undefined) {
|
|
25734
|
+
session.prmEscalationLevel = 0;
|
|
25735
|
+
}
|
|
25736
|
+
if (session.prmLastPatternDetected === undefined) {
|
|
25737
|
+
session.prmLastPatternDetected = null;
|
|
25738
|
+
}
|
|
25739
|
+
if (session.prmTrajectoryStep === undefined) {
|
|
25740
|
+
session.prmTrajectoryStep = 0;
|
|
25741
|
+
}
|
|
25742
|
+
if (session.prmHardStopPending === undefined) {
|
|
25743
|
+
session.prmHardStopPending = false;
|
|
25744
|
+
}
|
|
25660
25745
|
session.lastToolCallTime = now;
|
|
25661
25746
|
return session;
|
|
25662
25747
|
}
|
|
@@ -62200,7 +62285,7 @@ var init_curator_drift = __esm(() => {
|
|
|
62200
62285
|
|
|
62201
62286
|
// src/index.ts
|
|
62202
62287
|
init_agents();
|
|
62203
|
-
import * as
|
|
62288
|
+
import * as path101 from "path";
|
|
62204
62289
|
|
|
62205
62290
|
// src/background/index.ts
|
|
62206
62291
|
init_event_bus();
|
|
@@ -70563,6 +70648,996 @@ function createSteeringConsumedHook(directory) {
|
|
|
70563
70648
|
return safeHook(hook);
|
|
70564
70649
|
}
|
|
70565
70650
|
|
|
70651
|
+
// src/hooks/trajectory-logger.ts
|
|
70652
|
+
init_manager2();
|
|
70653
|
+
import * as fs52 from "fs/promises";
|
|
70654
|
+
import * as path66 from "path";
|
|
70655
|
+
|
|
70656
|
+
// src/prm/trajectory-store.ts
|
|
70657
|
+
init_utils2();
|
|
70658
|
+
import * as fs51 from "fs/promises";
|
|
70659
|
+
import * as path65 from "path";
|
|
70660
|
+
function getTrajectoryPath(sessionId, directory) {
|
|
70661
|
+
const relativePath = path65.join("trajectories", `${sessionId}.jsonl`);
|
|
70662
|
+
return validateSwarmPath(directory, relativePath);
|
|
70663
|
+
}
|
|
70664
|
+
var _inMemoryTrajectoryCache = new Map;
|
|
70665
|
+
function getInMemoryTrajectory(sessionId) {
|
|
70666
|
+
const cached3 = _inMemoryTrajectoryCache.get(sessionId);
|
|
70667
|
+
return cached3 ? [...cached3] : [];
|
|
70668
|
+
}
|
|
70669
|
+
async function appendTrajectoryEntry(sessionId, entry, directory, maxLines = 1000) {
|
|
70670
|
+
try {
|
|
70671
|
+
const cached3 = _inMemoryTrajectoryCache.get(sessionId) ?? [];
|
|
70672
|
+
cached3.push(entry);
|
|
70673
|
+
if (cached3.length > maxLines) {
|
|
70674
|
+
const keepCount = Math.max(1, Math.floor(maxLines / 2));
|
|
70675
|
+
_inMemoryTrajectoryCache.set(sessionId, cached3.slice(-keepCount));
|
|
70676
|
+
} else {
|
|
70677
|
+
_inMemoryTrajectoryCache.set(sessionId, cached3);
|
|
70678
|
+
}
|
|
70679
|
+
const trajectoryPath = getTrajectoryPath(sessionId, directory);
|
|
70680
|
+
await fs51.mkdir(path65.dirname(trajectoryPath), { recursive: true });
|
|
70681
|
+
const line = `${JSON.stringify(entry)}
|
|
70682
|
+
`;
|
|
70683
|
+
await fs51.appendFile(trajectoryPath, line, "utf-8");
|
|
70684
|
+
} catch (err2) {
|
|
70685
|
+
console.warn(`[trajectory-store] Failed to append trajectory entry: ${err2}`);
|
|
70686
|
+
}
|
|
70687
|
+
}
|
|
70688
|
+
async function readTrajectory(sessionId, directory) {
|
|
70689
|
+
try {
|
|
70690
|
+
const trajectoryPath = getTrajectoryPath(sessionId, directory);
|
|
70691
|
+
const content = await fs51.readFile(trajectoryPath, "utf-8");
|
|
70692
|
+
const lines = content.split(`
|
|
70693
|
+
`).filter((line) => line.trim().length > 0);
|
|
70694
|
+
const entries = [];
|
|
70695
|
+
for (const line of lines) {
|
|
70696
|
+
try {
|
|
70697
|
+
entries.push(JSON.parse(line));
|
|
70698
|
+
} catch {}
|
|
70699
|
+
}
|
|
70700
|
+
return entries;
|
|
70701
|
+
} catch (err2) {
|
|
70702
|
+
if (err2.code === "ENOENT") {
|
|
70703
|
+
return [];
|
|
70704
|
+
}
|
|
70705
|
+
console.warn(`[trajectory-store] Failed to read trajectory: ${err2}`);
|
|
70706
|
+
return [];
|
|
70707
|
+
}
|
|
70708
|
+
}
|
|
70709
|
+
async function cleanupOldTrajectoryFiles(directory, maxAgeDays = 7) {
|
|
70710
|
+
const cutoffMs = maxAgeDays * 24 * 60 * 60 * 1000;
|
|
70711
|
+
const now = Date.now();
|
|
70712
|
+
for (const subdir of ["trajectories", "replays"]) {
|
|
70713
|
+
try {
|
|
70714
|
+
const dirPath = validateSwarmPath(directory, subdir);
|
|
70715
|
+
const entries = await fs51.readdir(dirPath, { withFileTypes: true });
|
|
70716
|
+
for (const entry of entries) {
|
|
70717
|
+
if (!entry.isFile())
|
|
70718
|
+
continue;
|
|
70719
|
+
const filePath = path65.join(dirPath, entry.name);
|
|
70720
|
+
try {
|
|
70721
|
+
const stat4 = await fs51.stat(filePath);
|
|
70722
|
+
if (now - stat4.mtimeMs > cutoffMs) {
|
|
70723
|
+
await fs51.unlink(filePath);
|
|
70724
|
+
}
|
|
70725
|
+
} catch {}
|
|
70726
|
+
}
|
|
70727
|
+
} catch {}
|
|
70728
|
+
}
|
|
70729
|
+
}
|
|
70730
|
+
|
|
70731
|
+
// src/hooks/trajectory-logger.ts
|
|
70732
|
+
init_state();
|
|
70733
|
+
init_utils2();
|
|
70734
|
+
var callStartTimes2 = new Map;
|
|
70735
|
+
var sessionStepCounters = new Map;
|
|
70736
|
+
var SENSITIVE_FIELDS = new Set([
|
|
70737
|
+
"password",
|
|
70738
|
+
"token",
|
|
70739
|
+
"secret",
|
|
70740
|
+
"api_key",
|
|
70741
|
+
"apikey",
|
|
70742
|
+
"authorization",
|
|
70743
|
+
"access_token",
|
|
70744
|
+
"refresh_token",
|
|
70745
|
+
"private_key",
|
|
70746
|
+
"secret_key",
|
|
70747
|
+
"credential",
|
|
70748
|
+
"auth",
|
|
70749
|
+
"bearer",
|
|
70750
|
+
"x-api-key",
|
|
70751
|
+
"session_id",
|
|
70752
|
+
"cookie"
|
|
70753
|
+
]);
|
|
70754
|
+
var SENSITIVE_SUBSTRINGS = [
|
|
70755
|
+
"key",
|
|
70756
|
+
"secret",
|
|
70757
|
+
"token",
|
|
70758
|
+
"password",
|
|
70759
|
+
"auth",
|
|
70760
|
+
"credential",
|
|
70761
|
+
"private",
|
|
70762
|
+
"certificate",
|
|
70763
|
+
"bearer",
|
|
70764
|
+
"session",
|
|
70765
|
+
"cookie"
|
|
70766
|
+
];
|
|
70767
|
+
function isSensitiveKey(key) {
|
|
70768
|
+
const lower = key.toLowerCase();
|
|
70769
|
+
return SENSITIVE_SUBSTRINGS.some((substr) => lower.includes(substr));
|
|
70770
|
+
}
|
|
70771
|
+
async function truncateTrajectoryFile(filePath, maxLines) {
|
|
70772
|
+
try {
|
|
70773
|
+
const content = await fs52.readFile(filePath, "utf-8");
|
|
70774
|
+
const lines = content.split(`
|
|
70775
|
+
`).filter((line) => line.trim().length > 0);
|
|
70776
|
+
if (lines.length <= maxLines) {
|
|
70777
|
+
return;
|
|
70778
|
+
}
|
|
70779
|
+
const keepCount = Math.floor(maxLines / 2);
|
|
70780
|
+
const keptLines = lines.slice(-keepCount);
|
|
70781
|
+
await fs52.writeFile(filePath, `${keptLines.join(`
|
|
70782
|
+
`)}
|
|
70783
|
+
`, "utf-8");
|
|
70784
|
+
} catch {}
|
|
70785
|
+
}
|
|
70786
|
+
function deriveAction(tool3) {
|
|
70787
|
+
const toolLower = tool3.toLowerCase();
|
|
70788
|
+
if (toolLower === "task")
|
|
70789
|
+
return "delegate";
|
|
70790
|
+
if (["write", "edit", "apply_patch"].includes(toolLower))
|
|
70791
|
+
return "edit";
|
|
70792
|
+
if (["read", "glob", "search"].includes(toolLower))
|
|
70793
|
+
return "read";
|
|
70794
|
+
if (["bash", "shell"].includes(toolLower))
|
|
70795
|
+
return "execute";
|
|
70796
|
+
if (toolLower === "test_runner")
|
|
70797
|
+
return "test";
|
|
70798
|
+
return "tool_use";
|
|
70799
|
+
}
|
|
70800
|
+
function extractTarget(tool3, args2) {
|
|
70801
|
+
if (!args2)
|
|
70802
|
+
return "";
|
|
70803
|
+
if (tool3.toLowerCase() === "task") {
|
|
70804
|
+
const subagentType = args2.subagent_type;
|
|
70805
|
+
if (typeof subagentType === "string" && subagentType.length > 0) {
|
|
70806
|
+
return subagentType;
|
|
70807
|
+
}
|
|
70808
|
+
}
|
|
70809
|
+
const targetFields = ["filePath", "path", "file", "target"];
|
|
70810
|
+
for (const field of targetFields) {
|
|
70811
|
+
const value = args2[field];
|
|
70812
|
+
if (typeof value === "string" && value.length > 0) {
|
|
70813
|
+
return value;
|
|
70814
|
+
}
|
|
70815
|
+
}
|
|
70816
|
+
const toolLower = tool3.toLowerCase();
|
|
70817
|
+
if (toolLower === "bash" || toolLower === "shell" || toolLower === "execute" || toolLower === "command") {
|
|
70818
|
+
const command = args2.command;
|
|
70819
|
+
if (typeof command === "string" && command.length > 0) {
|
|
70820
|
+
const firstWord = command.split(/\s+/)[0] || "";
|
|
70821
|
+
if (firstWord.length > 0) {
|
|
70822
|
+
return firstWord;
|
|
70823
|
+
}
|
|
70824
|
+
}
|
|
70825
|
+
const description = args2.description;
|
|
70826
|
+
if (typeof description === "string" && description.length > 0) {
|
|
70827
|
+
return description.length > 30 ? `${description.slice(0, 27)}...` : description;
|
|
70828
|
+
}
|
|
70829
|
+
const argsStr = args2.args;
|
|
70830
|
+
if (typeof argsStr === "string" && argsStr.length > 0) {
|
|
70831
|
+
const firstWord = argsStr.split(/\s+/)[0] || "";
|
|
70832
|
+
if (firstWord.length > 0) {
|
|
70833
|
+
return firstWord;
|
|
70834
|
+
}
|
|
70835
|
+
}
|
|
70836
|
+
}
|
|
70837
|
+
return "";
|
|
70838
|
+
}
|
|
70839
|
+
function extractIntent(tool3, args2) {
|
|
70840
|
+
if (!args2)
|
|
70841
|
+
return "";
|
|
70842
|
+
if (tool3.toLowerCase() === "task") {
|
|
70843
|
+
const prompt = args2.prompt;
|
|
70844
|
+
const description = args2.description;
|
|
70845
|
+
const text = typeof prompt === "string" ? prompt : typeof description === "string" ? description : "";
|
|
70846
|
+
if (text.length > 100) {
|
|
70847
|
+
return `${text.slice(0, 97)}...`;
|
|
70848
|
+
}
|
|
70849
|
+
return text;
|
|
70850
|
+
}
|
|
70851
|
+
const intentFields = ["description", "task"];
|
|
70852
|
+
for (const field of intentFields) {
|
|
70853
|
+
const value = args2[field];
|
|
70854
|
+
if (typeof value === "string" && value.length > 0) {
|
|
70855
|
+
return value.length > 200 ? `${value.slice(0, 197)}...` : value;
|
|
70856
|
+
}
|
|
70857
|
+
}
|
|
70858
|
+
return "";
|
|
70859
|
+
}
|
|
70860
|
+
function mapResult(verdict) {
|
|
70861
|
+
if (verdict === "success")
|
|
70862
|
+
return "success";
|
|
70863
|
+
if (verdict === "failure")
|
|
70864
|
+
return "failure";
|
|
70865
|
+
return "pending";
|
|
70866
|
+
}
|
|
70867
|
+
function createTrajectoryLoggerHook(config3, _directory) {
|
|
70868
|
+
const enabled = config3.enabled ?? true;
|
|
70869
|
+
const maxLines = config3.max_lines ?? 500;
|
|
70870
|
+
return {
|
|
70871
|
+
toolAfter: async (input, output) => {
|
|
70872
|
+
if (!enabled)
|
|
70873
|
+
return;
|
|
70874
|
+
const sessionId = input.sessionID;
|
|
70875
|
+
const session = swarmState.agentSessions.get(sessionId);
|
|
70876
|
+
if (!session?.delegationActive) {
|
|
70877
|
+
return;
|
|
70878
|
+
}
|
|
70879
|
+
const taskId = session.currentTaskId;
|
|
70880
|
+
if (!taskId) {
|
|
70881
|
+
return;
|
|
70882
|
+
}
|
|
70883
|
+
const startKey = `${sessionId}:${input.callID}`;
|
|
70884
|
+
const startTime = callStartTimes2.get(startKey) ?? Date.now();
|
|
70885
|
+
callStartTimes2.delete(startKey);
|
|
70886
|
+
const elapsed_ms = Date.now() - startTime;
|
|
70887
|
+
const agentName = swarmState.activeAgent.get(sessionId) ?? session?.agentName ?? "unknown";
|
|
70888
|
+
const args_summary = summarizeArgs(input.args, 200);
|
|
70889
|
+
const verdict = deriveVerdict(output);
|
|
70890
|
+
const currentStep = sessionStepCounters.get(sessionId) ?? 0;
|
|
70891
|
+
const step = currentStep + 1;
|
|
70892
|
+
sessionStepCounters.set(sessionId, step);
|
|
70893
|
+
const action = deriveAction(input.tool);
|
|
70894
|
+
const target = extractTarget(input.tool, input.args);
|
|
70895
|
+
const intent = extractIntent(input.tool, input.args);
|
|
70896
|
+
const result = mapResult(verdict);
|
|
70897
|
+
const entry = {
|
|
70898
|
+
step,
|
|
70899
|
+
agent: agentName,
|
|
70900
|
+
action,
|
|
70901
|
+
target,
|
|
70902
|
+
intent,
|
|
70903
|
+
timestamp: new Date().toISOString(),
|
|
70904
|
+
result,
|
|
70905
|
+
tool: input.tool,
|
|
70906
|
+
args_summary,
|
|
70907
|
+
verdict,
|
|
70908
|
+
elapsed_ms
|
|
70909
|
+
};
|
|
70910
|
+
const sanitized = sanitizeTaskId2(taskId);
|
|
70911
|
+
const relativePath = path66.join("evidence", sanitized, "trajectory.jsonl");
|
|
70912
|
+
const trajectoryPath = validateSwarmPath(_directory, relativePath);
|
|
70913
|
+
try {
|
|
70914
|
+
await fs52.mkdir(path66.dirname(trajectoryPath), { recursive: true });
|
|
70915
|
+
const line = `${JSON.stringify(entry)}
|
|
70916
|
+
`;
|
|
70917
|
+
await fs52.appendFile(trajectoryPath, line, "utf-8");
|
|
70918
|
+
await truncateTrajectoryFile(trajectoryPath, maxLines);
|
|
70919
|
+
} catch {}
|
|
70920
|
+
try {
|
|
70921
|
+
await appendTrajectoryEntry(sessionId, entry, _directory, maxLines);
|
|
70922
|
+
} catch {}
|
|
70923
|
+
}
|
|
70924
|
+
};
|
|
70925
|
+
}
|
|
70926
|
+
function summarizeArgs(args2, maxLength) {
|
|
70927
|
+
if (!args2 || Object.keys(args2).length === 0) {
|
|
70928
|
+
return "";
|
|
70929
|
+
}
|
|
70930
|
+
const summaries = [];
|
|
70931
|
+
for (const [key, value] of Object.entries(args2)) {
|
|
70932
|
+
if (SENSITIVE_FIELDS.has(key) || isSensitiveKey(key)) {
|
|
70933
|
+
summaries.push(`${key}:[REDACTED]`);
|
|
70934
|
+
continue;
|
|
70935
|
+
}
|
|
70936
|
+
if (value === null || value === undefined) {
|
|
70937
|
+
summaries.push(`${key}:null`);
|
|
70938
|
+
} else if (typeof value === "string") {
|
|
70939
|
+
const truncated = value.length > 50 ? `${value.slice(0, 50)}...` : value;
|
|
70940
|
+
summaries.push(`${key}:"${truncated}"`);
|
|
70941
|
+
} else if (typeof value === "number" || typeof value === "boolean") {
|
|
70942
|
+
summaries.push(`${key}:${String(value)}`);
|
|
70943
|
+
} else if (Array.isArray(value)) {
|
|
70944
|
+
const itemSummary = value.length > 3 ? `${value.slice(0, 3).map(String).join(",")},...(+${value.length - 3})` : value.map(String).join(",");
|
|
70945
|
+
summaries.push(`${key}:[${itemSummary}]`);
|
|
70946
|
+
} else if (typeof value === "object") {
|
|
70947
|
+
const keys = Object.keys(value);
|
|
70948
|
+
summaries.push(`${key}:{${keys.join(",")}}`);
|
|
70949
|
+
} else {
|
|
70950
|
+
summaries.push(`${key}:${typeof value}`);
|
|
70951
|
+
}
|
|
70952
|
+
}
|
|
70953
|
+
const summary = summaries.join(" ");
|
|
70954
|
+
return summary.length > maxLength ? `${summary.slice(0, maxLength - 3)}...` : summary;
|
|
70955
|
+
}
|
|
70956
|
+
function deriveVerdict(output) {
|
|
70957
|
+
if (output.metadata && typeof output.metadata === "object" && !Array.isArray(output.metadata)) {
|
|
70958
|
+
const meta3 = output.metadata;
|
|
70959
|
+
if (typeof meta3.verdict === "string" && meta3.verdict.length > 0) {
|
|
70960
|
+
return meta3.verdict;
|
|
70961
|
+
}
|
|
70962
|
+
if (meta3.success === false || meta3.passed === false) {
|
|
70963
|
+
return "failure";
|
|
70964
|
+
}
|
|
70965
|
+
if (meta3.success === true || meta3.passed === true) {
|
|
70966
|
+
return "success";
|
|
70967
|
+
}
|
|
70968
|
+
}
|
|
70969
|
+
const outputStr = String(output.output ?? "");
|
|
70970
|
+
if (outputStr.startsWith("Error:") || outputStr.startsWith("error:") || outputStr.startsWith("Error: ")) {
|
|
70971
|
+
return "failure";
|
|
70972
|
+
}
|
|
70973
|
+
return "success";
|
|
70974
|
+
}
|
|
70975
|
+
|
|
70976
|
+
// src/prm/course-correction.ts
|
|
70977
|
+
var GUIDANCE_TEMPLATES = {
|
|
70978
|
+
repetition_loop: "Agent is repeating the same action on the same target. Consider consolidating changes, stepping back to review the approach, or delegating to a different agent.",
|
|
70979
|
+
ping_pong: "Agents are delegating back and forth without making progress. Consider having the architect take direct control or redefining the task boundaries.",
|
|
70980
|
+
expansion_drift: "Scope is expanding beyond the original task. Consider creating a follow-up task, reducing the current scope, or updating the spec.",
|
|
70981
|
+
stuck_on_test: "Repeated edit-test cycles detected. Consider reviewing the test expectations, checking for environmental issues, or seeking SME consultation.",
|
|
70982
|
+
context_thrash: "Agent is requesting increasingly large file sets. Consider focusing on the specific files needed for the current task or compacting context."
|
|
70983
|
+
};
|
|
70984
|
+
var ACTION_TEMPLATES = {
|
|
70985
|
+
repetition_loop: (match) => {
|
|
70986
|
+
const agents = match.affectedAgents.length > 0 ? match.affectedAgents.join(", ") : "current agent";
|
|
70987
|
+
const targets = match.affectedTargets.length > 0 ? match.affectedTargets.join(", ") : "current target";
|
|
70988
|
+
return `Stop repetitive edits to ${targets} by ${agents}. Take a step back and consolidate the changes made so far before proceeding.`;
|
|
70989
|
+
},
|
|
70990
|
+
ping_pong: () => {
|
|
70991
|
+
return `Interrupt the delegation cycle. Architect should take direct control of the task or explicitly redefine which agent owns which subtask.`;
|
|
70992
|
+
},
|
|
70993
|
+
expansion_drift: () => {
|
|
70994
|
+
return `Freeze current scope. Document what's been attempted and create a follow-up issue for additional work. Complete current task before expanding further.`;
|
|
70995
|
+
},
|
|
70996
|
+
stuck_on_test: (match) => {
|
|
70997
|
+
const agents = match.affectedAgents.length > 0 ? match.affectedAgents.join(", ") : "the agent";
|
|
70998
|
+
return `Pause edit-test cycle. ${agents} should review test expectations, verify environment is clean, and consult SME if root cause is unclear.`;
|
|
70999
|
+
},
|
|
71000
|
+
context_thrash: (match) => {
|
|
71001
|
+
const targets = match.affectedTargets.length > 0 ? match.affectedTargets.slice(0, 3).join(", ") : "requested files";
|
|
71002
|
+
return `Restrict file access to only ${targets}. Use targeted file selection instead of broad context requests.`;
|
|
71003
|
+
}
|
|
71004
|
+
};
|
|
71005
|
+
function generateCourseCorrection(match, trajectory) {
|
|
71006
|
+
const alert = `TRAJECTORY ALERT: ${match.pattern} detected (severity: ${match.severity}) at steps ${match.stepRange[0]}-${match.stepRange[1]}`;
|
|
71007
|
+
const guidance = GUIDANCE_TEMPLATES[match.pattern];
|
|
71008
|
+
const action = ACTION_TEMPLATES[match.pattern](match, trajectory);
|
|
71009
|
+
return {
|
|
71010
|
+
alert,
|
|
71011
|
+
category: match.category,
|
|
71012
|
+
guidance,
|
|
71013
|
+
action,
|
|
71014
|
+
pattern: match.pattern,
|
|
71015
|
+
stepRange: match.stepRange
|
|
71016
|
+
};
|
|
71017
|
+
}
|
|
71018
|
+
function formatCourseCorrectionForInjection(correction) {
|
|
71019
|
+
return `${correction.alert}
|
|
71020
|
+
CATEGORY: ${correction.category}
|
|
71021
|
+
GUIDANCE: ${correction.guidance}
|
|
71022
|
+
ACTION: ${correction.action}`;
|
|
71023
|
+
}
|
|
71024
|
+
// src/prm/escalation.ts
|
|
71025
|
+
init_telemetry();
|
|
71026
|
+
function createDefaultEscalationState() {
|
|
71027
|
+
return {
|
|
71028
|
+
patternCounts: new Map,
|
|
71029
|
+
escalationLevel: 0,
|
|
71030
|
+
lastPatternDetected: null,
|
|
71031
|
+
hardStopPending: false,
|
|
71032
|
+
correctionsPending: []
|
|
71033
|
+
};
|
|
71034
|
+
}
|
|
71035
|
+
function generateCorrection(match, level) {
|
|
71036
|
+
const levelPrefix = level === 1 ? "GUIDANCE" : level === 2 ? "STRONG GUIDANCE" : "HARD STOP";
|
|
71037
|
+
const alertTemplates = {
|
|
71038
|
+
repetition_loop: `${levelPrefix}: Repetitive action loop detected`,
|
|
71039
|
+
ping_pong: `${levelPrefix}: Delegation ping-pong detected`,
|
|
71040
|
+
expansion_drift: `${levelPrefix}: Scope expansion drift detected`,
|
|
71041
|
+
stuck_on_test: `${levelPrefix}: Stuck in edit-test cycle`,
|
|
71042
|
+
context_thrash: `${levelPrefix}: Excessive context requests detected`
|
|
71043
|
+
};
|
|
71044
|
+
const guidanceTemplates = {
|
|
71045
|
+
repetition_loop: "Stop the repetitive loop. Consolidate changes and take a different approach.",
|
|
71046
|
+
ping_pong: "Interrupt the delegation cycle. Architect should take direct control.",
|
|
71047
|
+
expansion_drift: "Freeze scope expansion. Complete current task before adding more work.",
|
|
71048
|
+
stuck_on_test: "Pause edit-test cycle. Review test expectations and verify environment.",
|
|
71049
|
+
context_thrash: "Restrict file access. Use targeted selection instead of broad context requests."
|
|
71050
|
+
};
|
|
71051
|
+
const actionTemplates = {
|
|
71052
|
+
repetition_loop: "Consolidate changes and change approach immediately.",
|
|
71053
|
+
ping_pong: "Architect take direct control or redefine agent task boundaries.",
|
|
71054
|
+
expansion_drift: "Document progress and create follow-up issue for additional work.",
|
|
71055
|
+
stuck_on_test: "Review test expectations, verify environment, consult SME if needed.",
|
|
71056
|
+
context_thrash: "Restrict to only the specific files needed for the current task."
|
|
71057
|
+
};
|
|
71058
|
+
return {
|
|
71059
|
+
alert: alertTemplates[match.pattern],
|
|
71060
|
+
category: match.category,
|
|
71061
|
+
guidance: guidanceTemplates[match.pattern],
|
|
71062
|
+
action: actionTemplates[match.pattern],
|
|
71063
|
+
pattern: match.pattern,
|
|
71064
|
+
stepRange: match.stepRange
|
|
71065
|
+
};
|
|
71066
|
+
}
|
|
71067
|
+
|
|
71068
|
+
class EscalationTracker {
|
|
71069
|
+
_sessionId;
|
|
71070
|
+
_state;
|
|
71071
|
+
constructor(sessionId, initialState) {
|
|
71072
|
+
this._sessionId = sessionId;
|
|
71073
|
+
this._state = initialState ?? createDefaultEscalationState();
|
|
71074
|
+
}
|
|
71075
|
+
recordDetection(match) {
|
|
71076
|
+
const currentCount = this._state.patternCounts.get(match.pattern) ?? 0;
|
|
71077
|
+
const newCount = currentCount + 1;
|
|
71078
|
+
this._state.patternCounts.set(match.pattern, newCount);
|
|
71079
|
+
this._state.lastPatternDetected = match;
|
|
71080
|
+
if (newCount === 1) {
|
|
71081
|
+
const correction = generateCorrection(match, 1);
|
|
71082
|
+
this._state.correctionsPending.push(correction);
|
|
71083
|
+
this._state.escalationLevel = 1;
|
|
71084
|
+
return {
|
|
71085
|
+
level: 1,
|
|
71086
|
+
correction,
|
|
71087
|
+
hardStop: false
|
|
71088
|
+
};
|
|
71089
|
+
} else if (newCount === 2) {
|
|
71090
|
+
const correction = generateCorrection(match, 2);
|
|
71091
|
+
this._state.correctionsPending.push(correction);
|
|
71092
|
+
this._state.escalationLevel = 2;
|
|
71093
|
+
telemetry.prmEscalationTriggered(this._sessionId, match.pattern, 2, newCount);
|
|
71094
|
+
return {
|
|
71095
|
+
level: 2,
|
|
71096
|
+
correction,
|
|
71097
|
+
hardStop: false
|
|
71098
|
+
};
|
|
71099
|
+
} else {
|
|
71100
|
+
const correction = generateCorrection(match, 3);
|
|
71101
|
+
this._state.correctionsPending.push(correction);
|
|
71102
|
+
this._state.escalationLevel = 3;
|
|
71103
|
+
this._state.hardStopPending = true;
|
|
71104
|
+
telemetry.prmHardStop(this._sessionId, match.pattern, 3, newCount);
|
|
71105
|
+
return {
|
|
71106
|
+
level: 3,
|
|
71107
|
+
correction,
|
|
71108
|
+
hardStop: true
|
|
71109
|
+
};
|
|
71110
|
+
}
|
|
71111
|
+
}
|
|
71112
|
+
getState() {
|
|
71113
|
+
return this._state;
|
|
71114
|
+
}
|
|
71115
|
+
reset() {
|
|
71116
|
+
this._state = createDefaultEscalationState();
|
|
71117
|
+
}
|
|
71118
|
+
getPendingCorrections() {
|
|
71119
|
+
return this._state.correctionsPending;
|
|
71120
|
+
}
|
|
71121
|
+
clearPendingCorrections() {
|
|
71122
|
+
this._state.correctionsPending = [];
|
|
71123
|
+
}
|
|
71124
|
+
isHardStopPending() {
|
|
71125
|
+
return this._state.hardStopPending;
|
|
71126
|
+
}
|
|
71127
|
+
}
|
|
71128
|
+
// src/prm/pattern-detector.ts
|
|
71129
|
+
var MAX_SANITIZED_LENGTH = 200;
|
|
71130
|
+
var INJECTION_PATTERNS2 = [
|
|
71131
|
+
/\[SYSTEM\]/gi,
|
|
71132
|
+
/SYSTEM\s*OVERRIDE/gi,
|
|
71133
|
+
/IGNORE\s*PREVIOUS/gi,
|
|
71134
|
+
/IGNORE\s*ALL/gi,
|
|
71135
|
+
/NEW\s*INSTRUCTION/gi,
|
|
71136
|
+
/Override\s*instructions/gi,
|
|
71137
|
+
/\bJAILBREAK/gi,
|
|
71138
|
+
/\bDAN\s*MODE/gi,
|
|
71139
|
+
/\bBYPASS/gi
|
|
71140
|
+
];
|
|
71141
|
+
function sanitizeString2(input) {
|
|
71142
|
+
if (!input || typeof input !== "string") {
|
|
71143
|
+
return "";
|
|
71144
|
+
}
|
|
71145
|
+
let result = input;
|
|
71146
|
+
result = result.replace(/[\n\r]/g, "");
|
|
71147
|
+
result = result.replace(/`/g, "");
|
|
71148
|
+
for (const pattern of INJECTION_PATTERNS2) {
|
|
71149
|
+
result = result.replace(pattern, "[REDACTED]");
|
|
71150
|
+
}
|
|
71151
|
+
result = result.trim();
|
|
71152
|
+
if (result.length > MAX_SANITIZED_LENGTH) {
|
|
71153
|
+
result = `${result.slice(0, MAX_SANITIZED_LENGTH - 3)}...`;
|
|
71154
|
+
}
|
|
71155
|
+
return result;
|
|
71156
|
+
}
|
|
71157
|
+
var DEFAULT_THRESHOLDS = {
|
|
71158
|
+
repetition_loop: 2,
|
|
71159
|
+
ping_pong: 2,
|
|
71160
|
+
expansion_drift: 3,
|
|
71161
|
+
stuck_on_test: 3,
|
|
71162
|
+
context_thrash: 3
|
|
71163
|
+
};
|
|
71164
|
+
function detectRepetitionLoop(trajectory, config3) {
|
|
71165
|
+
const matches = [];
|
|
71166
|
+
if (trajectory.length < 2) {
|
|
71167
|
+
return matches;
|
|
71168
|
+
}
|
|
71169
|
+
const windowSize = 10;
|
|
71170
|
+
const threshold = config3.pattern_thresholds?.repetition_loop ?? DEFAULT_THRESHOLDS.repetition_loop;
|
|
71171
|
+
for (let i2 = 0;i2 < trajectory.length; i2++) {
|
|
71172
|
+
const windowStart = Math.max(0, i2 - windowSize + 1);
|
|
71173
|
+
const window2 = trajectory.slice(windowStart, i2 + 1);
|
|
71174
|
+
const counts = new Map;
|
|
71175
|
+
for (const entry of window2) {
|
|
71176
|
+
const key = `${entry.agent}|${entry.action}|${entry.target}`;
|
|
71177
|
+
const existing = counts.get(key);
|
|
71178
|
+
if (existing) {
|
|
71179
|
+
existing.count++;
|
|
71180
|
+
existing.endStep = entry.step;
|
|
71181
|
+
} else {
|
|
71182
|
+
counts.set(key, {
|
|
71183
|
+
count: 1,
|
|
71184
|
+
startStep: entry.step,
|
|
71185
|
+
endStep: entry.step
|
|
71186
|
+
});
|
|
71187
|
+
}
|
|
71188
|
+
}
|
|
71189
|
+
for (const [key, data] of counts) {
|
|
71190
|
+
if (data.count >= threshold) {
|
|
71191
|
+
const [agent, action, target] = key.split("|");
|
|
71192
|
+
const severity = data.count >= 3 ? "high" : "medium";
|
|
71193
|
+
matches.push({
|
|
71194
|
+
pattern: "repetition_loop",
|
|
71195
|
+
severity,
|
|
71196
|
+
category: "coordination_error",
|
|
71197
|
+
stepRange: [data.startStep, data.endStep],
|
|
71198
|
+
description: `Agent "${sanitizeString2(agent)}" performed "${sanitizeString2(action)}" on "${sanitizeString2(target)}" ${data.count} times within ${windowSize} steps`,
|
|
71199
|
+
affectedAgents: [sanitizeString2(agent)],
|
|
71200
|
+
affectedTargets: [sanitizeString2(target)],
|
|
71201
|
+
occurrenceCount: data.count
|
|
71202
|
+
});
|
|
71203
|
+
}
|
|
71204
|
+
}
|
|
71205
|
+
}
|
|
71206
|
+
return matches;
|
|
71207
|
+
}
|
|
71208
|
+
function detectPingPong(trajectory, config3) {
|
|
71209
|
+
const matches = [];
|
|
71210
|
+
const threshold = config3.pattern_thresholds?.ping_pong ?? DEFAULT_THRESHOLDS.ping_pong;
|
|
71211
|
+
const minThreshold = 3;
|
|
71212
|
+
const effectiveThreshold = Math.max(threshold, minThreshold);
|
|
71213
|
+
const delegateEntries = trajectory.filter((e) => e.action === "delegate");
|
|
71214
|
+
if (delegateEntries.length < effectiveThreshold) {
|
|
71215
|
+
return matches;
|
|
71216
|
+
}
|
|
71217
|
+
const detectedPairs = new Set;
|
|
71218
|
+
let i2 = 0;
|
|
71219
|
+
while (i2 < delegateEntries.length) {
|
|
71220
|
+
if (i2 + 1 >= delegateEntries.length)
|
|
71221
|
+
break;
|
|
71222
|
+
const firstAgent = delegateEntries[i2].agent;
|
|
71223
|
+
const secondAgent = delegateEntries[i2 + 1].agent;
|
|
71224
|
+
const target = delegateEntries[i2].target;
|
|
71225
|
+
if (firstAgent === secondAgent) {
|
|
71226
|
+
i2++;
|
|
71227
|
+
continue;
|
|
71228
|
+
}
|
|
71229
|
+
let endIndex = i2 + 1;
|
|
71230
|
+
for (let j = i2 + 2;j < delegateEntries.length; j++) {
|
|
71231
|
+
const expectedAgent = (j - i2) % 2 === 0 ? firstAgent : secondAgent;
|
|
71232
|
+
if (delegateEntries[j].agent !== expectedAgent || delegateEntries[j].target !== target) {
|
|
71233
|
+
break;
|
|
71234
|
+
}
|
|
71235
|
+
endIndex = j;
|
|
71236
|
+
}
|
|
71237
|
+
const patternLength = endIndex - i2 + 1;
|
|
71238
|
+
if (patternLength >= effectiveThreshold) {
|
|
71239
|
+
const pairKey = `${[firstAgent, secondAgent].sort().join(",")}-${target}`;
|
|
71240
|
+
if (!detectedPairs.has(pairKey)) {
|
|
71241
|
+
detectedPairs.add(pairKey);
|
|
71242
|
+
const roundTrips = Math.floor(patternLength / 2);
|
|
71243
|
+
matches.push({
|
|
71244
|
+
pattern: "ping_pong",
|
|
71245
|
+
severity: "high",
|
|
71246
|
+
category: "coordination_error",
|
|
71247
|
+
stepRange: [delegateEntries[i2].step, delegateEntries[endIndex].step],
|
|
71248
|
+
description: `Ping-pong delegation detected: "${sanitizeString2(firstAgent)}" and "${sanitizeString2(secondAgent)}" alternating on "${sanitizeString2(target)}"`,
|
|
71249
|
+
affectedAgents: [
|
|
71250
|
+
sanitizeString2(firstAgent),
|
|
71251
|
+
sanitizeString2(secondAgent)
|
|
71252
|
+
],
|
|
71253
|
+
affectedTargets: [sanitizeString2(target)],
|
|
71254
|
+
occurrenceCount: roundTrips
|
|
71255
|
+
});
|
|
71256
|
+
}
|
|
71257
|
+
i2 = endIndex + 1;
|
|
71258
|
+
} else {
|
|
71259
|
+
i2++;
|
|
71260
|
+
}
|
|
71261
|
+
}
|
|
71262
|
+
return matches;
|
|
71263
|
+
}
|
|
71264
|
+
function detectExpansionDrift(trajectory, config3) {
|
|
71265
|
+
const matches = [];
|
|
71266
|
+
const threshold = config3.pattern_thresholds?.expansion_drift ?? DEFAULT_THRESHOLDS.expansion_drift;
|
|
71267
|
+
const windowSize = Math.max(threshold, 5);
|
|
71268
|
+
const minTrajectoryLength = windowSize * 2;
|
|
71269
|
+
if (trajectory.length < minTrajectoryLength) {
|
|
71270
|
+
return matches;
|
|
71271
|
+
}
|
|
71272
|
+
for (let i2 = windowSize * 2;i2 <= trajectory.length; i2 += windowSize) {
|
|
71273
|
+
const recentWindow = trajectory.slice(i2 - windowSize, i2);
|
|
71274
|
+
const previousWindow = trajectory.slice(i2 - windowSize * 2, i2 - windowSize);
|
|
71275
|
+
const recentTargets = new Set(recentWindow.map((e) => e.target));
|
|
71276
|
+
const previousTargets = new Set(previousWindow.map((e) => e.target));
|
|
71277
|
+
if (previousTargets.size > 0) {
|
|
71278
|
+
const expansionRatio = recentTargets.size / previousTargets.size;
|
|
71279
|
+
if (expansionRatio > 1.5) {
|
|
71280
|
+
matches.push({
|
|
71281
|
+
pattern: "expansion_drift",
|
|
71282
|
+
severity: "medium",
|
|
71283
|
+
category: "specification_error",
|
|
71284
|
+
stepRange: [
|
|
71285
|
+
previousWindow[0].step,
|
|
71286
|
+
recentWindow[recentWindow.length - 1].step
|
|
71287
|
+
],
|
|
71288
|
+
description: `Scope expansion detected: ${previousTargets.size} unique targets \u2192 ${recentTargets.size} unique targets (${expansionRatio.toFixed(1)}x increase)`,
|
|
71289
|
+
affectedAgents: [
|
|
71290
|
+
...new Set(recentWindow.map((e) => sanitizeString2(e.agent)))
|
|
71291
|
+
],
|
|
71292
|
+
affectedTargets: [...recentTargets].map((t) => sanitizeString2(t)),
|
|
71293
|
+
occurrenceCount: Math.floor(expansionRatio * 10) / 10
|
|
71294
|
+
});
|
|
71295
|
+
}
|
|
71296
|
+
}
|
|
71297
|
+
}
|
|
71298
|
+
return matches;
|
|
71299
|
+
}
|
|
71300
|
+
function detectStuckOnTest(trajectory, config3) {
|
|
71301
|
+
const matches = [];
|
|
71302
|
+
if (trajectory.length < 3) {
|
|
71303
|
+
return matches;
|
|
71304
|
+
}
|
|
71305
|
+
const threshold = config3.pattern_thresholds?.stuck_on_test ?? DEFAULT_THRESHOLDS.stuck_on_test;
|
|
71306
|
+
const fileCycles = new Map;
|
|
71307
|
+
for (let i2 = 0;i2 < trajectory.length; i2++) {
|
|
71308
|
+
const entry = trajectory[i2];
|
|
71309
|
+
if (entry.action === "edit") {
|
|
71310
|
+
const existing = fileCycles.get(entry.target);
|
|
71311
|
+
if (existing) {
|
|
71312
|
+
existing.edits++;
|
|
71313
|
+
existing.steps.push(entry.step);
|
|
71314
|
+
if (!existing.agents.includes(entry.agent)) {
|
|
71315
|
+
existing.agents.push(entry.agent);
|
|
71316
|
+
}
|
|
71317
|
+
} else {
|
|
71318
|
+
fileCycles.set(entry.target, {
|
|
71319
|
+
edits: 1,
|
|
71320
|
+
tests: 0,
|
|
71321
|
+
steps: [entry.step],
|
|
71322
|
+
agents: [entry.agent]
|
|
71323
|
+
});
|
|
71324
|
+
}
|
|
71325
|
+
} else if (entry.action === "test") {
|
|
71326
|
+
const existing = fileCycles.get(entry.target);
|
|
71327
|
+
if (existing) {
|
|
71328
|
+
existing.tests++;
|
|
71329
|
+
}
|
|
71330
|
+
}
|
|
71331
|
+
}
|
|
71332
|
+
for (const [file3, data] of fileCycles) {
|
|
71333
|
+
if (data.edits >= threshold && data.tests >= 1) {
|
|
71334
|
+
let cycleCount = 0;
|
|
71335
|
+
let lastEditStep = -1;
|
|
71336
|
+
let lastTestStep = -1;
|
|
71337
|
+
let cycleStart = -1;
|
|
71338
|
+
let cycleEnd = -1;
|
|
71339
|
+
for (let i2 = 0;i2 < trajectory.length; i2++) {
|
|
71340
|
+
const entry = trajectory[i2];
|
|
71341
|
+
if (entry.target === file3) {
|
|
71342
|
+
if (entry.action === "edit") {
|
|
71343
|
+
if (lastTestStep > lastEditStep && lastEditStep > 0) {
|
|
71344
|
+
cycleCount++;
|
|
71345
|
+
if (cycleStart === -1)
|
|
71346
|
+
cycleStart = lastEditStep;
|
|
71347
|
+
cycleEnd = entry.step;
|
|
71348
|
+
}
|
|
71349
|
+
lastEditStep = entry.step;
|
|
71350
|
+
} else if (entry.action === "test" && entry.result === "failure") {
|
|
71351
|
+
lastTestStep = entry.step;
|
|
71352
|
+
}
|
|
71353
|
+
}
|
|
71354
|
+
}
|
|
71355
|
+
if (cycleCount >= threshold) {
|
|
71356
|
+
matches.push({
|
|
71357
|
+
pattern: "stuck_on_test",
|
|
71358
|
+
severity: "high",
|
|
71359
|
+
category: "reasoning_error",
|
|
71360
|
+
stepRange: [cycleStart, cycleEnd],
|
|
71361
|
+
description: `Stuck on test detected: ${cycleCount} edit-test cycles on "${sanitizeString2(file3)}"`,
|
|
71362
|
+
affectedAgents: data.agents.map((a) => sanitizeString2(a)),
|
|
71363
|
+
affectedTargets: [sanitizeString2(file3)],
|
|
71364
|
+
occurrenceCount: cycleCount
|
|
71365
|
+
});
|
|
71366
|
+
}
|
|
71367
|
+
}
|
|
71368
|
+
}
|
|
71369
|
+
return matches;
|
|
71370
|
+
}
|
|
71371
|
+
function detectContextThrash(trajectory, config3) {
|
|
71372
|
+
const matches = [];
|
|
71373
|
+
if (trajectory.length < 2) {
|
|
71374
|
+
return matches;
|
|
71375
|
+
}
|
|
71376
|
+
const threshold = config3.pattern_thresholds?.context_thrash ?? DEFAULT_THRESHOLDS.context_thrash;
|
|
71377
|
+
const seenTargets = new Set;
|
|
71378
|
+
const cumulativeCounts = [];
|
|
71379
|
+
for (const entry of trajectory) {
|
|
71380
|
+
seenTargets.add(entry.target);
|
|
71381
|
+
cumulativeCounts.push(seenTargets.size);
|
|
71382
|
+
}
|
|
71383
|
+
let runStart = 0;
|
|
71384
|
+
let runLength = 1;
|
|
71385
|
+
for (let i2 = 1;i2 <= cumulativeCounts.length; i2++) {
|
|
71386
|
+
const extending = i2 < cumulativeCounts.length && cumulativeCounts[i2] > cumulativeCounts[i2 - 1];
|
|
71387
|
+
if (extending) {
|
|
71388
|
+
runLength++;
|
|
71389
|
+
} else {
|
|
71390
|
+
if (runLength >= threshold) {
|
|
71391
|
+
const runEnd = i2 - 1;
|
|
71392
|
+
const priorCount = runStart > 0 ? cumulativeCounts[runStart - 1] : 0;
|
|
71393
|
+
const finalCount = cumulativeCounts[runEnd];
|
|
71394
|
+
matches.push({
|
|
71395
|
+
pattern: "context_thrash",
|
|
71396
|
+
severity: "medium",
|
|
71397
|
+
category: "coordination_error",
|
|
71398
|
+
stepRange: [trajectory[runStart].step, trajectory[runEnd].step],
|
|
71399
|
+
description: `Context thrash detected: unique targets grew monotonically from ${priorCount} to ${finalCount} over ${runLength} steps`,
|
|
71400
|
+
affectedAgents: [
|
|
71401
|
+
...new Set(trajectory.slice(runStart, runEnd + 1).map((e) => sanitizeString2(e.agent)))
|
|
71402
|
+
],
|
|
71403
|
+
affectedTargets: [
|
|
71404
|
+
...new Set(trajectory.slice(runStart, runEnd + 1).map((e) => sanitizeString2(e.target)))
|
|
71405
|
+
],
|
|
71406
|
+
occurrenceCount: runLength
|
|
71407
|
+
});
|
|
71408
|
+
}
|
|
71409
|
+
runStart = i2;
|
|
71410
|
+
runLength = 1;
|
|
71411
|
+
}
|
|
71412
|
+
}
|
|
71413
|
+
return matches;
|
|
71414
|
+
}
|
|
71415
|
+
function detectPatterns(trajectory, config3, lastProcessedStep = 0) {
|
|
71416
|
+
const startTime = Date.now();
|
|
71417
|
+
if (config3.enabled === false) {
|
|
71418
|
+
return {
|
|
71419
|
+
matches: [],
|
|
71420
|
+
detectionTimeMs: 0,
|
|
71421
|
+
patternsChecked: 5
|
|
71422
|
+
};
|
|
71423
|
+
}
|
|
71424
|
+
const allMatches = [];
|
|
71425
|
+
allMatches.push(...detectRepetitionLoop(trajectory, config3));
|
|
71426
|
+
allMatches.push(...detectPingPong(trajectory, config3));
|
|
71427
|
+
allMatches.push(...detectExpansionDrift(trajectory, config3));
|
|
71428
|
+
allMatches.push(...detectStuckOnTest(trajectory, config3));
|
|
71429
|
+
allMatches.push(...detectContextThrash(trajectory, config3));
|
|
71430
|
+
const detectionTimeMs = Date.now() - startTime;
|
|
71431
|
+
const severityRank = {
|
|
71432
|
+
critical: 4,
|
|
71433
|
+
high: 3,
|
|
71434
|
+
medium: 2,
|
|
71435
|
+
low: 1
|
|
71436
|
+
};
|
|
71437
|
+
const dedupedMatches = new Map;
|
|
71438
|
+
for (const match of allMatches) {
|
|
71439
|
+
const key = `${match.pattern}-${match.affectedAgents.join(",")}-${match.affectedTargets.join(",")}-${match.stepRange[0]}-${match.stepRange[1]}`;
|
|
71440
|
+
const existing = dedupedMatches.get(key);
|
|
71441
|
+
if (!existing) {
|
|
71442
|
+
dedupedMatches.set(key, match);
|
|
71443
|
+
} else {
|
|
71444
|
+
const existingRank = severityRank[existing.severity] ?? 0;
|
|
71445
|
+
const newRank = severityRank[match.severity] ?? 0;
|
|
71446
|
+
if (newRank > existingRank) {
|
|
71447
|
+
dedupedMatches.set(key, match);
|
|
71448
|
+
}
|
|
71449
|
+
}
|
|
71450
|
+
}
|
|
71451
|
+
const newMatches = Array.from(dedupedMatches.values()).filter((match) => match.stepRange[1] > lastProcessedStep);
|
|
71452
|
+
return {
|
|
71453
|
+
matches: newMatches,
|
|
71454
|
+
detectionTimeMs,
|
|
71455
|
+
patternsChecked: 5
|
|
71456
|
+
};
|
|
71457
|
+
}
|
|
71458
|
+
|
|
71459
|
+
// src/prm/index.ts
|
|
71460
|
+
init_state();
|
|
71461
|
+
init_telemetry();
|
|
71462
|
+
|
|
71463
|
+
// src/prm/replay.ts
|
|
71464
|
+
import { promises as fs53 } from "fs";
|
|
71465
|
+
import path67 from "path";
|
|
71466
|
+
function isPathSafe2(targetPath, basePath) {
|
|
71467
|
+
const resolvedTarget = path67.resolve(targetPath);
|
|
71468
|
+
const resolvedBase = path67.resolve(basePath);
|
|
71469
|
+
const rel = path67.relative(resolvedBase, resolvedTarget);
|
|
71470
|
+
return !rel.startsWith("..") && !path67.isAbsolute(rel);
|
|
71471
|
+
}
|
|
71472
|
+
function isWithinReplaysDir(targetPath) {
|
|
71473
|
+
const resolved = path67.resolve(targetPath);
|
|
71474
|
+
const parts2 = resolved.split(path67.sep);
|
|
71475
|
+
for (let i2 = 0;i2 < parts2.length - 1; i2++) {
|
|
71476
|
+
if (parts2[i2] === ".swarm" && parts2[i2 + 1] === "replays") {
|
|
71477
|
+
return true;
|
|
71478
|
+
}
|
|
71479
|
+
}
|
|
71480
|
+
return false;
|
|
71481
|
+
}
|
|
71482
|
+
function sanitizeFilename(input) {
|
|
71483
|
+
return input.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
71484
|
+
}
|
|
71485
|
+
async function startReplayRecording(sessionID, directory) {
|
|
71486
|
+
try {
|
|
71487
|
+
const replayDir = path67.join(directory, ".swarm", "replays");
|
|
71488
|
+
const safeSessionID = sanitizeFilename(sessionID);
|
|
71489
|
+
const filename = `${safeSessionID}-${Date.now()}.jsonl`;
|
|
71490
|
+
const filepath = path67.join(replayDir, filename);
|
|
71491
|
+
if (!isPathSafe2(filepath, replayDir)) {
|
|
71492
|
+
console.warn(`[replay] Invalid path detected - path traversal attempt blocked for session ${sessionID}`);
|
|
71493
|
+
return null;
|
|
71494
|
+
}
|
|
71495
|
+
await fs53.mkdir(replayDir, { recursive: true });
|
|
71496
|
+
return filepath;
|
|
71497
|
+
} catch (err2) {
|
|
71498
|
+
console.warn(`[replay] Failed to start recording for session ${sessionID}: ${err2}`);
|
|
71499
|
+
return null;
|
|
71500
|
+
}
|
|
71501
|
+
}
|
|
71502
|
+
async function recordReplayEntry(artifactPath, sessionID, entry) {
|
|
71503
|
+
try {
|
|
71504
|
+
if (!isWithinReplaysDir(artifactPath)) {
|
|
71505
|
+
console.warn(`[replay] Invalid artifact path - not within .swarm/replays/: ${artifactPath}`);
|
|
71506
|
+
return;
|
|
71507
|
+
}
|
|
71508
|
+
const fullEntry = {
|
|
71509
|
+
timestamp: new Date().toISOString(),
|
|
71510
|
+
sessionID,
|
|
71511
|
+
...entry
|
|
71512
|
+
};
|
|
71513
|
+
const line = `${JSON.stringify(fullEntry)}
|
|
71514
|
+
`;
|
|
71515
|
+
await fs53.appendFile(artifactPath, line, "utf-8");
|
|
71516
|
+
} catch (err2) {
|
|
71517
|
+
console.warn(`[replay] Failed to record entry: ${err2}`);
|
|
71518
|
+
}
|
|
71519
|
+
}
|
|
71520
|
+
|
|
71521
|
+
// src/prm/index.ts
|
|
71522
|
+
function createPrmHook(config3, directory) {
|
|
71523
|
+
async function toolAfter(context) {
|
|
71524
|
+
if (!config3.enabled) {
|
|
71525
|
+
return;
|
|
71526
|
+
}
|
|
71527
|
+
const { sessionID } = context;
|
|
71528
|
+
const session = getAgentSession(sessionID);
|
|
71529
|
+
if (!session || !session.delegationActive) {
|
|
71530
|
+
return;
|
|
71531
|
+
}
|
|
71532
|
+
try {
|
|
71533
|
+
const cachedTrajectory = getInMemoryTrajectory(sessionID);
|
|
71534
|
+
const trajectory = cachedTrajectory.length > 0 ? cachedTrajectory : await readTrajectory(sessionID, directory);
|
|
71535
|
+
const detectionResult = detectPatterns(trajectory, config3, session.prmTrajectoryStep);
|
|
71536
|
+
if (detectionResult.matches.length === 0) {
|
|
71537
|
+
return;
|
|
71538
|
+
}
|
|
71539
|
+
const sessionPrmState = session;
|
|
71540
|
+
let escalationTracker = sessionPrmState.prmEscalationTracker;
|
|
71541
|
+
if (!sessionPrmState.replayArtifactPath) {
|
|
71542
|
+
sessionPrmState.replayArtifactPath = await startReplayRecording(sessionID, directory);
|
|
71543
|
+
}
|
|
71544
|
+
const artifactPath = sessionPrmState.replayArtifactPath;
|
|
71545
|
+
if (!sessionPrmState.prmInitialized) {
|
|
71546
|
+
sessionPrmState.prmInitialized = true;
|
|
71547
|
+
cleanupOldTrajectoryFiles(directory).catch(() => {});
|
|
71548
|
+
}
|
|
71549
|
+
if (!escalationTracker) {
|
|
71550
|
+
const initialState = session.prmLastPatternDetected ? {
|
|
71551
|
+
patternCounts: new Map(session.prmPatternCounts.entries()),
|
|
71552
|
+
escalationLevel: session.prmEscalationLevel,
|
|
71553
|
+
lastPatternDetected: session.prmLastPatternDetected,
|
|
71554
|
+
hardStopPending: session.prmHardStopPending,
|
|
71555
|
+
correctionsPending: []
|
|
71556
|
+
} : undefined;
|
|
71557
|
+
escalationTracker = new EscalationTracker(sessionID, initialState);
|
|
71558
|
+
sessionPrmState.prmEscalationTracker = escalationTracker;
|
|
71559
|
+
}
|
|
71560
|
+
const previousEscalationLevel = session.prmEscalationLevel;
|
|
71561
|
+
for (const match of detectionResult.matches) {
|
|
71562
|
+
const correction = generateCourseCorrection(match, trajectory);
|
|
71563
|
+
const formattedCorrection = formatCourseCorrectionForInjection(correction);
|
|
71564
|
+
if (!session.pendingAdvisoryMessages) {
|
|
71565
|
+
session.pendingAdvisoryMessages = [];
|
|
71566
|
+
}
|
|
71567
|
+
session.pendingAdvisoryMessages.push(formattedCorrection);
|
|
71568
|
+
let escalationLevel = 0;
|
|
71569
|
+
let hardStopPending = false;
|
|
71570
|
+
if (config3.escalation_enabled !== false) {
|
|
71571
|
+
const escalationResult = escalationTracker.recordDetection(match);
|
|
71572
|
+
escalationLevel = escalationResult.level;
|
|
71573
|
+
hardStopPending = escalationResult.hardStop;
|
|
71574
|
+
}
|
|
71575
|
+
escalationTracker.clearPendingCorrections();
|
|
71576
|
+
session.prmPatternCounts.set(match.pattern, (session.prmPatternCounts.get(match.pattern) ?? 0) + 1);
|
|
71577
|
+
session.prmEscalationLevel = escalationLevel;
|
|
71578
|
+
session.prmLastPatternDetected = match;
|
|
71579
|
+
session.prmHardStopPending = hardStopPending;
|
|
71580
|
+
telemetry.prmPatternDetected(sessionID, match.pattern, match.severity, match.category, match.stepRange);
|
|
71581
|
+
telemetry.prmCourseCorrectionInjected(sessionID, match.pattern, escalationLevel);
|
|
71582
|
+
if (artifactPath) {
|
|
71583
|
+
await recordReplayEntry(artifactPath, sessionID, {
|
|
71584
|
+
type: "pattern_detected",
|
|
71585
|
+
data: {
|
|
71586
|
+
pattern: match.pattern,
|
|
71587
|
+
severity: match.severity,
|
|
71588
|
+
category: match.category,
|
|
71589
|
+
stepRange: match.stepRange,
|
|
71590
|
+
description: match.description,
|
|
71591
|
+
affectedAgents: match.affectedAgents,
|
|
71592
|
+
affectedTargets: match.affectedTargets,
|
|
71593
|
+
occurrenceCount: match.occurrenceCount
|
|
71594
|
+
}
|
|
71595
|
+
});
|
|
71596
|
+
}
|
|
71597
|
+
if (artifactPath) {
|
|
71598
|
+
await recordReplayEntry(artifactPath, sessionID, {
|
|
71599
|
+
type: "course_correction",
|
|
71600
|
+
data: {
|
|
71601
|
+
pattern: correction.pattern,
|
|
71602
|
+
alert: correction.alert,
|
|
71603
|
+
category: correction.category,
|
|
71604
|
+
guidance: correction.guidance,
|
|
71605
|
+
action: correction.action,
|
|
71606
|
+
stepRange: correction.stepRange,
|
|
71607
|
+
escalationLevel
|
|
71608
|
+
}
|
|
71609
|
+
});
|
|
71610
|
+
}
|
|
71611
|
+
}
|
|
71612
|
+
if (artifactPath && session.prmEscalationLevel > previousEscalationLevel) {
|
|
71613
|
+
await recordReplayEntry(artifactPath, sessionID, {
|
|
71614
|
+
type: "escalation",
|
|
71615
|
+
data: {
|
|
71616
|
+
previousLevel: previousEscalationLevel,
|
|
71617
|
+
newLevel: session.prmEscalationLevel,
|
|
71618
|
+
hardStopPending: session.prmHardStopPending
|
|
71619
|
+
}
|
|
71620
|
+
});
|
|
71621
|
+
}
|
|
71622
|
+
if (artifactPath && session.prmHardStopPending && previousEscalationLevel < 3) {
|
|
71623
|
+
await recordReplayEntry(artifactPath, sessionID, {
|
|
71624
|
+
type: "hard_stop",
|
|
71625
|
+
data: {
|
|
71626
|
+
escalationLevel: session.prmEscalationLevel,
|
|
71627
|
+
triggeredAt: new Date().toISOString()
|
|
71628
|
+
}
|
|
71629
|
+
});
|
|
71630
|
+
}
|
|
71631
|
+
if (trajectory.length > 0) {
|
|
71632
|
+
session.prmTrajectoryStep = trajectory[trajectory.length - 1].step;
|
|
71633
|
+
}
|
|
71634
|
+
} catch (err2) {
|
|
71635
|
+
console.warn(`[prm] toolAfter error for session ${sessionID}: ${err2}`);
|
|
71636
|
+
}
|
|
71637
|
+
}
|
|
71638
|
+
return { toolAfter };
|
|
71639
|
+
}
|
|
71640
|
+
|
|
70566
71641
|
// src/index.ts
|
|
70567
71642
|
init_compaction_service();
|
|
70568
71643
|
init_config_doctor();
|
|
@@ -70666,6 +71741,11 @@ function deserializeAgentSession(s) {
|
|
|
70666
71741
|
fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
|
|
70667
71742
|
fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
|
|
70668
71743
|
fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
|
|
71744
|
+
prmPatternCounts: new Map,
|
|
71745
|
+
prmEscalationLevel: 0,
|
|
71746
|
+
prmLastPatternDetected: null,
|
|
71747
|
+
prmTrajectoryStep: 0,
|
|
71748
|
+
prmHardStopPending: false,
|
|
70669
71749
|
sessionRehydratedAt: s.sessionRehydratedAt ?? 0
|
|
70670
71750
|
};
|
|
70671
71751
|
}
|
|
@@ -70771,8 +71851,8 @@ init_telemetry();
|
|
|
70771
71851
|
// src/tools/batch-symbols.ts
|
|
70772
71852
|
init_tool();
|
|
70773
71853
|
init_create_tool();
|
|
70774
|
-
import * as
|
|
70775
|
-
import * as
|
|
71854
|
+
import * as fs54 from "fs";
|
|
71855
|
+
import * as path68 from "path";
|
|
70776
71856
|
init_path_security();
|
|
70777
71857
|
var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
70778
71858
|
function containsWindowsAttacks2(str) {
|
|
@@ -70789,14 +71869,14 @@ function containsWindowsAttacks2(str) {
|
|
|
70789
71869
|
}
|
|
70790
71870
|
function isPathInWorkspace2(filePath, workspace) {
|
|
70791
71871
|
try {
|
|
70792
|
-
const resolvedPath =
|
|
70793
|
-
if (!
|
|
71872
|
+
const resolvedPath = path68.resolve(workspace, filePath);
|
|
71873
|
+
if (!fs54.existsSync(resolvedPath)) {
|
|
70794
71874
|
return true;
|
|
70795
71875
|
}
|
|
70796
|
-
const realWorkspace =
|
|
70797
|
-
const realResolvedPath =
|
|
70798
|
-
const relativePath =
|
|
70799
|
-
if (relativePath.startsWith("..") ||
|
|
71876
|
+
const realWorkspace = fs54.realpathSync(workspace);
|
|
71877
|
+
const realResolvedPath = fs54.realpathSync(resolvedPath);
|
|
71878
|
+
const relativePath = path68.relative(realWorkspace, realResolvedPath);
|
|
71879
|
+
if (relativePath.startsWith("..") || path68.isAbsolute(relativePath)) {
|
|
70800
71880
|
return false;
|
|
70801
71881
|
}
|
|
70802
71882
|
return true;
|
|
@@ -70805,7 +71885,7 @@ function isPathInWorkspace2(filePath, workspace) {
|
|
|
70805
71885
|
}
|
|
70806
71886
|
}
|
|
70807
71887
|
function processFile2(file3, cwd, exportedOnly) {
|
|
70808
|
-
const ext =
|
|
71888
|
+
const ext = path68.extname(file3);
|
|
70809
71889
|
if (containsControlChars(file3)) {
|
|
70810
71890
|
return {
|
|
70811
71891
|
file: file3,
|
|
@@ -70838,8 +71918,8 @@ function processFile2(file3, cwd, exportedOnly) {
|
|
|
70838
71918
|
errorType: "path-outside-workspace"
|
|
70839
71919
|
};
|
|
70840
71920
|
}
|
|
70841
|
-
const fullPath =
|
|
70842
|
-
if (!
|
|
71921
|
+
const fullPath = path68.join(cwd, file3);
|
|
71922
|
+
if (!fs54.existsSync(fullPath)) {
|
|
70843
71923
|
return {
|
|
70844
71924
|
file: file3,
|
|
70845
71925
|
success: false,
|
|
@@ -70870,14 +71950,14 @@ function processFile2(file3, cwd, exportedOnly) {
|
|
|
70870
71950
|
}
|
|
70871
71951
|
let isEmptyFile = false;
|
|
70872
71952
|
try {
|
|
70873
|
-
const stats =
|
|
71953
|
+
const stats = fs54.statSync(fullPath);
|
|
70874
71954
|
if (stats.size === 0) {
|
|
70875
71955
|
isEmptyFile = true;
|
|
70876
71956
|
}
|
|
70877
71957
|
} catch {}
|
|
70878
71958
|
if (syms.length === 0) {
|
|
70879
71959
|
try {
|
|
70880
|
-
const content =
|
|
71960
|
+
const content = fs54.readFileSync(fullPath, "utf-8");
|
|
70881
71961
|
if (content.trim().length === 0) {
|
|
70882
71962
|
isEmptyFile = true;
|
|
70883
71963
|
}
|
|
@@ -71129,25 +72209,25 @@ init_manager2();
|
|
|
71129
72209
|
init_task_id();
|
|
71130
72210
|
init_create_tool();
|
|
71131
72211
|
init_resolve_working_directory();
|
|
71132
|
-
import * as
|
|
71133
|
-
import * as
|
|
72212
|
+
import * as fs55 from "fs";
|
|
72213
|
+
import * as path69 from "path";
|
|
71134
72214
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
71135
72215
|
function isValidTaskId3(taskId) {
|
|
71136
72216
|
return isStrictTaskId(taskId);
|
|
71137
72217
|
}
|
|
71138
72218
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
71139
|
-
const normalizedWorkspace =
|
|
71140
|
-
const swarmPath =
|
|
71141
|
-
const normalizedPath =
|
|
72219
|
+
const normalizedWorkspace = path69.resolve(workspaceRoot);
|
|
72220
|
+
const swarmPath = path69.join(normalizedWorkspace, ".swarm", "evidence");
|
|
72221
|
+
const normalizedPath = path69.resolve(filePath);
|
|
71142
72222
|
return normalizedPath.startsWith(swarmPath);
|
|
71143
72223
|
}
|
|
71144
72224
|
function readEvidenceFile(evidencePath) {
|
|
71145
|
-
if (!
|
|
72225
|
+
if (!fs55.existsSync(evidencePath)) {
|
|
71146
72226
|
return null;
|
|
71147
72227
|
}
|
|
71148
72228
|
let content;
|
|
71149
72229
|
try {
|
|
71150
|
-
content =
|
|
72230
|
+
content = fs55.readFileSync(evidencePath, "utf-8");
|
|
71151
72231
|
} catch {
|
|
71152
72232
|
return null;
|
|
71153
72233
|
}
|
|
@@ -71219,7 +72299,7 @@ var check_gate_status = createSwarmTool({
|
|
|
71219
72299
|
};
|
|
71220
72300
|
return JSON.stringify(errorResult, null, 2);
|
|
71221
72301
|
}
|
|
71222
|
-
const evidencePath =
|
|
72302
|
+
const evidencePath = path69.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
71223
72303
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
71224
72304
|
const errorResult = {
|
|
71225
72305
|
taskId: taskIdInput,
|
|
@@ -71315,8 +72395,8 @@ init_utils2();
|
|
|
71315
72395
|
init_state();
|
|
71316
72396
|
init_create_tool();
|
|
71317
72397
|
init_resolve_working_directory();
|
|
71318
|
-
import * as
|
|
71319
|
-
import * as
|
|
72398
|
+
import * as fs56 from "fs";
|
|
72399
|
+
import * as path70 from "path";
|
|
71320
72400
|
function extractMatches(regex, text) {
|
|
71321
72401
|
return Array.from(text.matchAll(regex));
|
|
71322
72402
|
}
|
|
@@ -71410,7 +72490,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71410
72490
|
let plan;
|
|
71411
72491
|
try {
|
|
71412
72492
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
71413
|
-
const planRaw =
|
|
72493
|
+
const planRaw = fs56.readFileSync(planPath, "utf-8");
|
|
71414
72494
|
plan = JSON.parse(planRaw);
|
|
71415
72495
|
} catch {
|
|
71416
72496
|
const result2 = {
|
|
@@ -71468,10 +72548,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71468
72548
|
let hasFileReadFailure = false;
|
|
71469
72549
|
for (const filePath of fileTargets) {
|
|
71470
72550
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
71471
|
-
const resolvedPath =
|
|
71472
|
-
const projectRoot =
|
|
71473
|
-
const relative16 =
|
|
71474
|
-
const withinProject = relative16 === "" || !relative16.startsWith("..") && !
|
|
72551
|
+
const resolvedPath = path70.resolve(directory, normalizedPath);
|
|
72552
|
+
const projectRoot = path70.resolve(directory);
|
|
72553
|
+
const relative16 = path70.relative(projectRoot, resolvedPath);
|
|
72554
|
+
const withinProject = relative16 === "" || !relative16.startsWith("..") && !path70.isAbsolute(relative16);
|
|
71475
72555
|
if (!withinProject) {
|
|
71476
72556
|
blockedTasks.push({
|
|
71477
72557
|
task_id: task.id,
|
|
@@ -71484,7 +72564,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71484
72564
|
}
|
|
71485
72565
|
let fileContent;
|
|
71486
72566
|
try {
|
|
71487
|
-
fileContent =
|
|
72567
|
+
fileContent = fs56.readFileSync(resolvedPath, "utf-8");
|
|
71488
72568
|
} catch {
|
|
71489
72569
|
blockedTasks.push({
|
|
71490
72570
|
task_id: task.id,
|
|
@@ -71526,9 +72606,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71526
72606
|
blockedTasks
|
|
71527
72607
|
};
|
|
71528
72608
|
try {
|
|
71529
|
-
const evidenceDir =
|
|
71530
|
-
const evidencePath =
|
|
71531
|
-
|
|
72609
|
+
const evidenceDir = path70.join(directory, ".swarm", "evidence", `${phase}`);
|
|
72610
|
+
const evidencePath = path70.join(evidenceDir, "completion-verify.json");
|
|
72611
|
+
fs56.mkdirSync(evidenceDir, { recursive: true });
|
|
71532
72612
|
const evidenceBundle = {
|
|
71533
72613
|
schema_version: "1.0.0",
|
|
71534
72614
|
task_id: "completion-verify",
|
|
@@ -71549,7 +72629,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71549
72629
|
}
|
|
71550
72630
|
]
|
|
71551
72631
|
};
|
|
71552
|
-
|
|
72632
|
+
fs56.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
71553
72633
|
} catch {}
|
|
71554
72634
|
return JSON.stringify(result, null, 2);
|
|
71555
72635
|
}
|
|
@@ -71603,12 +72683,12 @@ var completion_verify = createSwarmTool({
|
|
|
71603
72683
|
});
|
|
71604
72684
|
// src/tools/complexity-hotspots.ts
|
|
71605
72685
|
init_dist();
|
|
71606
|
-
import * as
|
|
71607
|
-
import * as
|
|
72686
|
+
import * as fs58 from "fs";
|
|
72687
|
+
import * as path72 from "path";
|
|
71608
72688
|
|
|
71609
72689
|
// src/quality/metrics.ts
|
|
71610
|
-
import * as
|
|
71611
|
-
import * as
|
|
72690
|
+
import * as fs57 from "fs";
|
|
72691
|
+
import * as path71 from "path";
|
|
71612
72692
|
var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
|
|
71613
72693
|
var MIN_DUPLICATION_LINES = 10;
|
|
71614
72694
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -71646,11 +72726,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
71646
72726
|
}
|
|
71647
72727
|
function getComplexityForFile(filePath) {
|
|
71648
72728
|
try {
|
|
71649
|
-
const
|
|
71650
|
-
if (
|
|
72729
|
+
const stat4 = fs57.statSync(filePath);
|
|
72730
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES4) {
|
|
71651
72731
|
return null;
|
|
71652
72732
|
}
|
|
71653
|
-
const content =
|
|
72733
|
+
const content = fs57.readFileSync(filePath, "utf-8");
|
|
71654
72734
|
return estimateCyclomaticComplexity(content);
|
|
71655
72735
|
} catch {
|
|
71656
72736
|
return null;
|
|
@@ -71660,8 +72740,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
71660
72740
|
let totalComplexity = 0;
|
|
71661
72741
|
const analyzedFiles = [];
|
|
71662
72742
|
for (const file3 of files) {
|
|
71663
|
-
const fullPath =
|
|
71664
|
-
if (!
|
|
72743
|
+
const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
|
|
72744
|
+
if (!fs57.existsSync(fullPath)) {
|
|
71665
72745
|
continue;
|
|
71666
72746
|
}
|
|
71667
72747
|
const complexity = getComplexityForFile(fullPath);
|
|
@@ -71782,8 +72862,8 @@ function countGoExports(content) {
|
|
|
71782
72862
|
}
|
|
71783
72863
|
function getExportCountForFile(filePath) {
|
|
71784
72864
|
try {
|
|
71785
|
-
const content =
|
|
71786
|
-
const ext =
|
|
72865
|
+
const content = fs57.readFileSync(filePath, "utf-8");
|
|
72866
|
+
const ext = path71.extname(filePath).toLowerCase();
|
|
71787
72867
|
switch (ext) {
|
|
71788
72868
|
case ".ts":
|
|
71789
72869
|
case ".tsx":
|
|
@@ -71809,8 +72889,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
71809
72889
|
let totalExports = 0;
|
|
71810
72890
|
const analyzedFiles = [];
|
|
71811
72891
|
for (const file3 of files) {
|
|
71812
|
-
const fullPath =
|
|
71813
|
-
if (!
|
|
72892
|
+
const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
|
|
72893
|
+
if (!fs57.existsSync(fullPath)) {
|
|
71814
72894
|
continue;
|
|
71815
72895
|
}
|
|
71816
72896
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -71843,16 +72923,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
71843
72923
|
let duplicateLines = 0;
|
|
71844
72924
|
const analyzedFiles = [];
|
|
71845
72925
|
for (const file3 of files) {
|
|
71846
|
-
const fullPath =
|
|
71847
|
-
if (!
|
|
72926
|
+
const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
|
|
72927
|
+
if (!fs57.existsSync(fullPath)) {
|
|
71848
72928
|
continue;
|
|
71849
72929
|
}
|
|
71850
72930
|
try {
|
|
71851
|
-
const
|
|
71852
|
-
if (
|
|
72931
|
+
const stat4 = fs57.statSync(fullPath);
|
|
72932
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES4) {
|
|
71853
72933
|
continue;
|
|
71854
72934
|
}
|
|
71855
|
-
const content =
|
|
72935
|
+
const content = fs57.readFileSync(fullPath, "utf-8");
|
|
71856
72936
|
const lines = content.split(`
|
|
71857
72937
|
`).filter((line) => line.trim().length > 0);
|
|
71858
72938
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -71876,8 +72956,8 @@ function countCodeLines(content) {
|
|
|
71876
72956
|
return lines.length;
|
|
71877
72957
|
}
|
|
71878
72958
|
function isTestFile(filePath) {
|
|
71879
|
-
const basename10 =
|
|
71880
|
-
const _ext =
|
|
72959
|
+
const basename10 = path71.basename(filePath);
|
|
72960
|
+
const _ext = path71.extname(filePath).toLowerCase();
|
|
71881
72961
|
const testPatterns = [
|
|
71882
72962
|
".test.",
|
|
71883
72963
|
".spec.",
|
|
@@ -71958,8 +73038,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
71958
73038
|
}
|
|
71959
73039
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
71960
73040
|
}
|
|
71961
|
-
function matchesGlobSegment(
|
|
71962
|
-
const normalizedPath =
|
|
73041
|
+
function matchesGlobSegment(path72, glob) {
|
|
73042
|
+
const normalizedPath = path72.replace(/\\/g, "/");
|
|
71963
73043
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
71964
73044
|
if (normalizedPath.includes("//")) {
|
|
71965
73045
|
return false;
|
|
@@ -71990,8 +73070,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
71990
73070
|
function hasGlobstar(glob) {
|
|
71991
73071
|
return glob.includes("**");
|
|
71992
73072
|
}
|
|
71993
|
-
function globMatches(
|
|
71994
|
-
const normalizedPath =
|
|
73073
|
+
function globMatches(path72, glob) {
|
|
73074
|
+
const normalizedPath = path72.replace(/\\/g, "/");
|
|
71995
73075
|
if (!glob || glob === "") {
|
|
71996
73076
|
if (normalizedPath.includes("//")) {
|
|
71997
73077
|
return false;
|
|
@@ -72027,31 +73107,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
72027
73107
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
72028
73108
|
let testLines = 0;
|
|
72029
73109
|
let codeLines = 0;
|
|
72030
|
-
const srcDir =
|
|
72031
|
-
if (
|
|
73110
|
+
const srcDir = path71.join(workingDir, "src");
|
|
73111
|
+
if (fs57.existsSync(srcDir)) {
|
|
72032
73112
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
72033
73113
|
codeLines += lines;
|
|
72034
73114
|
});
|
|
72035
73115
|
}
|
|
72036
73116
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
72037
73117
|
for (const dir of possibleSrcDirs) {
|
|
72038
|
-
const dirPath =
|
|
72039
|
-
if (
|
|
73118
|
+
const dirPath = path71.join(workingDir, dir);
|
|
73119
|
+
if (fs57.existsSync(dirPath)) {
|
|
72040
73120
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
72041
73121
|
codeLines += lines;
|
|
72042
73122
|
});
|
|
72043
73123
|
}
|
|
72044
73124
|
}
|
|
72045
|
-
const testsDir =
|
|
72046
|
-
if (
|
|
73125
|
+
const testsDir = path71.join(workingDir, "tests");
|
|
73126
|
+
if (fs57.existsSync(testsDir)) {
|
|
72047
73127
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
72048
73128
|
testLines += lines;
|
|
72049
73129
|
});
|
|
72050
73130
|
}
|
|
72051
73131
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
72052
73132
|
for (const dir of possibleTestDirs) {
|
|
72053
|
-
const dirPath =
|
|
72054
|
-
if (
|
|
73133
|
+
const dirPath = path71.join(workingDir, dir);
|
|
73134
|
+
if (fs57.existsSync(dirPath) && dirPath !== testsDir) {
|
|
72055
73135
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
72056
73136
|
testLines += lines;
|
|
72057
73137
|
});
|
|
@@ -72063,9 +73143,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
72063
73143
|
}
|
|
72064
73144
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
72065
73145
|
try {
|
|
72066
|
-
const entries =
|
|
73146
|
+
const entries = fs57.readdirSync(dirPath, { withFileTypes: true });
|
|
72067
73147
|
for (const entry of entries) {
|
|
72068
|
-
const fullPath =
|
|
73148
|
+
const fullPath = path71.join(dirPath, entry.name);
|
|
72069
73149
|
if (entry.isDirectory()) {
|
|
72070
73150
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
72071
73151
|
continue;
|
|
@@ -72073,7 +73153,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
72073
73153
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
72074
73154
|
} else if (entry.isFile()) {
|
|
72075
73155
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
72076
|
-
const ext =
|
|
73156
|
+
const ext = path71.extname(entry.name).toLowerCase();
|
|
72077
73157
|
const validExts = [
|
|
72078
73158
|
".ts",
|
|
72079
73159
|
".tsx",
|
|
@@ -72109,7 +73189,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
72109
73189
|
continue;
|
|
72110
73190
|
}
|
|
72111
73191
|
try {
|
|
72112
|
-
const content =
|
|
73192
|
+
const content = fs57.readFileSync(fullPath, "utf-8");
|
|
72113
73193
|
const lines = countCodeLines(content);
|
|
72114
73194
|
callback(lines);
|
|
72115
73195
|
} catch {}
|
|
@@ -72311,11 +73391,11 @@ async function getGitChurn(days, directory) {
|
|
|
72311
73391
|
}
|
|
72312
73392
|
function getComplexityForFile2(filePath) {
|
|
72313
73393
|
try {
|
|
72314
|
-
const
|
|
72315
|
-
if (
|
|
73394
|
+
const stat4 = fs58.statSync(filePath);
|
|
73395
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES5) {
|
|
72316
73396
|
return null;
|
|
72317
73397
|
}
|
|
72318
|
-
const content =
|
|
73398
|
+
const content = fs58.readFileSync(filePath, "utf-8");
|
|
72319
73399
|
return estimateCyclomaticComplexity(content);
|
|
72320
73400
|
} catch {
|
|
72321
73401
|
return null;
|
|
@@ -72326,7 +73406,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
72326
73406
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
72327
73407
|
const filteredChurn = new Map;
|
|
72328
73408
|
for (const [file3, count] of churnMap) {
|
|
72329
|
-
const ext =
|
|
73409
|
+
const ext = path72.extname(file3).toLowerCase();
|
|
72330
73410
|
if (extSet.has(ext)) {
|
|
72331
73411
|
filteredChurn.set(file3, count);
|
|
72332
73412
|
}
|
|
@@ -72336,8 +73416,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
72336
73416
|
let analyzedFiles = 0;
|
|
72337
73417
|
for (const [file3, churnCount] of filteredChurn) {
|
|
72338
73418
|
let fullPath = file3;
|
|
72339
|
-
if (!
|
|
72340
|
-
fullPath =
|
|
73419
|
+
if (!fs58.existsSync(fullPath)) {
|
|
73420
|
+
fullPath = path72.join(cwd, file3);
|
|
72341
73421
|
}
|
|
72342
73422
|
const complexity = getComplexityForFile2(fullPath);
|
|
72343
73423
|
if (complexity !== null) {
|
|
@@ -72512,7 +73592,7 @@ import {
|
|
|
72512
73592
|
readFileSync as readFileSync37,
|
|
72513
73593
|
writeFileSync as writeFileSync11
|
|
72514
73594
|
} from "fs";
|
|
72515
|
-
import { join as
|
|
73595
|
+
import { join as join65 } from "path";
|
|
72516
73596
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
72517
73597
|
var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
|
|
72518
73598
|
var COUNCIL_GATE_NAME = "council";
|
|
@@ -72546,9 +73626,9 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
72546
73626
|
if (!VALID_TASK_ID.test(synthesis.taskId)) {
|
|
72547
73627
|
throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" \u2014 must match N.M or N.M.P format`);
|
|
72548
73628
|
}
|
|
72549
|
-
const dir =
|
|
73629
|
+
const dir = join65(workingDir, EVIDENCE_DIR2);
|
|
72550
73630
|
mkdirSync18(dir, { recursive: true });
|
|
72551
|
-
const filePath =
|
|
73631
|
+
const filePath = join65(dir, `${synthesis.taskId}.json`);
|
|
72552
73632
|
const existingRoot = Object.create(null);
|
|
72553
73633
|
if (existsSync37(filePath)) {
|
|
72554
73634
|
try {
|
|
@@ -72581,7 +73661,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
72581
73661
|
updated.required_gates = [];
|
|
72582
73662
|
writeFileSync11(filePath, JSON.stringify(updated, null, 2));
|
|
72583
73663
|
try {
|
|
72584
|
-
const councilDir =
|
|
73664
|
+
const councilDir = join65(workingDir, ".swarm", "council");
|
|
72585
73665
|
mkdirSync18(councilDir, { recursive: true });
|
|
72586
73666
|
const auditLine = JSON.stringify({
|
|
72587
73667
|
round: synthesis.roundNumber,
|
|
@@ -72589,7 +73669,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
72589
73669
|
timestamp: synthesis.timestamp,
|
|
72590
73670
|
vetoedBy: synthesis.vetoedBy
|
|
72591
73671
|
});
|
|
72592
|
-
appendFileSync7(
|
|
73672
|
+
appendFileSync7(join65(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
|
|
72593
73673
|
`);
|
|
72594
73674
|
} catch (auditError) {
|
|
72595
73675
|
console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
|
|
@@ -72719,20 +73799,20 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
|
|
|
72719
73799
|
|
|
72720
73800
|
// src/council/criteria-store.ts
|
|
72721
73801
|
import { existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync38, writeFileSync as writeFileSync12 } from "fs";
|
|
72722
|
-
import { join as
|
|
73802
|
+
import { join as join66 } from "path";
|
|
72723
73803
|
var COUNCIL_DIR = ".swarm/council";
|
|
72724
73804
|
function writeCriteria(workingDir, taskId, criteria) {
|
|
72725
|
-
const dir =
|
|
73805
|
+
const dir = join66(workingDir, COUNCIL_DIR);
|
|
72726
73806
|
mkdirSync19(dir, { recursive: true });
|
|
72727
73807
|
const payload = {
|
|
72728
73808
|
taskId,
|
|
72729
73809
|
criteria,
|
|
72730
73810
|
declaredAt: new Date().toISOString()
|
|
72731
73811
|
};
|
|
72732
|
-
writeFileSync12(
|
|
73812
|
+
writeFileSync12(join66(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
|
|
72733
73813
|
}
|
|
72734
73814
|
function readCriteria(workingDir, taskId) {
|
|
72735
|
-
const filePath =
|
|
73815
|
+
const filePath = join66(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
|
|
72736
73816
|
if (!existsSync38(filePath))
|
|
72737
73817
|
return null;
|
|
72738
73818
|
try {
|
|
@@ -73069,8 +74149,8 @@ init_scope_persistence();
|
|
|
73069
74149
|
init_state();
|
|
73070
74150
|
init_task_id();
|
|
73071
74151
|
init_create_tool();
|
|
73072
|
-
import * as
|
|
73073
|
-
import * as
|
|
74152
|
+
import * as fs59 from "fs";
|
|
74153
|
+
import * as path73 from "path";
|
|
73074
74154
|
function validateTaskIdFormat2(taskId) {
|
|
73075
74155
|
return validateTaskIdFormat(taskId);
|
|
73076
74156
|
}
|
|
@@ -73144,8 +74224,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73144
74224
|
};
|
|
73145
74225
|
}
|
|
73146
74226
|
}
|
|
73147
|
-
normalizedDir =
|
|
73148
|
-
const pathParts = normalizedDir.split(
|
|
74227
|
+
normalizedDir = path73.normalize(args2.working_directory);
|
|
74228
|
+
const pathParts = normalizedDir.split(path73.sep);
|
|
73149
74229
|
if (pathParts.includes("..")) {
|
|
73150
74230
|
return {
|
|
73151
74231
|
success: false,
|
|
@@ -73155,11 +74235,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73155
74235
|
]
|
|
73156
74236
|
};
|
|
73157
74237
|
}
|
|
73158
|
-
const resolvedDir =
|
|
74238
|
+
const resolvedDir = path73.resolve(normalizedDir);
|
|
73159
74239
|
try {
|
|
73160
|
-
const realPath =
|
|
73161
|
-
const planPath2 =
|
|
73162
|
-
if (!
|
|
74240
|
+
const realPath = fs59.realpathSync(resolvedDir);
|
|
74241
|
+
const planPath2 = path73.join(realPath, ".swarm", "plan.json");
|
|
74242
|
+
if (!fs59.existsSync(planPath2)) {
|
|
73163
74243
|
return {
|
|
73164
74244
|
success: false,
|
|
73165
74245
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -73182,8 +74262,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73182
74262
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
73183
74263
|
}
|
|
73184
74264
|
const directory = normalizedDir || fallbackDir;
|
|
73185
|
-
const planPath =
|
|
73186
|
-
if (!
|
|
74265
|
+
const planPath = path73.resolve(directory, ".swarm", "plan.json");
|
|
74266
|
+
if (!fs59.existsSync(planPath)) {
|
|
73187
74267
|
return {
|
|
73188
74268
|
success: false,
|
|
73189
74269
|
message: "No plan found",
|
|
@@ -73192,7 +74272,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73192
74272
|
}
|
|
73193
74273
|
let planContent;
|
|
73194
74274
|
try {
|
|
73195
|
-
planContent = JSON.parse(
|
|
74275
|
+
planContent = JSON.parse(fs59.readFileSync(planPath, "utf-8"));
|
|
73196
74276
|
} catch {
|
|
73197
74277
|
return {
|
|
73198
74278
|
success: false,
|
|
@@ -73222,8 +74302,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73222
74302
|
const normalizeErrors = [];
|
|
73223
74303
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
73224
74304
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
73225
|
-
if (
|
|
73226
|
-
const relativePath =
|
|
74305
|
+
if (path73.isAbsolute(file3)) {
|
|
74306
|
+
const relativePath = path73.relative(dir, file3).replace(/\\/g, "/");
|
|
73227
74307
|
if (relativePath.startsWith("..")) {
|
|
73228
74308
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
73229
74309
|
return file3;
|
|
@@ -73283,8 +74363,8 @@ var declare_scope = createSwarmTool({
|
|
|
73283
74363
|
// src/tools/diff.ts
|
|
73284
74364
|
init_dist();
|
|
73285
74365
|
import * as child_process7 from "child_process";
|
|
73286
|
-
import * as
|
|
73287
|
-
import * as
|
|
74366
|
+
import * as fs60 from "fs";
|
|
74367
|
+
import * as path74 from "path";
|
|
73288
74368
|
init_create_tool();
|
|
73289
74369
|
var MAX_DIFF_LINES = 500;
|
|
73290
74370
|
var DIFF_TIMEOUT_MS = 30000;
|
|
@@ -73313,20 +74393,20 @@ function validateBase(base) {
|
|
|
73313
74393
|
function validatePaths(paths) {
|
|
73314
74394
|
if (!paths)
|
|
73315
74395
|
return null;
|
|
73316
|
-
for (const
|
|
73317
|
-
if (!
|
|
74396
|
+
for (const path75 of paths) {
|
|
74397
|
+
if (!path75 || path75.length === 0) {
|
|
73318
74398
|
return "empty path not allowed";
|
|
73319
74399
|
}
|
|
73320
|
-
if (
|
|
74400
|
+
if (path75.length > MAX_PATH_LENGTH) {
|
|
73321
74401
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
73322
74402
|
}
|
|
73323
|
-
if (SHELL_METACHARACTERS2.test(
|
|
74403
|
+
if (SHELL_METACHARACTERS2.test(path75)) {
|
|
73324
74404
|
return "path contains shell metacharacters";
|
|
73325
74405
|
}
|
|
73326
|
-
if (
|
|
74406
|
+
if (path75.startsWith("-")) {
|
|
73327
74407
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
73328
74408
|
}
|
|
73329
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
74409
|
+
if (CONTROL_CHAR_PATTERN2.test(path75)) {
|
|
73330
74410
|
return "path contains control characters";
|
|
73331
74411
|
}
|
|
73332
74412
|
}
|
|
@@ -73432,8 +74512,8 @@ var diff = createSwarmTool({
|
|
|
73432
74512
|
if (parts2.length >= 3) {
|
|
73433
74513
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
73434
74514
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
73435
|
-
const
|
|
73436
|
-
files.push({ path:
|
|
74515
|
+
const path75 = parts2[2];
|
|
74516
|
+
files.push({ path: path75, additions, deletions });
|
|
73437
74517
|
}
|
|
73438
74518
|
}
|
|
73439
74519
|
const contractChanges = [];
|
|
@@ -73473,7 +74553,7 @@ var diff = createSwarmTool({
|
|
|
73473
74553
|
} else if (base === "unstaged") {
|
|
73474
74554
|
const oldRef = `:${file3.path}`;
|
|
73475
74555
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
73476
|
-
newContent =
|
|
74556
|
+
newContent = fs60.readFileSync(path74.join(directory, file3.path), "utf-8");
|
|
73477
74557
|
} else {
|
|
73478
74558
|
const oldRef = `${base}:${file3.path}`;
|
|
73479
74559
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
@@ -73547,8 +74627,8 @@ var diff = createSwarmTool({
|
|
|
73547
74627
|
// src/tools/diff-summary.ts
|
|
73548
74628
|
init_dist();
|
|
73549
74629
|
import * as child_process8 from "child_process";
|
|
73550
|
-
import * as
|
|
73551
|
-
import * as
|
|
74630
|
+
import * as fs61 from "fs";
|
|
74631
|
+
import * as path75 from "path";
|
|
73552
74632
|
init_create_tool();
|
|
73553
74633
|
var diff_summary = createSwarmTool({
|
|
73554
74634
|
description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
|
|
@@ -73596,7 +74676,7 @@ var diff_summary = createSwarmTool({
|
|
|
73596
74676
|
}
|
|
73597
74677
|
try {
|
|
73598
74678
|
let oldContent;
|
|
73599
|
-
const newContent =
|
|
74679
|
+
const newContent = fs61.readFileSync(path75.join(workingDir, filePath), "utf-8");
|
|
73600
74680
|
if (fileExistsInHead) {
|
|
73601
74681
|
oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
|
|
73602
74682
|
encoding: "utf-8",
|
|
@@ -73823,8 +74903,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
73823
74903
|
init_dist();
|
|
73824
74904
|
init_create_tool();
|
|
73825
74905
|
init_path_security();
|
|
73826
|
-
import * as
|
|
73827
|
-
import * as
|
|
74906
|
+
import * as fs62 from "fs";
|
|
74907
|
+
import * as path76 from "path";
|
|
73828
74908
|
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
73829
74909
|
var MAX_EVIDENCE_FILES = 1000;
|
|
73830
74910
|
var EVIDENCE_DIR3 = ".swarm/evidence";
|
|
@@ -73851,9 +74931,9 @@ function validateRequiredTypes(input) {
|
|
|
73851
74931
|
return null;
|
|
73852
74932
|
}
|
|
73853
74933
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
73854
|
-
const normalizedCwd =
|
|
73855
|
-
const swarmPath =
|
|
73856
|
-
const normalizedPath =
|
|
74934
|
+
const normalizedCwd = path76.resolve(cwd);
|
|
74935
|
+
const swarmPath = path76.join(normalizedCwd, ".swarm");
|
|
74936
|
+
const normalizedPath = path76.resolve(filePath);
|
|
73857
74937
|
return normalizedPath.startsWith(swarmPath);
|
|
73858
74938
|
}
|
|
73859
74939
|
function parseCompletedTasks(planContent) {
|
|
@@ -73869,12 +74949,12 @@ function parseCompletedTasks(planContent) {
|
|
|
73869
74949
|
}
|
|
73870
74950
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
73871
74951
|
const evidence = [];
|
|
73872
|
-
if (!
|
|
74952
|
+
if (!fs62.existsSync(evidenceDir) || !fs62.statSync(evidenceDir).isDirectory()) {
|
|
73873
74953
|
return evidence;
|
|
73874
74954
|
}
|
|
73875
74955
|
let files;
|
|
73876
74956
|
try {
|
|
73877
|
-
files =
|
|
74957
|
+
files = fs62.readdirSync(evidenceDir);
|
|
73878
74958
|
} catch {
|
|
73879
74959
|
return evidence;
|
|
73880
74960
|
}
|
|
@@ -73883,15 +74963,15 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
73883
74963
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
73884
74964
|
continue;
|
|
73885
74965
|
}
|
|
73886
|
-
const filePath =
|
|
74966
|
+
const filePath = path76.join(evidenceDir, filename);
|
|
73887
74967
|
try {
|
|
73888
|
-
const resolvedPath =
|
|
73889
|
-
const evidenceDirResolved =
|
|
74968
|
+
const resolvedPath = path76.resolve(filePath);
|
|
74969
|
+
const evidenceDirResolved = path76.resolve(evidenceDir);
|
|
73890
74970
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
73891
74971
|
continue;
|
|
73892
74972
|
}
|
|
73893
|
-
const
|
|
73894
|
-
if (!
|
|
74973
|
+
const stat4 = fs62.lstatSync(filePath);
|
|
74974
|
+
if (!stat4.isFile()) {
|
|
73895
74975
|
continue;
|
|
73896
74976
|
}
|
|
73897
74977
|
} catch {
|
|
@@ -73899,7 +74979,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
73899
74979
|
}
|
|
73900
74980
|
let fileStat;
|
|
73901
74981
|
try {
|
|
73902
|
-
fileStat =
|
|
74982
|
+
fileStat = fs62.statSync(filePath);
|
|
73903
74983
|
if (fileStat.size > MAX_FILE_SIZE_BYTES6) {
|
|
73904
74984
|
continue;
|
|
73905
74985
|
}
|
|
@@ -73908,7 +74988,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
73908
74988
|
}
|
|
73909
74989
|
let content;
|
|
73910
74990
|
try {
|
|
73911
|
-
content =
|
|
74991
|
+
content = fs62.readFileSync(filePath, "utf-8");
|
|
73912
74992
|
} catch {
|
|
73913
74993
|
continue;
|
|
73914
74994
|
}
|
|
@@ -74004,7 +75084,7 @@ var evidence_check = createSwarmTool({
|
|
|
74004
75084
|
return JSON.stringify(errorResult, null, 2);
|
|
74005
75085
|
}
|
|
74006
75086
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
74007
|
-
const planPath =
|
|
75087
|
+
const planPath = path76.join(cwd, PLAN_FILE);
|
|
74008
75088
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
74009
75089
|
const errorResult = {
|
|
74010
75090
|
error: "plan file path validation failed",
|
|
@@ -74018,7 +75098,7 @@ var evidence_check = createSwarmTool({
|
|
|
74018
75098
|
}
|
|
74019
75099
|
let planContent;
|
|
74020
75100
|
try {
|
|
74021
|
-
planContent =
|
|
75101
|
+
planContent = fs62.readFileSync(planPath, "utf-8");
|
|
74022
75102
|
} catch {
|
|
74023
75103
|
const result2 = {
|
|
74024
75104
|
message: "No completed tasks found in plan.",
|
|
@@ -74036,7 +75116,7 @@ var evidence_check = createSwarmTool({
|
|
|
74036
75116
|
};
|
|
74037
75117
|
return JSON.stringify(result2, null, 2);
|
|
74038
75118
|
}
|
|
74039
|
-
const evidenceDir =
|
|
75119
|
+
const evidenceDir = path76.join(cwd, EVIDENCE_DIR3);
|
|
74040
75120
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
74041
75121
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
74042
75122
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -74053,8 +75133,8 @@ var evidence_check = createSwarmTool({
|
|
|
74053
75133
|
// src/tools/file-extractor.ts
|
|
74054
75134
|
init_tool();
|
|
74055
75135
|
init_create_tool();
|
|
74056
|
-
import * as
|
|
74057
|
-
import * as
|
|
75136
|
+
import * as fs63 from "fs";
|
|
75137
|
+
import * as path77 from "path";
|
|
74058
75138
|
var EXT_MAP = {
|
|
74059
75139
|
python: ".py",
|
|
74060
75140
|
py: ".py",
|
|
@@ -74116,8 +75196,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
74116
75196
|
execute: async (args2, directory) => {
|
|
74117
75197
|
const { content, output_dir, prefix } = args2;
|
|
74118
75198
|
const targetDir = output_dir || directory;
|
|
74119
|
-
if (!
|
|
74120
|
-
|
|
75199
|
+
if (!fs63.existsSync(targetDir)) {
|
|
75200
|
+
fs63.mkdirSync(targetDir, { recursive: true });
|
|
74121
75201
|
}
|
|
74122
75202
|
if (!content) {
|
|
74123
75203
|
return "Error: content is required";
|
|
@@ -74135,16 +75215,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
74135
75215
|
if (prefix) {
|
|
74136
75216
|
filename = `${prefix}_${filename}`;
|
|
74137
75217
|
}
|
|
74138
|
-
let filepath =
|
|
74139
|
-
const base =
|
|
74140
|
-
const ext =
|
|
75218
|
+
let filepath = path77.join(targetDir, filename);
|
|
75219
|
+
const base = path77.basename(filepath, path77.extname(filepath));
|
|
75220
|
+
const ext = path77.extname(filepath);
|
|
74141
75221
|
let counter = 1;
|
|
74142
|
-
while (
|
|
74143
|
-
filepath =
|
|
75222
|
+
while (fs63.existsSync(filepath)) {
|
|
75223
|
+
filepath = path77.join(targetDir, `${base}_${counter}${ext}`);
|
|
74144
75224
|
counter++;
|
|
74145
75225
|
}
|
|
74146
75226
|
try {
|
|
74147
|
-
|
|
75227
|
+
fs63.writeFileSync(filepath, code.trim(), "utf-8");
|
|
74148
75228
|
savedFiles.push(filepath);
|
|
74149
75229
|
} catch (error93) {
|
|
74150
75230
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -74403,8 +75483,8 @@ var gitingest = createSwarmTool({
|
|
|
74403
75483
|
init_dist();
|
|
74404
75484
|
init_create_tool();
|
|
74405
75485
|
init_path_security();
|
|
74406
|
-
import * as
|
|
74407
|
-
import * as
|
|
75486
|
+
import * as fs64 from "fs";
|
|
75487
|
+
import * as path78 from "path";
|
|
74408
75488
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
74409
75489
|
var MAX_SYMBOL_LENGTH = 256;
|
|
74410
75490
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
@@ -74452,7 +75532,7 @@ function validateSymbolInput(symbol3) {
|
|
|
74452
75532
|
return null;
|
|
74453
75533
|
}
|
|
74454
75534
|
function isBinaryFile2(filePath, buffer) {
|
|
74455
|
-
const ext =
|
|
75535
|
+
const ext = path78.extname(filePath).toLowerCase();
|
|
74456
75536
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
74457
75537
|
return false;
|
|
74458
75538
|
}
|
|
@@ -74476,15 +75556,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
74476
75556
|
const imports = [];
|
|
74477
75557
|
let _resolvedTarget;
|
|
74478
75558
|
try {
|
|
74479
|
-
_resolvedTarget =
|
|
75559
|
+
_resolvedTarget = path78.resolve(targetFile);
|
|
74480
75560
|
} catch {
|
|
74481
75561
|
_resolvedTarget = targetFile;
|
|
74482
75562
|
}
|
|
74483
|
-
const targetBasename =
|
|
75563
|
+
const targetBasename = path78.basename(targetFile, path78.extname(targetFile));
|
|
74484
75564
|
const targetWithExt = targetFile;
|
|
74485
75565
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
74486
|
-
const normalizedTargetWithExt =
|
|
74487
|
-
const normalizedTargetWithoutExt =
|
|
75566
|
+
const normalizedTargetWithExt = path78.normalize(targetWithExt).replace(/\\/g, "/");
|
|
75567
|
+
const normalizedTargetWithoutExt = path78.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
74488
75568
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
74489
75569
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
74490
75570
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -74507,9 +75587,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
74507
75587
|
}
|
|
74508
75588
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
74509
75589
|
let isMatch = false;
|
|
74510
|
-
const _targetDir =
|
|
74511
|
-
const targetExt =
|
|
74512
|
-
const targetBasenameNoExt =
|
|
75590
|
+
const _targetDir = path78.dirname(targetFile);
|
|
75591
|
+
const targetExt = path78.extname(targetFile);
|
|
75592
|
+
const targetBasenameNoExt = path78.basename(targetFile, targetExt);
|
|
74513
75593
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
74514
75594
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
74515
75595
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -74566,7 +75646,7 @@ var SKIP_DIRECTORIES4 = new Set([
|
|
|
74566
75646
|
function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
74567
75647
|
let entries;
|
|
74568
75648
|
try {
|
|
74569
|
-
entries =
|
|
75649
|
+
entries = fs64.readdirSync(dir);
|
|
74570
75650
|
} catch (e) {
|
|
74571
75651
|
stats.fileErrors.push({
|
|
74572
75652
|
path: dir,
|
|
@@ -74577,13 +75657,13 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
74577
75657
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
74578
75658
|
for (const entry of entries) {
|
|
74579
75659
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
74580
|
-
stats.skippedDirs.push(
|
|
75660
|
+
stats.skippedDirs.push(path78.join(dir, entry));
|
|
74581
75661
|
continue;
|
|
74582
75662
|
}
|
|
74583
|
-
const fullPath =
|
|
74584
|
-
let
|
|
75663
|
+
const fullPath = path78.join(dir, entry);
|
|
75664
|
+
let stat4;
|
|
74585
75665
|
try {
|
|
74586
|
-
|
|
75666
|
+
stat4 = fs64.statSync(fullPath);
|
|
74587
75667
|
} catch (e) {
|
|
74588
75668
|
stats.fileErrors.push({
|
|
74589
75669
|
path: fullPath,
|
|
@@ -74591,10 +75671,10 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
74591
75671
|
});
|
|
74592
75672
|
continue;
|
|
74593
75673
|
}
|
|
74594
|
-
if (
|
|
75674
|
+
if (stat4.isDirectory()) {
|
|
74595
75675
|
findSourceFiles3(fullPath, files, stats);
|
|
74596
|
-
} else if (
|
|
74597
|
-
const ext =
|
|
75676
|
+
} else if (stat4.isFile()) {
|
|
75677
|
+
const ext = path78.extname(fullPath).toLowerCase();
|
|
74598
75678
|
if (SUPPORTED_EXTENSIONS3.includes(ext)) {
|
|
74599
75679
|
files.push(fullPath);
|
|
74600
75680
|
}
|
|
@@ -74651,8 +75731,8 @@ var imports = createSwarmTool({
|
|
|
74651
75731
|
return JSON.stringify(errorResult, null, 2);
|
|
74652
75732
|
}
|
|
74653
75733
|
try {
|
|
74654
|
-
const targetFile =
|
|
74655
|
-
if (!
|
|
75734
|
+
const targetFile = path78.resolve(file3);
|
|
75735
|
+
if (!fs64.existsSync(targetFile)) {
|
|
74656
75736
|
const errorResult = {
|
|
74657
75737
|
error: `target file not found: ${file3}`,
|
|
74658
75738
|
target: file3,
|
|
@@ -74662,7 +75742,7 @@ var imports = createSwarmTool({
|
|
|
74662
75742
|
};
|
|
74663
75743
|
return JSON.stringify(errorResult, null, 2);
|
|
74664
75744
|
}
|
|
74665
|
-
const targetStat =
|
|
75745
|
+
const targetStat = fs64.statSync(targetFile);
|
|
74666
75746
|
if (!targetStat.isFile()) {
|
|
74667
75747
|
const errorResult = {
|
|
74668
75748
|
error: "target must be a file, not a directory",
|
|
@@ -74673,7 +75753,7 @@ var imports = createSwarmTool({
|
|
|
74673
75753
|
};
|
|
74674
75754
|
return JSON.stringify(errorResult, null, 2);
|
|
74675
75755
|
}
|
|
74676
|
-
const baseDir =
|
|
75756
|
+
const baseDir = path78.dirname(targetFile);
|
|
74677
75757
|
const scanStats = {
|
|
74678
75758
|
skippedDirs: [],
|
|
74679
75759
|
skippedFiles: 0,
|
|
@@ -74688,12 +75768,12 @@ var imports = createSwarmTool({
|
|
|
74688
75768
|
if (consumers.length >= MAX_CONSUMERS)
|
|
74689
75769
|
break;
|
|
74690
75770
|
try {
|
|
74691
|
-
const
|
|
74692
|
-
if (
|
|
75771
|
+
const stat4 = fs64.statSync(filePath);
|
|
75772
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES7) {
|
|
74693
75773
|
skippedFileCount++;
|
|
74694
75774
|
continue;
|
|
74695
75775
|
}
|
|
74696
|
-
const buffer =
|
|
75776
|
+
const buffer = fs64.readFileSync(filePath);
|
|
74697
75777
|
if (isBinaryFile2(filePath, buffer)) {
|
|
74698
75778
|
skippedFileCount++;
|
|
74699
75779
|
continue;
|
|
@@ -75205,8 +76285,8 @@ init_schema();
|
|
|
75205
76285
|
init_qa_gate_profile();
|
|
75206
76286
|
init_manager2();
|
|
75207
76287
|
init_curator();
|
|
75208
|
-
import * as
|
|
75209
|
-
import * as
|
|
76288
|
+
import * as fs65 from "fs";
|
|
76289
|
+
import * as path79 from "path";
|
|
75210
76290
|
init_knowledge_curator();
|
|
75211
76291
|
init_knowledge_reader();
|
|
75212
76292
|
init_knowledge_store();
|
|
@@ -75437,11 +76517,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75437
76517
|
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
75438
76518
|
}
|
|
75439
76519
|
try {
|
|
75440
|
-
const driftEvidencePath =
|
|
76520
|
+
const driftEvidencePath = path79.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
75441
76521
|
let driftVerdictFound = false;
|
|
75442
76522
|
let driftVerdictApproved = false;
|
|
75443
76523
|
try {
|
|
75444
|
-
const driftEvidenceContent =
|
|
76524
|
+
const driftEvidenceContent = fs65.readFileSync(driftEvidencePath, "utf-8");
|
|
75445
76525
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
75446
76526
|
const entries = driftEvidence.entries ?? [];
|
|
75447
76527
|
for (const entry of entries) {
|
|
@@ -75471,14 +76551,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75471
76551
|
driftVerdictFound = false;
|
|
75472
76552
|
}
|
|
75473
76553
|
if (!driftVerdictFound) {
|
|
75474
|
-
const specPath =
|
|
75475
|
-
const specExists =
|
|
76554
|
+
const specPath = path79.join(dir, ".swarm", "spec.md");
|
|
76555
|
+
const specExists = fs65.existsSync(specPath);
|
|
75476
76556
|
if (!specExists) {
|
|
75477
76557
|
let incompleteTaskCount = 0;
|
|
75478
76558
|
let planPhaseFound = false;
|
|
75479
76559
|
try {
|
|
75480
76560
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75481
|
-
const planRaw =
|
|
76561
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75482
76562
|
const plan = JSON.parse(planRaw);
|
|
75483
76563
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
75484
76564
|
if (targetPhase) {
|
|
@@ -75529,11 +76609,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75529
76609
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
75530
76610
|
const effective = getEffectiveGates(profile, overrides);
|
|
75531
76611
|
if (effective.hallucination_guard === true) {
|
|
75532
|
-
const hgPath =
|
|
76612
|
+
const hgPath = path79.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
75533
76613
|
let hgVerdictFound = false;
|
|
75534
76614
|
let hgVerdictApproved = false;
|
|
75535
76615
|
try {
|
|
75536
|
-
const hgContent =
|
|
76616
|
+
const hgContent = fs65.readFileSync(hgPath, "utf-8");
|
|
75537
76617
|
const hgBundle = JSON.parse(hgContent);
|
|
75538
76618
|
for (const entry of hgBundle.entries ?? []) {
|
|
75539
76619
|
if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
|
|
@@ -75601,7 +76681,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75601
76681
|
}
|
|
75602
76682
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
75603
76683
|
try {
|
|
75604
|
-
const projectName =
|
|
76684
|
+
const projectName = path79.basename(dir);
|
|
75605
76685
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
75606
76686
|
if (curationResult) {
|
|
75607
76687
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -75681,7 +76761,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75681
76761
|
let phaseRequiredAgents;
|
|
75682
76762
|
try {
|
|
75683
76763
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75684
|
-
const planRaw =
|
|
76764
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75685
76765
|
const plan = JSON.parse(planRaw);
|
|
75686
76766
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
75687
76767
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -75696,7 +76776,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75696
76776
|
if (agentsMissing.length > 0) {
|
|
75697
76777
|
try {
|
|
75698
76778
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75699
|
-
const planRaw =
|
|
76779
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75700
76780
|
const plan = JSON.parse(planRaw);
|
|
75701
76781
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
75702
76782
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -75736,7 +76816,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75736
76816
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
75737
76817
|
try {
|
|
75738
76818
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75739
|
-
const planRaw =
|
|
76819
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75740
76820
|
const plan = JSON.parse(planRaw);
|
|
75741
76821
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
75742
76822
|
if (targetPhase) {
|
|
@@ -75790,7 +76870,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75790
76870
|
}
|
|
75791
76871
|
try {
|
|
75792
76872
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
75793
|
-
|
|
76873
|
+
fs65.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
75794
76874
|
`, "utf-8");
|
|
75795
76875
|
} catch (writeError) {
|
|
75796
76876
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -75865,12 +76945,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75865
76945
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
75866
76946
|
try {
|
|
75867
76947
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75868
|
-
const planRaw =
|
|
76948
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75869
76949
|
const plan2 = JSON.parse(planRaw);
|
|
75870
76950
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
75871
76951
|
if (phaseObj) {
|
|
75872
76952
|
phaseObj.status = "complete";
|
|
75873
|
-
|
|
76953
|
+
fs65.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
75874
76954
|
}
|
|
75875
76955
|
} catch {}
|
|
75876
76956
|
} else if (plan) {
|
|
@@ -75907,12 +76987,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75907
76987
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
75908
76988
|
try {
|
|
75909
76989
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75910
|
-
const planRaw =
|
|
76990
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75911
76991
|
const plan = JSON.parse(planRaw);
|
|
75912
76992
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
75913
76993
|
if (phaseObj) {
|
|
75914
76994
|
phaseObj.status = "complete";
|
|
75915
|
-
|
|
76995
|
+
fs65.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
75916
76996
|
}
|
|
75917
76997
|
} catch {}
|
|
75918
76998
|
}
|
|
@@ -75969,8 +77049,8 @@ init_dist();
|
|
|
75969
77049
|
init_discovery();
|
|
75970
77050
|
init_utils();
|
|
75971
77051
|
init_create_tool();
|
|
75972
|
-
import * as
|
|
75973
|
-
import * as
|
|
77052
|
+
import * as fs66 from "fs";
|
|
77053
|
+
import * as path80 from "path";
|
|
75974
77054
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
75975
77055
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
75976
77056
|
function isValidEcosystem(value) {
|
|
@@ -75998,31 +77078,31 @@ function validateArgs3(args2) {
|
|
|
75998
77078
|
function detectEcosystems(directory) {
|
|
75999
77079
|
const ecosystems = [];
|
|
76000
77080
|
const cwd = directory;
|
|
76001
|
-
if (
|
|
77081
|
+
if (fs66.existsSync(path80.join(cwd, "package.json"))) {
|
|
76002
77082
|
ecosystems.push("npm");
|
|
76003
77083
|
}
|
|
76004
|
-
if (
|
|
77084
|
+
if (fs66.existsSync(path80.join(cwd, "pyproject.toml")) || fs66.existsSync(path80.join(cwd, "requirements.txt"))) {
|
|
76005
77085
|
ecosystems.push("pip");
|
|
76006
77086
|
}
|
|
76007
|
-
if (
|
|
77087
|
+
if (fs66.existsSync(path80.join(cwd, "Cargo.toml"))) {
|
|
76008
77088
|
ecosystems.push("cargo");
|
|
76009
77089
|
}
|
|
76010
|
-
if (
|
|
77090
|
+
if (fs66.existsSync(path80.join(cwd, "go.mod"))) {
|
|
76011
77091
|
ecosystems.push("go");
|
|
76012
77092
|
}
|
|
76013
77093
|
try {
|
|
76014
|
-
const files =
|
|
77094
|
+
const files = fs66.readdirSync(cwd);
|
|
76015
77095
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
76016
77096
|
ecosystems.push("dotnet");
|
|
76017
77097
|
}
|
|
76018
77098
|
} catch {}
|
|
76019
|
-
if (
|
|
77099
|
+
if (fs66.existsSync(path80.join(cwd, "Gemfile")) || fs66.existsSync(path80.join(cwd, "Gemfile.lock"))) {
|
|
76020
77100
|
ecosystems.push("ruby");
|
|
76021
77101
|
}
|
|
76022
|
-
if (
|
|
77102
|
+
if (fs66.existsSync(path80.join(cwd, "pubspec.yaml"))) {
|
|
76023
77103
|
ecosystems.push("dart");
|
|
76024
77104
|
}
|
|
76025
|
-
if (
|
|
77105
|
+
if (fs66.existsSync(path80.join(cwd, "composer.lock"))) {
|
|
76026
77106
|
ecosystems.push("composer");
|
|
76027
77107
|
}
|
|
76028
77108
|
return ecosystems;
|
|
@@ -77181,8 +78261,8 @@ var pkg_audit = createSwarmTool({
|
|
|
77181
78261
|
// src/tools/placeholder-scan.ts
|
|
77182
78262
|
init_dist();
|
|
77183
78263
|
init_manager2();
|
|
77184
|
-
import * as
|
|
77185
|
-
import * as
|
|
78264
|
+
import * as fs67 from "fs";
|
|
78265
|
+
import * as path81 from "path";
|
|
77186
78266
|
init_utils();
|
|
77187
78267
|
init_create_tool();
|
|
77188
78268
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -77305,7 +78385,7 @@ function isScaffoldFile(filePath) {
|
|
|
77305
78385
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
77306
78386
|
return true;
|
|
77307
78387
|
}
|
|
77308
|
-
const filename =
|
|
78388
|
+
const filename = path81.basename(filePath);
|
|
77309
78389
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
77310
78390
|
return true;
|
|
77311
78391
|
}
|
|
@@ -77322,7 +78402,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
77322
78402
|
if (regex.test(normalizedPath)) {
|
|
77323
78403
|
return true;
|
|
77324
78404
|
}
|
|
77325
|
-
const filename =
|
|
78405
|
+
const filename = path81.basename(filePath);
|
|
77326
78406
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
77327
78407
|
if (filenameRegex.test(filename)) {
|
|
77328
78408
|
return true;
|
|
@@ -77331,7 +78411,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
77331
78411
|
return false;
|
|
77332
78412
|
}
|
|
77333
78413
|
function isParserSupported(filePath) {
|
|
77334
|
-
const ext =
|
|
78414
|
+
const ext = path81.extname(filePath).toLowerCase();
|
|
77335
78415
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
77336
78416
|
}
|
|
77337
78417
|
function isPlanFile(filePath) {
|
|
@@ -77578,28 +78658,28 @@ async function placeholderScan(input, directory) {
|
|
|
77578
78658
|
let filesScanned = 0;
|
|
77579
78659
|
const filesWithFindings = new Set;
|
|
77580
78660
|
for (const filePath of changed_files) {
|
|
77581
|
-
const fullPath =
|
|
77582
|
-
const resolvedDirectory =
|
|
77583
|
-
if (!fullPath.startsWith(resolvedDirectory +
|
|
78661
|
+
const fullPath = path81.isAbsolute(filePath) ? filePath : path81.resolve(directory, filePath);
|
|
78662
|
+
const resolvedDirectory = path81.resolve(directory);
|
|
78663
|
+
if (!fullPath.startsWith(resolvedDirectory + path81.sep) && fullPath !== resolvedDirectory) {
|
|
77584
78664
|
continue;
|
|
77585
78665
|
}
|
|
77586
|
-
if (!
|
|
78666
|
+
if (!fs67.existsSync(fullPath)) {
|
|
77587
78667
|
continue;
|
|
77588
78668
|
}
|
|
77589
78669
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
77590
78670
|
continue;
|
|
77591
78671
|
}
|
|
77592
|
-
const relativeFilePath =
|
|
78672
|
+
const relativeFilePath = path81.relative(directory, fullPath).replace(/\\/g, "/");
|
|
77593
78673
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
77594
78674
|
continue;
|
|
77595
78675
|
}
|
|
77596
78676
|
let content;
|
|
77597
78677
|
try {
|
|
77598
|
-
const
|
|
77599
|
-
if (
|
|
78678
|
+
const stat4 = fs67.statSync(fullPath);
|
|
78679
|
+
if (stat4.size > MAX_FILE_SIZE) {
|
|
77600
78680
|
continue;
|
|
77601
78681
|
}
|
|
77602
|
-
content =
|
|
78682
|
+
content = fs67.readFileSync(fullPath, "utf-8");
|
|
77603
78683
|
} catch {
|
|
77604
78684
|
continue;
|
|
77605
78685
|
}
|
|
@@ -77661,8 +78741,8 @@ var placeholder_scan = createSwarmTool({
|
|
|
77661
78741
|
});
|
|
77662
78742
|
// src/tools/pre-check-batch.ts
|
|
77663
78743
|
init_dist();
|
|
77664
|
-
import * as
|
|
77665
|
-
import * as
|
|
78744
|
+
import * as fs70 from "fs";
|
|
78745
|
+
import * as path84 from "path";
|
|
77666
78746
|
init_manager2();
|
|
77667
78747
|
init_utils();
|
|
77668
78748
|
init_create_tool();
|
|
@@ -77797,8 +78877,8 @@ var quality_budget = createSwarmTool({
|
|
|
77797
78877
|
init_dist();
|
|
77798
78878
|
init_manager2();
|
|
77799
78879
|
init_detector();
|
|
77800
|
-
import * as
|
|
77801
|
-
import * as
|
|
78880
|
+
import * as fs69 from "fs";
|
|
78881
|
+
import * as path83 from "path";
|
|
77802
78882
|
import { extname as extname18 } from "path";
|
|
77803
78883
|
|
|
77804
78884
|
// src/sast/rules/c.ts
|
|
@@ -78691,25 +79771,25 @@ init_create_tool();
|
|
|
78691
79771
|
// src/tools/sast-baseline.ts
|
|
78692
79772
|
init_utils2();
|
|
78693
79773
|
import * as crypto8 from "crypto";
|
|
78694
|
-
import * as
|
|
78695
|
-
import * as
|
|
79774
|
+
import * as fs68 from "fs";
|
|
79775
|
+
import * as path82 from "path";
|
|
78696
79776
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
78697
79777
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
78698
79778
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
78699
79779
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
78700
79780
|
function normalizeFindingPath(directory, file3) {
|
|
78701
|
-
const resolved =
|
|
78702
|
-
const rel =
|
|
79781
|
+
const resolved = path82.isAbsolute(file3) ? file3 : path82.resolve(directory, file3);
|
|
79782
|
+
const rel = path82.relative(path82.resolve(directory), resolved);
|
|
78703
79783
|
return rel.replace(/\\/g, "/");
|
|
78704
79784
|
}
|
|
78705
79785
|
function baselineRelPath(phase) {
|
|
78706
|
-
return
|
|
79786
|
+
return path82.join("evidence", String(phase), "sast-baseline.json");
|
|
78707
79787
|
}
|
|
78708
79788
|
function tempRelPath(phase) {
|
|
78709
|
-
return
|
|
79789
|
+
return path82.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
78710
79790
|
}
|
|
78711
79791
|
function lockRelPath(phase) {
|
|
78712
|
-
return
|
|
79792
|
+
return path82.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
78713
79793
|
}
|
|
78714
79794
|
function getLine(lines, idx) {
|
|
78715
79795
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -78726,7 +79806,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
78726
79806
|
}
|
|
78727
79807
|
const lineNum = finding.location.line;
|
|
78728
79808
|
try {
|
|
78729
|
-
const content =
|
|
79809
|
+
const content = fs68.readFileSync(finding.location.file, "utf-8");
|
|
78730
79810
|
const lines = content.split(`
|
|
78731
79811
|
`);
|
|
78732
79812
|
const idx = lineNum - 1;
|
|
@@ -78757,7 +79837,7 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
78757
79837
|
try {
|
|
78758
79838
|
if (relFile.startsWith(".."))
|
|
78759
79839
|
throw new Error("escapes workspace");
|
|
78760
|
-
const content =
|
|
79840
|
+
const content = fs68.readFileSync(finding.location.file, "utf-8");
|
|
78761
79841
|
const lines = content.split(`
|
|
78762
79842
|
`);
|
|
78763
79843
|
const idx = lineNum - 1;
|
|
@@ -78786,11 +79866,11 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
78786
79866
|
async function acquireLock(lockPath) {
|
|
78787
79867
|
for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
|
|
78788
79868
|
try {
|
|
78789
|
-
const fd =
|
|
78790
|
-
|
|
79869
|
+
const fd = fs68.openSync(lockPath, "wx");
|
|
79870
|
+
fs68.closeSync(fd);
|
|
78791
79871
|
return () => {
|
|
78792
79872
|
try {
|
|
78793
|
-
|
|
79873
|
+
fs68.unlinkSync(lockPath);
|
|
78794
79874
|
} catch {}
|
|
78795
79875
|
};
|
|
78796
79876
|
} catch {
|
|
@@ -78830,12 +79910,12 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
78830
79910
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
78831
79911
|
};
|
|
78832
79912
|
}
|
|
78833
|
-
|
|
79913
|
+
fs68.mkdirSync(path82.dirname(baselinePath), { recursive: true });
|
|
78834
79914
|
const releaseLock = await acquireLock(lockPath);
|
|
78835
79915
|
try {
|
|
78836
79916
|
let existing = null;
|
|
78837
79917
|
try {
|
|
78838
|
-
const raw =
|
|
79918
|
+
const raw = fs68.readFileSync(baselinePath, "utf-8");
|
|
78839
79919
|
const parsed = JSON.parse(raw);
|
|
78840
79920
|
if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
|
|
78841
79921
|
existing = parsed;
|
|
@@ -78895,8 +79975,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
78895
79975
|
message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
78896
79976
|
};
|
|
78897
79977
|
}
|
|
78898
|
-
|
|
78899
|
-
|
|
79978
|
+
fs68.writeFileSync(tempPath, json4, "utf-8");
|
|
79979
|
+
fs68.renameSync(tempPath, baselinePath);
|
|
78900
79980
|
return {
|
|
78901
79981
|
status: "merged",
|
|
78902
79982
|
path: baselinePath,
|
|
@@ -78927,8 +80007,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
78927
80007
|
message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
78928
80008
|
};
|
|
78929
80009
|
}
|
|
78930
|
-
|
|
78931
|
-
|
|
80010
|
+
fs68.writeFileSync(tempPath, json3, "utf-8");
|
|
80011
|
+
fs68.renameSync(tempPath, baselinePath);
|
|
78932
80012
|
return {
|
|
78933
80013
|
status: "written",
|
|
78934
80014
|
path: baselinePath,
|
|
@@ -78953,7 +80033,7 @@ function loadBaseline(directory, phase) {
|
|
|
78953
80033
|
};
|
|
78954
80034
|
}
|
|
78955
80035
|
try {
|
|
78956
|
-
const raw =
|
|
80036
|
+
const raw = fs68.readFileSync(baselinePath, "utf-8");
|
|
78957
80037
|
const parsed = JSON.parse(raw);
|
|
78958
80038
|
if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
|
|
78959
80039
|
return {
|
|
@@ -78995,17 +80075,17 @@ var SEVERITY_ORDER = {
|
|
|
78995
80075
|
};
|
|
78996
80076
|
function shouldSkipFile(filePath) {
|
|
78997
80077
|
try {
|
|
78998
|
-
const stats =
|
|
80078
|
+
const stats = fs69.statSync(filePath);
|
|
78999
80079
|
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
79000
80080
|
return { skip: true, reason: "file too large" };
|
|
79001
80081
|
}
|
|
79002
80082
|
if (stats.size === 0) {
|
|
79003
80083
|
return { skip: true, reason: "empty file" };
|
|
79004
80084
|
}
|
|
79005
|
-
const fd =
|
|
80085
|
+
const fd = fs69.openSync(filePath, "r");
|
|
79006
80086
|
const buffer = Buffer.alloc(8192);
|
|
79007
|
-
const bytesRead =
|
|
79008
|
-
|
|
80087
|
+
const bytesRead = fs69.readSync(fd, buffer, 0, 8192, 0);
|
|
80088
|
+
fs69.closeSync(fd);
|
|
79009
80089
|
if (bytesRead > 0) {
|
|
79010
80090
|
let nullCount = 0;
|
|
79011
80091
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -79044,7 +80124,7 @@ function countBySeverity(findings) {
|
|
|
79044
80124
|
}
|
|
79045
80125
|
function scanFileWithTierA(filePath, language) {
|
|
79046
80126
|
try {
|
|
79047
|
-
const content =
|
|
80127
|
+
const content = fs69.readFileSync(filePath, "utf-8");
|
|
79048
80128
|
const findings = executeRulesSync(filePath, content, language);
|
|
79049
80129
|
return findings.map((f) => ({
|
|
79050
80130
|
rule_id: f.rule_id,
|
|
@@ -79097,13 +80177,13 @@ async function sastScan(input, directory, config3) {
|
|
|
79097
80177
|
_filesSkipped++;
|
|
79098
80178
|
continue;
|
|
79099
80179
|
}
|
|
79100
|
-
const resolvedPath =
|
|
79101
|
-
const resolvedDirectory =
|
|
79102
|
-
if (!resolvedPath.startsWith(resolvedDirectory +
|
|
80180
|
+
const resolvedPath = path83.isAbsolute(filePath) ? filePath : path83.resolve(directory, filePath);
|
|
80181
|
+
const resolvedDirectory = path83.resolve(directory);
|
|
80182
|
+
if (!resolvedPath.startsWith(resolvedDirectory + path83.sep) && resolvedPath !== resolvedDirectory) {
|
|
79103
80183
|
_filesSkipped++;
|
|
79104
80184
|
continue;
|
|
79105
80185
|
}
|
|
79106
|
-
if (!
|
|
80186
|
+
if (!fs69.existsSync(resolvedPath)) {
|
|
79107
80187
|
_filesSkipped++;
|
|
79108
80188
|
continue;
|
|
79109
80189
|
}
|
|
@@ -79410,18 +80490,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
79410
80490
|
let resolved;
|
|
79411
80491
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
79412
80492
|
if (isWinAbs) {
|
|
79413
|
-
resolved =
|
|
79414
|
-
} else if (
|
|
79415
|
-
resolved =
|
|
80493
|
+
resolved = path84.win32.resolve(inputPath);
|
|
80494
|
+
} else if (path84.isAbsolute(inputPath)) {
|
|
80495
|
+
resolved = path84.resolve(inputPath);
|
|
79416
80496
|
} else {
|
|
79417
|
-
resolved =
|
|
80497
|
+
resolved = path84.resolve(baseDir, inputPath);
|
|
79418
80498
|
}
|
|
79419
|
-
const workspaceResolved =
|
|
80499
|
+
const workspaceResolved = path84.resolve(workspaceDir);
|
|
79420
80500
|
let relative20;
|
|
79421
80501
|
if (isWinAbs) {
|
|
79422
|
-
relative20 =
|
|
80502
|
+
relative20 = path84.win32.relative(workspaceResolved, resolved);
|
|
79423
80503
|
} else {
|
|
79424
|
-
relative20 =
|
|
80504
|
+
relative20 = path84.relative(workspaceResolved, resolved);
|
|
79425
80505
|
}
|
|
79426
80506
|
if (relative20.startsWith("..")) {
|
|
79427
80507
|
return "path traversal detected";
|
|
@@ -79486,7 +80566,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
79486
80566
|
if (typeof file3 !== "string") {
|
|
79487
80567
|
continue;
|
|
79488
80568
|
}
|
|
79489
|
-
const resolvedPath =
|
|
80569
|
+
const resolvedPath = path84.resolve(file3);
|
|
79490
80570
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
79491
80571
|
if (validationError) {
|
|
79492
80572
|
continue;
|
|
@@ -79643,7 +80723,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
79643
80723
|
skippedFiles++;
|
|
79644
80724
|
continue;
|
|
79645
80725
|
}
|
|
79646
|
-
const resolvedPath =
|
|
80726
|
+
const resolvedPath = path84.resolve(file3);
|
|
79647
80727
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
79648
80728
|
if (validationError) {
|
|
79649
80729
|
skippedFiles++;
|
|
@@ -79661,25 +80741,25 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
79661
80741
|
};
|
|
79662
80742
|
}
|
|
79663
80743
|
for (const file3 of validatedFiles) {
|
|
79664
|
-
const ext =
|
|
80744
|
+
const ext = path84.extname(file3).toLowerCase();
|
|
79665
80745
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
79666
80746
|
skippedFiles++;
|
|
79667
80747
|
continue;
|
|
79668
80748
|
}
|
|
79669
|
-
let
|
|
80749
|
+
let stat4;
|
|
79670
80750
|
try {
|
|
79671
|
-
|
|
80751
|
+
stat4 = fs70.statSync(file3);
|
|
79672
80752
|
} catch {
|
|
79673
80753
|
skippedFiles++;
|
|
79674
80754
|
continue;
|
|
79675
80755
|
}
|
|
79676
|
-
if (
|
|
80756
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES9) {
|
|
79677
80757
|
skippedFiles++;
|
|
79678
80758
|
continue;
|
|
79679
80759
|
}
|
|
79680
80760
|
let content;
|
|
79681
80761
|
try {
|
|
79682
|
-
const buffer =
|
|
80762
|
+
const buffer = fs70.readFileSync(file3);
|
|
79683
80763
|
if (buffer.includes(0)) {
|
|
79684
80764
|
skippedFiles++;
|
|
79685
80765
|
continue;
|
|
@@ -79880,7 +80960,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
79880
80960
|
const preexistingFindings = [];
|
|
79881
80961
|
for (const finding of findings) {
|
|
79882
80962
|
const filePath = finding.location.file;
|
|
79883
|
-
const normalised =
|
|
80963
|
+
const normalised = path84.relative(directory, filePath).replace(/\\/g, "/");
|
|
79884
80964
|
const changedLines = changedLineRanges.get(normalised);
|
|
79885
80965
|
if (changedLines?.has(finding.location.line)) {
|
|
79886
80966
|
newFindings.push(finding);
|
|
@@ -79931,7 +81011,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
79931
81011
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
79932
81012
|
continue;
|
|
79933
81013
|
}
|
|
79934
|
-
changedFiles.push(
|
|
81014
|
+
changedFiles.push(path84.resolve(directory, file3));
|
|
79935
81015
|
}
|
|
79936
81016
|
if (changedFiles.length === 0) {
|
|
79937
81017
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -80132,7 +81212,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
80132
81212
|
};
|
|
80133
81213
|
return JSON.stringify(errorResult, null, 2);
|
|
80134
81214
|
}
|
|
80135
|
-
const resolvedDirectory =
|
|
81215
|
+
const resolvedDirectory = path84.resolve(typedArgs.directory);
|
|
80136
81216
|
const workspaceAnchor = resolvedDirectory;
|
|
80137
81217
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
80138
81218
|
if (dirError) {
|
|
@@ -80173,7 +81253,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
80173
81253
|
});
|
|
80174
81254
|
// src/tools/repo-map.ts
|
|
80175
81255
|
init_dist();
|
|
80176
|
-
import * as
|
|
81256
|
+
import * as path85 from "path";
|
|
80177
81257
|
init_path_security();
|
|
80178
81258
|
init_create_tool();
|
|
80179
81259
|
var VALID_ACTIONS = [
|
|
@@ -80198,7 +81278,7 @@ function validateFile(p) {
|
|
|
80198
81278
|
return "file contains control characters";
|
|
80199
81279
|
if (containsPathTraversal(p))
|
|
80200
81280
|
return "file contains path traversal";
|
|
80201
|
-
if (
|
|
81281
|
+
if (path85.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
80202
81282
|
return "file must be a workspace-relative path, not absolute";
|
|
80203
81283
|
}
|
|
80204
81284
|
return null;
|
|
@@ -80221,8 +81301,8 @@ function ok(action, payload) {
|
|
|
80221
81301
|
}
|
|
80222
81302
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
80223
81303
|
const normalized = input.replace(/\\/g, "/");
|
|
80224
|
-
if (
|
|
80225
|
-
const rel =
|
|
81304
|
+
if (path85.isAbsolute(normalized)) {
|
|
81305
|
+
const rel = path85.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
80226
81306
|
return normalizeGraphPath2(rel);
|
|
80227
81307
|
}
|
|
80228
81308
|
return normalizeGraphPath2(normalized);
|
|
@@ -80366,8 +81446,8 @@ var repo_map = createSwarmTool({
|
|
|
80366
81446
|
// src/tools/req-coverage.ts
|
|
80367
81447
|
init_dist();
|
|
80368
81448
|
init_create_tool();
|
|
80369
|
-
import * as
|
|
80370
|
-
import * as
|
|
81449
|
+
import * as fs71 from "fs";
|
|
81450
|
+
import * as path86 from "path";
|
|
80371
81451
|
var SPEC_FILE = ".swarm/spec.md";
|
|
80372
81452
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
80373
81453
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -80426,20 +81506,20 @@ function extractObligationAndText(id, lineText) {
|
|
|
80426
81506
|
var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
80427
81507
|
function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
80428
81508
|
const touchedFiles = new Set;
|
|
80429
|
-
if (!
|
|
81509
|
+
if (!fs71.existsSync(evidenceDir) || !fs71.statSync(evidenceDir).isDirectory()) {
|
|
80430
81510
|
return [];
|
|
80431
81511
|
}
|
|
80432
81512
|
let entries;
|
|
80433
81513
|
try {
|
|
80434
|
-
entries =
|
|
81514
|
+
entries = fs71.readdirSync(evidenceDir);
|
|
80435
81515
|
} catch {
|
|
80436
81516
|
return [];
|
|
80437
81517
|
}
|
|
80438
81518
|
for (const entry of entries) {
|
|
80439
|
-
const entryPath =
|
|
81519
|
+
const entryPath = path86.join(evidenceDir, entry);
|
|
80440
81520
|
try {
|
|
80441
|
-
const
|
|
80442
|
-
if (!
|
|
81521
|
+
const stat4 = fs71.statSync(entryPath);
|
|
81522
|
+
if (!stat4.isDirectory()) {
|
|
80443
81523
|
continue;
|
|
80444
81524
|
}
|
|
80445
81525
|
} catch {
|
|
@@ -80452,18 +81532,18 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
80452
81532
|
if (entryPhase !== String(phase)) {
|
|
80453
81533
|
continue;
|
|
80454
81534
|
}
|
|
80455
|
-
const evidenceFilePath =
|
|
81535
|
+
const evidenceFilePath = path86.join(entryPath, "evidence.json");
|
|
80456
81536
|
try {
|
|
80457
|
-
const resolvedPath =
|
|
80458
|
-
const evidenceDirResolved =
|
|
80459
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
81537
|
+
const resolvedPath = path86.resolve(evidenceFilePath);
|
|
81538
|
+
const evidenceDirResolved = path86.resolve(evidenceDir);
|
|
81539
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path86.sep)) {
|
|
80460
81540
|
continue;
|
|
80461
81541
|
}
|
|
80462
|
-
const
|
|
80463
|
-
if (!
|
|
81542
|
+
const stat4 = fs71.lstatSync(evidenceFilePath);
|
|
81543
|
+
if (!stat4.isFile()) {
|
|
80464
81544
|
continue;
|
|
80465
81545
|
}
|
|
80466
|
-
if (
|
|
81546
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES9) {
|
|
80467
81547
|
continue;
|
|
80468
81548
|
}
|
|
80469
81549
|
} catch {
|
|
@@ -80471,7 +81551,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
80471
81551
|
}
|
|
80472
81552
|
let content;
|
|
80473
81553
|
try {
|
|
80474
|
-
content =
|
|
81554
|
+
content = fs71.readFileSync(evidenceFilePath, "utf-8");
|
|
80475
81555
|
} catch {
|
|
80476
81556
|
continue;
|
|
80477
81557
|
}
|
|
@@ -80490,7 +81570,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
80490
81570
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
80491
81571
|
for (const file3 of diffEntry.files_changed) {
|
|
80492
81572
|
if (typeof file3 === "string") {
|
|
80493
|
-
touchedFiles.add(
|
|
81573
|
+
touchedFiles.add(path86.resolve(cwd, file3));
|
|
80494
81574
|
}
|
|
80495
81575
|
}
|
|
80496
81576
|
}
|
|
@@ -80503,12 +81583,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
80503
81583
|
}
|
|
80504
81584
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
80505
81585
|
try {
|
|
80506
|
-
const resolvedPath =
|
|
80507
|
-
const cwdResolved =
|
|
81586
|
+
const resolvedPath = path86.resolve(filePath);
|
|
81587
|
+
const cwdResolved = path86.resolve(cwd);
|
|
80508
81588
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
80509
81589
|
return false;
|
|
80510
81590
|
}
|
|
80511
|
-
const content =
|
|
81591
|
+
const content = fs71.readFileSync(resolvedPath, "utf-8");
|
|
80512
81592
|
for (const keyword of keywords) {
|
|
80513
81593
|
const regex = new RegExp(`\\b${keyword}\\b`, "i");
|
|
80514
81594
|
if (regex.test(content)) {
|
|
@@ -80638,10 +81718,10 @@ var req_coverage = createSwarmTool({
|
|
|
80638
81718
|
}, null, 2);
|
|
80639
81719
|
}
|
|
80640
81720
|
const cwd = inputDirectory || directory;
|
|
80641
|
-
const specPath =
|
|
81721
|
+
const specPath = path86.join(cwd, SPEC_FILE);
|
|
80642
81722
|
let specContent;
|
|
80643
81723
|
try {
|
|
80644
|
-
specContent =
|
|
81724
|
+
specContent = fs71.readFileSync(specPath, "utf-8");
|
|
80645
81725
|
} catch (readError) {
|
|
80646
81726
|
return JSON.stringify({
|
|
80647
81727
|
success: false,
|
|
@@ -80665,7 +81745,7 @@ var req_coverage = createSwarmTool({
|
|
|
80665
81745
|
message: "No FR requirements found in spec.md"
|
|
80666
81746
|
}, null, 2);
|
|
80667
81747
|
}
|
|
80668
|
-
const evidenceDir =
|
|
81748
|
+
const evidenceDir = path86.join(cwd, EVIDENCE_DIR4);
|
|
80669
81749
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
80670
81750
|
const analyzedRequirements = [];
|
|
80671
81751
|
let coveredCount = 0;
|
|
@@ -80691,12 +81771,12 @@ var req_coverage = createSwarmTool({
|
|
|
80691
81771
|
requirements: analyzedRequirements
|
|
80692
81772
|
};
|
|
80693
81773
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
80694
|
-
const reportPath =
|
|
81774
|
+
const reportPath = path86.join(evidenceDir, reportFilename);
|
|
80695
81775
|
try {
|
|
80696
|
-
if (!
|
|
80697
|
-
|
|
81776
|
+
if (!fs71.existsSync(evidenceDir)) {
|
|
81777
|
+
fs71.mkdirSync(evidenceDir, { recursive: true });
|
|
80698
81778
|
}
|
|
80699
|
-
|
|
81779
|
+
fs71.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
|
|
80700
81780
|
} catch (writeError) {
|
|
80701
81781
|
console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
80702
81782
|
}
|
|
@@ -80782,8 +81862,8 @@ init_manager();
|
|
|
80782
81862
|
init_state();
|
|
80783
81863
|
init_create_tool();
|
|
80784
81864
|
import * as crypto9 from "crypto";
|
|
80785
|
-
import * as
|
|
80786
|
-
import * as
|
|
81865
|
+
import * as fs72 from "fs";
|
|
81866
|
+
import * as path87 from "path";
|
|
80787
81867
|
function detectPlaceholderContent(args2) {
|
|
80788
81868
|
const issues = [];
|
|
80789
81869
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -80859,11 +81939,11 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
80859
81939
|
let specMtime;
|
|
80860
81940
|
let specHash;
|
|
80861
81941
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
80862
|
-
const specPath =
|
|
81942
|
+
const specPath = path87.join(targetWorkspace, ".swarm", "spec.md");
|
|
80863
81943
|
try {
|
|
80864
|
-
const
|
|
80865
|
-
specMtime =
|
|
80866
|
-
const content = await
|
|
81944
|
+
const stat4 = await fs72.promises.stat(specPath);
|
|
81945
|
+
specMtime = stat4.mtime.toISOString();
|
|
81946
|
+
const content = await fs72.promises.readFile(specPath, "utf8");
|
|
80867
81947
|
specHash = crypto9.createHash("sha256").update(content).digest("hex");
|
|
80868
81948
|
} catch {
|
|
80869
81949
|
return {
|
|
@@ -80999,14 +82079,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
80999
82079
|
}
|
|
81000
82080
|
await writeCheckpoint(dir).catch(() => {});
|
|
81001
82081
|
try {
|
|
81002
|
-
const markerPath =
|
|
82082
|
+
const markerPath = path87.join(dir, ".swarm", ".plan-write-marker");
|
|
81003
82083
|
const marker = JSON.stringify({
|
|
81004
82084
|
source: "save_plan",
|
|
81005
82085
|
timestamp: new Date().toISOString(),
|
|
81006
82086
|
phases_count: plan.phases.length,
|
|
81007
82087
|
tasks_count: tasksCount
|
|
81008
82088
|
});
|
|
81009
|
-
await
|
|
82089
|
+
await fs72.promises.writeFile(markerPath, marker, "utf8");
|
|
81010
82090
|
} catch {}
|
|
81011
82091
|
const warnings = [];
|
|
81012
82092
|
let criticReviewFound = false;
|
|
@@ -81022,7 +82102,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
81022
82102
|
return {
|
|
81023
82103
|
success: true,
|
|
81024
82104
|
message: "Plan saved successfully",
|
|
81025
|
-
plan_path:
|
|
82105
|
+
plan_path: path87.join(dir, ".swarm", "plan.json"),
|
|
81026
82106
|
phases_count: plan.phases.length,
|
|
81027
82107
|
tasks_count: tasksCount,
|
|
81028
82108
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -81074,8 +82154,8 @@ var save_plan = createSwarmTool({
|
|
|
81074
82154
|
// src/tools/sbom-generate.ts
|
|
81075
82155
|
init_dist();
|
|
81076
82156
|
init_manager2();
|
|
81077
|
-
import * as
|
|
81078
|
-
import * as
|
|
82157
|
+
import * as fs73 from "fs";
|
|
82158
|
+
import * as path88 from "path";
|
|
81079
82159
|
|
|
81080
82160
|
// src/sbom/detectors/index.ts
|
|
81081
82161
|
init_utils();
|
|
@@ -81923,9 +83003,9 @@ function findManifestFiles(rootDir) {
|
|
|
81923
83003
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
81924
83004
|
function searchDir(dir) {
|
|
81925
83005
|
try {
|
|
81926
|
-
const entries =
|
|
83006
|
+
const entries = fs73.readdirSync(dir, { withFileTypes: true });
|
|
81927
83007
|
for (const entry of entries) {
|
|
81928
|
-
const fullPath =
|
|
83008
|
+
const fullPath = path88.join(dir, entry.name);
|
|
81929
83009
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
81930
83010
|
continue;
|
|
81931
83011
|
}
|
|
@@ -81934,7 +83014,7 @@ function findManifestFiles(rootDir) {
|
|
|
81934
83014
|
} else if (entry.isFile()) {
|
|
81935
83015
|
for (const pattern of patterns) {
|
|
81936
83016
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
81937
|
-
manifestFiles.push(
|
|
83017
|
+
manifestFiles.push(path88.relative(rootDir, fullPath));
|
|
81938
83018
|
break;
|
|
81939
83019
|
}
|
|
81940
83020
|
}
|
|
@@ -81950,13 +83030,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
81950
83030
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
81951
83031
|
for (const dir of directories) {
|
|
81952
83032
|
try {
|
|
81953
|
-
const entries =
|
|
83033
|
+
const entries = fs73.readdirSync(dir, { withFileTypes: true });
|
|
81954
83034
|
for (const entry of entries) {
|
|
81955
|
-
const fullPath =
|
|
83035
|
+
const fullPath = path88.join(dir, entry.name);
|
|
81956
83036
|
if (entry.isFile()) {
|
|
81957
83037
|
for (const pattern of patterns) {
|
|
81958
83038
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
81959
|
-
found.push(
|
|
83039
|
+
found.push(path88.relative(workingDir, fullPath));
|
|
81960
83040
|
break;
|
|
81961
83041
|
}
|
|
81962
83042
|
}
|
|
@@ -81969,11 +83049,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
81969
83049
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
81970
83050
|
const dirs = new Set;
|
|
81971
83051
|
for (const file3 of changedFiles) {
|
|
81972
|
-
let currentDir =
|
|
83052
|
+
let currentDir = path88.dirname(file3);
|
|
81973
83053
|
while (true) {
|
|
81974
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
81975
|
-
dirs.add(
|
|
81976
|
-
const parent =
|
|
83054
|
+
if (currentDir && currentDir !== "." && currentDir !== path88.sep) {
|
|
83055
|
+
dirs.add(path88.join(workingDir, currentDir));
|
|
83056
|
+
const parent = path88.dirname(currentDir);
|
|
81977
83057
|
if (parent === currentDir)
|
|
81978
83058
|
break;
|
|
81979
83059
|
currentDir = parent;
|
|
@@ -81987,7 +83067,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
81987
83067
|
}
|
|
81988
83068
|
function ensureOutputDir(outputDir) {
|
|
81989
83069
|
try {
|
|
81990
|
-
|
|
83070
|
+
fs73.mkdirSync(outputDir, { recursive: true });
|
|
81991
83071
|
} catch (error93) {
|
|
81992
83072
|
if (!error93 || error93.code !== "EEXIST") {
|
|
81993
83073
|
throw error93;
|
|
@@ -82057,7 +83137,7 @@ var sbom_generate = createSwarmTool({
|
|
|
82057
83137
|
const changedFiles = obj.changed_files;
|
|
82058
83138
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
82059
83139
|
const workingDir = directory;
|
|
82060
|
-
const outputDir =
|
|
83140
|
+
const outputDir = path88.isAbsolute(relativeOutputDir) ? relativeOutputDir : path88.join(workingDir, relativeOutputDir);
|
|
82061
83141
|
let manifestFiles = [];
|
|
82062
83142
|
if (scope === "all") {
|
|
82063
83143
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -82080,11 +83160,11 @@ var sbom_generate = createSwarmTool({
|
|
|
82080
83160
|
const processedFiles = [];
|
|
82081
83161
|
for (const manifestFile of manifestFiles) {
|
|
82082
83162
|
try {
|
|
82083
|
-
const fullPath =
|
|
82084
|
-
if (!
|
|
83163
|
+
const fullPath = path88.isAbsolute(manifestFile) ? manifestFile : path88.join(workingDir, manifestFile);
|
|
83164
|
+
if (!fs73.existsSync(fullPath)) {
|
|
82085
83165
|
continue;
|
|
82086
83166
|
}
|
|
82087
|
-
const content =
|
|
83167
|
+
const content = fs73.readFileSync(fullPath, "utf-8");
|
|
82088
83168
|
const components = detectComponents(manifestFile, content);
|
|
82089
83169
|
processedFiles.push(manifestFile);
|
|
82090
83170
|
if (components.length > 0) {
|
|
@@ -82097,8 +83177,8 @@ var sbom_generate = createSwarmTool({
|
|
|
82097
83177
|
const bom = generateCycloneDX(allComponents);
|
|
82098
83178
|
const bomJson = serializeCycloneDX(bom);
|
|
82099
83179
|
const filename = generateSbomFilename();
|
|
82100
|
-
const outputPath =
|
|
82101
|
-
|
|
83180
|
+
const outputPath = path88.join(outputDir, filename);
|
|
83181
|
+
fs73.writeFileSync(outputPath, bomJson, "utf-8");
|
|
82102
83182
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
82103
83183
|
try {
|
|
82104
83184
|
const timestamp = new Date().toISOString();
|
|
@@ -82140,8 +83220,8 @@ var sbom_generate = createSwarmTool({
|
|
|
82140
83220
|
// src/tools/schema-drift.ts
|
|
82141
83221
|
init_dist();
|
|
82142
83222
|
init_create_tool();
|
|
82143
|
-
import * as
|
|
82144
|
-
import * as
|
|
83223
|
+
import * as fs74 from "fs";
|
|
83224
|
+
import * as path89 from "path";
|
|
82145
83225
|
var SPEC_CANDIDATES = [
|
|
82146
83226
|
"openapi.json",
|
|
82147
83227
|
"openapi.yaml",
|
|
@@ -82173,28 +83253,28 @@ function normalizePath3(p) {
|
|
|
82173
83253
|
}
|
|
82174
83254
|
function discoverSpecFile(cwd, specFileArg) {
|
|
82175
83255
|
if (specFileArg) {
|
|
82176
|
-
const resolvedPath =
|
|
82177
|
-
const normalizedCwd = cwd.endsWith(
|
|
83256
|
+
const resolvedPath = path89.resolve(cwd, specFileArg);
|
|
83257
|
+
const normalizedCwd = cwd.endsWith(path89.sep) ? cwd : cwd + path89.sep;
|
|
82178
83258
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
82179
83259
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
82180
83260
|
}
|
|
82181
|
-
const ext =
|
|
83261
|
+
const ext = path89.extname(resolvedPath).toLowerCase();
|
|
82182
83262
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
82183
83263
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
82184
83264
|
}
|
|
82185
|
-
const stats =
|
|
83265
|
+
const stats = fs74.statSync(resolvedPath);
|
|
82186
83266
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
82187
83267
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
82188
83268
|
}
|
|
82189
|
-
if (!
|
|
83269
|
+
if (!fs74.existsSync(resolvedPath)) {
|
|
82190
83270
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
82191
83271
|
}
|
|
82192
83272
|
return resolvedPath;
|
|
82193
83273
|
}
|
|
82194
83274
|
for (const candidate of SPEC_CANDIDATES) {
|
|
82195
|
-
const candidatePath =
|
|
82196
|
-
if (
|
|
82197
|
-
const stats =
|
|
83275
|
+
const candidatePath = path89.resolve(cwd, candidate);
|
|
83276
|
+
if (fs74.existsSync(candidatePath)) {
|
|
83277
|
+
const stats = fs74.statSync(candidatePath);
|
|
82198
83278
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
82199
83279
|
return candidatePath;
|
|
82200
83280
|
}
|
|
@@ -82203,8 +83283,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
82203
83283
|
return null;
|
|
82204
83284
|
}
|
|
82205
83285
|
function parseSpec(specFile) {
|
|
82206
|
-
const content =
|
|
82207
|
-
const ext =
|
|
83286
|
+
const content = fs74.readFileSync(specFile, "utf-8");
|
|
83287
|
+
const ext = path89.extname(specFile).toLowerCase();
|
|
82208
83288
|
if (ext === ".json") {
|
|
82209
83289
|
return parseJsonSpec(content);
|
|
82210
83290
|
}
|
|
@@ -82275,12 +83355,12 @@ function extractRoutes(cwd) {
|
|
|
82275
83355
|
function walkDir(dir) {
|
|
82276
83356
|
let entries;
|
|
82277
83357
|
try {
|
|
82278
|
-
entries =
|
|
83358
|
+
entries = fs74.readdirSync(dir, { withFileTypes: true });
|
|
82279
83359
|
} catch {
|
|
82280
83360
|
return;
|
|
82281
83361
|
}
|
|
82282
83362
|
for (const entry of entries) {
|
|
82283
|
-
const fullPath =
|
|
83363
|
+
const fullPath = path89.join(dir, entry.name);
|
|
82284
83364
|
if (entry.isSymbolicLink()) {
|
|
82285
83365
|
continue;
|
|
82286
83366
|
}
|
|
@@ -82290,7 +83370,7 @@ function extractRoutes(cwd) {
|
|
|
82290
83370
|
}
|
|
82291
83371
|
walkDir(fullPath);
|
|
82292
83372
|
} else if (entry.isFile()) {
|
|
82293
|
-
const ext =
|
|
83373
|
+
const ext = path89.extname(entry.name).toLowerCase();
|
|
82294
83374
|
const baseName = entry.name.toLowerCase();
|
|
82295
83375
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
82296
83376
|
continue;
|
|
@@ -82308,7 +83388,7 @@ function extractRoutes(cwd) {
|
|
|
82308
83388
|
}
|
|
82309
83389
|
function extractRoutesFromFile(filePath) {
|
|
82310
83390
|
const routes = [];
|
|
82311
|
-
const content =
|
|
83391
|
+
const content = fs74.readFileSync(filePath, "utf-8");
|
|
82312
83392
|
const lines = content.split(/\r?\n/);
|
|
82313
83393
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
82314
83394
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -82456,8 +83536,8 @@ var schema_drift = createSwarmTool({
|
|
|
82456
83536
|
init_tool();
|
|
82457
83537
|
init_path_security();
|
|
82458
83538
|
init_create_tool();
|
|
82459
|
-
import * as
|
|
82460
|
-
import * as
|
|
83539
|
+
import * as fs75 from "fs";
|
|
83540
|
+
import * as path90 from "path";
|
|
82461
83541
|
var DEFAULT_MAX_RESULTS = 100;
|
|
82462
83542
|
var DEFAULT_MAX_LINES = 200;
|
|
82463
83543
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -82493,11 +83573,11 @@ function containsWindowsAttacks3(str) {
|
|
|
82493
83573
|
}
|
|
82494
83574
|
function isPathInWorkspace3(filePath, workspace) {
|
|
82495
83575
|
try {
|
|
82496
|
-
const resolvedPath =
|
|
82497
|
-
const realWorkspace =
|
|
82498
|
-
const realResolvedPath =
|
|
82499
|
-
const relativePath =
|
|
82500
|
-
if (relativePath.startsWith("..") ||
|
|
83576
|
+
const resolvedPath = path90.resolve(workspace, filePath);
|
|
83577
|
+
const realWorkspace = fs75.realpathSync(workspace);
|
|
83578
|
+
const realResolvedPath = fs75.realpathSync(resolvedPath);
|
|
83579
|
+
const relativePath = path90.relative(realWorkspace, realResolvedPath);
|
|
83580
|
+
if (relativePath.startsWith("..") || path90.isAbsolute(relativePath)) {
|
|
82501
83581
|
return false;
|
|
82502
83582
|
}
|
|
82503
83583
|
return true;
|
|
@@ -82510,12 +83590,12 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
82510
83590
|
}
|
|
82511
83591
|
function findRgInEnvPath() {
|
|
82512
83592
|
const searchPath = process.env.PATH ?? "";
|
|
82513
|
-
for (const dir of searchPath.split(
|
|
83593
|
+
for (const dir of searchPath.split(path90.delimiter)) {
|
|
82514
83594
|
if (!dir)
|
|
82515
83595
|
continue;
|
|
82516
83596
|
const isWindows = process.platform === "win32";
|
|
82517
|
-
const candidate =
|
|
82518
|
-
if (
|
|
83597
|
+
const candidate = path90.join(dir, isWindows ? "rg.exe" : "rg");
|
|
83598
|
+
if (fs75.existsSync(candidate))
|
|
82519
83599
|
return candidate;
|
|
82520
83600
|
}
|
|
82521
83601
|
return null;
|
|
@@ -82642,10 +83722,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
82642
83722
|
return files;
|
|
82643
83723
|
}
|
|
82644
83724
|
try {
|
|
82645
|
-
const entries =
|
|
83725
|
+
const entries = fs75.readdirSync(dir, { withFileTypes: true });
|
|
82646
83726
|
for (const entry of entries) {
|
|
82647
|
-
const fullPath =
|
|
82648
|
-
const relativePath =
|
|
83727
|
+
const fullPath = path90.join(dir, entry.name);
|
|
83728
|
+
const relativePath = path90.relative(workspace, fullPath);
|
|
82649
83729
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
82650
83730
|
continue;
|
|
82651
83731
|
}
|
|
@@ -82686,13 +83766,13 @@ async function fallbackSearch(opts) {
|
|
|
82686
83766
|
const matches = [];
|
|
82687
83767
|
let total = 0;
|
|
82688
83768
|
for (const file3 of files) {
|
|
82689
|
-
const fullPath =
|
|
83769
|
+
const fullPath = path90.join(opts.workspace, file3);
|
|
82690
83770
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
82691
83771
|
continue;
|
|
82692
83772
|
}
|
|
82693
83773
|
let stats;
|
|
82694
83774
|
try {
|
|
82695
|
-
stats =
|
|
83775
|
+
stats = fs75.statSync(fullPath);
|
|
82696
83776
|
if (stats.size > MAX_FILE_SIZE_BYTES10) {
|
|
82697
83777
|
continue;
|
|
82698
83778
|
}
|
|
@@ -82701,7 +83781,7 @@ async function fallbackSearch(opts) {
|
|
|
82701
83781
|
}
|
|
82702
83782
|
let content;
|
|
82703
83783
|
try {
|
|
82704
|
-
content =
|
|
83784
|
+
content = fs75.readFileSync(fullPath, "utf-8");
|
|
82705
83785
|
} catch {
|
|
82706
83786
|
continue;
|
|
82707
83787
|
}
|
|
@@ -82813,7 +83893,7 @@ var search = createSwarmTool({
|
|
|
82813
83893
|
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
82814
83894
|
}, null, 2);
|
|
82815
83895
|
}
|
|
82816
|
-
if (!
|
|
83896
|
+
if (!fs75.existsSync(directory)) {
|
|
82817
83897
|
return JSON.stringify({
|
|
82818
83898
|
error: true,
|
|
82819
83899
|
type: "unknown",
|
|
@@ -82936,8 +84016,8 @@ var set_qa_gates = createSwarmTool({
|
|
|
82936
84016
|
init_tool();
|
|
82937
84017
|
init_path_security();
|
|
82938
84018
|
init_create_tool();
|
|
82939
|
-
import * as
|
|
82940
|
-
import * as
|
|
84019
|
+
import * as fs76 from "fs";
|
|
84020
|
+
import * as path91 from "path";
|
|
82941
84021
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
82942
84022
|
function containsWindowsAttacks4(str) {
|
|
82943
84023
|
if (/:[^\\/]/.test(str))
|
|
@@ -82951,14 +84031,14 @@ function containsWindowsAttacks4(str) {
|
|
|
82951
84031
|
}
|
|
82952
84032
|
function isPathInWorkspace4(filePath, workspace) {
|
|
82953
84033
|
try {
|
|
82954
|
-
const resolvedPath =
|
|
82955
|
-
if (!
|
|
84034
|
+
const resolvedPath = path91.resolve(workspace, filePath);
|
|
84035
|
+
if (!fs76.existsSync(resolvedPath)) {
|
|
82956
84036
|
return true;
|
|
82957
84037
|
}
|
|
82958
|
-
const realWorkspace =
|
|
82959
|
-
const realResolvedPath =
|
|
82960
|
-
const relativePath =
|
|
82961
|
-
if (relativePath.startsWith("..") ||
|
|
84038
|
+
const realWorkspace = fs76.realpathSync(workspace);
|
|
84039
|
+
const realResolvedPath = fs76.realpathSync(resolvedPath);
|
|
84040
|
+
const relativePath = path91.relative(realWorkspace, realResolvedPath);
|
|
84041
|
+
if (relativePath.startsWith("..") || path91.isAbsolute(relativePath)) {
|
|
82962
84042
|
return false;
|
|
82963
84043
|
}
|
|
82964
84044
|
return true;
|
|
@@ -83130,7 +84210,7 @@ var suggestPatch = createSwarmTool({
|
|
|
83130
84210
|
message: "changes cannot be empty"
|
|
83131
84211
|
}, null, 2);
|
|
83132
84212
|
}
|
|
83133
|
-
if (!
|
|
84213
|
+
if (!fs76.existsSync(directory)) {
|
|
83134
84214
|
return JSON.stringify({
|
|
83135
84215
|
success: false,
|
|
83136
84216
|
error: true,
|
|
@@ -83166,8 +84246,8 @@ var suggestPatch = createSwarmTool({
|
|
|
83166
84246
|
});
|
|
83167
84247
|
continue;
|
|
83168
84248
|
}
|
|
83169
|
-
const fullPath =
|
|
83170
|
-
if (!
|
|
84249
|
+
const fullPath = path91.resolve(directory, change.file);
|
|
84250
|
+
if (!fs76.existsSync(fullPath)) {
|
|
83171
84251
|
errors5.push({
|
|
83172
84252
|
success: false,
|
|
83173
84253
|
error: true,
|
|
@@ -83181,7 +84261,7 @@ var suggestPatch = createSwarmTool({
|
|
|
83181
84261
|
}
|
|
83182
84262
|
let content;
|
|
83183
84263
|
try {
|
|
83184
|
-
content =
|
|
84264
|
+
content = fs76.readFileSync(fullPath, "utf-8");
|
|
83185
84265
|
} catch (err3) {
|
|
83186
84266
|
errors5.push({
|
|
83187
84267
|
success: false,
|
|
@@ -83260,8 +84340,8 @@ var suggestPatch = createSwarmTool({
|
|
|
83260
84340
|
// src/tools/lint-spec.ts
|
|
83261
84341
|
init_spec_schema();
|
|
83262
84342
|
init_create_tool();
|
|
83263
|
-
import * as
|
|
83264
|
-
import * as
|
|
84343
|
+
import * as fs77 from "fs";
|
|
84344
|
+
import * as path92 from "path";
|
|
83265
84345
|
var SPEC_FILE_NAME = "spec.md";
|
|
83266
84346
|
var SWARM_DIR2 = ".swarm";
|
|
83267
84347
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -83314,8 +84394,8 @@ var lint_spec = createSwarmTool({
|
|
|
83314
84394
|
async execute(_args, directory) {
|
|
83315
84395
|
const errors5 = [];
|
|
83316
84396
|
const warnings = [];
|
|
83317
|
-
const specPath =
|
|
83318
|
-
if (!
|
|
84397
|
+
const specPath = path92.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
84398
|
+
if (!fs77.existsSync(specPath)) {
|
|
83319
84399
|
const result2 = {
|
|
83320
84400
|
valid: false,
|
|
83321
84401
|
specMtime: null,
|
|
@@ -83334,12 +84414,12 @@ var lint_spec = createSwarmTool({
|
|
|
83334
84414
|
}
|
|
83335
84415
|
let specMtime = null;
|
|
83336
84416
|
try {
|
|
83337
|
-
const stats =
|
|
84417
|
+
const stats = fs77.statSync(specPath);
|
|
83338
84418
|
specMtime = stats.mtime.toISOString();
|
|
83339
84419
|
} catch {}
|
|
83340
84420
|
let content;
|
|
83341
84421
|
try {
|
|
83342
|
-
content =
|
|
84422
|
+
content = fs77.readFileSync(specPath, "utf-8");
|
|
83343
84423
|
} catch (e) {
|
|
83344
84424
|
const result2 = {
|
|
83345
84425
|
valid: false,
|
|
@@ -83384,13 +84464,13 @@ var lint_spec = createSwarmTool({
|
|
|
83384
84464
|
});
|
|
83385
84465
|
// src/tools/mutation-test.ts
|
|
83386
84466
|
init_dist();
|
|
83387
|
-
import * as
|
|
83388
|
-
import * as
|
|
84467
|
+
import * as fs78 from "fs";
|
|
84468
|
+
import * as path94 from "path";
|
|
83389
84469
|
|
|
83390
84470
|
// src/mutation/engine.ts
|
|
83391
84471
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
83392
84472
|
import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync18 } from "fs";
|
|
83393
|
-
import * as
|
|
84473
|
+
import * as path93 from "path";
|
|
83394
84474
|
|
|
83395
84475
|
// src/mutation/equivalence.ts
|
|
83396
84476
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -83525,7 +84605,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
83525
84605
|
let patchFile;
|
|
83526
84606
|
try {
|
|
83527
84607
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
83528
|
-
patchFile =
|
|
84608
|
+
patchFile = path93.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
83529
84609
|
try {
|
|
83530
84610
|
writeFileSync18(patchFile, patch.patch);
|
|
83531
84611
|
} catch (writeErr) {
|
|
@@ -83919,8 +84999,8 @@ var mutation_test = createSwarmTool({
|
|
|
83919
84999
|
];
|
|
83920
85000
|
for (const filePath of uniquePaths) {
|
|
83921
85001
|
try {
|
|
83922
|
-
const resolvedPath =
|
|
83923
|
-
sourceFiles.set(filePath,
|
|
85002
|
+
const resolvedPath = path94.resolve(cwd, filePath);
|
|
85003
|
+
sourceFiles.set(filePath, fs78.readFileSync(resolvedPath, "utf-8"));
|
|
83924
85004
|
} catch {}
|
|
83925
85005
|
}
|
|
83926
85006
|
const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
|
|
@@ -83938,8 +85018,8 @@ var mutation_test = createSwarmTool({
|
|
|
83938
85018
|
init_dist();
|
|
83939
85019
|
init_manager2();
|
|
83940
85020
|
init_detector();
|
|
83941
|
-
import * as
|
|
83942
|
-
import * as
|
|
85021
|
+
import * as fs79 from "fs";
|
|
85022
|
+
import * as path95 from "path";
|
|
83943
85023
|
init_create_tool();
|
|
83944
85024
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
83945
85025
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -84005,7 +85085,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
84005
85085
|
if (languages?.length) {
|
|
84006
85086
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
84007
85087
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
84008
|
-
const ext =
|
|
85088
|
+
const ext = path95.extname(file3.path).toLowerCase();
|
|
84009
85089
|
const langDef = getLanguageForExtension(ext);
|
|
84010
85090
|
const fileProfile = getProfileForFile(file3.path);
|
|
84011
85091
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -84018,7 +85098,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
84018
85098
|
let skippedCount = 0;
|
|
84019
85099
|
for (const fileInfo of filesToCheck) {
|
|
84020
85100
|
const { path: filePath } = fileInfo;
|
|
84021
|
-
const fullPath =
|
|
85101
|
+
const fullPath = path95.isAbsolute(filePath) ? filePath : path95.join(directory, filePath);
|
|
84022
85102
|
const result = {
|
|
84023
85103
|
path: filePath,
|
|
84024
85104
|
language: "",
|
|
@@ -84048,7 +85128,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
84048
85128
|
}
|
|
84049
85129
|
let content;
|
|
84050
85130
|
try {
|
|
84051
|
-
content =
|
|
85131
|
+
content = fs79.readFileSync(fullPath, "utf8");
|
|
84052
85132
|
} catch {
|
|
84053
85133
|
result.skipped_reason = "file_read_error";
|
|
84054
85134
|
skippedCount++;
|
|
@@ -84067,7 +85147,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
84067
85147
|
results.push(result);
|
|
84068
85148
|
continue;
|
|
84069
85149
|
}
|
|
84070
|
-
const ext =
|
|
85150
|
+
const ext = path95.extname(filePath).toLowerCase();
|
|
84071
85151
|
const langDef = getLanguageForExtension(ext);
|
|
84072
85152
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
84073
85153
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -84159,8 +85239,8 @@ init_dist();
|
|
|
84159
85239
|
init_utils();
|
|
84160
85240
|
init_create_tool();
|
|
84161
85241
|
init_path_security();
|
|
84162
|
-
import * as
|
|
84163
|
-
import * as
|
|
85242
|
+
import * as fs80 from "fs";
|
|
85243
|
+
import * as path96 from "path";
|
|
84164
85244
|
var MAX_TEXT_LENGTH = 200;
|
|
84165
85245
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
84166
85246
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -84226,9 +85306,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
84226
85306
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
84227
85307
|
}
|
|
84228
85308
|
try {
|
|
84229
|
-
const resolvedPath =
|
|
84230
|
-
const normalizedCwd =
|
|
84231
|
-
const normalizedResolved =
|
|
85309
|
+
const resolvedPath = path96.resolve(paths);
|
|
85310
|
+
const normalizedCwd = path96.resolve(cwd);
|
|
85311
|
+
const normalizedResolved = path96.resolve(resolvedPath);
|
|
84232
85312
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
84233
85313
|
return {
|
|
84234
85314
|
error: "paths must be within the current working directory",
|
|
@@ -84244,13 +85324,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
84244
85324
|
}
|
|
84245
85325
|
}
|
|
84246
85326
|
function isSupportedExtension(filePath) {
|
|
84247
|
-
const ext =
|
|
85327
|
+
const ext = path96.extname(filePath).toLowerCase();
|
|
84248
85328
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
84249
85329
|
}
|
|
84250
85330
|
function findSourceFiles4(dir, files = []) {
|
|
84251
85331
|
let entries;
|
|
84252
85332
|
try {
|
|
84253
|
-
entries =
|
|
85333
|
+
entries = fs80.readdirSync(dir);
|
|
84254
85334
|
} catch {
|
|
84255
85335
|
return files;
|
|
84256
85336
|
}
|
|
@@ -84259,16 +85339,16 @@ function findSourceFiles4(dir, files = []) {
|
|
|
84259
85339
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
84260
85340
|
continue;
|
|
84261
85341
|
}
|
|
84262
|
-
const fullPath =
|
|
84263
|
-
let
|
|
85342
|
+
const fullPath = path96.join(dir, entry);
|
|
85343
|
+
let stat4;
|
|
84264
85344
|
try {
|
|
84265
|
-
|
|
85345
|
+
stat4 = fs80.statSync(fullPath);
|
|
84266
85346
|
} catch {
|
|
84267
85347
|
continue;
|
|
84268
85348
|
}
|
|
84269
|
-
if (
|
|
85349
|
+
if (stat4.isDirectory()) {
|
|
84270
85350
|
findSourceFiles4(fullPath, files);
|
|
84271
|
-
} else if (
|
|
85351
|
+
} else if (stat4.isFile()) {
|
|
84272
85352
|
if (isSupportedExtension(fullPath)) {
|
|
84273
85353
|
files.push(fullPath);
|
|
84274
85354
|
}
|
|
@@ -84355,7 +85435,7 @@ var todo_extract = createSwarmTool({
|
|
|
84355
85435
|
return JSON.stringify(errorResult, null, 2);
|
|
84356
85436
|
}
|
|
84357
85437
|
const scanPath = resolvedPath;
|
|
84358
|
-
if (!
|
|
85438
|
+
if (!fs80.existsSync(scanPath)) {
|
|
84359
85439
|
const errorResult = {
|
|
84360
85440
|
error: `path not found: ${pathsInput}`,
|
|
84361
85441
|
total: 0,
|
|
@@ -84365,13 +85445,13 @@ var todo_extract = createSwarmTool({
|
|
|
84365
85445
|
return JSON.stringify(errorResult, null, 2);
|
|
84366
85446
|
}
|
|
84367
85447
|
const filesToScan = [];
|
|
84368
|
-
const
|
|
84369
|
-
if (
|
|
85448
|
+
const stat4 = fs80.statSync(scanPath);
|
|
85449
|
+
if (stat4.isFile()) {
|
|
84370
85450
|
if (isSupportedExtension(scanPath)) {
|
|
84371
85451
|
filesToScan.push(scanPath);
|
|
84372
85452
|
} else {
|
|
84373
85453
|
const errorResult = {
|
|
84374
|
-
error: `unsupported file extension: ${
|
|
85454
|
+
error: `unsupported file extension: ${path96.extname(scanPath)}`,
|
|
84375
85455
|
total: 0,
|
|
84376
85456
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
84377
85457
|
entries: []
|
|
@@ -84384,11 +85464,11 @@ var todo_extract = createSwarmTool({
|
|
|
84384
85464
|
const allEntries = [];
|
|
84385
85465
|
for (const filePath of filesToScan) {
|
|
84386
85466
|
try {
|
|
84387
|
-
const fileStat =
|
|
85467
|
+
const fileStat = fs80.statSync(filePath);
|
|
84388
85468
|
if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
|
|
84389
85469
|
continue;
|
|
84390
85470
|
}
|
|
84391
|
-
const content =
|
|
85471
|
+
const content = fs80.readFileSync(filePath, "utf-8");
|
|
84392
85472
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
84393
85473
|
allEntries.push(...entries);
|
|
84394
85474
|
} catch {}
|
|
@@ -84418,18 +85498,18 @@ init_tool();
|
|
|
84418
85498
|
init_loader();
|
|
84419
85499
|
init_schema();
|
|
84420
85500
|
init_gate_evidence();
|
|
84421
|
-
import * as
|
|
84422
|
-
import * as
|
|
85501
|
+
import * as fs82 from "fs";
|
|
85502
|
+
import * as path98 from "path";
|
|
84423
85503
|
|
|
84424
85504
|
// src/hooks/diff-scope.ts
|
|
84425
|
-
import * as
|
|
84426
|
-
import * as
|
|
85505
|
+
import * as fs81 from "fs";
|
|
85506
|
+
import * as path97 from "path";
|
|
84427
85507
|
function getDeclaredScope(taskId, directory) {
|
|
84428
85508
|
try {
|
|
84429
|
-
const planPath =
|
|
84430
|
-
if (!
|
|
85509
|
+
const planPath = path97.join(directory, ".swarm", "plan.json");
|
|
85510
|
+
if (!fs81.existsSync(planPath))
|
|
84431
85511
|
return null;
|
|
84432
|
-
const raw =
|
|
85512
|
+
const raw = fs81.readFileSync(planPath, "utf-8");
|
|
84433
85513
|
const plan = JSON.parse(raw);
|
|
84434
85514
|
for (const phase of plan.phases ?? []) {
|
|
84435
85515
|
for (const task of phase.tasks ?? []) {
|
|
@@ -84545,7 +85625,7 @@ var TIER_3_PATTERNS = [
|
|
|
84545
85625
|
];
|
|
84546
85626
|
function matchesTier3Pattern(files) {
|
|
84547
85627
|
for (const file3 of files) {
|
|
84548
|
-
const fileName =
|
|
85628
|
+
const fileName = path98.basename(file3);
|
|
84549
85629
|
for (const pattern of TIER_3_PATTERNS) {
|
|
84550
85630
|
if (pattern.test(fileName)) {
|
|
84551
85631
|
return true;
|
|
@@ -84559,8 +85639,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
84559
85639
|
if (hasActiveTurboMode()) {
|
|
84560
85640
|
const resolvedDir2 = workingDirectory;
|
|
84561
85641
|
try {
|
|
84562
|
-
const planPath =
|
|
84563
|
-
const planRaw =
|
|
85642
|
+
const planPath = path98.join(resolvedDir2, ".swarm", "plan.json");
|
|
85643
|
+
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
84564
85644
|
const plan = JSON.parse(planRaw);
|
|
84565
85645
|
for (const planPhase of plan.phases ?? []) {
|
|
84566
85646
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -84629,8 +85709,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
84629
85709
|
}
|
|
84630
85710
|
try {
|
|
84631
85711
|
const resolvedDir2 = workingDirectory;
|
|
84632
|
-
const planPath =
|
|
84633
|
-
const planRaw =
|
|
85712
|
+
const planPath = path98.join(resolvedDir2, ".swarm", "plan.json");
|
|
85713
|
+
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
84634
85714
|
const plan = JSON.parse(planRaw);
|
|
84635
85715
|
for (const planPhase of plan.phases ?? []) {
|
|
84636
85716
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -84854,8 +85934,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
84854
85934
|
};
|
|
84855
85935
|
}
|
|
84856
85936
|
}
|
|
84857
|
-
normalizedDir =
|
|
84858
|
-
const pathParts = normalizedDir.split(
|
|
85937
|
+
normalizedDir = path98.normalize(args2.working_directory);
|
|
85938
|
+
const pathParts = normalizedDir.split(path98.sep);
|
|
84859
85939
|
if (pathParts.includes("..")) {
|
|
84860
85940
|
return {
|
|
84861
85941
|
success: false,
|
|
@@ -84865,11 +85945,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
84865
85945
|
]
|
|
84866
85946
|
};
|
|
84867
85947
|
}
|
|
84868
|
-
const resolvedDir =
|
|
85948
|
+
const resolvedDir = path98.resolve(normalizedDir);
|
|
84869
85949
|
try {
|
|
84870
|
-
const realPath =
|
|
84871
|
-
const planPath =
|
|
84872
|
-
if (!
|
|
85950
|
+
const realPath = fs82.realpathSync(resolvedDir);
|
|
85951
|
+
const planPath = path98.join(realPath, ".swarm", "plan.json");
|
|
85952
|
+
if (!fs82.existsSync(planPath)) {
|
|
84873
85953
|
return {
|
|
84874
85954
|
success: false,
|
|
84875
85955
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -84900,22 +85980,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
84900
85980
|
}
|
|
84901
85981
|
if (args2.status === "in_progress") {
|
|
84902
85982
|
try {
|
|
84903
|
-
const evidencePath =
|
|
84904
|
-
|
|
84905
|
-
const fd =
|
|
85983
|
+
const evidencePath = path98.join(directory, ".swarm", "evidence", `${args2.task_id}.json`);
|
|
85984
|
+
fs82.mkdirSync(path98.dirname(evidencePath), { recursive: true });
|
|
85985
|
+
const fd = fs82.openSync(evidencePath, "wx");
|
|
84906
85986
|
let writeOk = false;
|
|
84907
85987
|
try {
|
|
84908
|
-
|
|
85988
|
+
fs82.writeSync(fd, JSON.stringify({
|
|
84909
85989
|
taskId: args2.task_id,
|
|
84910
85990
|
required_gates: ["reviewer", "test_engineer"],
|
|
84911
85991
|
gates: {}
|
|
84912
85992
|
}, null, 2));
|
|
84913
85993
|
writeOk = true;
|
|
84914
85994
|
} finally {
|
|
84915
|
-
|
|
85995
|
+
fs82.closeSync(fd);
|
|
84916
85996
|
if (!writeOk) {
|
|
84917
85997
|
try {
|
|
84918
|
-
|
|
85998
|
+
fs82.unlinkSync(evidencePath);
|
|
84919
85999
|
} catch {}
|
|
84920
86000
|
}
|
|
84921
86001
|
}
|
|
@@ -84925,8 +86005,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
84925
86005
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
84926
86006
|
let phaseRequiresReviewer = true;
|
|
84927
86007
|
try {
|
|
84928
|
-
const planPath =
|
|
84929
|
-
const planRaw =
|
|
86008
|
+
const planPath = path98.join(directory, ".swarm", "plan.json");
|
|
86009
|
+
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
84930
86010
|
const plan = JSON.parse(planRaw);
|
|
84931
86011
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
84932
86012
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -85035,8 +86115,8 @@ init_utils2();
|
|
|
85035
86115
|
init_ledger();
|
|
85036
86116
|
init_manager();
|
|
85037
86117
|
init_create_tool();
|
|
85038
|
-
import
|
|
85039
|
-
import
|
|
86118
|
+
import fs83 from "fs";
|
|
86119
|
+
import path99 from "path";
|
|
85040
86120
|
function derivePlanId5(plan) {
|
|
85041
86121
|
return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
85042
86122
|
}
|
|
@@ -85087,7 +86167,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
85087
86167
|
entries: [evidenceEntry]
|
|
85088
86168
|
};
|
|
85089
86169
|
const filename = "drift-verifier.json";
|
|
85090
|
-
const relativePath =
|
|
86170
|
+
const relativePath = path99.join("evidence", String(phase), filename);
|
|
85091
86171
|
let validatedPath;
|
|
85092
86172
|
try {
|
|
85093
86173
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -85098,12 +86178,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
85098
86178
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
85099
86179
|
}, null, 2);
|
|
85100
86180
|
}
|
|
85101
|
-
const evidenceDir =
|
|
86181
|
+
const evidenceDir = path99.dirname(validatedPath);
|
|
85102
86182
|
try {
|
|
85103
|
-
await
|
|
85104
|
-
const tempPath =
|
|
85105
|
-
await
|
|
85106
|
-
await
|
|
86183
|
+
await fs83.promises.mkdir(evidenceDir, { recursive: true });
|
|
86184
|
+
const tempPath = path99.join(evidenceDir, `.${filename}.tmp`);
|
|
86185
|
+
await fs83.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
86186
|
+
await fs83.promises.rename(tempPath, validatedPath);
|
|
85107
86187
|
let snapshotInfo;
|
|
85108
86188
|
let snapshotError;
|
|
85109
86189
|
let qaProfileLocked;
|
|
@@ -85197,8 +86277,8 @@ var write_drift_evidence = createSwarmTool({
|
|
|
85197
86277
|
init_tool();
|
|
85198
86278
|
init_utils2();
|
|
85199
86279
|
init_create_tool();
|
|
85200
|
-
import
|
|
85201
|
-
import
|
|
86280
|
+
import fs84 from "fs";
|
|
86281
|
+
import path100 from "path";
|
|
85202
86282
|
function normalizeVerdict2(verdict) {
|
|
85203
86283
|
switch (verdict) {
|
|
85204
86284
|
case "APPROVED":
|
|
@@ -85246,7 +86326,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
85246
86326
|
entries: [evidenceEntry]
|
|
85247
86327
|
};
|
|
85248
86328
|
const filename = "hallucination-guard.json";
|
|
85249
|
-
const relativePath =
|
|
86329
|
+
const relativePath = path100.join("evidence", String(phase), filename);
|
|
85250
86330
|
let validatedPath;
|
|
85251
86331
|
try {
|
|
85252
86332
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -85257,12 +86337,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
85257
86337
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
85258
86338
|
}, null, 2);
|
|
85259
86339
|
}
|
|
85260
|
-
const evidenceDir =
|
|
86340
|
+
const evidenceDir = path100.dirname(validatedPath);
|
|
85261
86341
|
try {
|
|
85262
|
-
await
|
|
85263
|
-
const tempPath =
|
|
85264
|
-
await
|
|
85265
|
-
await
|
|
86342
|
+
await fs84.promises.mkdir(evidenceDir, { recursive: true });
|
|
86343
|
+
const tempPath = path100.join(evidenceDir, `.${filename}.tmp`);
|
|
86344
|
+
await fs84.promises.writeFile(tempPath, JSON.stringify(evidenceContent, null, 2), "utf-8");
|
|
86345
|
+
await fs84.promises.rename(tempPath, validatedPath);
|
|
85266
86346
|
return JSON.stringify({
|
|
85267
86347
|
success: true,
|
|
85268
86348
|
phase,
|
|
@@ -85369,6 +86449,11 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
85369
86449
|
const contextBudgetHandler = createContextBudgetHandler(config3);
|
|
85370
86450
|
const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
|
|
85371
86451
|
const activityHooks = createAgentActivityHooks(config3, ctx.directory);
|
|
86452
|
+
const prmHook = createPrmHook(config3.prm ?? PrmConfigSchema.parse({}), ctx.directory);
|
|
86453
|
+
const trajectoryLoggerHook = createTrajectoryLoggerHook({
|
|
86454
|
+
enabled: true,
|
|
86455
|
+
max_lines: 1000
|
|
86456
|
+
}, ctx.directory);
|
|
85372
86457
|
const delegationGateHooks = createDelegationGateHook(config3, ctx.directory);
|
|
85373
86458
|
const delegationSanitizerHook = createDelegationSanitizerHook(ctx.directory);
|
|
85374
86459
|
const guardrailsFallback = config3.guardrails?.enabled === false ? { ...config3.guardrails, enabled: false } : config3.guardrails ?? {};
|
|
@@ -85471,7 +86556,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
85471
86556
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
85472
86557
|
preflightTriggerManager = new PTM(automationConfig);
|
|
85473
86558
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
85474
|
-
const swarmDir =
|
|
86559
|
+
const swarmDir = path101.resolve(ctx.directory, ".swarm");
|
|
85475
86560
|
statusArtifact = new ASA(swarmDir);
|
|
85476
86561
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
85477
86562
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -85891,6 +86976,10 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
85891
86976
|
await activityHooks.toolAfter(input, output);
|
|
85892
86977
|
if (_dbg)
|
|
85893
86978
|
console.error(`[DIAG] toolAfter activity done tool=${_toolName}`);
|
|
86979
|
+
await safeHook(trajectoryLoggerHook.toolAfter)(input, output);
|
|
86980
|
+
if (_dbg)
|
|
86981
|
+
console.error(`[DIAG] toolAfter trajectoryLogger done tool=${_toolName}`);
|
|
86982
|
+
await safeHook(prmHook.toolAfter)(input, output);
|
|
85894
86983
|
await guardrailsHooks.toolAfter(input, output);
|
|
85895
86984
|
if (_dbg)
|
|
85896
86985
|
console.error(`[DIAG] toolAfter guardrails done tool=${_toolName}`);
|