opencode-swarm 6.80.1 → 6.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -0
- package/dist/cli/index.js +20 -0
- package/dist/config/schema.d.ts +27 -0
- package/dist/hooks/adversarial-detector.d.ts +2 -2
- package/dist/hooks/trajectory-logger.d.ts +14 -2
- package/dist/index.js +1560 -448
- 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();
|
|
@@ -65906,20 +65991,32 @@ Recommendation: Consider escalating to user or taking a different approach
|
|
|
65906
65991
|
The current fix strategy appears to be cycling without progress`;
|
|
65907
65992
|
return { eventLogged, checkpointCreated, message };
|
|
65908
65993
|
}
|
|
65909
|
-
var
|
|
65994
|
+
var recentToolCallsBySession = new Map;
|
|
65995
|
+
var lastSpiralTimestampBySession = new Map;
|
|
65910
65996
|
var MAX_RECENT_CALLS = 20;
|
|
65911
65997
|
var SPIRAL_THRESHOLD = 5;
|
|
65912
65998
|
var SPIRAL_WINDOW_MS = 300000;
|
|
65913
|
-
|
|
65999
|
+
var SPIRAL_COOLDOWN_MS = 60000;
|
|
66000
|
+
var MAX_TRACKED_SESSIONS = 500;
|
|
66001
|
+
function recordToolCall(tool3, args2, sessionId) {
|
|
65914
66002
|
const argsHash = typeof args2 === "string" ? args2.slice(0, 100) : JSON.stringify(args2 ?? "").slice(0, 100);
|
|
65915
|
-
|
|
65916
|
-
if (
|
|
65917
|
-
|
|
66003
|
+
let calls = recentToolCallsBySession.get(sessionId);
|
|
66004
|
+
if (!calls) {
|
|
66005
|
+
calls = [];
|
|
66006
|
+
recentToolCallsBySession.set(sessionId, calls);
|
|
66007
|
+
}
|
|
66008
|
+
calls.push({ tool: tool3, argsHash, timestamp: Date.now() });
|
|
66009
|
+
if (calls.length > MAX_RECENT_CALLS) {
|
|
66010
|
+
calls.shift();
|
|
65918
66011
|
}
|
|
65919
66012
|
}
|
|
65920
|
-
async function detectDebuggingSpiral(_directory) {
|
|
66013
|
+
async function detectDebuggingSpiral(_directory, sessionId) {
|
|
65921
66014
|
const now = Date.now();
|
|
65922
|
-
const
|
|
66015
|
+
const lastTrigger = lastSpiralTimestampBySession.get(sessionId) ?? 0;
|
|
66016
|
+
if (now - lastTrigger < SPIRAL_COOLDOWN_MS)
|
|
66017
|
+
return null;
|
|
66018
|
+
const calls = recentToolCallsBySession.get(sessionId) ?? [];
|
|
66019
|
+
const windowCalls = calls.filter((c) => now - c.timestamp < SPIRAL_WINDOW_MS);
|
|
65923
66020
|
if (windowCalls.length < SPIRAL_THRESHOLD)
|
|
65924
66021
|
return null;
|
|
65925
66022
|
const lastN = windowCalls.slice(-SPIRAL_THRESHOLD);
|
|
@@ -65928,6 +66025,17 @@ async function detectDebuggingSpiral(_directory) {
|
|
|
65928
66025
|
const allSameTool = lastN.every((c) => c.tool === firstTool);
|
|
65929
66026
|
const allSimilarArgs = lastN.every((c) => c.argsHash === firstArgs);
|
|
65930
66027
|
if (allSameTool && allSimilarArgs) {
|
|
66028
|
+
lastSpiralTimestampBySession.set(sessionId, now);
|
|
66029
|
+
recentToolCallsBySession.delete(sessionId);
|
|
66030
|
+
if (lastSpiralTimestampBySession.size > MAX_TRACKED_SESSIONS) {
|
|
66031
|
+
for (const oldest of lastSpiralTimestampBySession.keys()) {
|
|
66032
|
+
if (oldest !== sessionId) {
|
|
66033
|
+
lastSpiralTimestampBySession.delete(oldest);
|
|
66034
|
+
recentToolCallsBySession.delete(oldest);
|
|
66035
|
+
break;
|
|
66036
|
+
}
|
|
66037
|
+
}
|
|
66038
|
+
}
|
|
65931
66039
|
return {
|
|
65932
66040
|
pattern: "VELOCITY_RATIONALIZATION",
|
|
65933
66041
|
severity: "HIGH",
|
|
@@ -70540,6 +70648,996 @@ function createSteeringConsumedHook(directory) {
|
|
|
70540
70648
|
return safeHook(hook);
|
|
70541
70649
|
}
|
|
70542
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
|
+
|
|
70543
71641
|
// src/index.ts
|
|
70544
71642
|
init_compaction_service();
|
|
70545
71643
|
init_config_doctor();
|
|
@@ -70643,6 +71741,11 @@ function deserializeAgentSession(s) {
|
|
|
70643
71741
|
fullAutoInteractionCount: s.fullAutoInteractionCount ?? 0,
|
|
70644
71742
|
fullAutoDeadlockCount: s.fullAutoDeadlockCount ?? 0,
|
|
70645
71743
|
fullAutoLastQuestionHash: s.fullAutoLastQuestionHash ?? null,
|
|
71744
|
+
prmPatternCounts: new Map,
|
|
71745
|
+
prmEscalationLevel: 0,
|
|
71746
|
+
prmLastPatternDetected: null,
|
|
71747
|
+
prmTrajectoryStep: 0,
|
|
71748
|
+
prmHardStopPending: false,
|
|
70646
71749
|
sessionRehydratedAt: s.sessionRehydratedAt ?? 0
|
|
70647
71750
|
};
|
|
70648
71751
|
}
|
|
@@ -70748,8 +71851,8 @@ init_telemetry();
|
|
|
70748
71851
|
// src/tools/batch-symbols.ts
|
|
70749
71852
|
init_tool();
|
|
70750
71853
|
init_create_tool();
|
|
70751
|
-
import * as
|
|
70752
|
-
import * as
|
|
71854
|
+
import * as fs54 from "fs";
|
|
71855
|
+
import * as path68 from "path";
|
|
70753
71856
|
init_path_security();
|
|
70754
71857
|
var WINDOWS_RESERVED_NAMES2 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
70755
71858
|
function containsWindowsAttacks2(str) {
|
|
@@ -70766,14 +71869,14 @@ function containsWindowsAttacks2(str) {
|
|
|
70766
71869
|
}
|
|
70767
71870
|
function isPathInWorkspace2(filePath, workspace) {
|
|
70768
71871
|
try {
|
|
70769
|
-
const resolvedPath =
|
|
70770
|
-
if (!
|
|
71872
|
+
const resolvedPath = path68.resolve(workspace, filePath);
|
|
71873
|
+
if (!fs54.existsSync(resolvedPath)) {
|
|
70771
71874
|
return true;
|
|
70772
71875
|
}
|
|
70773
|
-
const realWorkspace =
|
|
70774
|
-
const realResolvedPath =
|
|
70775
|
-
const relativePath =
|
|
70776
|
-
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)) {
|
|
70777
71880
|
return false;
|
|
70778
71881
|
}
|
|
70779
71882
|
return true;
|
|
@@ -70782,7 +71885,7 @@ function isPathInWorkspace2(filePath, workspace) {
|
|
|
70782
71885
|
}
|
|
70783
71886
|
}
|
|
70784
71887
|
function processFile2(file3, cwd, exportedOnly) {
|
|
70785
|
-
const ext =
|
|
71888
|
+
const ext = path68.extname(file3);
|
|
70786
71889
|
if (containsControlChars(file3)) {
|
|
70787
71890
|
return {
|
|
70788
71891
|
file: file3,
|
|
@@ -70815,8 +71918,8 @@ function processFile2(file3, cwd, exportedOnly) {
|
|
|
70815
71918
|
errorType: "path-outside-workspace"
|
|
70816
71919
|
};
|
|
70817
71920
|
}
|
|
70818
|
-
const fullPath =
|
|
70819
|
-
if (!
|
|
71921
|
+
const fullPath = path68.join(cwd, file3);
|
|
71922
|
+
if (!fs54.existsSync(fullPath)) {
|
|
70820
71923
|
return {
|
|
70821
71924
|
file: file3,
|
|
70822
71925
|
success: false,
|
|
@@ -70847,14 +71950,14 @@ function processFile2(file3, cwd, exportedOnly) {
|
|
|
70847
71950
|
}
|
|
70848
71951
|
let isEmptyFile = false;
|
|
70849
71952
|
try {
|
|
70850
|
-
const stats =
|
|
71953
|
+
const stats = fs54.statSync(fullPath);
|
|
70851
71954
|
if (stats.size === 0) {
|
|
70852
71955
|
isEmptyFile = true;
|
|
70853
71956
|
}
|
|
70854
71957
|
} catch {}
|
|
70855
71958
|
if (syms.length === 0) {
|
|
70856
71959
|
try {
|
|
70857
|
-
const content =
|
|
71960
|
+
const content = fs54.readFileSync(fullPath, "utf-8");
|
|
70858
71961
|
if (content.trim().length === 0) {
|
|
70859
71962
|
isEmptyFile = true;
|
|
70860
71963
|
}
|
|
@@ -71106,25 +72209,25 @@ init_manager2();
|
|
|
71106
72209
|
init_task_id();
|
|
71107
72210
|
init_create_tool();
|
|
71108
72211
|
init_resolve_working_directory();
|
|
71109
|
-
import * as
|
|
71110
|
-
import * as
|
|
72212
|
+
import * as fs55 from "fs";
|
|
72213
|
+
import * as path69 from "path";
|
|
71111
72214
|
var EVIDENCE_DIR = ".swarm/evidence";
|
|
71112
72215
|
function isValidTaskId3(taskId) {
|
|
71113
72216
|
return isStrictTaskId(taskId);
|
|
71114
72217
|
}
|
|
71115
72218
|
function isPathWithinSwarm(filePath, workspaceRoot) {
|
|
71116
|
-
const normalizedWorkspace =
|
|
71117
|
-
const swarmPath =
|
|
71118
|
-
const normalizedPath =
|
|
72219
|
+
const normalizedWorkspace = path69.resolve(workspaceRoot);
|
|
72220
|
+
const swarmPath = path69.join(normalizedWorkspace, ".swarm", "evidence");
|
|
72221
|
+
const normalizedPath = path69.resolve(filePath);
|
|
71119
72222
|
return normalizedPath.startsWith(swarmPath);
|
|
71120
72223
|
}
|
|
71121
72224
|
function readEvidenceFile(evidencePath) {
|
|
71122
|
-
if (!
|
|
72225
|
+
if (!fs55.existsSync(evidencePath)) {
|
|
71123
72226
|
return null;
|
|
71124
72227
|
}
|
|
71125
72228
|
let content;
|
|
71126
72229
|
try {
|
|
71127
|
-
content =
|
|
72230
|
+
content = fs55.readFileSync(evidencePath, "utf-8");
|
|
71128
72231
|
} catch {
|
|
71129
72232
|
return null;
|
|
71130
72233
|
}
|
|
@@ -71196,7 +72299,7 @@ var check_gate_status = createSwarmTool({
|
|
|
71196
72299
|
};
|
|
71197
72300
|
return JSON.stringify(errorResult, null, 2);
|
|
71198
72301
|
}
|
|
71199
|
-
const evidencePath =
|
|
72302
|
+
const evidencePath = path69.join(directory, EVIDENCE_DIR, `${taskIdInput}.json`);
|
|
71200
72303
|
if (!isPathWithinSwarm(evidencePath, directory)) {
|
|
71201
72304
|
const errorResult = {
|
|
71202
72305
|
taskId: taskIdInput,
|
|
@@ -71292,8 +72395,8 @@ init_utils2();
|
|
|
71292
72395
|
init_state();
|
|
71293
72396
|
init_create_tool();
|
|
71294
72397
|
init_resolve_working_directory();
|
|
71295
|
-
import * as
|
|
71296
|
-
import * as
|
|
72398
|
+
import * as fs56 from "fs";
|
|
72399
|
+
import * as path70 from "path";
|
|
71297
72400
|
function extractMatches(regex, text) {
|
|
71298
72401
|
return Array.from(text.matchAll(regex));
|
|
71299
72402
|
}
|
|
@@ -71387,7 +72490,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71387
72490
|
let plan;
|
|
71388
72491
|
try {
|
|
71389
72492
|
const planPath = validateSwarmPath(directory, "plan.json");
|
|
71390
|
-
const planRaw =
|
|
72493
|
+
const planRaw = fs56.readFileSync(planPath, "utf-8");
|
|
71391
72494
|
plan = JSON.parse(planRaw);
|
|
71392
72495
|
} catch {
|
|
71393
72496
|
const result2 = {
|
|
@@ -71445,10 +72548,10 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71445
72548
|
let hasFileReadFailure = false;
|
|
71446
72549
|
for (const filePath of fileTargets) {
|
|
71447
72550
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
71448
|
-
const resolvedPath =
|
|
71449
|
-
const projectRoot =
|
|
71450
|
-
const relative16 =
|
|
71451
|
-
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);
|
|
71452
72555
|
if (!withinProject) {
|
|
71453
72556
|
blockedTasks.push({
|
|
71454
72557
|
task_id: task.id,
|
|
@@ -71461,7 +72564,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71461
72564
|
}
|
|
71462
72565
|
let fileContent;
|
|
71463
72566
|
try {
|
|
71464
|
-
fileContent =
|
|
72567
|
+
fileContent = fs56.readFileSync(resolvedPath, "utf-8");
|
|
71465
72568
|
} catch {
|
|
71466
72569
|
blockedTasks.push({
|
|
71467
72570
|
task_id: task.id,
|
|
@@ -71503,9 +72606,9 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71503
72606
|
blockedTasks
|
|
71504
72607
|
};
|
|
71505
72608
|
try {
|
|
71506
|
-
const evidenceDir =
|
|
71507
|
-
const evidencePath =
|
|
71508
|
-
|
|
72609
|
+
const evidenceDir = path70.join(directory, ".swarm", "evidence", `${phase}`);
|
|
72610
|
+
const evidencePath = path70.join(evidenceDir, "completion-verify.json");
|
|
72611
|
+
fs56.mkdirSync(evidenceDir, { recursive: true });
|
|
71509
72612
|
const evidenceBundle = {
|
|
71510
72613
|
schema_version: "1.0.0",
|
|
71511
72614
|
task_id: "completion-verify",
|
|
@@ -71526,7 +72629,7 @@ async function executeCompletionVerify(args2, directory) {
|
|
|
71526
72629
|
}
|
|
71527
72630
|
]
|
|
71528
72631
|
};
|
|
71529
|
-
|
|
72632
|
+
fs56.writeFileSync(evidencePath, JSON.stringify(evidenceBundle, null, 2), "utf-8");
|
|
71530
72633
|
} catch {}
|
|
71531
72634
|
return JSON.stringify(result, null, 2);
|
|
71532
72635
|
}
|
|
@@ -71580,12 +72683,12 @@ var completion_verify = createSwarmTool({
|
|
|
71580
72683
|
});
|
|
71581
72684
|
// src/tools/complexity-hotspots.ts
|
|
71582
72685
|
init_dist();
|
|
71583
|
-
import * as
|
|
71584
|
-
import * as
|
|
72686
|
+
import * as fs58 from "fs";
|
|
72687
|
+
import * as path72 from "path";
|
|
71585
72688
|
|
|
71586
72689
|
// src/quality/metrics.ts
|
|
71587
|
-
import * as
|
|
71588
|
-
import * as
|
|
72690
|
+
import * as fs57 from "fs";
|
|
72691
|
+
import * as path71 from "path";
|
|
71589
72692
|
var MAX_FILE_SIZE_BYTES4 = 256 * 1024;
|
|
71590
72693
|
var MIN_DUPLICATION_LINES = 10;
|
|
71591
72694
|
function estimateCyclomaticComplexity(content) {
|
|
@@ -71623,11 +72726,11 @@ function estimateCyclomaticComplexity(content) {
|
|
|
71623
72726
|
}
|
|
71624
72727
|
function getComplexityForFile(filePath) {
|
|
71625
72728
|
try {
|
|
71626
|
-
const
|
|
71627
|
-
if (
|
|
72729
|
+
const stat4 = fs57.statSync(filePath);
|
|
72730
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES4) {
|
|
71628
72731
|
return null;
|
|
71629
72732
|
}
|
|
71630
|
-
const content =
|
|
72733
|
+
const content = fs57.readFileSync(filePath, "utf-8");
|
|
71631
72734
|
return estimateCyclomaticComplexity(content);
|
|
71632
72735
|
} catch {
|
|
71633
72736
|
return null;
|
|
@@ -71637,8 +72740,8 @@ async function computeComplexityDelta(files, workingDir) {
|
|
|
71637
72740
|
let totalComplexity = 0;
|
|
71638
72741
|
const analyzedFiles = [];
|
|
71639
72742
|
for (const file3 of files) {
|
|
71640
|
-
const fullPath =
|
|
71641
|
-
if (!
|
|
72743
|
+
const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
|
|
72744
|
+
if (!fs57.existsSync(fullPath)) {
|
|
71642
72745
|
continue;
|
|
71643
72746
|
}
|
|
71644
72747
|
const complexity = getComplexityForFile(fullPath);
|
|
@@ -71759,8 +72862,8 @@ function countGoExports(content) {
|
|
|
71759
72862
|
}
|
|
71760
72863
|
function getExportCountForFile(filePath) {
|
|
71761
72864
|
try {
|
|
71762
|
-
const content =
|
|
71763
|
-
const ext =
|
|
72865
|
+
const content = fs57.readFileSync(filePath, "utf-8");
|
|
72866
|
+
const ext = path71.extname(filePath).toLowerCase();
|
|
71764
72867
|
switch (ext) {
|
|
71765
72868
|
case ".ts":
|
|
71766
72869
|
case ".tsx":
|
|
@@ -71786,8 +72889,8 @@ async function computePublicApiDelta(files, workingDir) {
|
|
|
71786
72889
|
let totalExports = 0;
|
|
71787
72890
|
const analyzedFiles = [];
|
|
71788
72891
|
for (const file3 of files) {
|
|
71789
|
-
const fullPath =
|
|
71790
|
-
if (!
|
|
72892
|
+
const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
|
|
72893
|
+
if (!fs57.existsSync(fullPath)) {
|
|
71791
72894
|
continue;
|
|
71792
72895
|
}
|
|
71793
72896
|
const exports = getExportCountForFile(fullPath);
|
|
@@ -71820,16 +72923,16 @@ async function computeDuplicationRatio(files, workingDir) {
|
|
|
71820
72923
|
let duplicateLines = 0;
|
|
71821
72924
|
const analyzedFiles = [];
|
|
71822
72925
|
for (const file3 of files) {
|
|
71823
|
-
const fullPath =
|
|
71824
|
-
if (!
|
|
72926
|
+
const fullPath = path71.isAbsolute(file3) ? file3 : path71.join(workingDir, file3);
|
|
72927
|
+
if (!fs57.existsSync(fullPath)) {
|
|
71825
72928
|
continue;
|
|
71826
72929
|
}
|
|
71827
72930
|
try {
|
|
71828
|
-
const
|
|
71829
|
-
if (
|
|
72931
|
+
const stat4 = fs57.statSync(fullPath);
|
|
72932
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES4) {
|
|
71830
72933
|
continue;
|
|
71831
72934
|
}
|
|
71832
|
-
const content =
|
|
72935
|
+
const content = fs57.readFileSync(fullPath, "utf-8");
|
|
71833
72936
|
const lines = content.split(`
|
|
71834
72937
|
`).filter((line) => line.trim().length > 0);
|
|
71835
72938
|
if (lines.length < MIN_DUPLICATION_LINES) {
|
|
@@ -71853,8 +72956,8 @@ function countCodeLines(content) {
|
|
|
71853
72956
|
return lines.length;
|
|
71854
72957
|
}
|
|
71855
72958
|
function isTestFile(filePath) {
|
|
71856
|
-
const basename10 =
|
|
71857
|
-
const _ext =
|
|
72959
|
+
const basename10 = path71.basename(filePath);
|
|
72960
|
+
const _ext = path71.extname(filePath).toLowerCase();
|
|
71858
72961
|
const testPatterns = [
|
|
71859
72962
|
".test.",
|
|
71860
72963
|
".spec.",
|
|
@@ -71935,8 +73038,8 @@ function matchGlobSegment(globSegments, pathSegments) {
|
|
|
71935
73038
|
}
|
|
71936
73039
|
return gIndex === globSegments.length && pIndex === pathSegments.length;
|
|
71937
73040
|
}
|
|
71938
|
-
function matchesGlobSegment(
|
|
71939
|
-
const normalizedPath =
|
|
73041
|
+
function matchesGlobSegment(path72, glob) {
|
|
73042
|
+
const normalizedPath = path72.replace(/\\/g, "/");
|
|
71940
73043
|
const normalizedGlob = glob.replace(/\\/g, "/");
|
|
71941
73044
|
if (normalizedPath.includes("//")) {
|
|
71942
73045
|
return false;
|
|
@@ -71967,8 +73070,8 @@ function simpleGlobToRegex2(glob) {
|
|
|
71967
73070
|
function hasGlobstar(glob) {
|
|
71968
73071
|
return glob.includes("**");
|
|
71969
73072
|
}
|
|
71970
|
-
function globMatches(
|
|
71971
|
-
const normalizedPath =
|
|
73073
|
+
function globMatches(path72, glob) {
|
|
73074
|
+
const normalizedPath = path72.replace(/\\/g, "/");
|
|
71972
73075
|
if (!glob || glob === "") {
|
|
71973
73076
|
if (normalizedPath.includes("//")) {
|
|
71974
73077
|
return false;
|
|
@@ -72004,31 +73107,31 @@ function shouldExcludeFile(filePath, excludeGlobs) {
|
|
|
72004
73107
|
async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
72005
73108
|
let testLines = 0;
|
|
72006
73109
|
let codeLines = 0;
|
|
72007
|
-
const srcDir =
|
|
72008
|
-
if (
|
|
73110
|
+
const srcDir = path71.join(workingDir, "src");
|
|
73111
|
+
if (fs57.existsSync(srcDir)) {
|
|
72009
73112
|
await scanDirectoryForLines(srcDir, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
72010
73113
|
codeLines += lines;
|
|
72011
73114
|
});
|
|
72012
73115
|
}
|
|
72013
73116
|
const possibleSrcDirs = ["lib", "app", "source", "core"];
|
|
72014
73117
|
for (const dir of possibleSrcDirs) {
|
|
72015
|
-
const dirPath =
|
|
72016
|
-
if (
|
|
73118
|
+
const dirPath = path71.join(workingDir, dir);
|
|
73119
|
+
if (fs57.existsSync(dirPath)) {
|
|
72017
73120
|
await scanDirectoryForLines(dirPath, enforceGlobs, excludeGlobs, false, (lines) => {
|
|
72018
73121
|
codeLines += lines;
|
|
72019
73122
|
});
|
|
72020
73123
|
}
|
|
72021
73124
|
}
|
|
72022
|
-
const testsDir =
|
|
72023
|
-
if (
|
|
73125
|
+
const testsDir = path71.join(workingDir, "tests");
|
|
73126
|
+
if (fs57.existsSync(testsDir)) {
|
|
72024
73127
|
await scanDirectoryForLines(testsDir, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
72025
73128
|
testLines += lines;
|
|
72026
73129
|
});
|
|
72027
73130
|
}
|
|
72028
73131
|
const possibleTestDirs = ["test", "__tests__", "specs"];
|
|
72029
73132
|
for (const dir of possibleTestDirs) {
|
|
72030
|
-
const dirPath =
|
|
72031
|
-
if (
|
|
73133
|
+
const dirPath = path71.join(workingDir, dir);
|
|
73134
|
+
if (fs57.existsSync(dirPath) && dirPath !== testsDir) {
|
|
72032
73135
|
await scanDirectoryForLines(dirPath, ["**"], ["node_modules", "dist"], true, (lines) => {
|
|
72033
73136
|
testLines += lines;
|
|
72034
73137
|
});
|
|
@@ -72040,9 +73143,9 @@ async function computeTestToCodeRatio(workingDir, enforceGlobs, excludeGlobs) {
|
|
|
72040
73143
|
}
|
|
72041
73144
|
async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTestScan, callback) {
|
|
72042
73145
|
try {
|
|
72043
|
-
const entries =
|
|
73146
|
+
const entries = fs57.readdirSync(dirPath, { withFileTypes: true });
|
|
72044
73147
|
for (const entry of entries) {
|
|
72045
|
-
const fullPath =
|
|
73148
|
+
const fullPath = path71.join(dirPath, entry.name);
|
|
72046
73149
|
if (entry.isDirectory()) {
|
|
72047
73150
|
if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
|
|
72048
73151
|
continue;
|
|
@@ -72050,7 +73153,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
72050
73153
|
await scanDirectoryForLines(fullPath, includeGlobs, excludeGlobs, isTestScan, callback);
|
|
72051
73154
|
} else if (entry.isFile()) {
|
|
72052
73155
|
const relativePath = fullPath.replace(`${dirPath}/`, "");
|
|
72053
|
-
const ext =
|
|
73156
|
+
const ext = path71.extname(entry.name).toLowerCase();
|
|
72054
73157
|
const validExts = [
|
|
72055
73158
|
".ts",
|
|
72056
73159
|
".tsx",
|
|
@@ -72086,7 +73189,7 @@ async function scanDirectoryForLines(dirPath, includeGlobs, excludeGlobs, isTest
|
|
|
72086
73189
|
continue;
|
|
72087
73190
|
}
|
|
72088
73191
|
try {
|
|
72089
|
-
const content =
|
|
73192
|
+
const content = fs57.readFileSync(fullPath, "utf-8");
|
|
72090
73193
|
const lines = countCodeLines(content);
|
|
72091
73194
|
callback(lines);
|
|
72092
73195
|
} catch {}
|
|
@@ -72288,11 +73391,11 @@ async function getGitChurn(days, directory) {
|
|
|
72288
73391
|
}
|
|
72289
73392
|
function getComplexityForFile2(filePath) {
|
|
72290
73393
|
try {
|
|
72291
|
-
const
|
|
72292
|
-
if (
|
|
73394
|
+
const stat4 = fs58.statSync(filePath);
|
|
73395
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES5) {
|
|
72293
73396
|
return null;
|
|
72294
73397
|
}
|
|
72295
|
-
const content =
|
|
73398
|
+
const content = fs58.readFileSync(filePath, "utf-8");
|
|
72296
73399
|
return estimateCyclomaticComplexity(content);
|
|
72297
73400
|
} catch {
|
|
72298
73401
|
return null;
|
|
@@ -72303,7 +73406,7 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
72303
73406
|
const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
|
|
72304
73407
|
const filteredChurn = new Map;
|
|
72305
73408
|
for (const [file3, count] of churnMap) {
|
|
72306
|
-
const ext =
|
|
73409
|
+
const ext = path72.extname(file3).toLowerCase();
|
|
72307
73410
|
if (extSet.has(ext)) {
|
|
72308
73411
|
filteredChurn.set(file3, count);
|
|
72309
73412
|
}
|
|
@@ -72313,8 +73416,8 @@ async function analyzeHotspots(days, topN, extensions, directory) {
|
|
|
72313
73416
|
let analyzedFiles = 0;
|
|
72314
73417
|
for (const [file3, churnCount] of filteredChurn) {
|
|
72315
73418
|
let fullPath = file3;
|
|
72316
|
-
if (!
|
|
72317
|
-
fullPath =
|
|
73419
|
+
if (!fs58.existsSync(fullPath)) {
|
|
73420
|
+
fullPath = path72.join(cwd, file3);
|
|
72318
73421
|
}
|
|
72319
73422
|
const complexity = getComplexityForFile2(fullPath);
|
|
72320
73423
|
if (complexity !== null) {
|
|
@@ -72489,7 +73592,7 @@ import {
|
|
|
72489
73592
|
readFileSync as readFileSync37,
|
|
72490
73593
|
writeFileSync as writeFileSync11
|
|
72491
73594
|
} from "fs";
|
|
72492
|
-
import { join as
|
|
73595
|
+
import { join as join65 } from "path";
|
|
72493
73596
|
var EVIDENCE_DIR2 = ".swarm/evidence";
|
|
72494
73597
|
var VALID_TASK_ID = /^\d+\.\d+(\.\d+)*$/;
|
|
72495
73598
|
var COUNCIL_GATE_NAME = "council";
|
|
@@ -72523,9 +73626,9 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
72523
73626
|
if (!VALID_TASK_ID.test(synthesis.taskId)) {
|
|
72524
73627
|
throw new Error(`writeCouncilEvidence: invalid taskId "${synthesis.taskId}" \u2014 must match N.M or N.M.P format`);
|
|
72525
73628
|
}
|
|
72526
|
-
const dir =
|
|
73629
|
+
const dir = join65(workingDir, EVIDENCE_DIR2);
|
|
72527
73630
|
mkdirSync18(dir, { recursive: true });
|
|
72528
|
-
const filePath =
|
|
73631
|
+
const filePath = join65(dir, `${synthesis.taskId}.json`);
|
|
72529
73632
|
const existingRoot = Object.create(null);
|
|
72530
73633
|
if (existsSync37(filePath)) {
|
|
72531
73634
|
try {
|
|
@@ -72558,7 +73661,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
72558
73661
|
updated.required_gates = [];
|
|
72559
73662
|
writeFileSync11(filePath, JSON.stringify(updated, null, 2));
|
|
72560
73663
|
try {
|
|
72561
|
-
const councilDir =
|
|
73664
|
+
const councilDir = join65(workingDir, ".swarm", "council");
|
|
72562
73665
|
mkdirSync18(councilDir, { recursive: true });
|
|
72563
73666
|
const auditLine = JSON.stringify({
|
|
72564
73667
|
round: synthesis.roundNumber,
|
|
@@ -72566,7 +73669,7 @@ function writeCouncilEvidence(workingDir, synthesis) {
|
|
|
72566
73669
|
timestamp: synthesis.timestamp,
|
|
72567
73670
|
vetoedBy: synthesis.vetoedBy
|
|
72568
73671
|
});
|
|
72569
|
-
appendFileSync7(
|
|
73672
|
+
appendFileSync7(join65(councilDir, `${synthesis.taskId}.rounds.jsonl`), `${auditLine}
|
|
72570
73673
|
`);
|
|
72571
73674
|
} catch (auditError) {
|
|
72572
73675
|
console.warn(`writeCouncilEvidence: failed to append round-history audit log: ${auditError instanceof Error ? auditError.message : String(auditError)}`);
|
|
@@ -72696,20 +73799,20 @@ function buildUnifiedFeedback(taskId, verdict, vetoedBy, requiredFixes, advisory
|
|
|
72696
73799
|
|
|
72697
73800
|
// src/council/criteria-store.ts
|
|
72698
73801
|
import { existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync38, writeFileSync as writeFileSync12 } from "fs";
|
|
72699
|
-
import { join as
|
|
73802
|
+
import { join as join66 } from "path";
|
|
72700
73803
|
var COUNCIL_DIR = ".swarm/council";
|
|
72701
73804
|
function writeCriteria(workingDir, taskId, criteria) {
|
|
72702
|
-
const dir =
|
|
73805
|
+
const dir = join66(workingDir, COUNCIL_DIR);
|
|
72703
73806
|
mkdirSync19(dir, { recursive: true });
|
|
72704
73807
|
const payload = {
|
|
72705
73808
|
taskId,
|
|
72706
73809
|
criteria,
|
|
72707
73810
|
declaredAt: new Date().toISOString()
|
|
72708
73811
|
};
|
|
72709
|
-
writeFileSync12(
|
|
73812
|
+
writeFileSync12(join66(dir, `${safeId(taskId)}.json`), JSON.stringify(payload, null, 2));
|
|
72710
73813
|
}
|
|
72711
73814
|
function readCriteria(workingDir, taskId) {
|
|
72712
|
-
const filePath =
|
|
73815
|
+
const filePath = join66(workingDir, COUNCIL_DIR, `${safeId(taskId)}.json`);
|
|
72713
73816
|
if (!existsSync38(filePath))
|
|
72714
73817
|
return null;
|
|
72715
73818
|
try {
|
|
@@ -73046,8 +74149,8 @@ init_scope_persistence();
|
|
|
73046
74149
|
init_state();
|
|
73047
74150
|
init_task_id();
|
|
73048
74151
|
init_create_tool();
|
|
73049
|
-
import * as
|
|
73050
|
-
import * as
|
|
74152
|
+
import * as fs59 from "fs";
|
|
74153
|
+
import * as path73 from "path";
|
|
73051
74154
|
function validateTaskIdFormat2(taskId) {
|
|
73052
74155
|
return validateTaskIdFormat(taskId);
|
|
73053
74156
|
}
|
|
@@ -73121,8 +74224,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73121
74224
|
};
|
|
73122
74225
|
}
|
|
73123
74226
|
}
|
|
73124
|
-
normalizedDir =
|
|
73125
|
-
const pathParts = normalizedDir.split(
|
|
74227
|
+
normalizedDir = path73.normalize(args2.working_directory);
|
|
74228
|
+
const pathParts = normalizedDir.split(path73.sep);
|
|
73126
74229
|
if (pathParts.includes("..")) {
|
|
73127
74230
|
return {
|
|
73128
74231
|
success: false,
|
|
@@ -73132,11 +74235,11 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73132
74235
|
]
|
|
73133
74236
|
};
|
|
73134
74237
|
}
|
|
73135
|
-
const resolvedDir =
|
|
74238
|
+
const resolvedDir = path73.resolve(normalizedDir);
|
|
73136
74239
|
try {
|
|
73137
|
-
const realPath =
|
|
73138
|
-
const planPath2 =
|
|
73139
|
-
if (!
|
|
74240
|
+
const realPath = fs59.realpathSync(resolvedDir);
|
|
74241
|
+
const planPath2 = path73.join(realPath, ".swarm", "plan.json");
|
|
74242
|
+
if (!fs59.existsSync(planPath2)) {
|
|
73140
74243
|
return {
|
|
73141
74244
|
success: false,
|
|
73142
74245
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -73159,8 +74262,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73159
74262
|
console.warn("[declare-scope] fallbackDir is undefined, falling back to process.cwd()");
|
|
73160
74263
|
}
|
|
73161
74264
|
const directory = normalizedDir || fallbackDir;
|
|
73162
|
-
const planPath =
|
|
73163
|
-
if (!
|
|
74265
|
+
const planPath = path73.resolve(directory, ".swarm", "plan.json");
|
|
74266
|
+
if (!fs59.existsSync(planPath)) {
|
|
73164
74267
|
return {
|
|
73165
74268
|
success: false,
|
|
73166
74269
|
message: "No plan found",
|
|
@@ -73169,7 +74272,7 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73169
74272
|
}
|
|
73170
74273
|
let planContent;
|
|
73171
74274
|
try {
|
|
73172
|
-
planContent = JSON.parse(
|
|
74275
|
+
planContent = JSON.parse(fs59.readFileSync(planPath, "utf-8"));
|
|
73173
74276
|
} catch {
|
|
73174
74277
|
return {
|
|
73175
74278
|
success: false,
|
|
@@ -73199,8 +74302,8 @@ async function executeDeclareScope(args2, fallbackDir) {
|
|
|
73199
74302
|
const normalizeErrors = [];
|
|
73200
74303
|
const dir = normalizedDir || fallbackDir || process.cwd();
|
|
73201
74304
|
const mergedFiles = rawMergedFiles.map((file3) => {
|
|
73202
|
-
if (
|
|
73203
|
-
const relativePath =
|
|
74305
|
+
if (path73.isAbsolute(file3)) {
|
|
74306
|
+
const relativePath = path73.relative(dir, file3).replace(/\\/g, "/");
|
|
73204
74307
|
if (relativePath.startsWith("..")) {
|
|
73205
74308
|
normalizeErrors.push(`Path '${file3}' resolves outside the project directory`);
|
|
73206
74309
|
return file3;
|
|
@@ -73260,8 +74363,8 @@ var declare_scope = createSwarmTool({
|
|
|
73260
74363
|
// src/tools/diff.ts
|
|
73261
74364
|
init_dist();
|
|
73262
74365
|
import * as child_process7 from "child_process";
|
|
73263
|
-
import * as
|
|
73264
|
-
import * as
|
|
74366
|
+
import * as fs60 from "fs";
|
|
74367
|
+
import * as path74 from "path";
|
|
73265
74368
|
init_create_tool();
|
|
73266
74369
|
var MAX_DIFF_LINES = 500;
|
|
73267
74370
|
var DIFF_TIMEOUT_MS = 30000;
|
|
@@ -73290,20 +74393,20 @@ function validateBase(base) {
|
|
|
73290
74393
|
function validatePaths(paths) {
|
|
73291
74394
|
if (!paths)
|
|
73292
74395
|
return null;
|
|
73293
|
-
for (const
|
|
73294
|
-
if (!
|
|
74396
|
+
for (const path75 of paths) {
|
|
74397
|
+
if (!path75 || path75.length === 0) {
|
|
73295
74398
|
return "empty path not allowed";
|
|
73296
74399
|
}
|
|
73297
|
-
if (
|
|
74400
|
+
if (path75.length > MAX_PATH_LENGTH) {
|
|
73298
74401
|
return `path exceeds maximum length of ${MAX_PATH_LENGTH}`;
|
|
73299
74402
|
}
|
|
73300
|
-
if (SHELL_METACHARACTERS2.test(
|
|
74403
|
+
if (SHELL_METACHARACTERS2.test(path75)) {
|
|
73301
74404
|
return "path contains shell metacharacters";
|
|
73302
74405
|
}
|
|
73303
|
-
if (
|
|
74406
|
+
if (path75.startsWith("-")) {
|
|
73304
74407
|
return 'path cannot start with "-" (option-like arguments not allowed)';
|
|
73305
74408
|
}
|
|
73306
|
-
if (CONTROL_CHAR_PATTERN2.test(
|
|
74409
|
+
if (CONTROL_CHAR_PATTERN2.test(path75)) {
|
|
73307
74410
|
return "path contains control characters";
|
|
73308
74411
|
}
|
|
73309
74412
|
}
|
|
@@ -73409,8 +74512,8 @@ var diff = createSwarmTool({
|
|
|
73409
74512
|
if (parts2.length >= 3) {
|
|
73410
74513
|
const additions = parseInt(parts2[0], 10) || 0;
|
|
73411
74514
|
const deletions = parseInt(parts2[1], 10) || 0;
|
|
73412
|
-
const
|
|
73413
|
-
files.push({ path:
|
|
74515
|
+
const path75 = parts2[2];
|
|
74516
|
+
files.push({ path: path75, additions, deletions });
|
|
73414
74517
|
}
|
|
73415
74518
|
}
|
|
73416
74519
|
const contractChanges = [];
|
|
@@ -73450,7 +74553,7 @@ var diff = createSwarmTool({
|
|
|
73450
74553
|
} else if (base === "unstaged") {
|
|
73451
74554
|
const oldRef = `:${file3.path}`;
|
|
73452
74555
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
73453
|
-
newContent =
|
|
74556
|
+
newContent = fs60.readFileSync(path74.join(directory, file3.path), "utf-8");
|
|
73454
74557
|
} else {
|
|
73455
74558
|
const oldRef = `${base}:${file3.path}`;
|
|
73456
74559
|
oldContent = fileExistsInRef(oldRef) ? getContentFromRef(oldRef) : "";
|
|
@@ -73524,8 +74627,8 @@ var diff = createSwarmTool({
|
|
|
73524
74627
|
// src/tools/diff-summary.ts
|
|
73525
74628
|
init_dist();
|
|
73526
74629
|
import * as child_process8 from "child_process";
|
|
73527
|
-
import * as
|
|
73528
|
-
import * as
|
|
74630
|
+
import * as fs61 from "fs";
|
|
74631
|
+
import * as path75 from "path";
|
|
73529
74632
|
init_create_tool();
|
|
73530
74633
|
var diff_summary = createSwarmTool({
|
|
73531
74634
|
description: "Generate a filtered semantic diff summary from AST analysis. Returns SemanticDiffSummary with optional filtering by classification or riskLevel.",
|
|
@@ -73573,7 +74676,7 @@ var diff_summary = createSwarmTool({
|
|
|
73573
74676
|
}
|
|
73574
74677
|
try {
|
|
73575
74678
|
let oldContent;
|
|
73576
|
-
const newContent =
|
|
74679
|
+
const newContent = fs61.readFileSync(path75.join(workingDir, filePath), "utf-8");
|
|
73577
74680
|
if (fileExistsInHead) {
|
|
73578
74681
|
oldContent = child_process8.execFileSync("git", ["show", `HEAD:${filePath}`], {
|
|
73579
74682
|
encoding: "utf-8",
|
|
@@ -73800,8 +74903,8 @@ Use these as DOMAIN values when delegating to @sme.`;
|
|
|
73800
74903
|
init_dist();
|
|
73801
74904
|
init_create_tool();
|
|
73802
74905
|
init_path_security();
|
|
73803
|
-
import * as
|
|
73804
|
-
import * as
|
|
74906
|
+
import * as fs62 from "fs";
|
|
74907
|
+
import * as path76 from "path";
|
|
73805
74908
|
var MAX_FILE_SIZE_BYTES6 = 1024 * 1024;
|
|
73806
74909
|
var MAX_EVIDENCE_FILES = 1000;
|
|
73807
74910
|
var EVIDENCE_DIR3 = ".swarm/evidence";
|
|
@@ -73828,9 +74931,9 @@ function validateRequiredTypes(input) {
|
|
|
73828
74931
|
return null;
|
|
73829
74932
|
}
|
|
73830
74933
|
function isPathWithinSwarm2(filePath, cwd) {
|
|
73831
|
-
const normalizedCwd =
|
|
73832
|
-
const swarmPath =
|
|
73833
|
-
const normalizedPath =
|
|
74934
|
+
const normalizedCwd = path76.resolve(cwd);
|
|
74935
|
+
const swarmPath = path76.join(normalizedCwd, ".swarm");
|
|
74936
|
+
const normalizedPath = path76.resolve(filePath);
|
|
73834
74937
|
return normalizedPath.startsWith(swarmPath);
|
|
73835
74938
|
}
|
|
73836
74939
|
function parseCompletedTasks(planContent) {
|
|
@@ -73846,12 +74949,12 @@ function parseCompletedTasks(planContent) {
|
|
|
73846
74949
|
}
|
|
73847
74950
|
function readEvidenceFiles(evidenceDir, _cwd) {
|
|
73848
74951
|
const evidence = [];
|
|
73849
|
-
if (!
|
|
74952
|
+
if (!fs62.existsSync(evidenceDir) || !fs62.statSync(evidenceDir).isDirectory()) {
|
|
73850
74953
|
return evidence;
|
|
73851
74954
|
}
|
|
73852
74955
|
let files;
|
|
73853
74956
|
try {
|
|
73854
|
-
files =
|
|
74957
|
+
files = fs62.readdirSync(evidenceDir);
|
|
73855
74958
|
} catch {
|
|
73856
74959
|
return evidence;
|
|
73857
74960
|
}
|
|
@@ -73860,15 +74963,15 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
73860
74963
|
if (!VALID_EVIDENCE_FILENAME_REGEX.test(filename)) {
|
|
73861
74964
|
continue;
|
|
73862
74965
|
}
|
|
73863
|
-
const filePath =
|
|
74966
|
+
const filePath = path76.join(evidenceDir, filename);
|
|
73864
74967
|
try {
|
|
73865
|
-
const resolvedPath =
|
|
73866
|
-
const evidenceDirResolved =
|
|
74968
|
+
const resolvedPath = path76.resolve(filePath);
|
|
74969
|
+
const evidenceDirResolved = path76.resolve(evidenceDir);
|
|
73867
74970
|
if (!resolvedPath.startsWith(evidenceDirResolved)) {
|
|
73868
74971
|
continue;
|
|
73869
74972
|
}
|
|
73870
|
-
const
|
|
73871
|
-
if (!
|
|
74973
|
+
const stat4 = fs62.lstatSync(filePath);
|
|
74974
|
+
if (!stat4.isFile()) {
|
|
73872
74975
|
continue;
|
|
73873
74976
|
}
|
|
73874
74977
|
} catch {
|
|
@@ -73876,7 +74979,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
73876
74979
|
}
|
|
73877
74980
|
let fileStat;
|
|
73878
74981
|
try {
|
|
73879
|
-
fileStat =
|
|
74982
|
+
fileStat = fs62.statSync(filePath);
|
|
73880
74983
|
if (fileStat.size > MAX_FILE_SIZE_BYTES6) {
|
|
73881
74984
|
continue;
|
|
73882
74985
|
}
|
|
@@ -73885,7 +74988,7 @@ function readEvidenceFiles(evidenceDir, _cwd) {
|
|
|
73885
74988
|
}
|
|
73886
74989
|
let content;
|
|
73887
74990
|
try {
|
|
73888
|
-
content =
|
|
74991
|
+
content = fs62.readFileSync(filePath, "utf-8");
|
|
73889
74992
|
} catch {
|
|
73890
74993
|
continue;
|
|
73891
74994
|
}
|
|
@@ -73981,7 +75084,7 @@ var evidence_check = createSwarmTool({
|
|
|
73981
75084
|
return JSON.stringify(errorResult, null, 2);
|
|
73982
75085
|
}
|
|
73983
75086
|
const requiredTypes = requiredTypesValue.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map(normalizeEvidenceType);
|
|
73984
|
-
const planPath =
|
|
75087
|
+
const planPath = path76.join(cwd, PLAN_FILE);
|
|
73985
75088
|
if (!isPathWithinSwarm2(planPath, cwd)) {
|
|
73986
75089
|
const errorResult = {
|
|
73987
75090
|
error: "plan file path validation failed",
|
|
@@ -73995,7 +75098,7 @@ var evidence_check = createSwarmTool({
|
|
|
73995
75098
|
}
|
|
73996
75099
|
let planContent;
|
|
73997
75100
|
try {
|
|
73998
|
-
planContent =
|
|
75101
|
+
planContent = fs62.readFileSync(planPath, "utf-8");
|
|
73999
75102
|
} catch {
|
|
74000
75103
|
const result2 = {
|
|
74001
75104
|
message: "No completed tasks found in plan.",
|
|
@@ -74013,7 +75116,7 @@ var evidence_check = createSwarmTool({
|
|
|
74013
75116
|
};
|
|
74014
75117
|
return JSON.stringify(result2, null, 2);
|
|
74015
75118
|
}
|
|
74016
|
-
const evidenceDir =
|
|
75119
|
+
const evidenceDir = path76.join(cwd, EVIDENCE_DIR3);
|
|
74017
75120
|
const evidence = readEvidenceFiles(evidenceDir, cwd);
|
|
74018
75121
|
const { tasksWithFullEvidence, gaps } = analyzeGaps(completedTasks, evidence, requiredTypes);
|
|
74019
75122
|
const completeness = completedTasks.length > 0 ? Math.round(tasksWithFullEvidence.length / completedTasks.length * 100) / 100 : 1;
|
|
@@ -74030,8 +75133,8 @@ var evidence_check = createSwarmTool({
|
|
|
74030
75133
|
// src/tools/file-extractor.ts
|
|
74031
75134
|
init_tool();
|
|
74032
75135
|
init_create_tool();
|
|
74033
|
-
import * as
|
|
74034
|
-
import * as
|
|
75136
|
+
import * as fs63 from "fs";
|
|
75137
|
+
import * as path77 from "path";
|
|
74035
75138
|
var EXT_MAP = {
|
|
74036
75139
|
python: ".py",
|
|
74037
75140
|
py: ".py",
|
|
@@ -74093,8 +75196,8 @@ var extract_code_blocks = createSwarmTool({
|
|
|
74093
75196
|
execute: async (args2, directory) => {
|
|
74094
75197
|
const { content, output_dir, prefix } = args2;
|
|
74095
75198
|
const targetDir = output_dir || directory;
|
|
74096
|
-
if (!
|
|
74097
|
-
|
|
75199
|
+
if (!fs63.existsSync(targetDir)) {
|
|
75200
|
+
fs63.mkdirSync(targetDir, { recursive: true });
|
|
74098
75201
|
}
|
|
74099
75202
|
if (!content) {
|
|
74100
75203
|
return "Error: content is required";
|
|
@@ -74112,16 +75215,16 @@ var extract_code_blocks = createSwarmTool({
|
|
|
74112
75215
|
if (prefix) {
|
|
74113
75216
|
filename = `${prefix}_${filename}`;
|
|
74114
75217
|
}
|
|
74115
|
-
let filepath =
|
|
74116
|
-
const base =
|
|
74117
|
-
const ext =
|
|
75218
|
+
let filepath = path77.join(targetDir, filename);
|
|
75219
|
+
const base = path77.basename(filepath, path77.extname(filepath));
|
|
75220
|
+
const ext = path77.extname(filepath);
|
|
74118
75221
|
let counter = 1;
|
|
74119
|
-
while (
|
|
74120
|
-
filepath =
|
|
75222
|
+
while (fs63.existsSync(filepath)) {
|
|
75223
|
+
filepath = path77.join(targetDir, `${base}_${counter}${ext}`);
|
|
74121
75224
|
counter++;
|
|
74122
75225
|
}
|
|
74123
75226
|
try {
|
|
74124
|
-
|
|
75227
|
+
fs63.writeFileSync(filepath, code.trim(), "utf-8");
|
|
74125
75228
|
savedFiles.push(filepath);
|
|
74126
75229
|
} catch (error93) {
|
|
74127
75230
|
errors5.push(`Failed to save ${filename}: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
@@ -74380,8 +75483,8 @@ var gitingest = createSwarmTool({
|
|
|
74380
75483
|
init_dist();
|
|
74381
75484
|
init_create_tool();
|
|
74382
75485
|
init_path_security();
|
|
74383
|
-
import * as
|
|
74384
|
-
import * as
|
|
75486
|
+
import * as fs64 from "fs";
|
|
75487
|
+
import * as path78 from "path";
|
|
74385
75488
|
var MAX_FILE_PATH_LENGTH2 = 500;
|
|
74386
75489
|
var MAX_SYMBOL_LENGTH = 256;
|
|
74387
75490
|
var MAX_FILE_SIZE_BYTES7 = 1024 * 1024;
|
|
@@ -74429,7 +75532,7 @@ function validateSymbolInput(symbol3) {
|
|
|
74429
75532
|
return null;
|
|
74430
75533
|
}
|
|
74431
75534
|
function isBinaryFile2(filePath, buffer) {
|
|
74432
|
-
const ext =
|
|
75535
|
+
const ext = path78.extname(filePath).toLowerCase();
|
|
74433
75536
|
if (ext === ".json" || ext === ".md" || ext === ".txt") {
|
|
74434
75537
|
return false;
|
|
74435
75538
|
}
|
|
@@ -74453,15 +75556,15 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
74453
75556
|
const imports = [];
|
|
74454
75557
|
let _resolvedTarget;
|
|
74455
75558
|
try {
|
|
74456
|
-
_resolvedTarget =
|
|
75559
|
+
_resolvedTarget = path78.resolve(targetFile);
|
|
74457
75560
|
} catch {
|
|
74458
75561
|
_resolvedTarget = targetFile;
|
|
74459
75562
|
}
|
|
74460
|
-
const targetBasename =
|
|
75563
|
+
const targetBasename = path78.basename(targetFile, path78.extname(targetFile));
|
|
74461
75564
|
const targetWithExt = targetFile;
|
|
74462
75565
|
const targetWithoutExt = targetFile.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
74463
|
-
const normalizedTargetWithExt =
|
|
74464
|
-
const normalizedTargetWithoutExt =
|
|
75566
|
+
const normalizedTargetWithExt = path78.normalize(targetWithExt).replace(/\\/g, "/");
|
|
75567
|
+
const normalizedTargetWithoutExt = path78.normalize(targetWithoutExt).replace(/\\/g, "/");
|
|
74465
75568
|
const importRegex = /import\s+(?:\{[\s\S]*?\}|(?:\*\s+as\s+\w+)|\w+)\s+from\s+['"`]([^'"`]+)['"`]|import\s+['"`]([^'"`]+)['"`]|require\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g;
|
|
74466
75569
|
for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
|
|
74467
75570
|
const modulePath = match[1] || match[2] || match[3];
|
|
@@ -74484,9 +75587,9 @@ function parseImports(content, targetFile, targetSymbol) {
|
|
|
74484
75587
|
}
|
|
74485
75588
|
const _normalizedModule = modulePath.replace(/^\.\//, "").replace(/^\.\.\\/, "../");
|
|
74486
75589
|
let isMatch = false;
|
|
74487
|
-
const _targetDir =
|
|
74488
|
-
const targetExt =
|
|
74489
|
-
const targetBasenameNoExt =
|
|
75590
|
+
const _targetDir = path78.dirname(targetFile);
|
|
75591
|
+
const targetExt = path78.extname(targetFile);
|
|
75592
|
+
const targetBasenameNoExt = path78.basename(targetFile, targetExt);
|
|
74490
75593
|
const moduleNormalized = modulePath.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
74491
75594
|
const moduleName = modulePath.split(/[/\\]/).pop() || "";
|
|
74492
75595
|
const moduleNameNoExt = moduleName.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/i, "");
|
|
@@ -74543,7 +75646,7 @@ var SKIP_DIRECTORIES4 = new Set([
|
|
|
74543
75646
|
function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFiles: 0, fileErrors: [] }) {
|
|
74544
75647
|
let entries;
|
|
74545
75648
|
try {
|
|
74546
|
-
entries =
|
|
75649
|
+
entries = fs64.readdirSync(dir);
|
|
74547
75650
|
} catch (e) {
|
|
74548
75651
|
stats.fileErrors.push({
|
|
74549
75652
|
path: dir,
|
|
@@ -74554,13 +75657,13 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
74554
75657
|
entries.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()));
|
|
74555
75658
|
for (const entry of entries) {
|
|
74556
75659
|
if (SKIP_DIRECTORIES4.has(entry)) {
|
|
74557
|
-
stats.skippedDirs.push(
|
|
75660
|
+
stats.skippedDirs.push(path78.join(dir, entry));
|
|
74558
75661
|
continue;
|
|
74559
75662
|
}
|
|
74560
|
-
const fullPath =
|
|
74561
|
-
let
|
|
75663
|
+
const fullPath = path78.join(dir, entry);
|
|
75664
|
+
let stat4;
|
|
74562
75665
|
try {
|
|
74563
|
-
|
|
75666
|
+
stat4 = fs64.statSync(fullPath);
|
|
74564
75667
|
} catch (e) {
|
|
74565
75668
|
stats.fileErrors.push({
|
|
74566
75669
|
path: fullPath,
|
|
@@ -74568,10 +75671,10 @@ function findSourceFiles3(dir, files = [], stats = { skippedDirs: [], skippedFil
|
|
|
74568
75671
|
});
|
|
74569
75672
|
continue;
|
|
74570
75673
|
}
|
|
74571
|
-
if (
|
|
75674
|
+
if (stat4.isDirectory()) {
|
|
74572
75675
|
findSourceFiles3(fullPath, files, stats);
|
|
74573
|
-
} else if (
|
|
74574
|
-
const ext =
|
|
75676
|
+
} else if (stat4.isFile()) {
|
|
75677
|
+
const ext = path78.extname(fullPath).toLowerCase();
|
|
74575
75678
|
if (SUPPORTED_EXTENSIONS3.includes(ext)) {
|
|
74576
75679
|
files.push(fullPath);
|
|
74577
75680
|
}
|
|
@@ -74628,8 +75731,8 @@ var imports = createSwarmTool({
|
|
|
74628
75731
|
return JSON.stringify(errorResult, null, 2);
|
|
74629
75732
|
}
|
|
74630
75733
|
try {
|
|
74631
|
-
const targetFile =
|
|
74632
|
-
if (!
|
|
75734
|
+
const targetFile = path78.resolve(file3);
|
|
75735
|
+
if (!fs64.existsSync(targetFile)) {
|
|
74633
75736
|
const errorResult = {
|
|
74634
75737
|
error: `target file not found: ${file3}`,
|
|
74635
75738
|
target: file3,
|
|
@@ -74639,7 +75742,7 @@ var imports = createSwarmTool({
|
|
|
74639
75742
|
};
|
|
74640
75743
|
return JSON.stringify(errorResult, null, 2);
|
|
74641
75744
|
}
|
|
74642
|
-
const targetStat =
|
|
75745
|
+
const targetStat = fs64.statSync(targetFile);
|
|
74643
75746
|
if (!targetStat.isFile()) {
|
|
74644
75747
|
const errorResult = {
|
|
74645
75748
|
error: "target must be a file, not a directory",
|
|
@@ -74650,7 +75753,7 @@ var imports = createSwarmTool({
|
|
|
74650
75753
|
};
|
|
74651
75754
|
return JSON.stringify(errorResult, null, 2);
|
|
74652
75755
|
}
|
|
74653
|
-
const baseDir =
|
|
75756
|
+
const baseDir = path78.dirname(targetFile);
|
|
74654
75757
|
const scanStats = {
|
|
74655
75758
|
skippedDirs: [],
|
|
74656
75759
|
skippedFiles: 0,
|
|
@@ -74665,12 +75768,12 @@ var imports = createSwarmTool({
|
|
|
74665
75768
|
if (consumers.length >= MAX_CONSUMERS)
|
|
74666
75769
|
break;
|
|
74667
75770
|
try {
|
|
74668
|
-
const
|
|
74669
|
-
if (
|
|
75771
|
+
const stat4 = fs64.statSync(filePath);
|
|
75772
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES7) {
|
|
74670
75773
|
skippedFileCount++;
|
|
74671
75774
|
continue;
|
|
74672
75775
|
}
|
|
74673
|
-
const buffer =
|
|
75776
|
+
const buffer = fs64.readFileSync(filePath);
|
|
74674
75777
|
if (isBinaryFile2(filePath, buffer)) {
|
|
74675
75778
|
skippedFileCount++;
|
|
74676
75779
|
continue;
|
|
@@ -75182,8 +76285,8 @@ init_schema();
|
|
|
75182
76285
|
init_qa_gate_profile();
|
|
75183
76286
|
init_manager2();
|
|
75184
76287
|
init_curator();
|
|
75185
|
-
import * as
|
|
75186
|
-
import * as
|
|
76288
|
+
import * as fs65 from "fs";
|
|
76289
|
+
import * as path79 from "path";
|
|
75187
76290
|
init_knowledge_curator();
|
|
75188
76291
|
init_knowledge_reader();
|
|
75189
76292
|
init_knowledge_store();
|
|
@@ -75414,11 +76517,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75414
76517
|
safeWarn(`[phase_complete] Completion verify error (non-blocking):`, completionError);
|
|
75415
76518
|
}
|
|
75416
76519
|
try {
|
|
75417
|
-
const driftEvidencePath =
|
|
76520
|
+
const driftEvidencePath = path79.join(dir, ".swarm", "evidence", String(phase), "drift-verifier.json");
|
|
75418
76521
|
let driftVerdictFound = false;
|
|
75419
76522
|
let driftVerdictApproved = false;
|
|
75420
76523
|
try {
|
|
75421
|
-
const driftEvidenceContent =
|
|
76524
|
+
const driftEvidenceContent = fs65.readFileSync(driftEvidencePath, "utf-8");
|
|
75422
76525
|
const driftEvidence = JSON.parse(driftEvidenceContent);
|
|
75423
76526
|
const entries = driftEvidence.entries ?? [];
|
|
75424
76527
|
for (const entry of entries) {
|
|
@@ -75448,14 +76551,14 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75448
76551
|
driftVerdictFound = false;
|
|
75449
76552
|
}
|
|
75450
76553
|
if (!driftVerdictFound) {
|
|
75451
|
-
const specPath =
|
|
75452
|
-
const specExists =
|
|
76554
|
+
const specPath = path79.join(dir, ".swarm", "spec.md");
|
|
76555
|
+
const specExists = fs65.existsSync(specPath);
|
|
75453
76556
|
if (!specExists) {
|
|
75454
76557
|
let incompleteTaskCount = 0;
|
|
75455
76558
|
let planPhaseFound = false;
|
|
75456
76559
|
try {
|
|
75457
76560
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75458
|
-
const planRaw =
|
|
76561
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75459
76562
|
const plan = JSON.parse(planRaw);
|
|
75460
76563
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
75461
76564
|
if (targetPhase) {
|
|
@@ -75506,11 +76609,11 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75506
76609
|
const overrides = session2?.qaGateSessionOverrides ?? {};
|
|
75507
76610
|
const effective = getEffectiveGates(profile, overrides);
|
|
75508
76611
|
if (effective.hallucination_guard === true) {
|
|
75509
|
-
const hgPath =
|
|
76612
|
+
const hgPath = path79.join(dir, ".swarm", "evidence", String(phase), "hallucination-guard.json");
|
|
75510
76613
|
let hgVerdictFound = false;
|
|
75511
76614
|
let hgVerdictApproved = false;
|
|
75512
76615
|
try {
|
|
75513
|
-
const hgContent =
|
|
76616
|
+
const hgContent = fs65.readFileSync(hgPath, "utf-8");
|
|
75514
76617
|
const hgBundle = JSON.parse(hgContent);
|
|
75515
76618
|
for (const entry of hgBundle.entries ?? []) {
|
|
75516
76619
|
if (typeof entry.type === "string" && entry.type.includes("hallucination") && typeof entry.verdict === "string") {
|
|
@@ -75578,7 +76681,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75578
76681
|
}
|
|
75579
76682
|
if (retroFound && retroEntry?.lessons_learned && retroEntry.lessons_learned.length > 0) {
|
|
75580
76683
|
try {
|
|
75581
|
-
const projectName =
|
|
76684
|
+
const projectName = path79.basename(dir);
|
|
75582
76685
|
const curationResult = await curateAndStoreSwarm(retroEntry.lessons_learned, projectName, { phase_number: phase }, dir, knowledgeConfig);
|
|
75583
76686
|
if (curationResult) {
|
|
75584
76687
|
const sessionState = swarmState.agentSessions.get(sessionID);
|
|
@@ -75658,7 +76761,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75658
76761
|
let phaseRequiredAgents;
|
|
75659
76762
|
try {
|
|
75660
76763
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75661
|
-
const planRaw =
|
|
76764
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75662
76765
|
const plan = JSON.parse(planRaw);
|
|
75663
76766
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
75664
76767
|
phaseRequiredAgents = phaseObj?.required_agents;
|
|
@@ -75673,7 +76776,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75673
76776
|
if (agentsMissing.length > 0) {
|
|
75674
76777
|
try {
|
|
75675
76778
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75676
|
-
const planRaw =
|
|
76779
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75677
76780
|
const plan = JSON.parse(planRaw);
|
|
75678
76781
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
75679
76782
|
if (targetPhase && targetPhase.tasks.length > 0 && targetPhase.tasks.every((t) => t.status === "completed")) {
|
|
@@ -75713,7 +76816,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75713
76816
|
if (phaseCompleteConfig.regression_sweep?.enforce) {
|
|
75714
76817
|
try {
|
|
75715
76818
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75716
|
-
const planRaw =
|
|
76819
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75717
76820
|
const plan = JSON.parse(planRaw);
|
|
75718
76821
|
const targetPhase = plan.phases.find((p) => p.id === phase);
|
|
75719
76822
|
if (targetPhase) {
|
|
@@ -75767,7 +76870,7 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75767
76870
|
}
|
|
75768
76871
|
try {
|
|
75769
76872
|
const eventsPath = validateSwarmPath(dir, "events.jsonl");
|
|
75770
|
-
|
|
76873
|
+
fs65.appendFileSync(eventsPath, `${JSON.stringify(event)}
|
|
75771
76874
|
`, "utf-8");
|
|
75772
76875
|
} catch (writeError) {
|
|
75773
76876
|
warnings.push(`Warning: failed to write phase complete event: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
@@ -75842,12 +76945,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75842
76945
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
75843
76946
|
try {
|
|
75844
76947
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75845
|
-
const planRaw =
|
|
76948
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75846
76949
|
const plan2 = JSON.parse(planRaw);
|
|
75847
76950
|
const phaseObj = plan2.phases.find((p) => p.id === phase);
|
|
75848
76951
|
if (phaseObj) {
|
|
75849
76952
|
phaseObj.status = "complete";
|
|
75850
|
-
|
|
76953
|
+
fs65.writeFileSync(planPath, JSON.stringify(plan2, null, 2), "utf-8");
|
|
75851
76954
|
}
|
|
75852
76955
|
} catch {}
|
|
75853
76956
|
} else if (plan) {
|
|
@@ -75884,12 +76987,12 @@ async function executePhaseComplete(args2, workingDirectory, directory) {
|
|
|
75884
76987
|
warnings.push(`Warning: failed to update plan.json phase status`);
|
|
75885
76988
|
try {
|
|
75886
76989
|
const planPath = validateSwarmPath(dir, "plan.json");
|
|
75887
|
-
const planRaw =
|
|
76990
|
+
const planRaw = fs65.readFileSync(planPath, "utf-8");
|
|
75888
76991
|
const plan = JSON.parse(planRaw);
|
|
75889
76992
|
const phaseObj = plan.phases.find((p) => p.id === phase);
|
|
75890
76993
|
if (phaseObj) {
|
|
75891
76994
|
phaseObj.status = "complete";
|
|
75892
|
-
|
|
76995
|
+
fs65.writeFileSync(planPath, JSON.stringify(plan, null, 2), "utf-8");
|
|
75893
76996
|
}
|
|
75894
76997
|
} catch {}
|
|
75895
76998
|
}
|
|
@@ -75946,8 +77049,8 @@ init_dist();
|
|
|
75946
77049
|
init_discovery();
|
|
75947
77050
|
init_utils();
|
|
75948
77051
|
init_create_tool();
|
|
75949
|
-
import * as
|
|
75950
|
-
import * as
|
|
77052
|
+
import * as fs66 from "fs";
|
|
77053
|
+
import * as path80 from "path";
|
|
75951
77054
|
var MAX_OUTPUT_BYTES5 = 52428800;
|
|
75952
77055
|
var AUDIT_TIMEOUT_MS = 120000;
|
|
75953
77056
|
function isValidEcosystem(value) {
|
|
@@ -75975,31 +77078,31 @@ function validateArgs3(args2) {
|
|
|
75975
77078
|
function detectEcosystems(directory) {
|
|
75976
77079
|
const ecosystems = [];
|
|
75977
77080
|
const cwd = directory;
|
|
75978
|
-
if (
|
|
77081
|
+
if (fs66.existsSync(path80.join(cwd, "package.json"))) {
|
|
75979
77082
|
ecosystems.push("npm");
|
|
75980
77083
|
}
|
|
75981
|
-
if (
|
|
77084
|
+
if (fs66.existsSync(path80.join(cwd, "pyproject.toml")) || fs66.existsSync(path80.join(cwd, "requirements.txt"))) {
|
|
75982
77085
|
ecosystems.push("pip");
|
|
75983
77086
|
}
|
|
75984
|
-
if (
|
|
77087
|
+
if (fs66.existsSync(path80.join(cwd, "Cargo.toml"))) {
|
|
75985
77088
|
ecosystems.push("cargo");
|
|
75986
77089
|
}
|
|
75987
|
-
if (
|
|
77090
|
+
if (fs66.existsSync(path80.join(cwd, "go.mod"))) {
|
|
75988
77091
|
ecosystems.push("go");
|
|
75989
77092
|
}
|
|
75990
77093
|
try {
|
|
75991
|
-
const files =
|
|
77094
|
+
const files = fs66.readdirSync(cwd);
|
|
75992
77095
|
if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"))) {
|
|
75993
77096
|
ecosystems.push("dotnet");
|
|
75994
77097
|
}
|
|
75995
77098
|
} catch {}
|
|
75996
|
-
if (
|
|
77099
|
+
if (fs66.existsSync(path80.join(cwd, "Gemfile")) || fs66.existsSync(path80.join(cwd, "Gemfile.lock"))) {
|
|
75997
77100
|
ecosystems.push("ruby");
|
|
75998
77101
|
}
|
|
75999
|
-
if (
|
|
77102
|
+
if (fs66.existsSync(path80.join(cwd, "pubspec.yaml"))) {
|
|
76000
77103
|
ecosystems.push("dart");
|
|
76001
77104
|
}
|
|
76002
|
-
if (
|
|
77105
|
+
if (fs66.existsSync(path80.join(cwd, "composer.lock"))) {
|
|
76003
77106
|
ecosystems.push("composer");
|
|
76004
77107
|
}
|
|
76005
77108
|
return ecosystems;
|
|
@@ -77158,8 +78261,8 @@ var pkg_audit = createSwarmTool({
|
|
|
77158
78261
|
// src/tools/placeholder-scan.ts
|
|
77159
78262
|
init_dist();
|
|
77160
78263
|
init_manager2();
|
|
77161
|
-
import * as
|
|
77162
|
-
import * as
|
|
78264
|
+
import * as fs67 from "fs";
|
|
78265
|
+
import * as path81 from "path";
|
|
77163
78266
|
init_utils();
|
|
77164
78267
|
init_create_tool();
|
|
77165
78268
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -77282,7 +78385,7 @@ function isScaffoldFile(filePath) {
|
|
|
77282
78385
|
if (SCAFFOLD_PATH_PATTERNS.some((pattern) => pattern.test(normalizedPath))) {
|
|
77283
78386
|
return true;
|
|
77284
78387
|
}
|
|
77285
|
-
const filename =
|
|
78388
|
+
const filename = path81.basename(filePath);
|
|
77286
78389
|
if (SCAFFOLD_FILENAME_PATTERNS.some((pattern) => pattern.test(filename))) {
|
|
77287
78390
|
return true;
|
|
77288
78391
|
}
|
|
@@ -77299,7 +78402,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
77299
78402
|
if (regex.test(normalizedPath)) {
|
|
77300
78403
|
return true;
|
|
77301
78404
|
}
|
|
77302
|
-
const filename =
|
|
78405
|
+
const filename = path81.basename(filePath);
|
|
77303
78406
|
const filenameRegex = new RegExp(`^${regexPattern}$`, "i");
|
|
77304
78407
|
if (filenameRegex.test(filename)) {
|
|
77305
78408
|
return true;
|
|
@@ -77308,7 +78411,7 @@ function isAllowedByGlobs(filePath, allowGlobs) {
|
|
|
77308
78411
|
return false;
|
|
77309
78412
|
}
|
|
77310
78413
|
function isParserSupported(filePath) {
|
|
77311
|
-
const ext =
|
|
78414
|
+
const ext = path81.extname(filePath).toLowerCase();
|
|
77312
78415
|
return SUPPORTED_PARSER_EXTENSIONS.has(ext);
|
|
77313
78416
|
}
|
|
77314
78417
|
function isPlanFile(filePath) {
|
|
@@ -77555,28 +78658,28 @@ async function placeholderScan(input, directory) {
|
|
|
77555
78658
|
let filesScanned = 0;
|
|
77556
78659
|
const filesWithFindings = new Set;
|
|
77557
78660
|
for (const filePath of changed_files) {
|
|
77558
|
-
const fullPath =
|
|
77559
|
-
const resolvedDirectory =
|
|
77560
|
-
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) {
|
|
77561
78664
|
continue;
|
|
77562
78665
|
}
|
|
77563
|
-
if (!
|
|
78666
|
+
if (!fs67.existsSync(fullPath)) {
|
|
77564
78667
|
continue;
|
|
77565
78668
|
}
|
|
77566
78669
|
if (isAllowedByGlobs(filePath, allow_globs)) {
|
|
77567
78670
|
continue;
|
|
77568
78671
|
}
|
|
77569
|
-
const relativeFilePath =
|
|
78672
|
+
const relativeFilePath = path81.relative(directory, fullPath).replace(/\\/g, "/");
|
|
77570
78673
|
if (FILE_ALLOWLIST.some((allowed) => relativeFilePath.endsWith(allowed))) {
|
|
77571
78674
|
continue;
|
|
77572
78675
|
}
|
|
77573
78676
|
let content;
|
|
77574
78677
|
try {
|
|
77575
|
-
const
|
|
77576
|
-
if (
|
|
78678
|
+
const stat4 = fs67.statSync(fullPath);
|
|
78679
|
+
if (stat4.size > MAX_FILE_SIZE) {
|
|
77577
78680
|
continue;
|
|
77578
78681
|
}
|
|
77579
|
-
content =
|
|
78682
|
+
content = fs67.readFileSync(fullPath, "utf-8");
|
|
77580
78683
|
} catch {
|
|
77581
78684
|
continue;
|
|
77582
78685
|
}
|
|
@@ -77638,8 +78741,8 @@ var placeholder_scan = createSwarmTool({
|
|
|
77638
78741
|
});
|
|
77639
78742
|
// src/tools/pre-check-batch.ts
|
|
77640
78743
|
init_dist();
|
|
77641
|
-
import * as
|
|
77642
|
-
import * as
|
|
78744
|
+
import * as fs70 from "fs";
|
|
78745
|
+
import * as path84 from "path";
|
|
77643
78746
|
init_manager2();
|
|
77644
78747
|
init_utils();
|
|
77645
78748
|
init_create_tool();
|
|
@@ -77774,8 +78877,8 @@ var quality_budget = createSwarmTool({
|
|
|
77774
78877
|
init_dist();
|
|
77775
78878
|
init_manager2();
|
|
77776
78879
|
init_detector();
|
|
77777
|
-
import * as
|
|
77778
|
-
import * as
|
|
78880
|
+
import * as fs69 from "fs";
|
|
78881
|
+
import * as path83 from "path";
|
|
77779
78882
|
import { extname as extname18 } from "path";
|
|
77780
78883
|
|
|
77781
78884
|
// src/sast/rules/c.ts
|
|
@@ -78668,25 +79771,25 @@ init_create_tool();
|
|
|
78668
79771
|
// src/tools/sast-baseline.ts
|
|
78669
79772
|
init_utils2();
|
|
78670
79773
|
import * as crypto8 from "crypto";
|
|
78671
|
-
import * as
|
|
78672
|
-
import * as
|
|
79774
|
+
import * as fs68 from "fs";
|
|
79775
|
+
import * as path82 from "path";
|
|
78673
79776
|
var BASELINE_SCHEMA_VERSION = "1.0.0";
|
|
78674
79777
|
var MAX_BASELINE_FINDINGS = 2000;
|
|
78675
79778
|
var MAX_BASELINE_BYTES = 2 * 1048576;
|
|
78676
79779
|
var LOCK_RETRY_DELAYS_MS = [50, 100, 200, 400, 800];
|
|
78677
79780
|
function normalizeFindingPath(directory, file3) {
|
|
78678
|
-
const resolved =
|
|
78679
|
-
const rel =
|
|
79781
|
+
const resolved = path82.isAbsolute(file3) ? file3 : path82.resolve(directory, file3);
|
|
79782
|
+
const rel = path82.relative(path82.resolve(directory), resolved);
|
|
78680
79783
|
return rel.replace(/\\/g, "/");
|
|
78681
79784
|
}
|
|
78682
79785
|
function baselineRelPath(phase) {
|
|
78683
|
-
return
|
|
79786
|
+
return path82.join("evidence", String(phase), "sast-baseline.json");
|
|
78684
79787
|
}
|
|
78685
79788
|
function tempRelPath(phase) {
|
|
78686
|
-
return
|
|
79789
|
+
return path82.join("evidence", String(phase), `sast-baseline.json.tmp.${Date.now()}.${process.pid}`);
|
|
78687
79790
|
}
|
|
78688
79791
|
function lockRelPath(phase) {
|
|
78689
|
-
return
|
|
79792
|
+
return path82.join("evidence", String(phase), "sast-baseline.json.lock");
|
|
78690
79793
|
}
|
|
78691
79794
|
function getLine(lines, idx) {
|
|
78692
79795
|
if (idx < 0 || idx >= lines.length)
|
|
@@ -78703,7 +79806,7 @@ function fingerprintFinding(finding, directory, occurrenceIndex) {
|
|
|
78703
79806
|
}
|
|
78704
79807
|
const lineNum = finding.location.line;
|
|
78705
79808
|
try {
|
|
78706
|
-
const content =
|
|
79809
|
+
const content = fs68.readFileSync(finding.location.file, "utf-8");
|
|
78707
79810
|
const lines = content.split(`
|
|
78708
79811
|
`);
|
|
78709
79812
|
const idx = lineNum - 1;
|
|
@@ -78734,7 +79837,7 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
78734
79837
|
try {
|
|
78735
79838
|
if (relFile.startsWith(".."))
|
|
78736
79839
|
throw new Error("escapes workspace");
|
|
78737
|
-
const content =
|
|
79840
|
+
const content = fs68.readFileSync(finding.location.file, "utf-8");
|
|
78738
79841
|
const lines = content.split(`
|
|
78739
79842
|
`);
|
|
78740
79843
|
const idx = lineNum - 1;
|
|
@@ -78763,11 +79866,11 @@ function assignOccurrenceIndices(findings, directory) {
|
|
|
78763
79866
|
async function acquireLock(lockPath) {
|
|
78764
79867
|
for (let attempt = 0;attempt <= LOCK_RETRY_DELAYS_MS.length; attempt++) {
|
|
78765
79868
|
try {
|
|
78766
|
-
const fd =
|
|
78767
|
-
|
|
79869
|
+
const fd = fs68.openSync(lockPath, "wx");
|
|
79870
|
+
fs68.closeSync(fd);
|
|
78768
79871
|
return () => {
|
|
78769
79872
|
try {
|
|
78770
|
-
|
|
79873
|
+
fs68.unlinkSync(lockPath);
|
|
78771
79874
|
} catch {}
|
|
78772
79875
|
};
|
|
78773
79876
|
} catch {
|
|
@@ -78807,12 +79910,12 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
78807
79910
|
message: e instanceof Error ? e.message : "Path validation failed"
|
|
78808
79911
|
};
|
|
78809
79912
|
}
|
|
78810
|
-
|
|
79913
|
+
fs68.mkdirSync(path82.dirname(baselinePath), { recursive: true });
|
|
78811
79914
|
const releaseLock = await acquireLock(lockPath);
|
|
78812
79915
|
try {
|
|
78813
79916
|
let existing = null;
|
|
78814
79917
|
try {
|
|
78815
|
-
const raw =
|
|
79918
|
+
const raw = fs68.readFileSync(baselinePath, "utf-8");
|
|
78816
79919
|
const parsed = JSON.parse(raw);
|
|
78817
79920
|
if (parsed.schema_version === BASELINE_SCHEMA_VERSION) {
|
|
78818
79921
|
existing = parsed;
|
|
@@ -78872,8 +79975,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
78872
79975
|
message: `Baseline would exceed size cap (${json4.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
78873
79976
|
};
|
|
78874
79977
|
}
|
|
78875
|
-
|
|
78876
|
-
|
|
79978
|
+
fs68.writeFileSync(tempPath, json4, "utf-8");
|
|
79979
|
+
fs68.renameSync(tempPath, baselinePath);
|
|
78877
79980
|
return {
|
|
78878
79981
|
status: "merged",
|
|
78879
79982
|
path: baselinePath,
|
|
@@ -78904,8 +80007,8 @@ async function captureOrMergeBaseline(directory, phase, findings, engine, scanne
|
|
|
78904
80007
|
message: `Baseline would exceed size cap (${json3.length} bytes > ${MAX_BASELINE_BYTES})`
|
|
78905
80008
|
};
|
|
78906
80009
|
}
|
|
78907
|
-
|
|
78908
|
-
|
|
80010
|
+
fs68.writeFileSync(tempPath, json3, "utf-8");
|
|
80011
|
+
fs68.renameSync(tempPath, baselinePath);
|
|
78909
80012
|
return {
|
|
78910
80013
|
status: "written",
|
|
78911
80014
|
path: baselinePath,
|
|
@@ -78930,7 +80033,7 @@ function loadBaseline(directory, phase) {
|
|
|
78930
80033
|
};
|
|
78931
80034
|
}
|
|
78932
80035
|
try {
|
|
78933
|
-
const raw =
|
|
80036
|
+
const raw = fs68.readFileSync(baselinePath, "utf-8");
|
|
78934
80037
|
const parsed = JSON.parse(raw);
|
|
78935
80038
|
if (parsed.schema_version !== BASELINE_SCHEMA_VERSION) {
|
|
78936
80039
|
return {
|
|
@@ -78972,17 +80075,17 @@ var SEVERITY_ORDER = {
|
|
|
78972
80075
|
};
|
|
78973
80076
|
function shouldSkipFile(filePath) {
|
|
78974
80077
|
try {
|
|
78975
|
-
const stats =
|
|
80078
|
+
const stats = fs69.statSync(filePath);
|
|
78976
80079
|
if (stats.size > MAX_FILE_SIZE_BYTES8) {
|
|
78977
80080
|
return { skip: true, reason: "file too large" };
|
|
78978
80081
|
}
|
|
78979
80082
|
if (stats.size === 0) {
|
|
78980
80083
|
return { skip: true, reason: "empty file" };
|
|
78981
80084
|
}
|
|
78982
|
-
const fd =
|
|
80085
|
+
const fd = fs69.openSync(filePath, "r");
|
|
78983
80086
|
const buffer = Buffer.alloc(8192);
|
|
78984
|
-
const bytesRead =
|
|
78985
|
-
|
|
80087
|
+
const bytesRead = fs69.readSync(fd, buffer, 0, 8192, 0);
|
|
80088
|
+
fs69.closeSync(fd);
|
|
78986
80089
|
if (bytesRead > 0) {
|
|
78987
80090
|
let nullCount = 0;
|
|
78988
80091
|
for (let i2 = 0;i2 < bytesRead; i2++) {
|
|
@@ -79021,7 +80124,7 @@ function countBySeverity(findings) {
|
|
|
79021
80124
|
}
|
|
79022
80125
|
function scanFileWithTierA(filePath, language) {
|
|
79023
80126
|
try {
|
|
79024
|
-
const content =
|
|
80127
|
+
const content = fs69.readFileSync(filePath, "utf-8");
|
|
79025
80128
|
const findings = executeRulesSync(filePath, content, language);
|
|
79026
80129
|
return findings.map((f) => ({
|
|
79027
80130
|
rule_id: f.rule_id,
|
|
@@ -79074,13 +80177,13 @@ async function sastScan(input, directory, config3) {
|
|
|
79074
80177
|
_filesSkipped++;
|
|
79075
80178
|
continue;
|
|
79076
80179
|
}
|
|
79077
|
-
const resolvedPath =
|
|
79078
|
-
const resolvedDirectory =
|
|
79079
|
-
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) {
|
|
79080
80183
|
_filesSkipped++;
|
|
79081
80184
|
continue;
|
|
79082
80185
|
}
|
|
79083
|
-
if (!
|
|
80186
|
+
if (!fs69.existsSync(resolvedPath)) {
|
|
79084
80187
|
_filesSkipped++;
|
|
79085
80188
|
continue;
|
|
79086
80189
|
}
|
|
@@ -79387,18 +80490,18 @@ function validatePath(inputPath, baseDir, workspaceDir) {
|
|
|
79387
80490
|
let resolved;
|
|
79388
80491
|
const isWinAbs = isWindowsAbsolutePath(inputPath);
|
|
79389
80492
|
if (isWinAbs) {
|
|
79390
|
-
resolved =
|
|
79391
|
-
} else if (
|
|
79392
|
-
resolved =
|
|
80493
|
+
resolved = path84.win32.resolve(inputPath);
|
|
80494
|
+
} else if (path84.isAbsolute(inputPath)) {
|
|
80495
|
+
resolved = path84.resolve(inputPath);
|
|
79393
80496
|
} else {
|
|
79394
|
-
resolved =
|
|
80497
|
+
resolved = path84.resolve(baseDir, inputPath);
|
|
79395
80498
|
}
|
|
79396
|
-
const workspaceResolved =
|
|
80499
|
+
const workspaceResolved = path84.resolve(workspaceDir);
|
|
79397
80500
|
let relative20;
|
|
79398
80501
|
if (isWinAbs) {
|
|
79399
|
-
relative20 =
|
|
80502
|
+
relative20 = path84.win32.relative(workspaceResolved, resolved);
|
|
79400
80503
|
} else {
|
|
79401
|
-
relative20 =
|
|
80504
|
+
relative20 = path84.relative(workspaceResolved, resolved);
|
|
79402
80505
|
}
|
|
79403
80506
|
if (relative20.startsWith("..")) {
|
|
79404
80507
|
return "path traversal detected";
|
|
@@ -79463,7 +80566,7 @@ async function runLintOnFiles(linter, files, workspaceDir) {
|
|
|
79463
80566
|
if (typeof file3 !== "string") {
|
|
79464
80567
|
continue;
|
|
79465
80568
|
}
|
|
79466
|
-
const resolvedPath =
|
|
80569
|
+
const resolvedPath = path84.resolve(file3);
|
|
79467
80570
|
const validationError = validatePath(resolvedPath, workspaceDir, workspaceDir);
|
|
79468
80571
|
if (validationError) {
|
|
79469
80572
|
continue;
|
|
@@ -79620,7 +80723,7 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
79620
80723
|
skippedFiles++;
|
|
79621
80724
|
continue;
|
|
79622
80725
|
}
|
|
79623
|
-
const resolvedPath =
|
|
80726
|
+
const resolvedPath = path84.resolve(file3);
|
|
79624
80727
|
const validationError = validatePath(resolvedPath, directory, directory);
|
|
79625
80728
|
if (validationError) {
|
|
79626
80729
|
skippedFiles++;
|
|
@@ -79638,25 +80741,25 @@ async function runSecretscanWithFiles(files, directory) {
|
|
|
79638
80741
|
};
|
|
79639
80742
|
}
|
|
79640
80743
|
for (const file3 of validatedFiles) {
|
|
79641
|
-
const ext =
|
|
80744
|
+
const ext = path84.extname(file3).toLowerCase();
|
|
79642
80745
|
if (DEFAULT_EXCLUDE_EXTENSIONS2.has(ext)) {
|
|
79643
80746
|
skippedFiles++;
|
|
79644
80747
|
continue;
|
|
79645
80748
|
}
|
|
79646
|
-
let
|
|
80749
|
+
let stat4;
|
|
79647
80750
|
try {
|
|
79648
|
-
|
|
80751
|
+
stat4 = fs70.statSync(file3);
|
|
79649
80752
|
} catch {
|
|
79650
80753
|
skippedFiles++;
|
|
79651
80754
|
continue;
|
|
79652
80755
|
}
|
|
79653
|
-
if (
|
|
80756
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES9) {
|
|
79654
80757
|
skippedFiles++;
|
|
79655
80758
|
continue;
|
|
79656
80759
|
}
|
|
79657
80760
|
let content;
|
|
79658
80761
|
try {
|
|
79659
|
-
const buffer =
|
|
80762
|
+
const buffer = fs70.readFileSync(file3);
|
|
79660
80763
|
if (buffer.includes(0)) {
|
|
79661
80764
|
skippedFiles++;
|
|
79662
80765
|
continue;
|
|
@@ -79857,7 +80960,7 @@ function classifySastFindings(findings, changedLineRanges, directory) {
|
|
|
79857
80960
|
const preexistingFindings = [];
|
|
79858
80961
|
for (const finding of findings) {
|
|
79859
80962
|
const filePath = finding.location.file;
|
|
79860
|
-
const normalised =
|
|
80963
|
+
const normalised = path84.relative(directory, filePath).replace(/\\/g, "/");
|
|
79861
80964
|
const changedLines = changedLineRanges.get(normalised);
|
|
79862
80965
|
if (changedLines?.has(finding.location.line)) {
|
|
79863
80966
|
newFindings.push(finding);
|
|
@@ -79908,7 +81011,7 @@ async function runPreCheckBatch(input, workspaceDir, contextDir) {
|
|
|
79908
81011
|
warn(`pre_check_batch: Invalid file path: ${file3}`);
|
|
79909
81012
|
continue;
|
|
79910
81013
|
}
|
|
79911
|
-
changedFiles.push(
|
|
81014
|
+
changedFiles.push(path84.resolve(directory, file3));
|
|
79912
81015
|
}
|
|
79913
81016
|
if (changedFiles.length === 0) {
|
|
79914
81017
|
warn("pre_check_batch: No valid files after validation, skipping all tools (fail-closed)");
|
|
@@ -80109,7 +81212,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
80109
81212
|
};
|
|
80110
81213
|
return JSON.stringify(errorResult, null, 2);
|
|
80111
81214
|
}
|
|
80112
|
-
const resolvedDirectory =
|
|
81215
|
+
const resolvedDirectory = path84.resolve(typedArgs.directory);
|
|
80113
81216
|
const workspaceAnchor = resolvedDirectory;
|
|
80114
81217
|
const dirError = validateDirectory2(resolvedDirectory, workspaceAnchor);
|
|
80115
81218
|
if (dirError) {
|
|
@@ -80150,7 +81253,7 @@ var pre_check_batch = createSwarmTool({
|
|
|
80150
81253
|
});
|
|
80151
81254
|
// src/tools/repo-map.ts
|
|
80152
81255
|
init_dist();
|
|
80153
|
-
import * as
|
|
81256
|
+
import * as path85 from "path";
|
|
80154
81257
|
init_path_security();
|
|
80155
81258
|
init_create_tool();
|
|
80156
81259
|
var VALID_ACTIONS = [
|
|
@@ -80175,7 +81278,7 @@ function validateFile(p) {
|
|
|
80175
81278
|
return "file contains control characters";
|
|
80176
81279
|
if (containsPathTraversal(p))
|
|
80177
81280
|
return "file contains path traversal";
|
|
80178
|
-
if (
|
|
81281
|
+
if (path85.isAbsolute(p) || /^[a-zA-Z]:[\\/]/.test(p)) {
|
|
80179
81282
|
return "file must be a workspace-relative path, not absolute";
|
|
80180
81283
|
}
|
|
80181
81284
|
return null;
|
|
@@ -80198,8 +81301,8 @@ function ok(action, payload) {
|
|
|
80198
81301
|
}
|
|
80199
81302
|
function toRelativeGraphPath(input, workspaceRoot) {
|
|
80200
81303
|
const normalized = input.replace(/\\/g, "/");
|
|
80201
|
-
if (
|
|
80202
|
-
const rel =
|
|
81304
|
+
if (path85.isAbsolute(normalized)) {
|
|
81305
|
+
const rel = path85.relative(workspaceRoot, normalized).replace(/\\/g, "/");
|
|
80203
81306
|
return normalizeGraphPath2(rel);
|
|
80204
81307
|
}
|
|
80205
81308
|
return normalizeGraphPath2(normalized);
|
|
@@ -80343,8 +81446,8 @@ var repo_map = createSwarmTool({
|
|
|
80343
81446
|
// src/tools/req-coverage.ts
|
|
80344
81447
|
init_dist();
|
|
80345
81448
|
init_create_tool();
|
|
80346
|
-
import * as
|
|
80347
|
-
import * as
|
|
81449
|
+
import * as fs71 from "fs";
|
|
81450
|
+
import * as path86 from "path";
|
|
80348
81451
|
var SPEC_FILE = ".swarm/spec.md";
|
|
80349
81452
|
var EVIDENCE_DIR4 = ".swarm/evidence";
|
|
80350
81453
|
var OBLIGATION_KEYWORDS = ["MUST", "SHOULD", "SHALL"];
|
|
@@ -80403,20 +81506,20 @@ function extractObligationAndText(id, lineText) {
|
|
|
80403
81506
|
var PHASE_TASK_ID_REGEX = /^\d+\.\d+(\.\d+)*$/;
|
|
80404
81507
|
function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
80405
81508
|
const touchedFiles = new Set;
|
|
80406
|
-
if (!
|
|
81509
|
+
if (!fs71.existsSync(evidenceDir) || !fs71.statSync(evidenceDir).isDirectory()) {
|
|
80407
81510
|
return [];
|
|
80408
81511
|
}
|
|
80409
81512
|
let entries;
|
|
80410
81513
|
try {
|
|
80411
|
-
entries =
|
|
81514
|
+
entries = fs71.readdirSync(evidenceDir);
|
|
80412
81515
|
} catch {
|
|
80413
81516
|
return [];
|
|
80414
81517
|
}
|
|
80415
81518
|
for (const entry of entries) {
|
|
80416
|
-
const entryPath =
|
|
81519
|
+
const entryPath = path86.join(evidenceDir, entry);
|
|
80417
81520
|
try {
|
|
80418
|
-
const
|
|
80419
|
-
if (!
|
|
81521
|
+
const stat4 = fs71.statSync(entryPath);
|
|
81522
|
+
if (!stat4.isDirectory()) {
|
|
80420
81523
|
continue;
|
|
80421
81524
|
}
|
|
80422
81525
|
} catch {
|
|
@@ -80429,18 +81532,18 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
80429
81532
|
if (entryPhase !== String(phase)) {
|
|
80430
81533
|
continue;
|
|
80431
81534
|
}
|
|
80432
|
-
const evidenceFilePath =
|
|
81535
|
+
const evidenceFilePath = path86.join(entryPath, "evidence.json");
|
|
80433
81536
|
try {
|
|
80434
|
-
const resolvedPath =
|
|
80435
|
-
const evidenceDirResolved =
|
|
80436
|
-
if (!resolvedPath.startsWith(evidenceDirResolved +
|
|
81537
|
+
const resolvedPath = path86.resolve(evidenceFilePath);
|
|
81538
|
+
const evidenceDirResolved = path86.resolve(evidenceDir);
|
|
81539
|
+
if (!resolvedPath.startsWith(evidenceDirResolved + path86.sep)) {
|
|
80437
81540
|
continue;
|
|
80438
81541
|
}
|
|
80439
|
-
const
|
|
80440
|
-
if (!
|
|
81542
|
+
const stat4 = fs71.lstatSync(evidenceFilePath);
|
|
81543
|
+
if (!stat4.isFile()) {
|
|
80441
81544
|
continue;
|
|
80442
81545
|
}
|
|
80443
|
-
if (
|
|
81546
|
+
if (stat4.size > MAX_FILE_SIZE_BYTES9) {
|
|
80444
81547
|
continue;
|
|
80445
81548
|
}
|
|
80446
81549
|
} catch {
|
|
@@ -80448,7 +81551,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
80448
81551
|
}
|
|
80449
81552
|
let content;
|
|
80450
81553
|
try {
|
|
80451
|
-
content =
|
|
81554
|
+
content = fs71.readFileSync(evidenceFilePath, "utf-8");
|
|
80452
81555
|
} catch {
|
|
80453
81556
|
continue;
|
|
80454
81557
|
}
|
|
@@ -80467,7 +81570,7 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
80467
81570
|
if (Array.isArray(diffEntry.files_changed)) {
|
|
80468
81571
|
for (const file3 of diffEntry.files_changed) {
|
|
80469
81572
|
if (typeof file3 === "string") {
|
|
80470
|
-
touchedFiles.add(
|
|
81573
|
+
touchedFiles.add(path86.resolve(cwd, file3));
|
|
80471
81574
|
}
|
|
80472
81575
|
}
|
|
80473
81576
|
}
|
|
@@ -80480,12 +81583,12 @@ function readTouchedFiles(evidenceDir, phase, cwd) {
|
|
|
80480
81583
|
}
|
|
80481
81584
|
function searchFileForKeywords(filePath, keywords, cwd) {
|
|
80482
81585
|
try {
|
|
80483
|
-
const resolvedPath =
|
|
80484
|
-
const cwdResolved =
|
|
81586
|
+
const resolvedPath = path86.resolve(filePath);
|
|
81587
|
+
const cwdResolved = path86.resolve(cwd);
|
|
80485
81588
|
if (!resolvedPath.startsWith(cwdResolved)) {
|
|
80486
81589
|
return false;
|
|
80487
81590
|
}
|
|
80488
|
-
const content =
|
|
81591
|
+
const content = fs71.readFileSync(resolvedPath, "utf-8");
|
|
80489
81592
|
for (const keyword of keywords) {
|
|
80490
81593
|
const regex = new RegExp(`\\b${keyword}\\b`, "i");
|
|
80491
81594
|
if (regex.test(content)) {
|
|
@@ -80615,10 +81718,10 @@ var req_coverage = createSwarmTool({
|
|
|
80615
81718
|
}, null, 2);
|
|
80616
81719
|
}
|
|
80617
81720
|
const cwd = inputDirectory || directory;
|
|
80618
|
-
const specPath =
|
|
81721
|
+
const specPath = path86.join(cwd, SPEC_FILE);
|
|
80619
81722
|
let specContent;
|
|
80620
81723
|
try {
|
|
80621
|
-
specContent =
|
|
81724
|
+
specContent = fs71.readFileSync(specPath, "utf-8");
|
|
80622
81725
|
} catch (readError) {
|
|
80623
81726
|
return JSON.stringify({
|
|
80624
81727
|
success: false,
|
|
@@ -80642,7 +81745,7 @@ var req_coverage = createSwarmTool({
|
|
|
80642
81745
|
message: "No FR requirements found in spec.md"
|
|
80643
81746
|
}, null, 2);
|
|
80644
81747
|
}
|
|
80645
|
-
const evidenceDir =
|
|
81748
|
+
const evidenceDir = path86.join(cwd, EVIDENCE_DIR4);
|
|
80646
81749
|
const touchedFiles = readTouchedFiles(evidenceDir, phase, cwd);
|
|
80647
81750
|
const analyzedRequirements = [];
|
|
80648
81751
|
let coveredCount = 0;
|
|
@@ -80668,12 +81771,12 @@ var req_coverage = createSwarmTool({
|
|
|
80668
81771
|
requirements: analyzedRequirements
|
|
80669
81772
|
};
|
|
80670
81773
|
const reportFilename = `req-coverage-phase-${phase}.json`;
|
|
80671
|
-
const reportPath =
|
|
81774
|
+
const reportPath = path86.join(evidenceDir, reportFilename);
|
|
80672
81775
|
try {
|
|
80673
|
-
if (!
|
|
80674
|
-
|
|
81776
|
+
if (!fs71.existsSync(evidenceDir)) {
|
|
81777
|
+
fs71.mkdirSync(evidenceDir, { recursive: true });
|
|
80675
81778
|
}
|
|
80676
|
-
|
|
81779
|
+
fs71.writeFileSync(reportPath, JSON.stringify(result, null, 2), "utf-8");
|
|
80677
81780
|
} catch (writeError) {
|
|
80678
81781
|
console.warn(`Failed to write coverage report: ${writeError instanceof Error ? writeError.message : String(writeError)}`);
|
|
80679
81782
|
}
|
|
@@ -80759,8 +81862,8 @@ init_manager();
|
|
|
80759
81862
|
init_state();
|
|
80760
81863
|
init_create_tool();
|
|
80761
81864
|
import * as crypto9 from "crypto";
|
|
80762
|
-
import * as
|
|
80763
|
-
import * as
|
|
81865
|
+
import * as fs72 from "fs";
|
|
81866
|
+
import * as path87 from "path";
|
|
80764
81867
|
function detectPlaceholderContent(args2) {
|
|
80765
81868
|
const issues = [];
|
|
80766
81869
|
const placeholderPattern = /^\[\w[\w\s]*\]$/;
|
|
@@ -80836,11 +81939,11 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
80836
81939
|
let specMtime;
|
|
80837
81940
|
let specHash;
|
|
80838
81941
|
if (process.env.SWARM_SKIP_SPEC_GATE !== "1") {
|
|
80839
|
-
const specPath =
|
|
81942
|
+
const specPath = path87.join(targetWorkspace, ".swarm", "spec.md");
|
|
80840
81943
|
try {
|
|
80841
|
-
const
|
|
80842
|
-
specMtime =
|
|
80843
|
-
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");
|
|
80844
81947
|
specHash = crypto9.createHash("sha256").update(content).digest("hex");
|
|
80845
81948
|
} catch {
|
|
80846
81949
|
return {
|
|
@@ -80976,14 +82079,14 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
80976
82079
|
}
|
|
80977
82080
|
await writeCheckpoint(dir).catch(() => {});
|
|
80978
82081
|
try {
|
|
80979
|
-
const markerPath =
|
|
82082
|
+
const markerPath = path87.join(dir, ".swarm", ".plan-write-marker");
|
|
80980
82083
|
const marker = JSON.stringify({
|
|
80981
82084
|
source: "save_plan",
|
|
80982
82085
|
timestamp: new Date().toISOString(),
|
|
80983
82086
|
phases_count: plan.phases.length,
|
|
80984
82087
|
tasks_count: tasksCount
|
|
80985
82088
|
});
|
|
80986
|
-
await
|
|
82089
|
+
await fs72.promises.writeFile(markerPath, marker, "utf8");
|
|
80987
82090
|
} catch {}
|
|
80988
82091
|
const warnings = [];
|
|
80989
82092
|
let criticReviewFound = false;
|
|
@@ -80999,7 +82102,7 @@ async function executeSavePlan(args2, fallbackDir) {
|
|
|
80999
82102
|
return {
|
|
81000
82103
|
success: true,
|
|
81001
82104
|
message: "Plan saved successfully",
|
|
81002
|
-
plan_path:
|
|
82105
|
+
plan_path: path87.join(dir, ".swarm", "plan.json"),
|
|
81003
82106
|
phases_count: plan.phases.length,
|
|
81004
82107
|
tasks_count: tasksCount,
|
|
81005
82108
|
...resolvedProfile !== undefined ? { execution_profile: resolvedProfile } : {},
|
|
@@ -81051,8 +82154,8 @@ var save_plan = createSwarmTool({
|
|
|
81051
82154
|
// src/tools/sbom-generate.ts
|
|
81052
82155
|
init_dist();
|
|
81053
82156
|
init_manager2();
|
|
81054
|
-
import * as
|
|
81055
|
-
import * as
|
|
82157
|
+
import * as fs73 from "fs";
|
|
82158
|
+
import * as path88 from "path";
|
|
81056
82159
|
|
|
81057
82160
|
// src/sbom/detectors/index.ts
|
|
81058
82161
|
init_utils();
|
|
@@ -81900,9 +83003,9 @@ function findManifestFiles(rootDir) {
|
|
|
81900
83003
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
81901
83004
|
function searchDir(dir) {
|
|
81902
83005
|
try {
|
|
81903
|
-
const entries =
|
|
83006
|
+
const entries = fs73.readdirSync(dir, { withFileTypes: true });
|
|
81904
83007
|
for (const entry of entries) {
|
|
81905
|
-
const fullPath =
|
|
83008
|
+
const fullPath = path88.join(dir, entry.name);
|
|
81906
83009
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === "target") {
|
|
81907
83010
|
continue;
|
|
81908
83011
|
}
|
|
@@ -81911,7 +83014,7 @@ function findManifestFiles(rootDir) {
|
|
|
81911
83014
|
} else if (entry.isFile()) {
|
|
81912
83015
|
for (const pattern of patterns) {
|
|
81913
83016
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
81914
|
-
manifestFiles.push(
|
|
83017
|
+
manifestFiles.push(path88.relative(rootDir, fullPath));
|
|
81915
83018
|
break;
|
|
81916
83019
|
}
|
|
81917
83020
|
}
|
|
@@ -81927,13 +83030,13 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
81927
83030
|
const patterns = [...new Set(allDetectors.flatMap((d) => d.patterns))];
|
|
81928
83031
|
for (const dir of directories) {
|
|
81929
83032
|
try {
|
|
81930
|
-
const entries =
|
|
83033
|
+
const entries = fs73.readdirSync(dir, { withFileTypes: true });
|
|
81931
83034
|
for (const entry of entries) {
|
|
81932
|
-
const fullPath =
|
|
83035
|
+
const fullPath = path88.join(dir, entry.name);
|
|
81933
83036
|
if (entry.isFile()) {
|
|
81934
83037
|
for (const pattern of patterns) {
|
|
81935
83038
|
if (simpleGlobToRegex(pattern).test(entry.name)) {
|
|
81936
|
-
found.push(
|
|
83039
|
+
found.push(path88.relative(workingDir, fullPath));
|
|
81937
83040
|
break;
|
|
81938
83041
|
}
|
|
81939
83042
|
}
|
|
@@ -81946,11 +83049,11 @@ function findManifestFilesInDirs(directories, workingDir) {
|
|
|
81946
83049
|
function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
81947
83050
|
const dirs = new Set;
|
|
81948
83051
|
for (const file3 of changedFiles) {
|
|
81949
|
-
let currentDir =
|
|
83052
|
+
let currentDir = path88.dirname(file3);
|
|
81950
83053
|
while (true) {
|
|
81951
|
-
if (currentDir && currentDir !== "." && currentDir !==
|
|
81952
|
-
dirs.add(
|
|
81953
|
-
const parent =
|
|
83054
|
+
if (currentDir && currentDir !== "." && currentDir !== path88.sep) {
|
|
83055
|
+
dirs.add(path88.join(workingDir, currentDir));
|
|
83056
|
+
const parent = path88.dirname(currentDir);
|
|
81954
83057
|
if (parent === currentDir)
|
|
81955
83058
|
break;
|
|
81956
83059
|
currentDir = parent;
|
|
@@ -81964,7 +83067,7 @@ function getDirectoriesFromChangedFiles(changedFiles, workingDir) {
|
|
|
81964
83067
|
}
|
|
81965
83068
|
function ensureOutputDir(outputDir) {
|
|
81966
83069
|
try {
|
|
81967
|
-
|
|
83070
|
+
fs73.mkdirSync(outputDir, { recursive: true });
|
|
81968
83071
|
} catch (error93) {
|
|
81969
83072
|
if (!error93 || error93.code !== "EEXIST") {
|
|
81970
83073
|
throw error93;
|
|
@@ -82034,7 +83137,7 @@ var sbom_generate = createSwarmTool({
|
|
|
82034
83137
|
const changedFiles = obj.changed_files;
|
|
82035
83138
|
const relativeOutputDir = obj.output_dir || DEFAULT_OUTPUT_DIR;
|
|
82036
83139
|
const workingDir = directory;
|
|
82037
|
-
const outputDir =
|
|
83140
|
+
const outputDir = path88.isAbsolute(relativeOutputDir) ? relativeOutputDir : path88.join(workingDir, relativeOutputDir);
|
|
82038
83141
|
let manifestFiles = [];
|
|
82039
83142
|
if (scope === "all") {
|
|
82040
83143
|
manifestFiles = findManifestFiles(workingDir);
|
|
@@ -82057,11 +83160,11 @@ var sbom_generate = createSwarmTool({
|
|
|
82057
83160
|
const processedFiles = [];
|
|
82058
83161
|
for (const manifestFile of manifestFiles) {
|
|
82059
83162
|
try {
|
|
82060
|
-
const fullPath =
|
|
82061
|
-
if (!
|
|
83163
|
+
const fullPath = path88.isAbsolute(manifestFile) ? manifestFile : path88.join(workingDir, manifestFile);
|
|
83164
|
+
if (!fs73.existsSync(fullPath)) {
|
|
82062
83165
|
continue;
|
|
82063
83166
|
}
|
|
82064
|
-
const content =
|
|
83167
|
+
const content = fs73.readFileSync(fullPath, "utf-8");
|
|
82065
83168
|
const components = detectComponents(manifestFile, content);
|
|
82066
83169
|
processedFiles.push(manifestFile);
|
|
82067
83170
|
if (components.length > 0) {
|
|
@@ -82074,8 +83177,8 @@ var sbom_generate = createSwarmTool({
|
|
|
82074
83177
|
const bom = generateCycloneDX(allComponents);
|
|
82075
83178
|
const bomJson = serializeCycloneDX(bom);
|
|
82076
83179
|
const filename = generateSbomFilename();
|
|
82077
|
-
const outputPath =
|
|
82078
|
-
|
|
83180
|
+
const outputPath = path88.join(outputDir, filename);
|
|
83181
|
+
fs73.writeFileSync(outputPath, bomJson, "utf-8");
|
|
82079
83182
|
const verdict = processedFiles.length > 0 ? "pass" : "pass";
|
|
82080
83183
|
try {
|
|
82081
83184
|
const timestamp = new Date().toISOString();
|
|
@@ -82117,8 +83220,8 @@ var sbom_generate = createSwarmTool({
|
|
|
82117
83220
|
// src/tools/schema-drift.ts
|
|
82118
83221
|
init_dist();
|
|
82119
83222
|
init_create_tool();
|
|
82120
|
-
import * as
|
|
82121
|
-
import * as
|
|
83223
|
+
import * as fs74 from "fs";
|
|
83224
|
+
import * as path89 from "path";
|
|
82122
83225
|
var SPEC_CANDIDATES = [
|
|
82123
83226
|
"openapi.json",
|
|
82124
83227
|
"openapi.yaml",
|
|
@@ -82150,28 +83253,28 @@ function normalizePath3(p) {
|
|
|
82150
83253
|
}
|
|
82151
83254
|
function discoverSpecFile(cwd, specFileArg) {
|
|
82152
83255
|
if (specFileArg) {
|
|
82153
|
-
const resolvedPath =
|
|
82154
|
-
const normalizedCwd = cwd.endsWith(
|
|
83256
|
+
const resolvedPath = path89.resolve(cwd, specFileArg);
|
|
83257
|
+
const normalizedCwd = cwd.endsWith(path89.sep) ? cwd : cwd + path89.sep;
|
|
82155
83258
|
if (!resolvedPath.startsWith(normalizedCwd) && resolvedPath !== cwd) {
|
|
82156
83259
|
throw new Error("Invalid spec_file: path traversal detected");
|
|
82157
83260
|
}
|
|
82158
|
-
const ext =
|
|
83261
|
+
const ext = path89.extname(resolvedPath).toLowerCase();
|
|
82159
83262
|
if (!ALLOWED_EXTENSIONS.includes(ext)) {
|
|
82160
83263
|
throw new Error(`Invalid spec_file: must end in .json, .yaml, or .yml, got ${ext}`);
|
|
82161
83264
|
}
|
|
82162
|
-
const stats =
|
|
83265
|
+
const stats = fs74.statSync(resolvedPath);
|
|
82163
83266
|
if (stats.size > MAX_SPEC_SIZE) {
|
|
82164
83267
|
throw new Error(`Invalid spec_file: file exceeds ${MAX_SPEC_SIZE / 1024 / 1024}MB limit`);
|
|
82165
83268
|
}
|
|
82166
|
-
if (!
|
|
83269
|
+
if (!fs74.existsSync(resolvedPath)) {
|
|
82167
83270
|
throw new Error(`Spec file not found: ${resolvedPath}`);
|
|
82168
83271
|
}
|
|
82169
83272
|
return resolvedPath;
|
|
82170
83273
|
}
|
|
82171
83274
|
for (const candidate of SPEC_CANDIDATES) {
|
|
82172
|
-
const candidatePath =
|
|
82173
|
-
if (
|
|
82174
|
-
const stats =
|
|
83275
|
+
const candidatePath = path89.resolve(cwd, candidate);
|
|
83276
|
+
if (fs74.existsSync(candidatePath)) {
|
|
83277
|
+
const stats = fs74.statSync(candidatePath);
|
|
82175
83278
|
if (stats.size <= MAX_SPEC_SIZE) {
|
|
82176
83279
|
return candidatePath;
|
|
82177
83280
|
}
|
|
@@ -82180,8 +83283,8 @@ function discoverSpecFile(cwd, specFileArg) {
|
|
|
82180
83283
|
return null;
|
|
82181
83284
|
}
|
|
82182
83285
|
function parseSpec(specFile) {
|
|
82183
|
-
const content =
|
|
82184
|
-
const ext =
|
|
83286
|
+
const content = fs74.readFileSync(specFile, "utf-8");
|
|
83287
|
+
const ext = path89.extname(specFile).toLowerCase();
|
|
82185
83288
|
if (ext === ".json") {
|
|
82186
83289
|
return parseJsonSpec(content);
|
|
82187
83290
|
}
|
|
@@ -82252,12 +83355,12 @@ function extractRoutes(cwd) {
|
|
|
82252
83355
|
function walkDir(dir) {
|
|
82253
83356
|
let entries;
|
|
82254
83357
|
try {
|
|
82255
|
-
entries =
|
|
83358
|
+
entries = fs74.readdirSync(dir, { withFileTypes: true });
|
|
82256
83359
|
} catch {
|
|
82257
83360
|
return;
|
|
82258
83361
|
}
|
|
82259
83362
|
for (const entry of entries) {
|
|
82260
|
-
const fullPath =
|
|
83363
|
+
const fullPath = path89.join(dir, entry.name);
|
|
82261
83364
|
if (entry.isSymbolicLink()) {
|
|
82262
83365
|
continue;
|
|
82263
83366
|
}
|
|
@@ -82267,7 +83370,7 @@ function extractRoutes(cwd) {
|
|
|
82267
83370
|
}
|
|
82268
83371
|
walkDir(fullPath);
|
|
82269
83372
|
} else if (entry.isFile()) {
|
|
82270
|
-
const ext =
|
|
83373
|
+
const ext = path89.extname(entry.name).toLowerCase();
|
|
82271
83374
|
const baseName = entry.name.toLowerCase();
|
|
82272
83375
|
if (![".ts", ".js", ".mjs"].includes(ext)) {
|
|
82273
83376
|
continue;
|
|
@@ -82285,7 +83388,7 @@ function extractRoutes(cwd) {
|
|
|
82285
83388
|
}
|
|
82286
83389
|
function extractRoutesFromFile(filePath) {
|
|
82287
83390
|
const routes = [];
|
|
82288
|
-
const content =
|
|
83391
|
+
const content = fs74.readFileSync(filePath, "utf-8");
|
|
82289
83392
|
const lines = content.split(/\r?\n/);
|
|
82290
83393
|
const expressRegex = /(?:app|router|server|express)\.(get|post|put|patch|delete|options|head)\s*\(\s*['"`]([^'"`]+)['"`]/g;
|
|
82291
83394
|
const flaskRegex = /@(?:app|blueprint|bp)\.route\s*\(\s*['"]([^'"]+)['"]/g;
|
|
@@ -82433,8 +83536,8 @@ var schema_drift = createSwarmTool({
|
|
|
82433
83536
|
init_tool();
|
|
82434
83537
|
init_path_security();
|
|
82435
83538
|
init_create_tool();
|
|
82436
|
-
import * as
|
|
82437
|
-
import * as
|
|
83539
|
+
import * as fs75 from "fs";
|
|
83540
|
+
import * as path90 from "path";
|
|
82438
83541
|
var DEFAULT_MAX_RESULTS = 100;
|
|
82439
83542
|
var DEFAULT_MAX_LINES = 200;
|
|
82440
83543
|
var REGEX_TIMEOUT_MS = 5000;
|
|
@@ -82470,11 +83573,11 @@ function containsWindowsAttacks3(str) {
|
|
|
82470
83573
|
}
|
|
82471
83574
|
function isPathInWorkspace3(filePath, workspace) {
|
|
82472
83575
|
try {
|
|
82473
|
-
const resolvedPath =
|
|
82474
|
-
const realWorkspace =
|
|
82475
|
-
const realResolvedPath =
|
|
82476
|
-
const relativePath =
|
|
82477
|
-
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)) {
|
|
82478
83581
|
return false;
|
|
82479
83582
|
}
|
|
82480
83583
|
return true;
|
|
@@ -82487,12 +83590,12 @@ function validatePathForRead2(filePath, workspace) {
|
|
|
82487
83590
|
}
|
|
82488
83591
|
function findRgInEnvPath() {
|
|
82489
83592
|
const searchPath = process.env.PATH ?? "";
|
|
82490
|
-
for (const dir of searchPath.split(
|
|
83593
|
+
for (const dir of searchPath.split(path90.delimiter)) {
|
|
82491
83594
|
if (!dir)
|
|
82492
83595
|
continue;
|
|
82493
83596
|
const isWindows = process.platform === "win32";
|
|
82494
|
-
const candidate =
|
|
82495
|
-
if (
|
|
83597
|
+
const candidate = path90.join(dir, isWindows ? "rg.exe" : "rg");
|
|
83598
|
+
if (fs75.existsSync(candidate))
|
|
82496
83599
|
return candidate;
|
|
82497
83600
|
}
|
|
82498
83601
|
return null;
|
|
@@ -82619,10 +83722,10 @@ function collectFiles(dir, workspace, includeGlobs, excludeGlobs) {
|
|
|
82619
83722
|
return files;
|
|
82620
83723
|
}
|
|
82621
83724
|
try {
|
|
82622
|
-
const entries =
|
|
83725
|
+
const entries = fs75.readdirSync(dir, { withFileTypes: true });
|
|
82623
83726
|
for (const entry of entries) {
|
|
82624
|
-
const fullPath =
|
|
82625
|
-
const relativePath =
|
|
83727
|
+
const fullPath = path90.join(dir, entry.name);
|
|
83728
|
+
const relativePath = path90.relative(workspace, fullPath);
|
|
82626
83729
|
if (!validatePathForRead2(fullPath, workspace)) {
|
|
82627
83730
|
continue;
|
|
82628
83731
|
}
|
|
@@ -82663,13 +83766,13 @@ async function fallbackSearch(opts) {
|
|
|
82663
83766
|
const matches = [];
|
|
82664
83767
|
let total = 0;
|
|
82665
83768
|
for (const file3 of files) {
|
|
82666
|
-
const fullPath =
|
|
83769
|
+
const fullPath = path90.join(opts.workspace, file3);
|
|
82667
83770
|
if (!validatePathForRead2(fullPath, opts.workspace)) {
|
|
82668
83771
|
continue;
|
|
82669
83772
|
}
|
|
82670
83773
|
let stats;
|
|
82671
83774
|
try {
|
|
82672
|
-
stats =
|
|
83775
|
+
stats = fs75.statSync(fullPath);
|
|
82673
83776
|
if (stats.size > MAX_FILE_SIZE_BYTES10) {
|
|
82674
83777
|
continue;
|
|
82675
83778
|
}
|
|
@@ -82678,7 +83781,7 @@ async function fallbackSearch(opts) {
|
|
|
82678
83781
|
}
|
|
82679
83782
|
let content;
|
|
82680
83783
|
try {
|
|
82681
|
-
content =
|
|
83784
|
+
content = fs75.readFileSync(fullPath, "utf-8");
|
|
82682
83785
|
} catch {
|
|
82683
83786
|
continue;
|
|
82684
83787
|
}
|
|
@@ -82790,7 +83893,7 @@ var search = createSwarmTool({
|
|
|
82790
83893
|
message: "Exclude pattern contains invalid Windows-specific sequence"
|
|
82791
83894
|
}, null, 2);
|
|
82792
83895
|
}
|
|
82793
|
-
if (!
|
|
83896
|
+
if (!fs75.existsSync(directory)) {
|
|
82794
83897
|
return JSON.stringify({
|
|
82795
83898
|
error: true,
|
|
82796
83899
|
type: "unknown",
|
|
@@ -82913,8 +84016,8 @@ var set_qa_gates = createSwarmTool({
|
|
|
82913
84016
|
init_tool();
|
|
82914
84017
|
init_path_security();
|
|
82915
84018
|
init_create_tool();
|
|
82916
|
-
import * as
|
|
82917
|
-
import * as
|
|
84019
|
+
import * as fs76 from "fs";
|
|
84020
|
+
import * as path91 from "path";
|
|
82918
84021
|
var WINDOWS_RESERVED_NAMES4 = /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(\.|:|$)/i;
|
|
82919
84022
|
function containsWindowsAttacks4(str) {
|
|
82920
84023
|
if (/:[^\\/]/.test(str))
|
|
@@ -82928,14 +84031,14 @@ function containsWindowsAttacks4(str) {
|
|
|
82928
84031
|
}
|
|
82929
84032
|
function isPathInWorkspace4(filePath, workspace) {
|
|
82930
84033
|
try {
|
|
82931
|
-
const resolvedPath =
|
|
82932
|
-
if (!
|
|
84034
|
+
const resolvedPath = path91.resolve(workspace, filePath);
|
|
84035
|
+
if (!fs76.existsSync(resolvedPath)) {
|
|
82933
84036
|
return true;
|
|
82934
84037
|
}
|
|
82935
|
-
const realWorkspace =
|
|
82936
|
-
const realResolvedPath =
|
|
82937
|
-
const relativePath =
|
|
82938
|
-
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)) {
|
|
82939
84042
|
return false;
|
|
82940
84043
|
}
|
|
82941
84044
|
return true;
|
|
@@ -83107,7 +84210,7 @@ var suggestPatch = createSwarmTool({
|
|
|
83107
84210
|
message: "changes cannot be empty"
|
|
83108
84211
|
}, null, 2);
|
|
83109
84212
|
}
|
|
83110
|
-
if (!
|
|
84213
|
+
if (!fs76.existsSync(directory)) {
|
|
83111
84214
|
return JSON.stringify({
|
|
83112
84215
|
success: false,
|
|
83113
84216
|
error: true,
|
|
@@ -83143,8 +84246,8 @@ var suggestPatch = createSwarmTool({
|
|
|
83143
84246
|
});
|
|
83144
84247
|
continue;
|
|
83145
84248
|
}
|
|
83146
|
-
const fullPath =
|
|
83147
|
-
if (!
|
|
84249
|
+
const fullPath = path91.resolve(directory, change.file);
|
|
84250
|
+
if (!fs76.existsSync(fullPath)) {
|
|
83148
84251
|
errors5.push({
|
|
83149
84252
|
success: false,
|
|
83150
84253
|
error: true,
|
|
@@ -83158,7 +84261,7 @@ var suggestPatch = createSwarmTool({
|
|
|
83158
84261
|
}
|
|
83159
84262
|
let content;
|
|
83160
84263
|
try {
|
|
83161
|
-
content =
|
|
84264
|
+
content = fs76.readFileSync(fullPath, "utf-8");
|
|
83162
84265
|
} catch (err3) {
|
|
83163
84266
|
errors5.push({
|
|
83164
84267
|
success: false,
|
|
@@ -83237,8 +84340,8 @@ var suggestPatch = createSwarmTool({
|
|
|
83237
84340
|
// src/tools/lint-spec.ts
|
|
83238
84341
|
init_spec_schema();
|
|
83239
84342
|
init_create_tool();
|
|
83240
|
-
import * as
|
|
83241
|
-
import * as
|
|
84343
|
+
import * as fs77 from "fs";
|
|
84344
|
+
import * as path92 from "path";
|
|
83242
84345
|
var SPEC_FILE_NAME = "spec.md";
|
|
83243
84346
|
var SWARM_DIR2 = ".swarm";
|
|
83244
84347
|
var OBLIGATION_KEYWORDS2 = ["MUST", "SHALL", "SHOULD", "MAY"];
|
|
@@ -83291,8 +84394,8 @@ var lint_spec = createSwarmTool({
|
|
|
83291
84394
|
async execute(_args, directory) {
|
|
83292
84395
|
const errors5 = [];
|
|
83293
84396
|
const warnings = [];
|
|
83294
|
-
const specPath =
|
|
83295
|
-
if (!
|
|
84397
|
+
const specPath = path92.join(directory, SWARM_DIR2, SPEC_FILE_NAME);
|
|
84398
|
+
if (!fs77.existsSync(specPath)) {
|
|
83296
84399
|
const result2 = {
|
|
83297
84400
|
valid: false,
|
|
83298
84401
|
specMtime: null,
|
|
@@ -83311,12 +84414,12 @@ var lint_spec = createSwarmTool({
|
|
|
83311
84414
|
}
|
|
83312
84415
|
let specMtime = null;
|
|
83313
84416
|
try {
|
|
83314
|
-
const stats =
|
|
84417
|
+
const stats = fs77.statSync(specPath);
|
|
83315
84418
|
specMtime = stats.mtime.toISOString();
|
|
83316
84419
|
} catch {}
|
|
83317
84420
|
let content;
|
|
83318
84421
|
try {
|
|
83319
|
-
content =
|
|
84422
|
+
content = fs77.readFileSync(specPath, "utf-8");
|
|
83320
84423
|
} catch (e) {
|
|
83321
84424
|
const result2 = {
|
|
83322
84425
|
valid: false,
|
|
@@ -83361,13 +84464,13 @@ var lint_spec = createSwarmTool({
|
|
|
83361
84464
|
});
|
|
83362
84465
|
// src/tools/mutation-test.ts
|
|
83363
84466
|
init_dist();
|
|
83364
|
-
import * as
|
|
83365
|
-
import * as
|
|
84467
|
+
import * as fs78 from "fs";
|
|
84468
|
+
import * as path94 from "path";
|
|
83366
84469
|
|
|
83367
84470
|
// src/mutation/engine.ts
|
|
83368
84471
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
83369
84472
|
import { unlinkSync as unlinkSync12, writeFileSync as writeFileSync18 } from "fs";
|
|
83370
|
-
import * as
|
|
84473
|
+
import * as path93 from "path";
|
|
83371
84474
|
|
|
83372
84475
|
// src/mutation/equivalence.ts
|
|
83373
84476
|
function isStaticallyEquivalent(originalCode, mutatedCode) {
|
|
@@ -83502,7 +84605,7 @@ async function executeMutation(patch, testCommand, _testFiles, workingDir) {
|
|
|
83502
84605
|
let patchFile;
|
|
83503
84606
|
try {
|
|
83504
84607
|
const safeId2 = patch.id.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
83505
|
-
patchFile =
|
|
84608
|
+
patchFile = path93.join(workingDir, `.mutation_patch_${safeId2}.diff`);
|
|
83506
84609
|
try {
|
|
83507
84610
|
writeFileSync18(patchFile, patch.patch);
|
|
83508
84611
|
} catch (writeErr) {
|
|
@@ -83896,8 +84999,8 @@ var mutation_test = createSwarmTool({
|
|
|
83896
84999
|
];
|
|
83897
85000
|
for (const filePath of uniquePaths) {
|
|
83898
85001
|
try {
|
|
83899
|
-
const resolvedPath =
|
|
83900
|
-
sourceFiles.set(filePath,
|
|
85002
|
+
const resolvedPath = path94.resolve(cwd, filePath);
|
|
85003
|
+
sourceFiles.set(filePath, fs78.readFileSync(resolvedPath, "utf-8"));
|
|
83901
85004
|
} catch {}
|
|
83902
85005
|
}
|
|
83903
85006
|
const report = await executeMutationSuite(typedArgs.patches, typedArgs.test_command, typedArgs.files, cwd, undefined, undefined, sourceFiles.size > 0 ? sourceFiles : undefined);
|
|
@@ -83915,8 +85018,8 @@ var mutation_test = createSwarmTool({
|
|
|
83915
85018
|
init_dist();
|
|
83916
85019
|
init_manager2();
|
|
83917
85020
|
init_detector();
|
|
83918
|
-
import * as
|
|
83919
|
-
import * as
|
|
85021
|
+
import * as fs79 from "fs";
|
|
85022
|
+
import * as path95 from "path";
|
|
83920
85023
|
init_create_tool();
|
|
83921
85024
|
var MAX_FILE_SIZE2 = 2 * 1024 * 1024;
|
|
83922
85025
|
var BINARY_CHECK_BYTES = 8192;
|
|
@@ -83982,7 +85085,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
83982
85085
|
if (languages?.length) {
|
|
83983
85086
|
const lowerLangs = languages.map((l) => l.toLowerCase());
|
|
83984
85087
|
filesToCheck = filesToCheck.filter((file3) => {
|
|
83985
|
-
const ext =
|
|
85088
|
+
const ext = path95.extname(file3.path).toLowerCase();
|
|
83986
85089
|
const langDef = getLanguageForExtension(ext);
|
|
83987
85090
|
const fileProfile = getProfileForFile(file3.path);
|
|
83988
85091
|
const langId = fileProfile?.id || langDef?.id;
|
|
@@ -83995,7 +85098,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
83995
85098
|
let skippedCount = 0;
|
|
83996
85099
|
for (const fileInfo of filesToCheck) {
|
|
83997
85100
|
const { path: filePath } = fileInfo;
|
|
83998
|
-
const fullPath =
|
|
85101
|
+
const fullPath = path95.isAbsolute(filePath) ? filePath : path95.join(directory, filePath);
|
|
83999
85102
|
const result = {
|
|
84000
85103
|
path: filePath,
|
|
84001
85104
|
language: "",
|
|
@@ -84025,7 +85128,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
84025
85128
|
}
|
|
84026
85129
|
let content;
|
|
84027
85130
|
try {
|
|
84028
|
-
content =
|
|
85131
|
+
content = fs79.readFileSync(fullPath, "utf8");
|
|
84029
85132
|
} catch {
|
|
84030
85133
|
result.skipped_reason = "file_read_error";
|
|
84031
85134
|
skippedCount++;
|
|
@@ -84044,7 +85147,7 @@ async function syntaxCheck(input, directory, config3) {
|
|
|
84044
85147
|
results.push(result);
|
|
84045
85148
|
continue;
|
|
84046
85149
|
}
|
|
84047
|
-
const ext =
|
|
85150
|
+
const ext = path95.extname(filePath).toLowerCase();
|
|
84048
85151
|
const langDef = getLanguageForExtension(ext);
|
|
84049
85152
|
result.language = profile?.id || langDef?.id || "unknown";
|
|
84050
85153
|
const errors5 = extractSyntaxErrors(parser, content);
|
|
@@ -84136,8 +85239,8 @@ init_dist();
|
|
|
84136
85239
|
init_utils();
|
|
84137
85240
|
init_create_tool();
|
|
84138
85241
|
init_path_security();
|
|
84139
|
-
import * as
|
|
84140
|
-
import * as
|
|
85242
|
+
import * as fs80 from "fs";
|
|
85243
|
+
import * as path96 from "path";
|
|
84141
85244
|
var MAX_TEXT_LENGTH = 200;
|
|
84142
85245
|
var MAX_FILE_SIZE_BYTES11 = 1024 * 1024;
|
|
84143
85246
|
var SUPPORTED_EXTENSIONS4 = new Set([
|
|
@@ -84203,9 +85306,9 @@ function validatePathsInput(paths, cwd) {
|
|
|
84203
85306
|
return { error: "paths contains path traversal", resolvedPath: null };
|
|
84204
85307
|
}
|
|
84205
85308
|
try {
|
|
84206
|
-
const resolvedPath =
|
|
84207
|
-
const normalizedCwd =
|
|
84208
|
-
const normalizedResolved =
|
|
85309
|
+
const resolvedPath = path96.resolve(paths);
|
|
85310
|
+
const normalizedCwd = path96.resolve(cwd);
|
|
85311
|
+
const normalizedResolved = path96.resolve(resolvedPath);
|
|
84209
85312
|
if (!normalizedResolved.startsWith(normalizedCwd)) {
|
|
84210
85313
|
return {
|
|
84211
85314
|
error: "paths must be within the current working directory",
|
|
@@ -84221,13 +85324,13 @@ function validatePathsInput(paths, cwd) {
|
|
|
84221
85324
|
}
|
|
84222
85325
|
}
|
|
84223
85326
|
function isSupportedExtension(filePath) {
|
|
84224
|
-
const ext =
|
|
85327
|
+
const ext = path96.extname(filePath).toLowerCase();
|
|
84225
85328
|
return SUPPORTED_EXTENSIONS4.has(ext);
|
|
84226
85329
|
}
|
|
84227
85330
|
function findSourceFiles4(dir, files = []) {
|
|
84228
85331
|
let entries;
|
|
84229
85332
|
try {
|
|
84230
|
-
entries =
|
|
85333
|
+
entries = fs80.readdirSync(dir);
|
|
84231
85334
|
} catch {
|
|
84232
85335
|
return files;
|
|
84233
85336
|
}
|
|
@@ -84236,16 +85339,16 @@ function findSourceFiles4(dir, files = []) {
|
|
|
84236
85339
|
if (SKIP_DIRECTORIES5.has(entry)) {
|
|
84237
85340
|
continue;
|
|
84238
85341
|
}
|
|
84239
|
-
const fullPath =
|
|
84240
|
-
let
|
|
85342
|
+
const fullPath = path96.join(dir, entry);
|
|
85343
|
+
let stat4;
|
|
84241
85344
|
try {
|
|
84242
|
-
|
|
85345
|
+
stat4 = fs80.statSync(fullPath);
|
|
84243
85346
|
} catch {
|
|
84244
85347
|
continue;
|
|
84245
85348
|
}
|
|
84246
|
-
if (
|
|
85349
|
+
if (stat4.isDirectory()) {
|
|
84247
85350
|
findSourceFiles4(fullPath, files);
|
|
84248
|
-
} else if (
|
|
85351
|
+
} else if (stat4.isFile()) {
|
|
84249
85352
|
if (isSupportedExtension(fullPath)) {
|
|
84250
85353
|
files.push(fullPath);
|
|
84251
85354
|
}
|
|
@@ -84332,7 +85435,7 @@ var todo_extract = createSwarmTool({
|
|
|
84332
85435
|
return JSON.stringify(errorResult, null, 2);
|
|
84333
85436
|
}
|
|
84334
85437
|
const scanPath = resolvedPath;
|
|
84335
|
-
if (!
|
|
85438
|
+
if (!fs80.existsSync(scanPath)) {
|
|
84336
85439
|
const errorResult = {
|
|
84337
85440
|
error: `path not found: ${pathsInput}`,
|
|
84338
85441
|
total: 0,
|
|
@@ -84342,13 +85445,13 @@ var todo_extract = createSwarmTool({
|
|
|
84342
85445
|
return JSON.stringify(errorResult, null, 2);
|
|
84343
85446
|
}
|
|
84344
85447
|
const filesToScan = [];
|
|
84345
|
-
const
|
|
84346
|
-
if (
|
|
85448
|
+
const stat4 = fs80.statSync(scanPath);
|
|
85449
|
+
if (stat4.isFile()) {
|
|
84347
85450
|
if (isSupportedExtension(scanPath)) {
|
|
84348
85451
|
filesToScan.push(scanPath);
|
|
84349
85452
|
} else {
|
|
84350
85453
|
const errorResult = {
|
|
84351
|
-
error: `unsupported file extension: ${
|
|
85454
|
+
error: `unsupported file extension: ${path96.extname(scanPath)}`,
|
|
84352
85455
|
total: 0,
|
|
84353
85456
|
byPriority: { high: 0, medium: 0, low: 0 },
|
|
84354
85457
|
entries: []
|
|
@@ -84361,11 +85464,11 @@ var todo_extract = createSwarmTool({
|
|
|
84361
85464
|
const allEntries = [];
|
|
84362
85465
|
for (const filePath of filesToScan) {
|
|
84363
85466
|
try {
|
|
84364
|
-
const fileStat =
|
|
85467
|
+
const fileStat = fs80.statSync(filePath);
|
|
84365
85468
|
if (fileStat.size > MAX_FILE_SIZE_BYTES11) {
|
|
84366
85469
|
continue;
|
|
84367
85470
|
}
|
|
84368
|
-
const content =
|
|
85471
|
+
const content = fs80.readFileSync(filePath, "utf-8");
|
|
84369
85472
|
const entries = parseTodoComments(content, filePath, tagsSet);
|
|
84370
85473
|
allEntries.push(...entries);
|
|
84371
85474
|
} catch {}
|
|
@@ -84395,18 +85498,18 @@ init_tool();
|
|
|
84395
85498
|
init_loader();
|
|
84396
85499
|
init_schema();
|
|
84397
85500
|
init_gate_evidence();
|
|
84398
|
-
import * as
|
|
84399
|
-
import * as
|
|
85501
|
+
import * as fs82 from "fs";
|
|
85502
|
+
import * as path98 from "path";
|
|
84400
85503
|
|
|
84401
85504
|
// src/hooks/diff-scope.ts
|
|
84402
|
-
import * as
|
|
84403
|
-
import * as
|
|
85505
|
+
import * as fs81 from "fs";
|
|
85506
|
+
import * as path97 from "path";
|
|
84404
85507
|
function getDeclaredScope(taskId, directory) {
|
|
84405
85508
|
try {
|
|
84406
|
-
const planPath =
|
|
84407
|
-
if (!
|
|
85509
|
+
const planPath = path97.join(directory, ".swarm", "plan.json");
|
|
85510
|
+
if (!fs81.existsSync(planPath))
|
|
84408
85511
|
return null;
|
|
84409
|
-
const raw =
|
|
85512
|
+
const raw = fs81.readFileSync(planPath, "utf-8");
|
|
84410
85513
|
const plan = JSON.parse(raw);
|
|
84411
85514
|
for (const phase of plan.phases ?? []) {
|
|
84412
85515
|
for (const task of phase.tasks ?? []) {
|
|
@@ -84522,7 +85625,7 @@ var TIER_3_PATTERNS = [
|
|
|
84522
85625
|
];
|
|
84523
85626
|
function matchesTier3Pattern(files) {
|
|
84524
85627
|
for (const file3 of files) {
|
|
84525
|
-
const fileName =
|
|
85628
|
+
const fileName = path98.basename(file3);
|
|
84526
85629
|
for (const pattern of TIER_3_PATTERNS) {
|
|
84527
85630
|
if (pattern.test(fileName)) {
|
|
84528
85631
|
return true;
|
|
@@ -84536,8 +85639,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
84536
85639
|
if (hasActiveTurboMode()) {
|
|
84537
85640
|
const resolvedDir2 = workingDirectory;
|
|
84538
85641
|
try {
|
|
84539
|
-
const planPath =
|
|
84540
|
-
const planRaw =
|
|
85642
|
+
const planPath = path98.join(resolvedDir2, ".swarm", "plan.json");
|
|
85643
|
+
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
84541
85644
|
const plan = JSON.parse(planRaw);
|
|
84542
85645
|
for (const planPhase of plan.phases ?? []) {
|
|
84543
85646
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -84606,8 +85709,8 @@ function checkReviewerGate(taskId, workingDirectory, stageBParallelEnabled = fal
|
|
|
84606
85709
|
}
|
|
84607
85710
|
try {
|
|
84608
85711
|
const resolvedDir2 = workingDirectory;
|
|
84609
|
-
const planPath =
|
|
84610
|
-
const planRaw =
|
|
85712
|
+
const planPath = path98.join(resolvedDir2, ".swarm", "plan.json");
|
|
85713
|
+
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
84611
85714
|
const plan = JSON.parse(planRaw);
|
|
84612
85715
|
for (const planPhase of plan.phases ?? []) {
|
|
84613
85716
|
for (const task of planPhase.tasks ?? []) {
|
|
@@ -84831,8 +85934,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
84831
85934
|
};
|
|
84832
85935
|
}
|
|
84833
85936
|
}
|
|
84834
|
-
normalizedDir =
|
|
84835
|
-
const pathParts = normalizedDir.split(
|
|
85937
|
+
normalizedDir = path98.normalize(args2.working_directory);
|
|
85938
|
+
const pathParts = normalizedDir.split(path98.sep);
|
|
84836
85939
|
if (pathParts.includes("..")) {
|
|
84837
85940
|
return {
|
|
84838
85941
|
success: false,
|
|
@@ -84842,11 +85945,11 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
84842
85945
|
]
|
|
84843
85946
|
};
|
|
84844
85947
|
}
|
|
84845
|
-
const resolvedDir =
|
|
85948
|
+
const resolvedDir = path98.resolve(normalizedDir);
|
|
84846
85949
|
try {
|
|
84847
|
-
const realPath =
|
|
84848
|
-
const planPath =
|
|
84849
|
-
if (!
|
|
85950
|
+
const realPath = fs82.realpathSync(resolvedDir);
|
|
85951
|
+
const planPath = path98.join(realPath, ".swarm", "plan.json");
|
|
85952
|
+
if (!fs82.existsSync(planPath)) {
|
|
84850
85953
|
return {
|
|
84851
85954
|
success: false,
|
|
84852
85955
|
message: `Invalid working_directory: plan not found in "${realPath}"`,
|
|
@@ -84877,22 +85980,22 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
84877
85980
|
}
|
|
84878
85981
|
if (args2.status === "in_progress") {
|
|
84879
85982
|
try {
|
|
84880
|
-
const evidencePath =
|
|
84881
|
-
|
|
84882
|
-
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");
|
|
84883
85986
|
let writeOk = false;
|
|
84884
85987
|
try {
|
|
84885
|
-
|
|
85988
|
+
fs82.writeSync(fd, JSON.stringify({
|
|
84886
85989
|
taskId: args2.task_id,
|
|
84887
85990
|
required_gates: ["reviewer", "test_engineer"],
|
|
84888
85991
|
gates: {}
|
|
84889
85992
|
}, null, 2));
|
|
84890
85993
|
writeOk = true;
|
|
84891
85994
|
} finally {
|
|
84892
|
-
|
|
85995
|
+
fs82.closeSync(fd);
|
|
84893
85996
|
if (!writeOk) {
|
|
84894
85997
|
try {
|
|
84895
|
-
|
|
85998
|
+
fs82.unlinkSync(evidencePath);
|
|
84896
85999
|
} catch {}
|
|
84897
86000
|
}
|
|
84898
86001
|
}
|
|
@@ -84902,8 +86005,8 @@ async function executeUpdateTaskStatus(args2, fallbackDir) {
|
|
|
84902
86005
|
recoverTaskStateFromDelegations(args2.task_id);
|
|
84903
86006
|
let phaseRequiresReviewer = true;
|
|
84904
86007
|
try {
|
|
84905
|
-
const planPath =
|
|
84906
|
-
const planRaw =
|
|
86008
|
+
const planPath = path98.join(directory, ".swarm", "plan.json");
|
|
86009
|
+
const planRaw = fs82.readFileSync(planPath, "utf-8");
|
|
84907
86010
|
const plan = JSON.parse(planRaw);
|
|
84908
86011
|
const taskPhase = plan.phases.find((p) => p.tasks.some((t) => t.id === args2.task_id));
|
|
84909
86012
|
if (taskPhase?.required_agents && !taskPhase.required_agents.includes("reviewer")) {
|
|
@@ -85012,8 +86115,8 @@ init_utils2();
|
|
|
85012
86115
|
init_ledger();
|
|
85013
86116
|
init_manager();
|
|
85014
86117
|
init_create_tool();
|
|
85015
|
-
import
|
|
85016
|
-
import
|
|
86118
|
+
import fs83 from "fs";
|
|
86119
|
+
import path99 from "path";
|
|
85017
86120
|
function derivePlanId5(plan) {
|
|
85018
86121
|
return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
85019
86122
|
}
|
|
@@ -85064,7 +86167,7 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
85064
86167
|
entries: [evidenceEntry]
|
|
85065
86168
|
};
|
|
85066
86169
|
const filename = "drift-verifier.json";
|
|
85067
|
-
const relativePath =
|
|
86170
|
+
const relativePath = path99.join("evidence", String(phase), filename);
|
|
85068
86171
|
let validatedPath;
|
|
85069
86172
|
try {
|
|
85070
86173
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -85075,12 +86178,12 @@ async function executeWriteDriftEvidence(args2, directory) {
|
|
|
85075
86178
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
85076
86179
|
}, null, 2);
|
|
85077
86180
|
}
|
|
85078
|
-
const evidenceDir =
|
|
86181
|
+
const evidenceDir = path99.dirname(validatedPath);
|
|
85079
86182
|
try {
|
|
85080
|
-
await
|
|
85081
|
-
const tempPath =
|
|
85082
|
-
await
|
|
85083
|
-
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);
|
|
85084
86187
|
let snapshotInfo;
|
|
85085
86188
|
let snapshotError;
|
|
85086
86189
|
let qaProfileLocked;
|
|
@@ -85174,8 +86277,8 @@ var write_drift_evidence = createSwarmTool({
|
|
|
85174
86277
|
init_tool();
|
|
85175
86278
|
init_utils2();
|
|
85176
86279
|
init_create_tool();
|
|
85177
|
-
import
|
|
85178
|
-
import
|
|
86280
|
+
import fs84 from "fs";
|
|
86281
|
+
import path100 from "path";
|
|
85179
86282
|
function normalizeVerdict2(verdict) {
|
|
85180
86283
|
switch (verdict) {
|
|
85181
86284
|
case "APPROVED":
|
|
@@ -85223,7 +86326,7 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
85223
86326
|
entries: [evidenceEntry]
|
|
85224
86327
|
};
|
|
85225
86328
|
const filename = "hallucination-guard.json";
|
|
85226
|
-
const relativePath =
|
|
86329
|
+
const relativePath = path100.join("evidence", String(phase), filename);
|
|
85227
86330
|
let validatedPath;
|
|
85228
86331
|
try {
|
|
85229
86332
|
validatedPath = validateSwarmPath(directory, relativePath);
|
|
@@ -85234,12 +86337,12 @@ async function executeWriteHallucinationEvidence(args2, directory) {
|
|
|
85234
86337
|
message: error93 instanceof Error ? error93.message : "Failed to validate path"
|
|
85235
86338
|
}, null, 2);
|
|
85236
86339
|
}
|
|
85237
|
-
const evidenceDir =
|
|
86340
|
+
const evidenceDir = path100.dirname(validatedPath);
|
|
85238
86341
|
try {
|
|
85239
|
-
await
|
|
85240
|
-
const tempPath =
|
|
85241
|
-
await
|
|
85242
|
-
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);
|
|
85243
86346
|
return JSON.stringify({
|
|
85244
86347
|
success: true,
|
|
85245
86348
|
phase,
|
|
@@ -85346,6 +86449,11 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
85346
86449
|
const contextBudgetHandler = createContextBudgetHandler(config3);
|
|
85347
86450
|
const commandHandler = createSwarmCommandHandler(ctx.directory, Object.fromEntries(agentDefinitions.map((agent) => [agent.name, agent])));
|
|
85348
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);
|
|
85349
86457
|
const delegationGateHooks = createDelegationGateHook(config3, ctx.directory);
|
|
85350
86458
|
const delegationSanitizerHook = createDelegationSanitizerHook(ctx.directory);
|
|
85351
86459
|
const guardrailsFallback = config3.guardrails?.enabled === false ? { ...config3.guardrails, enabled: false } : config3.guardrails ?? {};
|
|
@@ -85448,7 +86556,7 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
85448
86556
|
const { PreflightTriggerManager: PTM } = await Promise.resolve().then(() => (init_trigger(), exports_trigger));
|
|
85449
86557
|
preflightTriggerManager = new PTM(automationConfig);
|
|
85450
86558
|
const { AutomationStatusArtifact: ASA } = await Promise.resolve().then(() => (init_status_artifact(), exports_status_artifact));
|
|
85451
|
-
const swarmDir =
|
|
86559
|
+
const swarmDir = path101.resolve(ctx.directory, ".swarm");
|
|
85452
86560
|
statusArtifact = new ASA(swarmDir);
|
|
85453
86561
|
statusArtifact.updateConfig(automationConfig.mode, automationConfig.capabilities);
|
|
85454
86562
|
if (automationConfig.capabilities?.evidence_auto_summaries === true) {
|
|
@@ -85868,6 +86976,10 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
85868
86976
|
await activityHooks.toolAfter(input, output);
|
|
85869
86977
|
if (_dbg)
|
|
85870
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);
|
|
85871
86983
|
await guardrailsHooks.toolAfter(input, output);
|
|
85872
86984
|
if (_dbg)
|
|
85873
86985
|
console.error(`[DIAG] toolAfter guardrails done tool=${_toolName}`);
|
|
@@ -85897,12 +87009,12 @@ var OpenCodeSwarm = async (ctx) => {
|
|
|
85897
87009
|
} catch {}
|
|
85898
87010
|
}
|
|
85899
87011
|
try {
|
|
85900
|
-
recordToolCall(normalizedTool, input.args);
|
|
87012
|
+
recordToolCall(normalizedTool, input.args, input.sessionID);
|
|
85901
87013
|
} catch {}
|
|
85902
87014
|
try {
|
|
85903
|
-
const spiralMatch = await detectDebuggingSpiral(ctx.directory);
|
|
87015
|
+
const spiralMatch = await detectDebuggingSpiral(ctx.directory, input.sessionID);
|
|
85904
87016
|
if (spiralMatch) {
|
|
85905
|
-
const taskId = swarmState.agentSessions.get(input.sessionID)?.currentTaskId ??
|
|
87017
|
+
const taskId = swarmState.agentSessions.get(input.sessionID)?.currentTaskId ?? `session-${input.sessionID.slice(0, 12)}`;
|
|
85906
87018
|
const spiralResult = await handleDebuggingSpiral(spiralMatch, taskId, ctx.directory);
|
|
85907
87019
|
const session = swarmState.agentSessions.get(input.sessionID);
|
|
85908
87020
|
if (session) {
|