opencode-swarm 7.66.2 → 7.67.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 +4 -0
- package/dist/agents/index.d.ts +14 -1
- package/dist/background/event-bus.d.ts +1 -1
- package/dist/background/index.d.ts +2 -0
- package/dist/background/pr-event-subscribers.d.ts +46 -0
- package/dist/background/pr-monitor-worker.d.ts +154 -0
- package/dist/background/pr-subscriptions.d.ts +115 -0
- package/dist/cli/index.js +893 -472
- package/dist/commands/pr-monitor-status.d.ts +36 -0
- package/dist/commands/pr-subscribe.d.ts +33 -0
- package/dist/commands/pr-unsubscribe.d.ts +32 -0
- package/dist/commands/registry.d.ts +21 -0
- package/dist/config/schema.d.ts +37 -0
- package/dist/git/pr.d.ts +80 -0
- package/dist/hooks/guardrails.d.ts +2 -1
- package/dist/index.js +3706 -2270
- package/dist/state.d.ts +25 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -52,7 +52,7 @@ var package_default;
|
|
|
52
52
|
var init_package = __esm(() => {
|
|
53
53
|
package_default = {
|
|
54
54
|
name: "opencode-swarm",
|
|
55
|
-
version: "7.
|
|
55
|
+
version: "7.67.0",
|
|
56
56
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
57
57
|
main: "dist/index.js",
|
|
58
58
|
types: "dist/index.d.ts",
|
|
@@ -17968,7 +17968,7 @@ function resolveExternalSkillsConfig(input) {
|
|
|
17968
17968
|
};
|
|
17969
17969
|
return merged;
|
|
17970
17970
|
}
|
|
17971
|
-
var SEPARATORS, CANONICAL_ROLES_LONGEST_FIRST, CANONICAL_ROLES_SET, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, DesignDocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, ContextMapConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, MemoryConfigSchema, CuratorConfigSchema, ArchitecturalSupervisionConfigSchema, KnowledgeApplicationConfigSchema, SkillPropagationConfigSchema, SkillImproverConfigSchema, SpecWriterConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PrmConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, GeneralCouncilMemberConfigSchema, GeneralCouncilConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, WorktreeIsolationConfigSchema, LeanTurboConfigSchema, StandardTurboConfigSchema, LeanTurboStrategyConfigSchema, TurboConfigSchema, ExternalSkillCandidateSourceTypeSchema, ExternalSkillCandidateEvaluationVerdictSchema, DiscoverySourceSchema, ExternalSkillCandidateSchema, ExternalSkillsConfigSchema, DEFAULT_EXTERNAL_SKILLS_CONFIG, PluginConfigSchema;
|
|
17971
|
+
var SEPARATORS, CANONICAL_ROLES_LONGEST_FIRST, CANONICAL_ROLES_SET, AgentOverrideConfigSchema, SwarmConfigSchema, HooksConfigSchema, ScoringWeightsSchema, DecisionDecaySchema, TokenRatiosSchema, ScoringConfigSchema, ContextBudgetConfigSchema, EvidenceConfigSchema, GateFeatureSchema, PlaceholderScanConfigSchema, QualityBudgetConfigSchema, GateConfigSchema, PipelineConfigSchema, PhaseCompleteConfigSchema, SummaryConfigSchema, ReviewPassesConfigSchema, AdversarialDetectionConfigSchema, AdversarialTestingConfigSchemaBase, AdversarialTestingConfigSchema, IntegrationAnalysisConfigSchema, DocsConfigSchema, DesignDocsConfigSchema, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, ContextMapConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, MemoryConfigSchema, CuratorConfigSchema, ArchitecturalSupervisionConfigSchema, KnowledgeApplicationConfigSchema, SkillPropagationConfigSchema, SkillImproverConfigSchema, SpecWriterConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PrmConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, GeneralCouncilMemberConfigSchema, GeneralCouncilConfigSchema, CouncilConfigSchema, PrMonitorConfigSchema, ParallelizationConfigSchema, WorktreeIsolationConfigSchema, LeanTurboConfigSchema, StandardTurboConfigSchema, LeanTurboStrategyConfigSchema, TurboConfigSchema, ExternalSkillCandidateSourceTypeSchema, ExternalSkillCandidateEvaluationVerdictSchema, DiscoverySourceSchema, ExternalSkillCandidateSchema, ExternalSkillsConfigSchema, DEFAULT_EXTERNAL_SKILLS_CONFIG, PluginConfigSchema;
|
|
17972
17972
|
var init_schema = __esm(() => {
|
|
17973
17973
|
init_zod();
|
|
17974
17974
|
init_constants();
|
|
@@ -18647,6 +18647,24 @@ var init_schema = __esm(() => {
|
|
|
18647
18647
|
phaseConcernsAllowComplete: exports_external.boolean().default(true).describe("When true, a phase-level council CONCERNS verdict with only MEDIUM/LOW findings does NOT block phase completion \u2014 the advisory notes are logged as warnings and the phase proceeds. When false, CONCERNS blocks like REJECT. Note: HIGH/CRITICAL findings from CONCERNS members are always promoted to requiredFixes and block at the tool level regardless of this setting. Default: true."),
|
|
18648
18648
|
general: GeneralCouncilConfigSchema.optional()
|
|
18649
18649
|
}).strict();
|
|
18650
|
+
PrMonitorConfigSchema = exports_external.object({
|
|
18651
|
+
enabled: exports_external.boolean().default(false),
|
|
18652
|
+
poll_interval_seconds: exports_external.number().int().min(30).max(300).default(60),
|
|
18653
|
+
max_subscriptions: exports_external.number().int().min(1).max(100).default(20),
|
|
18654
|
+
max_prs_per_cycle: exports_external.number().int().min(1).max(20).default(5),
|
|
18655
|
+
max_concurrent_pr_polls: exports_external.number().int().min(1).max(10).default(3),
|
|
18656
|
+
poll_timeout_ms: exports_external.number().int().min(5000).max(120000).default(30000),
|
|
18657
|
+
failure_threshold: exports_external.number().int().min(1).max(20).default(5),
|
|
18658
|
+
cooldown_seconds: exports_external.number().int().min(5).max(600).default(30),
|
|
18659
|
+
max_cooldown_seconds: exports_external.number().int().min(30).max(3600).default(300),
|
|
18660
|
+
cleanup_ttl_days: exports_external.number().int().min(1).max(90).default(7),
|
|
18661
|
+
auto_unsubscribe_on_merge: exports_external.boolean().default(true),
|
|
18662
|
+
auto_unsubscribe_on_close: exports_external.boolean().default(true),
|
|
18663
|
+
notify_ci_failure: exports_external.boolean().default(true),
|
|
18664
|
+
notify_new_comments: exports_external.boolean().default(true),
|
|
18665
|
+
notify_merge_conflict: exports_external.boolean().default(true),
|
|
18666
|
+
auto_pr_feedback: exports_external.boolean().default(false)
|
|
18667
|
+
}).strict();
|
|
18650
18668
|
ParallelizationConfigSchema = exports_external.object({
|
|
18651
18669
|
enabled: exports_external.boolean().default(false),
|
|
18652
18670
|
maxConcurrentTasks: exports_external.number().int().min(1).max(64).default(1),
|
|
@@ -18788,7 +18806,7 @@ var init_schema = __esm(() => {
|
|
|
18788
18806
|
const trimmed = v.trim();
|
|
18789
18807
|
return trimmed === "" ? false : trimmed;
|
|
18790
18808
|
}),
|
|
18791
|
-
swarms: exports_external.record(exports_external.string(), SwarmConfigSchema).optional(),
|
|
18809
|
+
swarms: exports_external.record(exports_external.string().regex(/^[^_]+$/, "Swarm ID must not contain underscores"), SwarmConfigSchema).optional(),
|
|
18792
18810
|
max_iterations: exports_external.number().min(1).max(10).default(5),
|
|
18793
18811
|
pipeline: PipelineConfigSchema.optional(),
|
|
18794
18812
|
phase_complete: PhaseCompleteConfigSchema.optional(),
|
|
@@ -18991,6 +19009,7 @@ var init_schema = __esm(() => {
|
|
|
18991
19009
|
every_minutes: 20
|
|
18992
19010
|
}
|
|
18993
19011
|
})),
|
|
19012
|
+
pr_monitor: PrMonitorConfigSchema.optional(),
|
|
18994
19013
|
external_skills: ExternalSkillsConfigSchema.optional()
|
|
18995
19014
|
});
|
|
18996
19015
|
});
|
|
@@ -22299,7 +22318,7 @@ var init_docs = () => {};
|
|
|
22299
22318
|
// src/agents/reviewer.ts
|
|
22300
22319
|
var init_reviewer = () => {};
|
|
22301
22320
|
// src/agents/index.ts
|
|
22302
|
-
var warnedAgents, KNOWN_VARIANT_VALUES;
|
|
22321
|
+
var warnedAgents, _swarmAgentsMap, KNOWN_VARIANT_VALUES;
|
|
22303
22322
|
var init_agents2 = __esm(() => {
|
|
22304
22323
|
init_config();
|
|
22305
22324
|
init_constants();
|
|
@@ -22318,6 +22337,7 @@ var init_agents2 = __esm(() => {
|
|
|
22318
22337
|
init_docs();
|
|
22319
22338
|
init_reviewer();
|
|
22320
22339
|
warnedAgents = new Set;
|
|
22340
|
+
_swarmAgentsMap = new Map;
|
|
22321
22341
|
KNOWN_VARIANT_VALUES = new Set([
|
|
22322
22342
|
"low",
|
|
22323
22343
|
"medium",
|
|
@@ -53493,6 +53513,217 @@ var init_pr_feedback = __esm(() => {
|
|
|
53493
53513
|
init_pr_ref();
|
|
53494
53514
|
});
|
|
53495
53515
|
|
|
53516
|
+
// src/background/pr-subscriptions.ts
|
|
53517
|
+
import * as fs17 from "fs";
|
|
53518
|
+
import * as path43 from "path";
|
|
53519
|
+
function storePath(directory) {
|
|
53520
|
+
return validateSwarmPath(directory, PR_SUBSCRIPTIONS_FILE);
|
|
53521
|
+
}
|
|
53522
|
+
function ensureSwarmDir2(directory) {
|
|
53523
|
+
fs17.mkdirSync(path43.resolve(directory, ".swarm", "pr-monitor"), {
|
|
53524
|
+
recursive: true
|
|
53525
|
+
});
|
|
53526
|
+
}
|
|
53527
|
+
function buildCorrelationId(sessionID, repoFullName, prNumber) {
|
|
53528
|
+
return `${sessionID}::${repoFullName}::${prNumber}`;
|
|
53529
|
+
}
|
|
53530
|
+
function readAllRecords(directory) {
|
|
53531
|
+
let raw;
|
|
53532
|
+
try {
|
|
53533
|
+
raw = fs17.readFileSync(storePath(directory), "utf-8");
|
|
53534
|
+
} catch (err) {
|
|
53535
|
+
if (err.code === "ENOENT")
|
|
53536
|
+
return [];
|
|
53537
|
+
log(`[pr-monitor] readAllRecords failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
53538
|
+
return [];
|
|
53539
|
+
}
|
|
53540
|
+
const folded = new Map;
|
|
53541
|
+
for (const line of raw.split(`
|
|
53542
|
+
`)) {
|
|
53543
|
+
const trimmed = line.trim();
|
|
53544
|
+
if (trimmed.length === 0)
|
|
53545
|
+
continue;
|
|
53546
|
+
let parsedJson;
|
|
53547
|
+
try {
|
|
53548
|
+
parsedJson = JSON.parse(trimmed);
|
|
53549
|
+
} catch {
|
|
53550
|
+
continue;
|
|
53551
|
+
}
|
|
53552
|
+
const result = RecordSchema.safeParse(parsedJson);
|
|
53553
|
+
if (!result.success)
|
|
53554
|
+
continue;
|
|
53555
|
+
folded.set(result.data.correlationId, result.data);
|
|
53556
|
+
}
|
|
53557
|
+
return [...folded.values()];
|
|
53558
|
+
}
|
|
53559
|
+
function appendRecord(directory, record3) {
|
|
53560
|
+
const result = RecordSchema.safeParse(record3);
|
|
53561
|
+
if (!result.success) {
|
|
53562
|
+
throw new Error(`Invalid subscription record: ${result.error.message}`);
|
|
53563
|
+
}
|
|
53564
|
+
ensureSwarmDir2(directory);
|
|
53565
|
+
fs17.appendFileSync(storePath(directory), `${JSON.stringify(record3)}
|
|
53566
|
+
`, "utf-8");
|
|
53567
|
+
}
|
|
53568
|
+
async function subscribe(directory, input) {
|
|
53569
|
+
if (!directory || directory.trim() === "") {
|
|
53570
|
+
throw new Error("directory is required");
|
|
53571
|
+
}
|
|
53572
|
+
if (!input.sessionID || input.sessionID.trim() === "") {
|
|
53573
|
+
throw new Error("sessionID is required and must be non-empty");
|
|
53574
|
+
}
|
|
53575
|
+
if (!input.repoFullName || input.repoFullName.trim() === "") {
|
|
53576
|
+
throw new Error("repoFullName is required and must be non-empty");
|
|
53577
|
+
}
|
|
53578
|
+
if (!input.prUrl || input.prUrl.trim() === "") {
|
|
53579
|
+
throw new Error("prUrl is required and must be non-empty");
|
|
53580
|
+
}
|
|
53581
|
+
if (!input.prNumber || !Number.isInteger(input.prNumber) || input.prNumber <= 0) {
|
|
53582
|
+
throw new Error("prNumber is required and must be a positive integer");
|
|
53583
|
+
}
|
|
53584
|
+
const correlationId = buildCorrelationId(input.sessionID, input.repoFullName, input.prNumber);
|
|
53585
|
+
const now = Date.now();
|
|
53586
|
+
return withEvidenceLock(directory, PR_SUBSCRIPTIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
|
|
53587
|
+
const existing = readAllRecords(directory);
|
|
53588
|
+
const match = existing.find((r) => r.correlationId === correlationId && r.status === "active");
|
|
53589
|
+
if (match) {
|
|
53590
|
+
onSubscriptionCreated?.(directory, match);
|
|
53591
|
+
return match;
|
|
53592
|
+
}
|
|
53593
|
+
if (input.maxSubscriptions !== undefined && input.maxSubscriptions > 0) {
|
|
53594
|
+
const activeCount = existing.filter((r) => r.status === "active").length;
|
|
53595
|
+
if (activeCount >= input.maxSubscriptions) {
|
|
53596
|
+
throw new Error(`PR subscription limit reached: ${activeCount}/${input.maxSubscriptions}`);
|
|
53597
|
+
}
|
|
53598
|
+
}
|
|
53599
|
+
const record3 = {
|
|
53600
|
+
correlationId,
|
|
53601
|
+
sessionID: input.sessionID,
|
|
53602
|
+
prNumber: input.prNumber,
|
|
53603
|
+
repoFullName: input.repoFullName,
|
|
53604
|
+
prUrl: input.prUrl,
|
|
53605
|
+
lastCheckedAt: now,
|
|
53606
|
+
isWatching: true,
|
|
53607
|
+
hasUnaddressedEvents: false,
|
|
53608
|
+
status: "active",
|
|
53609
|
+
createdAt: now,
|
|
53610
|
+
updatedAt: now,
|
|
53611
|
+
errorCount: 0
|
|
53612
|
+
};
|
|
53613
|
+
appendRecord(directory, record3);
|
|
53614
|
+
onSubscriptionCreated?.(directory, record3);
|
|
53615
|
+
return record3;
|
|
53616
|
+
});
|
|
53617
|
+
}
|
|
53618
|
+
async function unsubscribe(directory, correlationId) {
|
|
53619
|
+
if (!correlationId)
|
|
53620
|
+
return null;
|
|
53621
|
+
return withEvidenceLock(directory, PR_SUBSCRIPTIONS_FILE, STORE_LOCK_AGENT, STORE_LOCK_TASK, async () => {
|
|
53622
|
+
const existing = readAllRecords(directory);
|
|
53623
|
+
const match = existing.find((r) => r.correlationId === correlationId && r.status === "active");
|
|
53624
|
+
if (!match)
|
|
53625
|
+
return null;
|
|
53626
|
+
const now = Date.now();
|
|
53627
|
+
const removed = {
|
|
53628
|
+
...match,
|
|
53629
|
+
status: "removed",
|
|
53630
|
+
isWatching: false,
|
|
53631
|
+
updatedAt: now
|
|
53632
|
+
};
|
|
53633
|
+
appendRecord(directory, removed);
|
|
53634
|
+
return removed;
|
|
53635
|
+
});
|
|
53636
|
+
}
|
|
53637
|
+
async function listActive(directory) {
|
|
53638
|
+
return readAllRecords(directory).filter((r) => r.status === "active");
|
|
53639
|
+
}
|
|
53640
|
+
var PR_SUBSCRIPTIONS_FILE = "pr-monitor/subscriptions.jsonl", STORE_LOCK_AGENT = "pr-monitor", STORE_LOCK_TASK = "pr-subscriptions", onSubscriptionCreated = null, RecordSchema;
|
|
53641
|
+
var init_pr_subscriptions = __esm(() => {
|
|
53642
|
+
init_zod();
|
|
53643
|
+
init_lock();
|
|
53644
|
+
init_utils2();
|
|
53645
|
+
init_utils();
|
|
53646
|
+
RecordSchema = exports_external.object({
|
|
53647
|
+
correlationId: exports_external.string().min(1),
|
|
53648
|
+
sessionID: exports_external.string().min(1),
|
|
53649
|
+
prNumber: exports_external.number().int().positive(),
|
|
53650
|
+
repoFullName: exports_external.string().regex(/^[^/]+\/[^/]+$/, "Must be owner/repo format"),
|
|
53651
|
+
prUrl: exports_external.string().min(1).regex(/^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+$/, "Must be a valid GitHub PR URL"),
|
|
53652
|
+
headRefOid: exports_external.string().optional(),
|
|
53653
|
+
lastCheckedAt: exports_external.number(),
|
|
53654
|
+
lastCommentId: exports_external.string().optional(),
|
|
53655
|
+
lastCheckRunSet: exports_external.string().optional(),
|
|
53656
|
+
mergeableState: exports_external.string().optional(),
|
|
53657
|
+
isWatching: exports_external.boolean(),
|
|
53658
|
+
hasUnaddressedEvents: exports_external.boolean(),
|
|
53659
|
+
status: exports_external.enum(["active", "removed", "expired"]),
|
|
53660
|
+
createdAt: exports_external.number(),
|
|
53661
|
+
updatedAt: exports_external.number(),
|
|
53662
|
+
errorCount: exports_external.number().int().min(0),
|
|
53663
|
+
customPollIntervalSeconds: exports_external.number().int().positive().optional(),
|
|
53664
|
+
customFailureThreshold: exports_external.number().int().min(0).optional(),
|
|
53665
|
+
customCooldownSeconds: exports_external.number().int().min(0).optional()
|
|
53666
|
+
}).strict();
|
|
53667
|
+
});
|
|
53668
|
+
|
|
53669
|
+
// src/commands/pr-monitor-status.ts
|
|
53670
|
+
function formatRelativeTime(epochMs) {
|
|
53671
|
+
const diffMs = Date.now() - epochMs;
|
|
53672
|
+
if (diffMs < 0)
|
|
53673
|
+
return "just now";
|
|
53674
|
+
if (diffMs < 5000)
|
|
53675
|
+
return "just now";
|
|
53676
|
+
const diffSeconds = Math.floor(diffMs / 1000);
|
|
53677
|
+
if (diffSeconds < 60)
|
|
53678
|
+
return `${diffSeconds} seconds ago`;
|
|
53679
|
+
const diffMinutes = Math.floor(diffSeconds / 60);
|
|
53680
|
+
if (diffMinutes < 60)
|
|
53681
|
+
return `${diffMinutes} minute${diffMinutes === 1 ? "" : "s"} ago`;
|
|
53682
|
+
const diffHours = Math.floor(diffMinutes / 60);
|
|
53683
|
+
if (diffHours < 24)
|
|
53684
|
+
return `${diffHours} hour${diffHours === 1 ? "" : "s"} ago`;
|
|
53685
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
53686
|
+
return `${diffDays} day${diffDays === 1 ? "" : "s"} ago`;
|
|
53687
|
+
}
|
|
53688
|
+
async function handlePrMonitorStatusCommand(directory, _args, sessionID) {
|
|
53689
|
+
const allActive = await _internals26.listActive(directory);
|
|
53690
|
+
const sessionSubs = allActive.filter((record3) => record3.sessionID === sessionID);
|
|
53691
|
+
if (sessionSubs.length === 0) {
|
|
53692
|
+
return "No active PR subscriptions for this session.";
|
|
53693
|
+
}
|
|
53694
|
+
const lines = [];
|
|
53695
|
+
lines.push(`PR Monitor Status \u2014 Session: ${sessionID}`);
|
|
53696
|
+
lines.push("");
|
|
53697
|
+
const totalActive = allActive.length;
|
|
53698
|
+
lines.push(`Active subscriptions (${sessionSubs.length}):`);
|
|
53699
|
+
for (let i = 0;i < sessionSubs.length; i++) {
|
|
53700
|
+
const sub = sessionSubs[i];
|
|
53701
|
+
const index = i + 1;
|
|
53702
|
+
lines.push(` ${index}. ${sub.repoFullName}#${sub.prNumber}`);
|
|
53703
|
+
lines.push(` URL: ${sub.prUrl}`);
|
|
53704
|
+
lines.push(` Last checked: ${formatRelativeTime(sub.lastCheckedAt)}`);
|
|
53705
|
+
lines.push(` Watching: ${sub.isWatching ? "yes" : "no"}`);
|
|
53706
|
+
lines.push(` Errors: ${sub.errorCount}`);
|
|
53707
|
+
if (i < sessionSubs.length - 1) {
|
|
53708
|
+
lines.push("");
|
|
53709
|
+
}
|
|
53710
|
+
}
|
|
53711
|
+
lines.push("");
|
|
53712
|
+
if (totalActive !== sessionSubs.length) {
|
|
53713
|
+
lines.push(`Total active across all sessions: ${totalActive}`);
|
|
53714
|
+
}
|
|
53715
|
+
return lines.join(`
|
|
53716
|
+
`);
|
|
53717
|
+
}
|
|
53718
|
+
var _internals26;
|
|
53719
|
+
var init_pr_monitor_status = __esm(() => {
|
|
53720
|
+
init_pr_subscriptions();
|
|
53721
|
+
_internals26 = {
|
|
53722
|
+
formatRelativeTime,
|
|
53723
|
+
listActive
|
|
53724
|
+
};
|
|
53725
|
+
});
|
|
53726
|
+
|
|
53496
53727
|
// src/commands/pr-review.ts
|
|
53497
53728
|
function parseArgs6(args) {
|
|
53498
53729
|
const out = { council: false, rest: [] };
|
|
@@ -53552,6 +53783,172 @@ var init_pr_review = __esm(() => {
|
|
|
53552
53783
|
`);
|
|
53553
53784
|
});
|
|
53554
53785
|
|
|
53786
|
+
// src/commands/pr-subscribe.ts
|
|
53787
|
+
async function handlePrSubscribeCommand(directory, args, sessionID) {
|
|
53788
|
+
const rest = args.filter((t) => t.trim().length > 0);
|
|
53789
|
+
if (rest.length === 0) {
|
|
53790
|
+
return [
|
|
53791
|
+
"Usage: /swarm pr subscribe <pr-url|owner/repo#N|N>",
|
|
53792
|
+
"",
|
|
53793
|
+
"Subscribes the current session to receive advisory notifications",
|
|
53794
|
+
"for the specified PR. Requires pr_monitor.enabled: true in config.",
|
|
53795
|
+
"",
|
|
53796
|
+
" /swarm pr subscribe https://github.com/owner/repo/pull/42",
|
|
53797
|
+
" /swarm pr subscribe owner/repo#42",
|
|
53798
|
+
" /swarm pr subscribe 42"
|
|
53799
|
+
].join(`
|
|
53800
|
+
`);
|
|
53801
|
+
}
|
|
53802
|
+
const refToken = rest[0];
|
|
53803
|
+
const prInfo = parsePrRef(refToken, directory);
|
|
53804
|
+
if (!prInfo) {
|
|
53805
|
+
if (looksLikePrRef(refToken)) {
|
|
53806
|
+
return [
|
|
53807
|
+
`Error: Could not resolve PR reference from "${refToken}".`,
|
|
53808
|
+
"",
|
|
53809
|
+
"That looked like a PR reference but could not be resolved.",
|
|
53810
|
+
"Pass a full URL or `owner/repo#N`, or verify your git",
|
|
53811
|
+
"`origin` remote points to a GitHub repository."
|
|
53812
|
+
].join(`
|
|
53813
|
+
`);
|
|
53814
|
+
}
|
|
53815
|
+
return [
|
|
53816
|
+
`Error: "${refToken}" is not a valid PR reference.`,
|
|
53817
|
+
"",
|
|
53818
|
+
"Expected: full GitHub URL, owner/repo#N shorthand,",
|
|
53819
|
+
"or a bare PR number (resolved against origin)."
|
|
53820
|
+
].join(`
|
|
53821
|
+
`);
|
|
53822
|
+
}
|
|
53823
|
+
const repoFullName = `${prInfo.owner}/${prInfo.repo}`;
|
|
53824
|
+
const prUrl = `https://github.com/${prInfo.owner}/${prInfo.repo}/pull/${prInfo.number}`;
|
|
53825
|
+
try {
|
|
53826
|
+
const config3 = _internals27.loadPluginConfig(directory);
|
|
53827
|
+
const prMonitorConfig = config3.pr_monitor;
|
|
53828
|
+
if (!prMonitorConfig?.enabled) {
|
|
53829
|
+
return [
|
|
53830
|
+
"Error: PR Monitor is not enabled.",
|
|
53831
|
+
"",
|
|
53832
|
+
"Set `pr_monitor.enabled: true` in your opencode config to enable."
|
|
53833
|
+
].join(`
|
|
53834
|
+
`);
|
|
53835
|
+
}
|
|
53836
|
+
await _internals27.subscribe(directory, {
|
|
53837
|
+
sessionID,
|
|
53838
|
+
prNumber: prInfo.number,
|
|
53839
|
+
repoFullName,
|
|
53840
|
+
prUrl,
|
|
53841
|
+
maxSubscriptions: prMonitorConfig?.max_subscriptions
|
|
53842
|
+
});
|
|
53843
|
+
return [
|
|
53844
|
+
`Subscribed to ${prUrl}`,
|
|
53845
|
+
`Session: ${sessionID}`,
|
|
53846
|
+
`PR: ${repoFullName}#${prInfo.number}`,
|
|
53847
|
+
"",
|
|
53848
|
+
"The background PR monitor will now check this PR for",
|
|
53849
|
+
"CI failures, new comments, review state changes, and",
|
|
53850
|
+
"merge/close events. Notifications appear as session-scoped",
|
|
53851
|
+
"advisories with dedup tokens."
|
|
53852
|
+
].join(`
|
|
53853
|
+
`);
|
|
53854
|
+
} catch (err) {
|
|
53855
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53856
|
+
return [`Error: Failed to subscribe to ${prUrl}`, "", message].join(`
|
|
53857
|
+
`);
|
|
53858
|
+
}
|
|
53859
|
+
}
|
|
53860
|
+
var _internals27;
|
|
53861
|
+
var init_pr_subscribe = __esm(() => {
|
|
53862
|
+
init_pr_subscriptions();
|
|
53863
|
+
init_loader();
|
|
53864
|
+
init_pr_ref();
|
|
53865
|
+
_internals27 = {
|
|
53866
|
+
loadPluginConfig,
|
|
53867
|
+
subscribe
|
|
53868
|
+
};
|
|
53869
|
+
});
|
|
53870
|
+
|
|
53871
|
+
// src/commands/pr-unsubscribe.ts
|
|
53872
|
+
async function handlePrUnsubscribeCommand(directory, args, sessionID) {
|
|
53873
|
+
const rest = args.filter((t) => t.trim().length > 0);
|
|
53874
|
+
if (rest.length === 0) {
|
|
53875
|
+
return [
|
|
53876
|
+
"Usage: /swarm pr unsubscribe <pr-url|owner/repo#N|N>",
|
|
53877
|
+
"",
|
|
53878
|
+
"Unsubscribes the current session from receiving advisory",
|
|
53879
|
+
"notifications for the specified PR. Removes the active",
|
|
53880
|
+
"subscription record.",
|
|
53881
|
+
"",
|
|
53882
|
+
" /swarm pr unsubscribe https://github.com/owner/repo/pull/42",
|
|
53883
|
+
" /swarm pr unsubscribe owner/repo#42",
|
|
53884
|
+
" /swarm pr unsubscribe 42"
|
|
53885
|
+
].join(`
|
|
53886
|
+
`);
|
|
53887
|
+
}
|
|
53888
|
+
const refToken = rest[0];
|
|
53889
|
+
const prInfo = _internals28.parsePrRef(refToken, directory);
|
|
53890
|
+
if (!prInfo) {
|
|
53891
|
+
if (_internals28.looksLikePrRef(refToken)) {
|
|
53892
|
+
return [
|
|
53893
|
+
`Error: Could not resolve PR reference from "${refToken}".`,
|
|
53894
|
+
"",
|
|
53895
|
+
"That looked like a PR reference but could not be resolved.",
|
|
53896
|
+
"Pass a full URL or `owner/repo#N`, or verify your git",
|
|
53897
|
+
"`origin` remote points to a GitHub repository."
|
|
53898
|
+
].join(`
|
|
53899
|
+
`);
|
|
53900
|
+
}
|
|
53901
|
+
return [
|
|
53902
|
+
`Error: "${refToken}" is not a valid PR reference.`,
|
|
53903
|
+
"",
|
|
53904
|
+
"Expected: full GitHub URL, owner/repo#N shorthand,",
|
|
53905
|
+
"or a bare PR number (resolved against origin)."
|
|
53906
|
+
].join(`
|
|
53907
|
+
`);
|
|
53908
|
+
}
|
|
53909
|
+
const repoFullName = `${prInfo.owner}/${prInfo.repo}`;
|
|
53910
|
+
const prUrl = `https://github.com/${prInfo.owner}/${prInfo.repo}/pull/${prInfo.number}`;
|
|
53911
|
+
try {
|
|
53912
|
+
const correlationId = _internals28.buildCorrelationId(sessionID, repoFullName, prInfo.number);
|
|
53913
|
+
const result = await _internals28.unsubscribe(directory, correlationId);
|
|
53914
|
+
if (!result) {
|
|
53915
|
+
return [
|
|
53916
|
+
`Not subscribed to ${prUrl}`,
|
|
53917
|
+
`Session: ${sessionID}`,
|
|
53918
|
+
`PR: ${repoFullName}#${prInfo.number}`,
|
|
53919
|
+
"",
|
|
53920
|
+
"No active subscription found for this session and PR.",
|
|
53921
|
+
"Use /swarm pr subscribe to start monitoring."
|
|
53922
|
+
].join(`
|
|
53923
|
+
`);
|
|
53924
|
+
}
|
|
53925
|
+
return [
|
|
53926
|
+
`Unsubscribed from ${prUrl}`,
|
|
53927
|
+
`Session: ${sessionID}`,
|
|
53928
|
+
`PR: ${repoFullName}#${prInfo.number}`,
|
|
53929
|
+
"",
|
|
53930
|
+
"The background PR monitor will no longer check this PR for",
|
|
53931
|
+
"the current session. Use /swarm pr subscribe to re-subscribe."
|
|
53932
|
+
].join(`
|
|
53933
|
+
`);
|
|
53934
|
+
} catch (err) {
|
|
53935
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53936
|
+
return [`Error: Failed to unsubscribe from ${prUrl}`, "", message].join(`
|
|
53937
|
+
`);
|
|
53938
|
+
}
|
|
53939
|
+
}
|
|
53940
|
+
var _internals28;
|
|
53941
|
+
var init_pr_unsubscribe = __esm(() => {
|
|
53942
|
+
init_pr_subscriptions();
|
|
53943
|
+
init_pr_ref();
|
|
53944
|
+
_internals28 = {
|
|
53945
|
+
unsubscribe,
|
|
53946
|
+
buildCorrelationId,
|
|
53947
|
+
parsePrRef,
|
|
53948
|
+
looksLikePrRef
|
|
53949
|
+
};
|
|
53950
|
+
});
|
|
53951
|
+
|
|
53555
53952
|
// src/utils/path-security.ts
|
|
53556
53953
|
function containsPathTraversal(str) {
|
|
53557
53954
|
if (/\.\.[/\\]/.test(str))
|
|
@@ -53584,8 +53981,8 @@ function containsControlChars(str) {
|
|
|
53584
53981
|
var init_path_security = () => {};
|
|
53585
53982
|
|
|
53586
53983
|
// src/tools/lint.ts
|
|
53587
|
-
import * as
|
|
53588
|
-
import * as
|
|
53984
|
+
import * as fs18 from "fs";
|
|
53985
|
+
import * as path44 from "path";
|
|
53589
53986
|
function validateArgs(args) {
|
|
53590
53987
|
if (typeof args !== "object" || args === null)
|
|
53591
53988
|
return false;
|
|
@@ -53596,9 +53993,9 @@ function validateArgs(args) {
|
|
|
53596
53993
|
}
|
|
53597
53994
|
function getLinterCommand(linter, mode, projectDir) {
|
|
53598
53995
|
const isWindows = process.platform === "win32";
|
|
53599
|
-
const binDir =
|
|
53600
|
-
const biomeBin = isWindows ?
|
|
53601
|
-
const eslintBin = isWindows ?
|
|
53996
|
+
const binDir = path44.join(projectDir, "node_modules", ".bin");
|
|
53997
|
+
const biomeBin = isWindows ? path44.join(binDir, "biome.EXE") : path44.join(binDir, "biome");
|
|
53998
|
+
const eslintBin = isWindows ? path44.join(binDir, "eslint.cmd") : path44.join(binDir, "eslint");
|
|
53602
53999
|
switch (linter) {
|
|
53603
54000
|
case "biome":
|
|
53604
54001
|
if (mode === "fix") {
|
|
@@ -53614,7 +54011,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
53614
54011
|
}
|
|
53615
54012
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
53616
54013
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
53617
|
-
const gradlew =
|
|
54014
|
+
const gradlew = fs18.existsSync(path44.join(cwd, gradlewName)) ? path44.join(cwd, gradlewName) : null;
|
|
53618
54015
|
switch (linter) {
|
|
53619
54016
|
case "ruff":
|
|
53620
54017
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -53648,12 +54045,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
53648
54045
|
}
|
|
53649
54046
|
}
|
|
53650
54047
|
function detectRuff(cwd) {
|
|
53651
|
-
if (
|
|
54048
|
+
if (fs18.existsSync(path44.join(cwd, "ruff.toml")))
|
|
53652
54049
|
return isCommandAvailable("ruff");
|
|
53653
54050
|
try {
|
|
53654
|
-
const pyproject =
|
|
53655
|
-
if (
|
|
53656
|
-
const content =
|
|
54051
|
+
const pyproject = path44.join(cwd, "pyproject.toml");
|
|
54052
|
+
if (fs18.existsSync(pyproject)) {
|
|
54053
|
+
const content = fs18.readFileSync(pyproject, "utf-8");
|
|
53657
54054
|
if (content.includes("[tool.ruff]"))
|
|
53658
54055
|
return isCommandAvailable("ruff");
|
|
53659
54056
|
}
|
|
@@ -53661,21 +54058,21 @@ function detectRuff(cwd) {
|
|
|
53661
54058
|
return false;
|
|
53662
54059
|
}
|
|
53663
54060
|
function detectClippy(cwd) {
|
|
53664
|
-
return
|
|
54061
|
+
return fs18.existsSync(path44.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
53665
54062
|
}
|
|
53666
54063
|
function detectGolangciLint(cwd) {
|
|
53667
|
-
return
|
|
54064
|
+
return fs18.existsSync(path44.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
53668
54065
|
}
|
|
53669
54066
|
function detectCheckstyle(cwd) {
|
|
53670
|
-
const hasMaven =
|
|
53671
|
-
const hasGradle =
|
|
53672
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (
|
|
54067
|
+
const hasMaven = fs18.existsSync(path44.join(cwd, "pom.xml"));
|
|
54068
|
+
const hasGradle = fs18.existsSync(path44.join(cwd, "build.gradle")) || fs18.existsSync(path44.join(cwd, "build.gradle.kts"));
|
|
54069
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs18.existsSync(path44.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
53673
54070
|
return (hasMaven || hasGradle) && hasBinary;
|
|
53674
54071
|
}
|
|
53675
54072
|
function detectKtlint(cwd) {
|
|
53676
|
-
const hasKotlin =
|
|
54073
|
+
const hasKotlin = fs18.existsSync(path44.join(cwd, "build.gradle.kts")) || fs18.existsSync(path44.join(cwd, "build.gradle")) || (() => {
|
|
53677
54074
|
try {
|
|
53678
|
-
return
|
|
54075
|
+
return fs18.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
53679
54076
|
} catch {
|
|
53680
54077
|
return false;
|
|
53681
54078
|
}
|
|
@@ -53684,7 +54081,7 @@ function detectKtlint(cwd) {
|
|
|
53684
54081
|
}
|
|
53685
54082
|
function detectDotnetFormat(cwd) {
|
|
53686
54083
|
try {
|
|
53687
|
-
const files =
|
|
54084
|
+
const files = fs18.readdirSync(cwd);
|
|
53688
54085
|
const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
|
|
53689
54086
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
53690
54087
|
} catch {
|
|
@@ -53692,14 +54089,14 @@ function detectDotnetFormat(cwd) {
|
|
|
53692
54089
|
}
|
|
53693
54090
|
}
|
|
53694
54091
|
function detectCppcheck(cwd) {
|
|
53695
|
-
if (
|
|
54092
|
+
if (fs18.existsSync(path44.join(cwd, "CMakeLists.txt"))) {
|
|
53696
54093
|
return isCommandAvailable("cppcheck");
|
|
53697
54094
|
}
|
|
53698
54095
|
try {
|
|
53699
|
-
const dirsToCheck = [cwd,
|
|
54096
|
+
const dirsToCheck = [cwd, path44.join(cwd, "src")];
|
|
53700
54097
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
53701
54098
|
try {
|
|
53702
|
-
return
|
|
54099
|
+
return fs18.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
53703
54100
|
} catch {
|
|
53704
54101
|
return false;
|
|
53705
54102
|
}
|
|
@@ -53710,13 +54107,13 @@ function detectCppcheck(cwd) {
|
|
|
53710
54107
|
}
|
|
53711
54108
|
}
|
|
53712
54109
|
function detectSwiftlint(cwd) {
|
|
53713
|
-
return
|
|
54110
|
+
return fs18.existsSync(path44.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
53714
54111
|
}
|
|
53715
54112
|
function detectDartAnalyze(cwd) {
|
|
53716
|
-
return
|
|
54113
|
+
return fs18.existsSync(path44.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
53717
54114
|
}
|
|
53718
54115
|
function detectRubocop(cwd) {
|
|
53719
|
-
return (
|
|
54116
|
+
return (fs18.existsSync(path44.join(cwd, "Gemfile")) || fs18.existsSync(path44.join(cwd, "gems.rb")) || fs18.existsSync(path44.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
53720
54117
|
}
|
|
53721
54118
|
function detectAdditionalLinter(cwd) {
|
|
53722
54119
|
if (detectRuff(cwd))
|
|
@@ -53744,10 +54141,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
53744
54141
|
function findBinInAncestors(startDir, binName) {
|
|
53745
54142
|
let dir = startDir;
|
|
53746
54143
|
while (true) {
|
|
53747
|
-
const candidate =
|
|
53748
|
-
if (
|
|
54144
|
+
const candidate = path44.join(dir, "node_modules", ".bin", binName);
|
|
54145
|
+
if (fs18.existsSync(candidate))
|
|
53749
54146
|
return candidate;
|
|
53750
|
-
const parent =
|
|
54147
|
+
const parent = path44.dirname(dir);
|
|
53751
54148
|
if (parent === dir)
|
|
53752
54149
|
break;
|
|
53753
54150
|
dir = parent;
|
|
@@ -53756,11 +54153,11 @@ function findBinInAncestors(startDir, binName) {
|
|
|
53756
54153
|
}
|
|
53757
54154
|
function findBinInEnvPath(binName) {
|
|
53758
54155
|
const searchPath = process.env.PATH ?? "";
|
|
53759
|
-
for (const dir of searchPath.split(
|
|
54156
|
+
for (const dir of searchPath.split(path44.delimiter)) {
|
|
53760
54157
|
if (!dir)
|
|
53761
54158
|
continue;
|
|
53762
|
-
const candidate =
|
|
53763
|
-
if (
|
|
54159
|
+
const candidate = path44.join(dir, binName);
|
|
54160
|
+
if (fs18.existsSync(candidate))
|
|
53764
54161
|
return candidate;
|
|
53765
54162
|
}
|
|
53766
54163
|
return null;
|
|
@@ -53768,17 +54165,17 @@ function findBinInEnvPath(binName) {
|
|
|
53768
54165
|
async function detectAvailableLinter(directory) {
|
|
53769
54166
|
if (!directory)
|
|
53770
54167
|
return null;
|
|
53771
|
-
if (!
|
|
54168
|
+
if (!fs18.existsSync(directory))
|
|
53772
54169
|
return null;
|
|
53773
54170
|
const projectDir = directory;
|
|
53774
54171
|
const isWindows = process.platform === "win32";
|
|
53775
|
-
const biomeBin = isWindows ?
|
|
53776
|
-
const eslintBin = isWindows ?
|
|
54172
|
+
const biomeBin = isWindows ? path44.join(projectDir, "node_modules", ".bin", "biome.EXE") : path44.join(projectDir, "node_modules", ".bin", "biome");
|
|
54173
|
+
const eslintBin = isWindows ? path44.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path44.join(projectDir, "node_modules", ".bin", "eslint");
|
|
53777
54174
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
53778
54175
|
if (localResult)
|
|
53779
54176
|
return localResult;
|
|
53780
|
-
const biomeAncestor = findBinInAncestors(
|
|
53781
|
-
const eslintAncestor = findBinInAncestors(
|
|
54177
|
+
const biomeAncestor = findBinInAncestors(path44.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
54178
|
+
const eslintAncestor = findBinInAncestors(path44.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
53782
54179
|
if (biomeAncestor || eslintAncestor) {
|
|
53783
54180
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
53784
54181
|
}
|
|
@@ -53797,11 +54194,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
53797
54194
|
stderr: "pipe"
|
|
53798
54195
|
});
|
|
53799
54196
|
const biomeExit = biomeProc.exited;
|
|
53800
|
-
const timeout = new Promise((
|
|
54197
|
+
const timeout = new Promise((resolve16) => setTimeout(() => resolve16("timeout"), DETECT_TIMEOUT));
|
|
53801
54198
|
const result = await Promise.race([biomeExit, timeout]);
|
|
53802
54199
|
if (result === "timeout") {
|
|
53803
54200
|
biomeProc.kill();
|
|
53804
|
-
} else if (biomeProc.exitCode === 0 &&
|
|
54201
|
+
} else if (biomeProc.exitCode === 0 && fs18.existsSync(biomeBin)) {
|
|
53805
54202
|
return "biome";
|
|
53806
54203
|
}
|
|
53807
54204
|
} catch {}
|
|
@@ -53811,11 +54208,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
53811
54208
|
stderr: "pipe"
|
|
53812
54209
|
});
|
|
53813
54210
|
const eslintExit = eslintProc.exited;
|
|
53814
|
-
const timeout = new Promise((
|
|
54211
|
+
const timeout = new Promise((resolve16) => setTimeout(() => resolve16("timeout"), DETECT_TIMEOUT));
|
|
53815
54212
|
const result = await Promise.race([eslintExit, timeout]);
|
|
53816
54213
|
if (result === "timeout") {
|
|
53817
54214
|
eslintProc.kill();
|
|
53818
|
-
} else if (eslintProc.exitCode === 0 &&
|
|
54215
|
+
} else if (eslintProc.exitCode === 0 && fs18.existsSync(eslintBin)) {
|
|
53819
54216
|
return "eslint";
|
|
53820
54217
|
}
|
|
53821
54218
|
} catch {}
|
|
@@ -53937,7 +54334,7 @@ async function runAdditionalLint(linter, mode, cwd) {
|
|
|
53937
54334
|
};
|
|
53938
54335
|
}
|
|
53939
54336
|
}
|
|
53940
|
-
var MAX_OUTPUT_BYTES = 512000, MAX_COMMAND_LENGTH = 500, lint,
|
|
54337
|
+
var MAX_OUTPUT_BYTES = 512000, MAX_COMMAND_LENGTH = 500, lint, _internals29;
|
|
53941
54338
|
var init_lint = __esm(() => {
|
|
53942
54339
|
init_zod();
|
|
53943
54340
|
init_discovery();
|
|
@@ -53969,15 +54366,15 @@ var init_lint = __esm(() => {
|
|
|
53969
54366
|
}
|
|
53970
54367
|
const { mode } = args;
|
|
53971
54368
|
const cwd = directory;
|
|
53972
|
-
const linter = await
|
|
54369
|
+
const linter = await _internals29.detectAvailableLinter(directory);
|
|
53973
54370
|
if (linter) {
|
|
53974
|
-
const result = await
|
|
54371
|
+
const result = await _internals29.runLint(linter, mode, directory);
|
|
53975
54372
|
return JSON.stringify(result, null, 2);
|
|
53976
54373
|
}
|
|
53977
|
-
const additionalLinter =
|
|
54374
|
+
const additionalLinter = _internals29.detectAdditionalLinter(cwd);
|
|
53978
54375
|
if (additionalLinter) {
|
|
53979
54376
|
warn(`[lint] Using ${additionalLinter} linter for this project`);
|
|
53980
|
-
const result = await
|
|
54377
|
+
const result = await _internals29.runAdditionalLint(additionalLinter, mode, cwd);
|
|
53981
54378
|
return JSON.stringify(result, null, 2);
|
|
53982
54379
|
}
|
|
53983
54380
|
const errorResult = {
|
|
@@ -53991,7 +54388,7 @@ For Rust: rustup component add clippy`
|
|
|
53991
54388
|
return JSON.stringify(errorResult, null, 2);
|
|
53992
54389
|
}
|
|
53993
54390
|
});
|
|
53994
|
-
|
|
54391
|
+
_internals29 = {
|
|
53995
54392
|
detectAvailableLinter,
|
|
53996
54393
|
runLint,
|
|
53997
54394
|
detectAdditionalLinter,
|
|
@@ -54000,8 +54397,8 @@ For Rust: rustup component add clippy`
|
|
|
54000
54397
|
});
|
|
54001
54398
|
|
|
54002
54399
|
// src/tools/secretscan.ts
|
|
54003
|
-
import * as
|
|
54004
|
-
import * as
|
|
54400
|
+
import * as fs19 from "fs";
|
|
54401
|
+
import * as path45 from "path";
|
|
54005
54402
|
function calculateShannonEntropy(str) {
|
|
54006
54403
|
if (str.length === 0)
|
|
54007
54404
|
return 0;
|
|
@@ -54049,11 +54446,11 @@ function isGlobOrPathPattern(pattern) {
|
|
|
54049
54446
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
54050
54447
|
}
|
|
54051
54448
|
function loadSecretScanIgnore(scanDir) {
|
|
54052
|
-
const ignorePath =
|
|
54449
|
+
const ignorePath = path45.join(scanDir, ".secretscanignore");
|
|
54053
54450
|
try {
|
|
54054
|
-
if (!
|
|
54451
|
+
if (!fs19.existsSync(ignorePath))
|
|
54055
54452
|
return [];
|
|
54056
|
-
const content =
|
|
54453
|
+
const content = fs19.readFileSync(ignorePath, "utf8");
|
|
54057
54454
|
const patterns = [];
|
|
54058
54455
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
54059
54456
|
const line = rawLine.trim();
|
|
@@ -54072,7 +54469,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
54072
54469
|
if (exactNames.has(entry))
|
|
54073
54470
|
return true;
|
|
54074
54471
|
for (const pattern of globPatterns) {
|
|
54075
|
-
if (
|
|
54472
|
+
if (path45.matchesGlob(relPath, pattern))
|
|
54076
54473
|
return true;
|
|
54077
54474
|
}
|
|
54078
54475
|
return false;
|
|
@@ -54093,7 +54490,7 @@ function validateDirectoryInput(dir) {
|
|
|
54093
54490
|
return null;
|
|
54094
54491
|
}
|
|
54095
54492
|
function isBinaryFile(filePath, buffer) {
|
|
54096
|
-
const ext =
|
|
54493
|
+
const ext = path45.extname(filePath).toLowerCase();
|
|
54097
54494
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
54098
54495
|
return true;
|
|
54099
54496
|
}
|
|
@@ -54171,7 +54568,7 @@ function createRedactedContext(line, findings) {
|
|
|
54171
54568
|
function scanFileForSecrets(filePath) {
|
|
54172
54569
|
const findings = [];
|
|
54173
54570
|
try {
|
|
54174
|
-
const lstat =
|
|
54571
|
+
const lstat = fs19.lstatSync(filePath);
|
|
54175
54572
|
if (lstat.isSymbolicLink()) {
|
|
54176
54573
|
return findings;
|
|
54177
54574
|
}
|
|
@@ -54180,14 +54577,14 @@ function scanFileForSecrets(filePath) {
|
|
|
54180
54577
|
}
|
|
54181
54578
|
let buffer;
|
|
54182
54579
|
if (O_NOFOLLOW !== undefined) {
|
|
54183
|
-
const fd =
|
|
54580
|
+
const fd = fs19.openSync(filePath, "r", O_NOFOLLOW);
|
|
54184
54581
|
try {
|
|
54185
|
-
buffer =
|
|
54582
|
+
buffer = fs19.readFileSync(fd);
|
|
54186
54583
|
} finally {
|
|
54187
|
-
|
|
54584
|
+
fs19.closeSync(fd);
|
|
54188
54585
|
}
|
|
54189
54586
|
} else {
|
|
54190
|
-
buffer =
|
|
54587
|
+
buffer = fs19.readFileSync(filePath);
|
|
54191
54588
|
}
|
|
54192
54589
|
if (isBinaryFile(filePath, buffer)) {
|
|
54193
54590
|
return findings;
|
|
@@ -54229,9 +54626,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
54229
54626
|
return false;
|
|
54230
54627
|
}
|
|
54231
54628
|
function isPathWithinScope(realPath, scanDir) {
|
|
54232
|
-
const resolvedScanDir =
|
|
54233
|
-
const resolvedRealPath =
|
|
54234
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
54629
|
+
const resolvedScanDir = path45.resolve(scanDir);
|
|
54630
|
+
const resolvedRealPath = path45.resolve(realPath);
|
|
54631
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path45.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
54235
54632
|
}
|
|
54236
54633
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
54237
54634
|
skippedDirs: 0,
|
|
@@ -54242,7 +54639,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
54242
54639
|
const files = [];
|
|
54243
54640
|
let entries;
|
|
54244
54641
|
try {
|
|
54245
|
-
entries =
|
|
54642
|
+
entries = fs19.readdirSync(dir);
|
|
54246
54643
|
} catch {
|
|
54247
54644
|
stats.fileErrors++;
|
|
54248
54645
|
return files;
|
|
@@ -54257,15 +54654,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
54257
54654
|
return a.localeCompare(b);
|
|
54258
54655
|
});
|
|
54259
54656
|
for (const entry of entries) {
|
|
54260
|
-
const fullPath =
|
|
54261
|
-
const relPath =
|
|
54657
|
+
const fullPath = path45.join(dir, entry);
|
|
54658
|
+
const relPath = path45.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
54262
54659
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
54263
54660
|
stats.skippedDirs++;
|
|
54264
54661
|
continue;
|
|
54265
54662
|
}
|
|
54266
54663
|
let lstat;
|
|
54267
54664
|
try {
|
|
54268
|
-
lstat =
|
|
54665
|
+
lstat = fs19.lstatSync(fullPath);
|
|
54269
54666
|
} catch {
|
|
54270
54667
|
stats.fileErrors++;
|
|
54271
54668
|
continue;
|
|
@@ -54277,7 +54674,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
54277
54674
|
if (lstat.isDirectory()) {
|
|
54278
54675
|
let realPath;
|
|
54279
54676
|
try {
|
|
54280
|
-
realPath =
|
|
54677
|
+
realPath = fs19.realpathSync(fullPath);
|
|
54281
54678
|
} catch {
|
|
54282
54679
|
stats.fileErrors++;
|
|
54283
54680
|
continue;
|
|
@@ -54293,7 +54690,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
54293
54690
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
54294
54691
|
files.push(...subFiles);
|
|
54295
54692
|
} else if (lstat.isFile()) {
|
|
54296
|
-
const ext =
|
|
54693
|
+
const ext = path45.extname(fullPath).toLowerCase();
|
|
54297
54694
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
54298
54695
|
files.push(fullPath);
|
|
54299
54696
|
} else {
|
|
@@ -54305,7 +54702,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
54305
54702
|
}
|
|
54306
54703
|
async function runSecretscan(directory) {
|
|
54307
54704
|
try {
|
|
54308
|
-
const result = await
|
|
54705
|
+
const result = await _internals30.secretscan.execute({ directory }, {});
|
|
54309
54706
|
const jsonStr = typeof result === "string" ? result : result.output;
|
|
54310
54707
|
return JSON.parse(jsonStr);
|
|
54311
54708
|
} catch (e) {
|
|
@@ -54320,7 +54717,7 @@ async function runSecretscan(directory) {
|
|
|
54320
54717
|
return errorResult;
|
|
54321
54718
|
}
|
|
54322
54719
|
}
|
|
54323
|
-
var MAX_FILE_PATH_LENGTH = 500, MAX_FILE_SIZE_BYTES, MAX_FILES_SCANNED = 1000, MAX_FINDINGS = 100, MAX_OUTPUT_BYTES2 = 512000, MAX_LINE_LENGTH = 1e4, MAX_CONTENT_BYTES, BINARY_SIGNATURES, BINARY_PREFIX_BYTES = 4, BINARY_NULL_CHECK_BYTES = 8192, BINARY_NULL_THRESHOLD = 0.1, DEFAULT_EXCLUDE_DIRS, DEFAULT_EXCLUDE_EXTENSIONS, SECRET_PATTERNS2, O_NOFOLLOW, secretscan,
|
|
54720
|
+
var MAX_FILE_PATH_LENGTH = 500, MAX_FILE_SIZE_BYTES, MAX_FILES_SCANNED = 1000, MAX_FINDINGS = 100, MAX_OUTPUT_BYTES2 = 512000, MAX_LINE_LENGTH = 1e4, MAX_CONTENT_BYTES, BINARY_SIGNATURES, BINARY_PREFIX_BYTES = 4, BINARY_NULL_CHECK_BYTES = 8192, BINARY_NULL_THRESHOLD = 0.1, DEFAULT_EXCLUDE_DIRS, DEFAULT_EXCLUDE_EXTENSIONS, SECRET_PATTERNS2, O_NOFOLLOW, secretscan, _internals30;
|
|
54324
54721
|
var init_secretscan = __esm(() => {
|
|
54325
54722
|
init_zod();
|
|
54326
54723
|
init_path_security();
|
|
@@ -54496,7 +54893,7 @@ var init_secretscan = __esm(() => {
|
|
|
54496
54893
|
redactTemplate: () => "SK[REDACTED]"
|
|
54497
54894
|
}
|
|
54498
54895
|
];
|
|
54499
|
-
O_NOFOLLOW = process.platform !== "win32" ?
|
|
54896
|
+
O_NOFOLLOW = process.platform !== "win32" ? fs19.constants.O_NOFOLLOW : undefined;
|
|
54500
54897
|
secretscan = createSwarmTool({
|
|
54501
54898
|
description: "Scan directory for potential secrets (API keys, tokens, passwords) using regex patterns and entropy heuristics. Returns metadata-only findings with redacted previews - NEVER returns raw secrets. Excludes common directories (node_modules, .git, dist, etc.) by default. Supports glob patterns (e.g. **/.svelte-kit/**, **/*.test.ts) and reads .secretscanignore at the scan root.",
|
|
54502
54899
|
args: {
|
|
@@ -54553,15 +54950,15 @@ var init_secretscan = __esm(() => {
|
|
|
54553
54950
|
}
|
|
54554
54951
|
}
|
|
54555
54952
|
try {
|
|
54556
|
-
const _scanDirRaw =
|
|
54953
|
+
const _scanDirRaw = path45.resolve(directory);
|
|
54557
54954
|
const scanDir = (() => {
|
|
54558
54955
|
try {
|
|
54559
|
-
return
|
|
54956
|
+
return fs19.realpathSync(_scanDirRaw);
|
|
54560
54957
|
} catch {
|
|
54561
54958
|
return _scanDirRaw;
|
|
54562
54959
|
}
|
|
54563
54960
|
})();
|
|
54564
|
-
if (!
|
|
54961
|
+
if (!fs19.existsSync(scanDir)) {
|
|
54565
54962
|
const errorResult = {
|
|
54566
54963
|
error: "directory not found",
|
|
54567
54964
|
scan_dir: directory,
|
|
@@ -54572,7 +54969,7 @@ var init_secretscan = __esm(() => {
|
|
|
54572
54969
|
};
|
|
54573
54970
|
return JSON.stringify(errorResult, null, 2);
|
|
54574
54971
|
}
|
|
54575
|
-
const dirStat =
|
|
54972
|
+
const dirStat = fs19.statSync(scanDir);
|
|
54576
54973
|
if (!dirStat.isDirectory()) {
|
|
54577
54974
|
const errorResult = {
|
|
54578
54975
|
error: "target must be a directory, not a file",
|
|
@@ -54623,7 +55020,7 @@ var init_secretscan = __esm(() => {
|
|
|
54623
55020
|
break;
|
|
54624
55021
|
const fileFindings = scanFileForSecrets(filePath);
|
|
54625
55022
|
try {
|
|
54626
|
-
const stat5 =
|
|
55023
|
+
const stat5 = fs19.statSync(filePath);
|
|
54627
55024
|
if (stat5.size > MAX_FILE_SIZE_BYTES) {
|
|
54628
55025
|
skippedFiles++;
|
|
54629
55026
|
continue;
|
|
@@ -54692,19 +55089,19 @@ var init_secretscan = __esm(() => {
|
|
|
54692
55089
|
}
|
|
54693
55090
|
}
|
|
54694
55091
|
});
|
|
54695
|
-
|
|
55092
|
+
_internals30 = {
|
|
54696
55093
|
secretscan,
|
|
54697
55094
|
runSecretscan
|
|
54698
55095
|
};
|
|
54699
55096
|
});
|
|
54700
55097
|
|
|
54701
55098
|
// src/lang/default-backend.ts
|
|
54702
|
-
import * as
|
|
54703
|
-
import * as
|
|
55099
|
+
import * as fs20 from "fs";
|
|
55100
|
+
import * as path46 from "path";
|
|
54704
55101
|
function detectFileExists(dir, pattern) {
|
|
54705
55102
|
if (pattern.includes("*") || pattern.includes("?")) {
|
|
54706
55103
|
try {
|
|
54707
|
-
const files =
|
|
55104
|
+
const files = fs20.readdirSync(dir);
|
|
54708
55105
|
const regex = new RegExp(`^${pattern.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
|
|
54709
55106
|
return files.some((f) => regex.test(f));
|
|
54710
55107
|
} catch {
|
|
@@ -54712,7 +55109,7 @@ function detectFileExists(dir, pattern) {
|
|
|
54712
55109
|
}
|
|
54713
55110
|
}
|
|
54714
55111
|
try {
|
|
54715
|
-
|
|
55112
|
+
fs20.accessSync(path46.join(dir, pattern));
|
|
54716
55113
|
return true;
|
|
54717
55114
|
} catch {
|
|
54718
55115
|
return false;
|
|
@@ -54851,8 +55248,8 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
54851
55248
|
return ["mvn", "test"];
|
|
54852
55249
|
case "gradle": {
|
|
54853
55250
|
const isWindows = process.platform === "win32";
|
|
54854
|
-
const hasGradlewBat =
|
|
54855
|
-
const hasGradlew =
|
|
55251
|
+
const hasGradlewBat = fs20.existsSync(path46.join(dir, "gradlew.bat"));
|
|
55252
|
+
const hasGradlew = fs20.existsSync(path46.join(dir, "gradlew"));
|
|
54856
55253
|
if (hasGradlewBat && isWindows)
|
|
54857
55254
|
return ["gradlew.bat", "test"];
|
|
54858
55255
|
if (hasGradlew)
|
|
@@ -54869,7 +55266,7 @@ function defaultBuildTestCommand(profile, framework, files, dir = ".", opts = {}
|
|
|
54869
55266
|
"cmake-build-release",
|
|
54870
55267
|
"out"
|
|
54871
55268
|
];
|
|
54872
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
55269
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs20.existsSync(path46.join(dir, d, "CMakeCache.txt"))) ?? "build";
|
|
54873
55270
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
54874
55271
|
}
|
|
54875
55272
|
case "swift-test":
|
|
@@ -55158,23 +55555,23 @@ async function defaultSelectBuildCommand(profile, dir) {
|
|
|
55158
55555
|
return null;
|
|
55159
55556
|
}
|
|
55160
55557
|
async function defaultTestFilesFor(profile, sourceFile, dir) {
|
|
55161
|
-
const ext =
|
|
55558
|
+
const ext = path46.extname(sourceFile);
|
|
55162
55559
|
if (!profile.extensions.includes(ext))
|
|
55163
55560
|
return [];
|
|
55164
|
-
const base =
|
|
55165
|
-
const rel =
|
|
55166
|
-
const relDir =
|
|
55561
|
+
const base = path46.basename(sourceFile, ext);
|
|
55562
|
+
const rel = path46.relative(dir, sourceFile);
|
|
55563
|
+
const relDir = path46.dirname(rel);
|
|
55167
55564
|
const stripSrc = relDir.replace(/^src(\/|\\)/, "");
|
|
55168
55565
|
const candidates = new Set;
|
|
55169
55566
|
for (const tDir of ["tests", "test", "__tests__", "spec"]) {
|
|
55170
55567
|
for (const suffix of ["", "_test", ".test", "_spec", ".spec"]) {
|
|
55171
|
-
candidates.add(
|
|
55568
|
+
candidates.add(path46.join(dir, tDir, stripSrc, `${base}${suffix}${ext}`));
|
|
55172
55569
|
}
|
|
55173
55570
|
}
|
|
55174
55571
|
const existing = [];
|
|
55175
55572
|
for (const c of candidates) {
|
|
55176
55573
|
try {
|
|
55177
|
-
|
|
55574
|
+
fs20.accessSync(c);
|
|
55178
55575
|
existing.push(c);
|
|
55179
55576
|
} catch {}
|
|
55180
55577
|
}
|
|
@@ -55208,8 +55605,8 @@ var init_default_backend = __esm(() => {
|
|
|
55208
55605
|
});
|
|
55209
55606
|
|
|
55210
55607
|
// src/lang/backends/go.ts
|
|
55211
|
-
import * as
|
|
55212
|
-
import * as
|
|
55608
|
+
import * as fs21 from "fs";
|
|
55609
|
+
import * as path47 from "path";
|
|
55213
55610
|
function extractImports(_sourceFile, source) {
|
|
55214
55611
|
const out = new Set;
|
|
55215
55612
|
IMPORT_REGEX_SINGLE.lastIndex = 0;
|
|
@@ -55235,7 +55632,7 @@ function extractImports(_sourceFile, source) {
|
|
|
55235
55632
|
async function selectFramework(dir) {
|
|
55236
55633
|
let content;
|
|
55237
55634
|
try {
|
|
55238
|
-
content =
|
|
55635
|
+
content = fs21.readFileSync(path47.join(dir, "go.mod"), "utf-8");
|
|
55239
55636
|
} catch {
|
|
55240
55637
|
return null;
|
|
55241
55638
|
}
|
|
@@ -55256,16 +55653,16 @@ async function selectFramework(dir) {
|
|
|
55256
55653
|
async function selectEntryPoints(dir) {
|
|
55257
55654
|
const points = [];
|
|
55258
55655
|
try {
|
|
55259
|
-
|
|
55656
|
+
fs21.accessSync(path47.join(dir, "main.go"));
|
|
55260
55657
|
points.push("main.go");
|
|
55261
55658
|
} catch {}
|
|
55262
55659
|
try {
|
|
55263
|
-
const cmdDir =
|
|
55264
|
-
const subdirs =
|
|
55660
|
+
const cmdDir = path47.join(dir, "cmd");
|
|
55661
|
+
const subdirs = fs21.readdirSync(cmdDir, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
55265
55662
|
for (const sub of subdirs) {
|
|
55266
|
-
const main =
|
|
55663
|
+
const main = path47.join("cmd", sub.name, "main.go");
|
|
55267
55664
|
try {
|
|
55268
|
-
|
|
55665
|
+
fs21.accessSync(path47.join(dir, main));
|
|
55269
55666
|
points.push(main);
|
|
55270
55667
|
} catch {}
|
|
55271
55668
|
}
|
|
@@ -55284,19 +55681,19 @@ function buildGoBackend() {
|
|
|
55284
55681
|
selectEntryPoints
|
|
55285
55682
|
};
|
|
55286
55683
|
}
|
|
55287
|
-
var PROFILE_ID = "go", IMPORT_REGEX_SINGLE, IMPORT_REGEX_GROUP, IMPORT_REGEX_GROUP_LINE,
|
|
55684
|
+
var PROFILE_ID = "go", IMPORT_REGEX_SINGLE, IMPORT_REGEX_GROUP, IMPORT_REGEX_GROUP_LINE, _internals31;
|
|
55288
55685
|
var init_go = __esm(() => {
|
|
55289
55686
|
init_default_backend();
|
|
55290
55687
|
init_profiles();
|
|
55291
55688
|
IMPORT_REGEX_SINGLE = /^\s*import\s+(?:[a-zA-Z_.][a-zA-Z0-9_]*\s+)?"([^"]+)"/gm;
|
|
55292
55689
|
IMPORT_REGEX_GROUP = /^\s*import\s*\(([\s\S]*?)\)/gm;
|
|
55293
55690
|
IMPORT_REGEX_GROUP_LINE = /(?:[a-zA-Z_.][a-zA-Z0-9_]*\s+)?"([^"]+)"/g;
|
|
55294
|
-
|
|
55691
|
+
_internals31 = { extractImports };
|
|
55295
55692
|
});
|
|
55296
55693
|
|
|
55297
55694
|
// src/lang/backends/python.ts
|
|
55298
|
-
import * as
|
|
55299
|
-
import * as
|
|
55695
|
+
import * as fs22 from "fs";
|
|
55696
|
+
import * as path48 from "path";
|
|
55300
55697
|
function parseImportTargets(rawTargets) {
|
|
55301
55698
|
const cleaned = rawTargets.replace(/[()]/g, "").split(`
|
|
55302
55699
|
`).map((line) => line.replace(/#.*$/, "").replace(/\\\s*$/, "")).join(" ");
|
|
@@ -55356,7 +55753,7 @@ async function selectFramework2(dir) {
|
|
|
55356
55753
|
];
|
|
55357
55754
|
for (const candidate of ["pyproject.toml", "requirements.txt", "setup.py"]) {
|
|
55358
55755
|
try {
|
|
55359
|
-
const content =
|
|
55756
|
+
const content = fs22.readFileSync(path48.join(dir, candidate), "utf-8");
|
|
55360
55757
|
const lower = content.toLowerCase();
|
|
55361
55758
|
for (const [pkg, name] of candidates) {
|
|
55362
55759
|
if (lower.includes(pkg)) {
|
|
@@ -55370,7 +55767,7 @@ async function selectFramework2(dir) {
|
|
|
55370
55767
|
async function selectEntryPoints2(dir) {
|
|
55371
55768
|
const points = new Set;
|
|
55372
55769
|
try {
|
|
55373
|
-
const content =
|
|
55770
|
+
const content = fs22.readFileSync(path48.join(dir, "pyproject.toml"), "utf-8");
|
|
55374
55771
|
const scriptsBlock = content.match(/\[project\.scripts\][\s\S]*?(?=\n\[|$)/);
|
|
55375
55772
|
if (scriptsBlock) {
|
|
55376
55773
|
for (const line of scriptsBlock[0].split(`
|
|
@@ -55385,7 +55782,7 @@ async function selectEntryPoints2(dir) {
|
|
|
55385
55782
|
} catch {}
|
|
55386
55783
|
for (const name of ["manage.py", "main.py", "app.py", "__main__.py"]) {
|
|
55387
55784
|
try {
|
|
55388
|
-
|
|
55785
|
+
fs22.accessSync(path48.join(dir, name));
|
|
55389
55786
|
points.add(name);
|
|
55390
55787
|
} catch {}
|
|
55391
55788
|
}
|
|
@@ -55403,18 +55800,18 @@ function buildPythonBackend() {
|
|
|
55403
55800
|
selectEntryPoints: selectEntryPoints2
|
|
55404
55801
|
};
|
|
55405
55802
|
}
|
|
55406
|
-
var PROFILE_ID2 = "python", IMPORT_REGEX_FROM_WITH_TARGETS, IMPORT_REGEX_IMPORT,
|
|
55803
|
+
var PROFILE_ID2 = "python", IMPORT_REGEX_FROM_WITH_TARGETS, IMPORT_REGEX_IMPORT, _internals32;
|
|
55407
55804
|
var init_python = __esm(() => {
|
|
55408
55805
|
init_default_backend();
|
|
55409
55806
|
init_profiles();
|
|
55410
55807
|
IMPORT_REGEX_FROM_WITH_TARGETS = /^\s*from\s+(\.*[\w.]*)\s+import\s+(\([^)]*\)|[^\n#]+)/gm;
|
|
55411
55808
|
IMPORT_REGEX_IMPORT = /^\s*import\s+([^\n#]+)/gm;
|
|
55412
|
-
|
|
55809
|
+
_internals32 = { extractImports: extractImports2 };
|
|
55413
55810
|
});
|
|
55414
55811
|
|
|
55415
55812
|
// src/test-impact/analyzer.ts
|
|
55416
|
-
import
|
|
55417
|
-
import
|
|
55813
|
+
import fs23 from "fs";
|
|
55814
|
+
import path49 from "path";
|
|
55418
55815
|
function normalizePath(p) {
|
|
55419
55816
|
return p.replace(/\\/g, "/");
|
|
55420
55817
|
}
|
|
@@ -55434,7 +55831,7 @@ function sharedTrailingSegments(a, b) {
|
|
|
55434
55831
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
55435
55832
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
55436
55833
|
try {
|
|
55437
|
-
const stat5 =
|
|
55834
|
+
const stat5 = fs23.statSync(sourcePath);
|
|
55438
55835
|
if (stat5.mtimeMs > generatedAtMs) {
|
|
55439
55836
|
return true;
|
|
55440
55837
|
}
|
|
@@ -55448,15 +55845,15 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
55448
55845
|
if (!importPath.startsWith(".")) {
|
|
55449
55846
|
return null;
|
|
55450
55847
|
}
|
|
55451
|
-
const resolved =
|
|
55452
|
-
if (
|
|
55453
|
-
if (
|
|
55848
|
+
const resolved = path49.resolve(fromDir, importPath);
|
|
55849
|
+
if (path49.extname(resolved)) {
|
|
55850
|
+
if (fs23.existsSync(resolved) && fs23.statSync(resolved).isFile()) {
|
|
55454
55851
|
return normalizePath(resolved);
|
|
55455
55852
|
}
|
|
55456
55853
|
} else {
|
|
55457
55854
|
for (const ext of EXTENSIONS_TO_TRY) {
|
|
55458
55855
|
const withExt = resolved + ext;
|
|
55459
|
-
if (
|
|
55856
|
+
if (fs23.existsSync(withExt) && fs23.statSync(withExt).isFile()) {
|
|
55460
55857
|
return normalizePath(withExt);
|
|
55461
55858
|
}
|
|
55462
55859
|
}
|
|
@@ -55469,29 +55866,29 @@ function resolvePythonImport(fromDir, module) {
|
|
|
55469
55866
|
const leadingDots = module.match(/^\.+/)?.[0].length ?? 0;
|
|
55470
55867
|
let baseDir = fromDir;
|
|
55471
55868
|
for (let i = 1;i < leadingDots; i++) {
|
|
55472
|
-
baseDir =
|
|
55869
|
+
baseDir = path49.dirname(baseDir);
|
|
55473
55870
|
}
|
|
55474
55871
|
const rest = module.slice(leadingDots);
|
|
55475
55872
|
if (rest.length === 0) {
|
|
55476
|
-
const initPath =
|
|
55477
|
-
if (
|
|
55873
|
+
const initPath = path49.join(baseDir, "__init__.py");
|
|
55874
|
+
if (fs23.existsSync(initPath) && fs23.statSync(initPath).isFile()) {
|
|
55478
55875
|
return normalizePath(initPath);
|
|
55479
55876
|
}
|
|
55480
55877
|
return null;
|
|
55481
55878
|
}
|
|
55482
|
-
const subpath = rest.replace(/\./g,
|
|
55879
|
+
const subpath = rest.replace(/\./g, path49.sep);
|
|
55483
55880
|
const candidates = [
|
|
55484
|
-
`${
|
|
55485
|
-
|
|
55881
|
+
`${path49.join(baseDir, subpath)}.py`,
|
|
55882
|
+
path49.join(baseDir, subpath, "__init__.py")
|
|
55486
55883
|
];
|
|
55487
55884
|
for (const c of candidates) {
|
|
55488
|
-
if (
|
|
55885
|
+
if (fs23.existsSync(c) && fs23.statSync(c).isFile())
|
|
55489
55886
|
return normalizePath(c);
|
|
55490
55887
|
}
|
|
55491
55888
|
return null;
|
|
55492
55889
|
}
|
|
55493
55890
|
function findGoModule(fromDir) {
|
|
55494
|
-
const resolved =
|
|
55891
|
+
const resolved = path49.resolve(fromDir);
|
|
55495
55892
|
let cur = resolved;
|
|
55496
55893
|
const walked = [];
|
|
55497
55894
|
for (let i = 0;i < 16; i++) {
|
|
@@ -55503,8 +55900,8 @@ function findGoModule(fromDir) {
|
|
|
55503
55900
|
}
|
|
55504
55901
|
walked.push(cur);
|
|
55505
55902
|
try {
|
|
55506
|
-
const goMod =
|
|
55507
|
-
const content =
|
|
55903
|
+
const goMod = path49.join(cur, "go.mod");
|
|
55904
|
+
const content = fs23.readFileSync(goMod, "utf-8");
|
|
55508
55905
|
const moduleMatch = content.match(/^\s*module\s+"?([^"\s/]+(?:\/[^"\s]+)*)"?/m);
|
|
55509
55906
|
if (moduleMatch) {
|
|
55510
55907
|
const result = { moduleRoot: cur, modulePath: moduleMatch[1] };
|
|
@@ -55514,10 +55911,10 @@ function findGoModule(fromDir) {
|
|
|
55514
55911
|
}
|
|
55515
55912
|
} catch {}
|
|
55516
55913
|
try {
|
|
55517
|
-
|
|
55914
|
+
fs23.accessSync(path49.join(cur, ".git"));
|
|
55518
55915
|
break;
|
|
55519
55916
|
} catch {}
|
|
55520
|
-
const parent =
|
|
55917
|
+
const parent = path49.dirname(cur);
|
|
55521
55918
|
if (parent === cur)
|
|
55522
55919
|
break;
|
|
55523
55920
|
cur = parent;
|
|
@@ -55529,20 +55926,20 @@ function findGoModule(fromDir) {
|
|
|
55529
55926
|
function resolveGoImport(fromDir, importPath) {
|
|
55530
55927
|
let dir = null;
|
|
55531
55928
|
if (importPath.startsWith(".")) {
|
|
55532
|
-
dir =
|
|
55929
|
+
dir = path49.resolve(fromDir, importPath);
|
|
55533
55930
|
} else {
|
|
55534
55931
|
const mod = findGoModule(fromDir);
|
|
55535
55932
|
if (mod && (importPath === mod.modulePath || importPath.startsWith(`${mod.modulePath}/`))) {
|
|
55536
55933
|
const subpath = importPath.slice(mod.modulePath.length);
|
|
55537
|
-
dir =
|
|
55934
|
+
dir = path49.join(mod.moduleRoot, subpath);
|
|
55538
55935
|
}
|
|
55539
55936
|
}
|
|
55540
55937
|
if (dir === null)
|
|
55541
55938
|
return [];
|
|
55542
|
-
if (!
|
|
55939
|
+
if (!fs23.existsSync(dir) || !fs23.statSync(dir).isDirectory())
|
|
55543
55940
|
return [];
|
|
55544
55941
|
try {
|
|
55545
|
-
return
|
|
55942
|
+
return fs23.readdirSync(dir).filter((f) => f.endsWith(".go") && !f.endsWith("_test.go")).map((f) => normalizePath(path49.join(dir, f)));
|
|
55546
55943
|
} catch {
|
|
55547
55944
|
return [];
|
|
55548
55945
|
}
|
|
@@ -55562,13 +55959,13 @@ function findTestFilesSync(cwd) {
|
|
|
55562
55959
|
function walk(dir, visitedInodes) {
|
|
55563
55960
|
let entries;
|
|
55564
55961
|
try {
|
|
55565
|
-
entries =
|
|
55962
|
+
entries = fs23.readdirSync(dir, { withFileTypes: true });
|
|
55566
55963
|
} catch {
|
|
55567
55964
|
return;
|
|
55568
55965
|
}
|
|
55569
55966
|
let dirInode;
|
|
55570
55967
|
try {
|
|
55571
|
-
dirInode =
|
|
55968
|
+
dirInode = fs23.statSync(dir).ino;
|
|
55572
55969
|
} catch {
|
|
55573
55970
|
return;
|
|
55574
55971
|
}
|
|
@@ -55581,15 +55978,15 @@ function findTestFilesSync(cwd) {
|
|
|
55581
55978
|
for (const entry of entries) {
|
|
55582
55979
|
if (entry.isDirectory()) {
|
|
55583
55980
|
if (!skipDirs.has(entry.name)) {
|
|
55584
|
-
walk(
|
|
55981
|
+
walk(path49.join(dir, entry.name), visitedInodes);
|
|
55585
55982
|
}
|
|
55586
55983
|
} else if (entry.isFile()) {
|
|
55587
55984
|
const name = entry.name;
|
|
55588
55985
|
const isTsTest = /\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name);
|
|
55589
|
-
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${
|
|
55986
|
+
const isPyTest = /^test_.+\.py$/.test(name) || /.+_test\.py$/.test(name) || dir.includes(`${path49.sep}tests${path49.sep}`) && name.endsWith(".py");
|
|
55590
55987
|
const isGoTest = /.+_test\.go$/.test(name);
|
|
55591
55988
|
if (isTsTest || isPyTest || isGoTest) {
|
|
55592
|
-
testFiles.push(normalizePath(
|
|
55989
|
+
testFiles.push(normalizePath(path49.join(dir, entry.name)));
|
|
55593
55990
|
}
|
|
55594
55991
|
}
|
|
55595
55992
|
}
|
|
@@ -55614,8 +56011,8 @@ function extractImports3(content) {
|
|
|
55614
56011
|
];
|
|
55615
56012
|
}
|
|
55616
56013
|
function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
55617
|
-
const ext =
|
|
55618
|
-
const testDir =
|
|
56014
|
+
const ext = path49.extname(testFile).toLowerCase();
|
|
56015
|
+
const testDir = path49.dirname(testFile);
|
|
55619
56016
|
function addEdge(source) {
|
|
55620
56017
|
if (!impactMap[source])
|
|
55621
56018
|
impactMap[source] = [];
|
|
@@ -55633,7 +56030,7 @@ function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
|
55633
56030
|
return;
|
|
55634
56031
|
}
|
|
55635
56032
|
if (PYTHON_EXTENSIONS.has(ext)) {
|
|
55636
|
-
const modules =
|
|
56033
|
+
const modules = _internals32.extractImports(testFile, content);
|
|
55637
56034
|
for (const mod of modules) {
|
|
55638
56035
|
const resolved = resolvePythonImport(testDir, mod);
|
|
55639
56036
|
if (resolved !== null)
|
|
@@ -55642,7 +56039,7 @@ function addImpactEdgesForTestFile(testFile, content, impactMap) {
|
|
|
55642
56039
|
return;
|
|
55643
56040
|
}
|
|
55644
56041
|
if (GO_EXTENSIONS.has(ext)) {
|
|
55645
|
-
const imports =
|
|
56042
|
+
const imports = _internals31.extractImports(testFile, content);
|
|
55646
56043
|
for (const importPath of imports) {
|
|
55647
56044
|
const sourceFiles = resolveGoImport(testDir, importPath);
|
|
55648
56045
|
for (const source of sourceFiles)
|
|
@@ -55657,7 +56054,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
55657
56054
|
for (const testFile of testFiles) {
|
|
55658
56055
|
let content;
|
|
55659
56056
|
try {
|
|
55660
|
-
content =
|
|
56057
|
+
content = fs23.readFileSync(testFile, "utf-8");
|
|
55661
56058
|
} catch {
|
|
55662
56059
|
continue;
|
|
55663
56060
|
}
|
|
@@ -55669,22 +56066,22 @@ async function buildImpactMapInternal(cwd) {
|
|
|
55669
56066
|
return impactMap;
|
|
55670
56067
|
}
|
|
55671
56068
|
async function buildImpactMap(cwd) {
|
|
55672
|
-
const impactMap = await
|
|
55673
|
-
await
|
|
56069
|
+
const impactMap = await _internals33.buildImpactMapInternal(cwd);
|
|
56070
|
+
await _internals33.saveImpactMap(cwd, impactMap);
|
|
55674
56071
|
return impactMap;
|
|
55675
56072
|
}
|
|
55676
56073
|
async function loadImpactMap(cwd, options) {
|
|
55677
|
-
const cachePath =
|
|
55678
|
-
if (
|
|
56074
|
+
const cachePath = path49.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
56075
|
+
if (fs23.existsSync(cachePath)) {
|
|
55679
56076
|
try {
|
|
55680
|
-
const content =
|
|
56077
|
+
const content = fs23.readFileSync(cachePath, "utf-8");
|
|
55681
56078
|
const data = JSON.parse(content);
|
|
55682
56079
|
if (data.map !== null && typeof data.map === "object" && !Array.isArray(data.map)) {
|
|
55683
56080
|
const map3 = data.map;
|
|
55684
56081
|
const hasValidValues = Object.values(map3).every((v) => Array.isArray(v) && v.every((item) => typeof item === "string"));
|
|
55685
56082
|
if (hasValidValues) {
|
|
55686
56083
|
const generatedAt = new Date(data.generatedAt).getTime();
|
|
55687
|
-
if (!
|
|
56084
|
+
if (!_internals33.isCacheStale(map3, generatedAt)) {
|
|
55688
56085
|
return map3;
|
|
55689
56086
|
}
|
|
55690
56087
|
if (options?.skipRebuild) {
|
|
@@ -55704,24 +56101,24 @@ async function loadImpactMap(cwd, options) {
|
|
|
55704
56101
|
if (options?.skipRebuild) {
|
|
55705
56102
|
return {};
|
|
55706
56103
|
}
|
|
55707
|
-
return
|
|
56104
|
+
return _internals33.buildImpactMap(cwd);
|
|
55708
56105
|
}
|
|
55709
56106
|
async function saveImpactMap(cwd, impactMap) {
|
|
55710
|
-
if (!
|
|
56107
|
+
if (!path49.isAbsolute(cwd)) {
|
|
55711
56108
|
throw new Error(`saveImpactMap requires an absolute project root path, got: "${cwd}"`);
|
|
55712
56109
|
}
|
|
55713
|
-
|
|
55714
|
-
const cacheDir2 =
|
|
55715
|
-
const cachePath =
|
|
55716
|
-
if (!
|
|
55717
|
-
|
|
56110
|
+
_internals33.validateProjectRoot(cwd);
|
|
56111
|
+
const cacheDir2 = path49.join(cwd, ".swarm", "cache");
|
|
56112
|
+
const cachePath = path49.join(cacheDir2, "impact-map.json");
|
|
56113
|
+
if (!fs23.existsSync(cacheDir2)) {
|
|
56114
|
+
fs23.mkdirSync(cacheDir2, { recursive: true });
|
|
55718
56115
|
}
|
|
55719
56116
|
const data = {
|
|
55720
56117
|
generatedAt: new Date().toISOString(),
|
|
55721
56118
|
fileCount: Object.keys(impactMap).length,
|
|
55722
56119
|
map: impactMap
|
|
55723
56120
|
};
|
|
55724
|
-
|
|
56121
|
+
fs23.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
55725
56122
|
}
|
|
55726
56123
|
async function analyzeImpact(changedFiles, cwd, budget) {
|
|
55727
56124
|
if (!Array.isArray(changedFiles)) {
|
|
@@ -55734,7 +56131,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
55734
56131
|
};
|
|
55735
56132
|
}
|
|
55736
56133
|
const validFiles = changedFiles.filter((f) => typeof f === "string" && f.length > 0 && !f.includes("\x00"));
|
|
55737
|
-
const impactMap = await
|
|
56134
|
+
const impactMap = await _internals33.loadImpactMap(cwd);
|
|
55738
56135
|
const impactedTestsSet = new Set;
|
|
55739
56136
|
const untestedFiles = [];
|
|
55740
56137
|
let visitedCount = 0;
|
|
@@ -55744,7 +56141,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
55744
56141
|
budgetExceeded = true;
|
|
55745
56142
|
break;
|
|
55746
56143
|
}
|
|
55747
|
-
const normalizedChanged = normalizePath(
|
|
56144
|
+
const normalizedChanged = normalizePath(path49.resolve(changedFile));
|
|
55748
56145
|
const tests = impactMap[normalizedChanged];
|
|
55749
56146
|
if (tests && tests.length > 0) {
|
|
55750
56147
|
for (const test of tests) {
|
|
@@ -55758,13 +56155,13 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
55758
56155
|
if (budgetExceeded)
|
|
55759
56156
|
break;
|
|
55760
56157
|
} else {
|
|
55761
|
-
const changedDir = normalizePath(
|
|
55762
|
-
const changedInputDir = normalizePath(
|
|
56158
|
+
const changedDir = normalizePath(path49.dirname(normalizedChanged));
|
|
56159
|
+
const changedInputDir = normalizePath(path49.dirname(changedFile));
|
|
55763
56160
|
const suffixMatches = Object.entries(impactMap).filter(([sourcePath]) => {
|
|
55764
56161
|
return sourcePath.endsWith(changedFile) || changedFile.endsWith(sourcePath) || sourcePath.endsWith(normalizedChanged) || normalizedChanged.endsWith(sourcePath);
|
|
55765
56162
|
}).sort(([sourceA], [sourceB]) => {
|
|
55766
|
-
const sourceDirA = normalizePath(
|
|
55767
|
-
const sourceDirB = normalizePath(
|
|
56163
|
+
const sourceDirA = normalizePath(path49.dirname(sourceA));
|
|
56164
|
+
const sourceDirB = normalizePath(path49.dirname(sourceB));
|
|
55768
56165
|
const exactA = sourceDirA === changedDir || changedInputDir !== "." && (sourceDirA === changedInputDir || sourceDirA.endsWith(`/${changedInputDir}`));
|
|
55769
56166
|
const exactB = sourceDirB === changedDir || changedInputDir !== "." && (sourceDirB === changedInputDir || sourceDirB.endsWith(`/${changedInputDir}`));
|
|
55770
56167
|
if (exactA !== exactB)
|
|
@@ -55819,7 +56216,7 @@ async function analyzeImpact(changedFiles, cwd, budget) {
|
|
|
55819
56216
|
budgetExceeded
|
|
55820
56217
|
};
|
|
55821
56218
|
}
|
|
55822
|
-
var IMPORT_REGEX_ES, IMPORT_REGEX_REQUIRE, IMPORT_REGEX_REEXPORT, TS_EXTENSIONS, PYTHON_EXTENSIONS, GO_EXTENSIONS, EXTENSIONS_TO_TRY, goModuleCache,
|
|
56219
|
+
var IMPORT_REGEX_ES, IMPORT_REGEX_REQUIRE, IMPORT_REGEX_REEXPORT, TS_EXTENSIONS, PYTHON_EXTENSIONS, GO_EXTENSIONS, EXTENSIONS_TO_TRY, goModuleCache, _internals33;
|
|
55823
56220
|
var init_analyzer = __esm(() => {
|
|
55824
56221
|
init_manager2();
|
|
55825
56222
|
init_go();
|
|
@@ -55832,7 +56229,7 @@ var init_analyzer = __esm(() => {
|
|
|
55832
56229
|
GO_EXTENSIONS = new Set([".go"]);
|
|
55833
56230
|
EXTENSIONS_TO_TRY = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
55834
56231
|
goModuleCache = new Map;
|
|
55835
|
-
|
|
56232
|
+
_internals33 = {
|
|
55836
56233
|
validateProjectRoot,
|
|
55837
56234
|
normalizePath,
|
|
55838
56235
|
isCacheStale,
|
|
@@ -56071,16 +56468,16 @@ function detectFlakyTests(allHistory) {
|
|
|
56071
56468
|
var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
|
|
56072
56469
|
|
|
56073
56470
|
// src/test-impact/history-store.ts
|
|
56074
|
-
import
|
|
56075
|
-
import
|
|
56471
|
+
import fs24 from "fs";
|
|
56472
|
+
import path50 from "path";
|
|
56076
56473
|
function getHistoryPath(workingDir) {
|
|
56077
56474
|
if (!workingDir) {
|
|
56078
56475
|
throw new Error("getHistoryPath requires a working directory \u2014 project root must be provided by the caller");
|
|
56079
56476
|
}
|
|
56080
|
-
if (!
|
|
56477
|
+
if (!path50.isAbsolute(workingDir)) {
|
|
56081
56478
|
throw new Error(`getHistoryPath requires an absolute project root path, got: "${workingDir}"`);
|
|
56082
56479
|
}
|
|
56083
|
-
return
|
|
56480
|
+
return path50.join(workingDir, ".swarm", "cache", "test-history.jsonl");
|
|
56084
56481
|
}
|
|
56085
56482
|
function sanitizeErrorMessage(errorMessage) {
|
|
56086
56483
|
if (errorMessage === undefined) {
|
|
@@ -56167,13 +56564,13 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
56167
56564
|
}
|
|
56168
56565
|
}
|
|
56169
56566
|
const historyPath = getHistoryPath(workingDir);
|
|
56170
|
-
const historyDir =
|
|
56171
|
-
|
|
56172
|
-
if (!
|
|
56173
|
-
|
|
56567
|
+
const historyDir = path50.dirname(historyPath);
|
|
56568
|
+
_internals34.validateProjectRoot(workingDir);
|
|
56569
|
+
if (!fs24.existsSync(historyDir)) {
|
|
56570
|
+
fs24.mkdirSync(historyDir, { recursive: true });
|
|
56174
56571
|
}
|
|
56175
56572
|
withHistoryWriteLock(historyPath, () => {
|
|
56176
|
-
const existingRecords =
|
|
56573
|
+
const existingRecords = readAllRecords2(historyPath);
|
|
56177
56574
|
const sanitizedRecords = records.map((record3) => ({
|
|
56178
56575
|
...record3,
|
|
56179
56576
|
timestamp: record3.timestamp || new Date().toISOString(),
|
|
@@ -56204,13 +56601,13 @@ function batchAppendTestRuns(records, workingDir) {
|
|
|
56204
56601
|
`)}
|
|
56205
56602
|
`;
|
|
56206
56603
|
const tempPath = `${historyPath}.tmp`;
|
|
56207
|
-
|
|
56208
|
-
|
|
56604
|
+
fs24.writeFileSync(tempPath, content, "utf-8");
|
|
56605
|
+
fs24.renameSync(tempPath, historyPath);
|
|
56209
56606
|
} catch (err) {
|
|
56210
56607
|
try {
|
|
56211
56608
|
const tempPath = `${historyPath}.tmp`;
|
|
56212
|
-
if (
|
|
56213
|
-
|
|
56609
|
+
if (fs24.existsSync(tempPath)) {
|
|
56610
|
+
fs24.unlinkSync(tempPath);
|
|
56214
56611
|
}
|
|
56215
56612
|
} catch {}
|
|
56216
56613
|
throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -56222,7 +56619,7 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
56222
56619
|
const deadline = Date.now() + HISTORY_WRITE_LOCK_TIMEOUT_MS;
|
|
56223
56620
|
while (true) {
|
|
56224
56621
|
try {
|
|
56225
|
-
|
|
56622
|
+
fs24.mkdirSync(lockPath);
|
|
56226
56623
|
break;
|
|
56227
56624
|
} catch (error93) {
|
|
56228
56625
|
const code = error93 instanceof Error && "code" in error93 ? error93.code : undefined;
|
|
@@ -56233,9 +56630,9 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
56233
56630
|
throw new Error(`Timed out waiting for test history lock: ${historyPath}`);
|
|
56234
56631
|
}
|
|
56235
56632
|
try {
|
|
56236
|
-
const lockStat =
|
|
56633
|
+
const lockStat = fs24.statSync(lockPath);
|
|
56237
56634
|
if (Date.now() - lockStat.mtimeMs >= HISTORY_WRITE_LOCK_STALE_MS) {
|
|
56238
|
-
|
|
56635
|
+
fs24.rmSync(lockPath, { recursive: true, force: true });
|
|
56239
56636
|
continue;
|
|
56240
56637
|
}
|
|
56241
56638
|
} catch {}
|
|
@@ -56250,7 +56647,7 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
56250
56647
|
return fn();
|
|
56251
56648
|
} finally {
|
|
56252
56649
|
try {
|
|
56253
|
-
|
|
56650
|
+
fs24.rmSync(lockPath, { recursive: true, force: true });
|
|
56254
56651
|
} catch {}
|
|
56255
56652
|
}
|
|
56256
56653
|
function sleepSync(ms) {
|
|
@@ -56258,12 +56655,12 @@ function withHistoryWriteLock(historyPath, fn) {
|
|
|
56258
56655
|
while (Date.now() < until) {}
|
|
56259
56656
|
}
|
|
56260
56657
|
}
|
|
56261
|
-
function
|
|
56262
|
-
if (!
|
|
56658
|
+
function readAllRecords2(historyPath) {
|
|
56659
|
+
if (!fs24.existsSync(historyPath)) {
|
|
56263
56660
|
return [];
|
|
56264
56661
|
}
|
|
56265
56662
|
try {
|
|
56266
|
-
const content =
|
|
56663
|
+
const content = fs24.readFileSync(historyPath, "utf-8");
|
|
56267
56664
|
const lines = content.split(`
|
|
56268
56665
|
`);
|
|
56269
56666
|
const records = [];
|
|
@@ -56287,11 +56684,11 @@ function readAllRecords(historyPath) {
|
|
|
56287
56684
|
}
|
|
56288
56685
|
function getAllHistory(workingDir) {
|
|
56289
56686
|
const historyPath = getHistoryPath(workingDir);
|
|
56290
|
-
const records =
|
|
56687
|
+
const records = readAllRecords2(historyPath);
|
|
56291
56688
|
records.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
|
|
56292
56689
|
return records;
|
|
56293
56690
|
}
|
|
56294
|
-
var MAX_HISTORY_PER_TEST = 20, MAX_ERROR_LENGTH = 500, MAX_STACK_LENGTH = 200, MAX_CHANGED_FILES = 50, HISTORY_WRITE_LOCK_TIMEOUT_MS = 5000, HISTORY_WRITE_LOCK_STALE_MS = 60000, HISTORY_WRITE_LOCK_BACKOFF_MS = 10, DANGEROUS_PROPERTY_NAMES,
|
|
56691
|
+
var MAX_HISTORY_PER_TEST = 20, MAX_ERROR_LENGTH = 500, MAX_STACK_LENGTH = 200, MAX_CHANGED_FILES = 50, HISTORY_WRITE_LOCK_TIMEOUT_MS = 5000, HISTORY_WRITE_LOCK_STALE_MS = 60000, HISTORY_WRITE_LOCK_BACKOFF_MS = 10, DANGEROUS_PROPERTY_NAMES, _internals34;
|
|
56295
56692
|
var init_history_store = __esm(() => {
|
|
56296
56693
|
init_manager2();
|
|
56297
56694
|
DANGEROUS_PROPERTY_NAMES = new Set([
|
|
@@ -56299,14 +56696,14 @@ var init_history_store = __esm(() => {
|
|
|
56299
56696
|
"constructor",
|
|
56300
56697
|
"prototype"
|
|
56301
56698
|
]);
|
|
56302
|
-
|
|
56699
|
+
_internals34 = {
|
|
56303
56700
|
validateProjectRoot
|
|
56304
56701
|
};
|
|
56305
56702
|
});
|
|
56306
56703
|
|
|
56307
56704
|
// src/tools/resolve-working-directory.ts
|
|
56308
|
-
import * as
|
|
56309
|
-
import * as
|
|
56705
|
+
import * as fs25 from "fs";
|
|
56706
|
+
import * as path51 from "path";
|
|
56310
56707
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
56311
56708
|
if (workingDirectory == null || workingDirectory === "") {
|
|
56312
56709
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
@@ -56338,18 +56735,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
56338
56735
|
};
|
|
56339
56736
|
}
|
|
56340
56737
|
}
|
|
56341
|
-
const rawPathParts = workingDirectory.split(
|
|
56738
|
+
const rawPathParts = workingDirectory.split(path51.sep);
|
|
56342
56739
|
if (rawPathParts.includes("..")) {
|
|
56343
56740
|
return {
|
|
56344
56741
|
success: false,
|
|
56345
56742
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
56346
56743
|
};
|
|
56347
56744
|
}
|
|
56348
|
-
const normalizedDir =
|
|
56349
|
-
const resolvedDir =
|
|
56745
|
+
const normalizedDir = path51.normalize(workingDirectory);
|
|
56746
|
+
const resolvedDir = path51.resolve(normalizedDir);
|
|
56350
56747
|
let statResult;
|
|
56351
56748
|
try {
|
|
56352
|
-
statResult =
|
|
56749
|
+
statResult = fs25.statSync(resolvedDir);
|
|
56353
56750
|
} catch {
|
|
56354
56751
|
return {
|
|
56355
56752
|
success: false,
|
|
@@ -56365,16 +56762,16 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
56365
56762
|
if (typeof fallbackDirectory !== "string" || fallbackDirectory === "") {
|
|
56366
56763
|
return { success: true, directory: resolvedDir };
|
|
56367
56764
|
}
|
|
56368
|
-
const resolvedFallback =
|
|
56765
|
+
const resolvedFallback = path51.resolve(fallbackDirectory);
|
|
56369
56766
|
let fallbackExists = false;
|
|
56370
56767
|
try {
|
|
56371
|
-
|
|
56768
|
+
fs25.statSync(resolvedFallback);
|
|
56372
56769
|
fallbackExists = true;
|
|
56373
56770
|
} catch {
|
|
56374
56771
|
fallbackExists = false;
|
|
56375
56772
|
}
|
|
56376
56773
|
if (fallbackExists) {
|
|
56377
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
56774
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path51.sep);
|
|
56378
56775
|
if (isSubdirectory) {
|
|
56379
56776
|
return {
|
|
56380
56777
|
success: false,
|
|
@@ -56420,8 +56817,8 @@ var init_registry_backend = __esm(() => {
|
|
|
56420
56817
|
});
|
|
56421
56818
|
|
|
56422
56819
|
// src/lang/framework-detector.ts
|
|
56423
|
-
import * as
|
|
56424
|
-
import * as
|
|
56820
|
+
import * as fs26 from "fs";
|
|
56821
|
+
import * as path52 from "path";
|
|
56425
56822
|
function detectLaravelProject(directory) {
|
|
56426
56823
|
const signals = getLaravelSignals(directory);
|
|
56427
56824
|
const signalCount = [
|
|
@@ -56438,21 +56835,21 @@ function getLaravelSignals(directory) {
|
|
|
56438
56835
|
return { hasArtisanFile, hasLaravelFrameworkDep, hasConfigApp };
|
|
56439
56836
|
}
|
|
56440
56837
|
function checkArtisanFile(directory) {
|
|
56441
|
-
const artisanPath =
|
|
56442
|
-
if (!
|
|
56838
|
+
const artisanPath = path52.join(directory, "artisan");
|
|
56839
|
+
if (!fs26.existsSync(artisanPath))
|
|
56443
56840
|
return false;
|
|
56444
56841
|
try {
|
|
56445
|
-
return
|
|
56842
|
+
return fs26.statSync(artisanPath).isFile();
|
|
56446
56843
|
} catch {
|
|
56447
56844
|
return false;
|
|
56448
56845
|
}
|
|
56449
56846
|
}
|
|
56450
56847
|
function checkLaravelFrameworkDep(directory) {
|
|
56451
|
-
const composerPath =
|
|
56452
|
-
if (!
|
|
56848
|
+
const composerPath = path52.join(directory, "composer.json");
|
|
56849
|
+
if (!fs26.existsSync(composerPath))
|
|
56453
56850
|
return false;
|
|
56454
56851
|
try {
|
|
56455
|
-
const content =
|
|
56852
|
+
const content = fs26.readFileSync(composerPath, "utf-8");
|
|
56456
56853
|
const parsed = JSON.parse(content);
|
|
56457
56854
|
const require2 = parsed?.require ?? {};
|
|
56458
56855
|
return typeof require2["laravel/framework"] === "string";
|
|
@@ -56461,7 +56858,7 @@ function checkLaravelFrameworkDep(directory) {
|
|
|
56461
56858
|
}
|
|
56462
56859
|
}
|
|
56463
56860
|
function checkConfigApp(directory) {
|
|
56464
|
-
return
|
|
56861
|
+
return fs26.existsSync(path52.join(directory, "config", "app.php"));
|
|
56465
56862
|
}
|
|
56466
56863
|
var init_framework_detector = () => {};
|
|
56467
56864
|
|
|
@@ -56493,18 +56890,18 @@ var init_php = __esm(() => {
|
|
|
56493
56890
|
});
|
|
56494
56891
|
|
|
56495
56892
|
// src/lang/backends/typescript.ts
|
|
56496
|
-
import * as
|
|
56497
|
-
import * as
|
|
56893
|
+
import * as fs27 from "fs";
|
|
56894
|
+
import * as path53 from "path";
|
|
56498
56895
|
function readPackageJsonRaw(dir) {
|
|
56499
56896
|
try {
|
|
56500
|
-
const content =
|
|
56897
|
+
const content = fs27.readFileSync(path53.join(dir, "package.json"), "utf-8");
|
|
56501
56898
|
return JSON.parse(content);
|
|
56502
56899
|
} catch {
|
|
56503
56900
|
return null;
|
|
56504
56901
|
}
|
|
56505
56902
|
}
|
|
56506
56903
|
function readPackageJson(dir) {
|
|
56507
|
-
return
|
|
56904
|
+
return _internals35.readPackageJsonRaw(dir);
|
|
56508
56905
|
}
|
|
56509
56906
|
function readPackageJsonTestScript(dir) {
|
|
56510
56907
|
return readPackageJson(dir)?.scripts?.test ?? null;
|
|
@@ -56674,7 +57071,7 @@ function buildTypescriptBackend() {
|
|
|
56674
57071
|
selectEntryPoints: selectEntryPoints3
|
|
56675
57072
|
};
|
|
56676
57073
|
}
|
|
56677
|
-
var PROFILE_ID4 = "typescript", IMPORT_REGEX_ES2, IMPORT_REGEX_BARE, IMPORT_REGEX_REQUIRE2, IMPORT_REGEX_DYNAMIC, IMPORT_REGEX_REEXPORT2,
|
|
57074
|
+
var PROFILE_ID4 = "typescript", IMPORT_REGEX_ES2, IMPORT_REGEX_BARE, IMPORT_REGEX_REQUIRE2, IMPORT_REGEX_DYNAMIC, IMPORT_REGEX_REEXPORT2, _internals35;
|
|
56678
57075
|
var init_typescript = __esm(() => {
|
|
56679
57076
|
init_default_backend();
|
|
56680
57077
|
init_profiles();
|
|
@@ -56683,7 +57080,7 @@ var init_typescript = __esm(() => {
|
|
|
56683
57080
|
IMPORT_REGEX_REQUIRE2 = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
56684
57081
|
IMPORT_REGEX_DYNAMIC = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
56685
57082
|
IMPORT_REGEX_REEXPORT2 = /export\s+(?:\{[^}]*\}|\*)\s+from\s+['"]([^'"]+)['"]/g;
|
|
56686
|
-
|
|
57083
|
+
_internals35 = {
|
|
56687
57084
|
readPackageJsonRaw,
|
|
56688
57085
|
readPackageJsonTestScript,
|
|
56689
57086
|
frameworkFromScriptsTest
|
|
@@ -56716,13 +57113,13 @@ __export(exports_dispatch, {
|
|
|
56716
57113
|
pickedProfiles: () => pickedProfiles,
|
|
56717
57114
|
pickBackend: () => pickBackend,
|
|
56718
57115
|
clearDispatchCache: () => clearDispatchCache,
|
|
56719
|
-
_internals: () =>
|
|
57116
|
+
_internals: () => _internals36
|
|
56720
57117
|
});
|
|
56721
|
-
import * as
|
|
56722
|
-
import * as
|
|
57118
|
+
import * as fs28 from "fs";
|
|
57119
|
+
import * as path54 from "path";
|
|
56723
57120
|
function safeReaddirSet(dir) {
|
|
56724
57121
|
try {
|
|
56725
|
-
return new Set(
|
|
57122
|
+
return new Set(fs28.readdirSync(dir));
|
|
56726
57123
|
} catch {
|
|
56727
57124
|
return new Set;
|
|
56728
57125
|
}
|
|
@@ -56736,14 +57133,14 @@ function manifestHash(dir) {
|
|
|
56736
57133
|
if (!entries.has(name))
|
|
56737
57134
|
continue;
|
|
56738
57135
|
try {
|
|
56739
|
-
const stat5 =
|
|
57136
|
+
const stat5 = fs28.statSync(path54.join(dir, name));
|
|
56740
57137
|
parts.push(`${name}:${stat5.size}:${stat5.mtimeMs}:${stat5.ino}`);
|
|
56741
57138
|
} catch {}
|
|
56742
57139
|
}
|
|
56743
57140
|
return parts.join("|");
|
|
56744
57141
|
}
|
|
56745
57142
|
function findManifestRoot(start) {
|
|
56746
|
-
const resolved =
|
|
57143
|
+
const resolved = path54.resolve(start);
|
|
56747
57144
|
const cached3 = manifestRootCache.get(resolved);
|
|
56748
57145
|
if (cached3 !== undefined)
|
|
56749
57146
|
return cached3;
|
|
@@ -56762,7 +57159,7 @@ function findManifestRoot(start) {
|
|
|
56762
57159
|
return cur;
|
|
56763
57160
|
}
|
|
56764
57161
|
}
|
|
56765
|
-
const parent =
|
|
57162
|
+
const parent = path54.dirname(cur);
|
|
56766
57163
|
if (parent === cur)
|
|
56767
57164
|
break;
|
|
56768
57165
|
cur = parent;
|
|
@@ -56771,7 +57168,7 @@ function findManifestRoot(start) {
|
|
|
56771
57168
|
return start;
|
|
56772
57169
|
}
|
|
56773
57170
|
function evictIfNeeded() {
|
|
56774
|
-
if (cache.size <=
|
|
57171
|
+
if (cache.size <= _internals36.cacheCapacity)
|
|
56775
57172
|
return;
|
|
56776
57173
|
let oldestKey;
|
|
56777
57174
|
let oldestOrder = Infinity;
|
|
@@ -56802,7 +57199,7 @@ async function pickBackend(dir) {
|
|
|
56802
57199
|
evictIfNeeded();
|
|
56803
57200
|
return null;
|
|
56804
57201
|
}
|
|
56805
|
-
const profiles = await
|
|
57202
|
+
const profiles = await _internals36.detectProjectLanguages(root);
|
|
56806
57203
|
if (profiles.length === 0) {
|
|
56807
57204
|
cache.set(cacheKey, {
|
|
56808
57205
|
hash: hash4,
|
|
@@ -56834,12 +57231,12 @@ function clearDispatchCache() {
|
|
|
56834
57231
|
manifestRootCache.clear();
|
|
56835
57232
|
insertCounter = 0;
|
|
56836
57233
|
}
|
|
56837
|
-
var
|
|
57234
|
+
var _internals36, cache, insertCounter = 0, MANIFEST_FILES, _MANIFEST_SET, manifestRootCache;
|
|
56838
57235
|
var init_dispatch = __esm(() => {
|
|
56839
57236
|
init_backends();
|
|
56840
57237
|
init_detector();
|
|
56841
57238
|
init_registry_backend();
|
|
56842
|
-
|
|
57239
|
+
_internals36 = {
|
|
56843
57240
|
detectProjectLanguages,
|
|
56844
57241
|
cacheCapacity: 64
|
|
56845
57242
|
};
|
|
@@ -56871,14 +57268,14 @@ var init_dispatch = __esm(() => {
|
|
|
56871
57268
|
});
|
|
56872
57269
|
|
|
56873
57270
|
// src/tools/test-runner.ts
|
|
56874
|
-
import * as
|
|
56875
|
-
import * as
|
|
57271
|
+
import * as fs29 from "fs";
|
|
57272
|
+
import * as path55 from "path";
|
|
56876
57273
|
async function estimateFanOut(sourceFiles, cwd) {
|
|
56877
57274
|
try {
|
|
56878
57275
|
const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
|
|
56879
57276
|
const uniqueTestFiles = new Set;
|
|
56880
57277
|
for (const sourceFile of sourceFiles) {
|
|
56881
|
-
const resolvedPath =
|
|
57278
|
+
const resolvedPath = path55.resolve(cwd, sourceFile);
|
|
56882
57279
|
const normalizedPath = resolvedPath.replace(/\\/g, "/");
|
|
56883
57280
|
const testFiles = impactMap[normalizedPath];
|
|
56884
57281
|
if (testFiles) {
|
|
@@ -56960,19 +57357,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
56960
57357
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
56961
57358
|
}
|
|
56962
57359
|
function detectGoTest(cwd) {
|
|
56963
|
-
return
|
|
57360
|
+
return fs29.existsSync(path55.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
56964
57361
|
}
|
|
56965
57362
|
function detectJavaMaven(cwd) {
|
|
56966
|
-
return
|
|
57363
|
+
return fs29.existsSync(path55.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
56967
57364
|
}
|
|
56968
57365
|
function detectGradle(cwd) {
|
|
56969
|
-
const hasBuildFile =
|
|
56970
|
-
const hasGradlew =
|
|
57366
|
+
const hasBuildFile = fs29.existsSync(path55.join(cwd, "build.gradle")) || fs29.existsSync(path55.join(cwd, "build.gradle.kts"));
|
|
57367
|
+
const hasGradlew = fs29.existsSync(path55.join(cwd, "gradlew")) || fs29.existsSync(path55.join(cwd, "gradlew.bat"));
|
|
56971
57368
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
56972
57369
|
}
|
|
56973
57370
|
function detectDotnetTest(cwd) {
|
|
56974
57371
|
try {
|
|
56975
|
-
const files =
|
|
57372
|
+
const files = fs29.readdirSync(cwd);
|
|
56976
57373
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
56977
57374
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
56978
57375
|
} catch {
|
|
@@ -56980,25 +57377,25 @@ function detectDotnetTest(cwd) {
|
|
|
56980
57377
|
}
|
|
56981
57378
|
}
|
|
56982
57379
|
function detectCTest(cwd) {
|
|
56983
|
-
const hasSource =
|
|
56984
|
-
const hasBuildCache =
|
|
57380
|
+
const hasSource = fs29.existsSync(path55.join(cwd, "CMakeLists.txt"));
|
|
57381
|
+
const hasBuildCache = fs29.existsSync(path55.join(cwd, "CMakeCache.txt")) || fs29.existsSync(path55.join(cwd, "build", "CMakeCache.txt"));
|
|
56985
57382
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
56986
57383
|
}
|
|
56987
57384
|
function detectSwiftTest(cwd) {
|
|
56988
|
-
return
|
|
57385
|
+
return fs29.existsSync(path55.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
56989
57386
|
}
|
|
56990
57387
|
function detectDartTest(cwd) {
|
|
56991
|
-
return
|
|
57388
|
+
return fs29.existsSync(path55.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
56992
57389
|
}
|
|
56993
57390
|
function detectRSpec(cwd) {
|
|
56994
|
-
const hasRSpecFile =
|
|
56995
|
-
const hasGemfile =
|
|
56996
|
-
const hasSpecDir =
|
|
57391
|
+
const hasRSpecFile = fs29.existsSync(path55.join(cwd, ".rspec"));
|
|
57392
|
+
const hasGemfile = fs29.existsSync(path55.join(cwd, "Gemfile"));
|
|
57393
|
+
const hasSpecDir = fs29.existsSync(path55.join(cwd, "spec"));
|
|
56997
57394
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
56998
57395
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
56999
57396
|
}
|
|
57000
57397
|
function detectMinitest(cwd) {
|
|
57001
|
-
return
|
|
57398
|
+
return fs29.existsSync(path55.join(cwd, "test")) && (fs29.existsSync(path55.join(cwd, "Gemfile")) || fs29.existsSync(path55.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
57002
57399
|
}
|
|
57003
57400
|
async function detectTestFrameworkViaDispatch(cwd) {
|
|
57004
57401
|
try {
|
|
@@ -57061,9 +57458,9 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
|
|
|
57061
57458
|
async function detectTestFramework(cwd) {
|
|
57062
57459
|
const baseDir = cwd;
|
|
57063
57460
|
try {
|
|
57064
|
-
const packageJsonPath =
|
|
57065
|
-
if (
|
|
57066
|
-
const content =
|
|
57461
|
+
const packageJsonPath = path55.join(baseDir, "package.json");
|
|
57462
|
+
if (fs29.existsSync(packageJsonPath)) {
|
|
57463
|
+
const content = fs29.readFileSync(packageJsonPath, "utf-8");
|
|
57067
57464
|
const pkg = JSON.parse(content);
|
|
57068
57465
|
const _deps = pkg.dependencies || {};
|
|
57069
57466
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -57082,38 +57479,38 @@ async function detectTestFramework(cwd) {
|
|
|
57082
57479
|
return "jest";
|
|
57083
57480
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
57084
57481
|
return "mocha";
|
|
57085
|
-
if (
|
|
57482
|
+
if (fs29.existsSync(path55.join(baseDir, "bun.lockb")) || fs29.existsSync(path55.join(baseDir, "bun.lock"))) {
|
|
57086
57483
|
if (scripts.test?.includes("bun"))
|
|
57087
57484
|
return "bun";
|
|
57088
57485
|
}
|
|
57089
57486
|
}
|
|
57090
57487
|
} catch {}
|
|
57091
57488
|
try {
|
|
57092
|
-
const pyprojectTomlPath =
|
|
57093
|
-
const setupCfgPath =
|
|
57094
|
-
const requirementsTxtPath =
|
|
57095
|
-
if (
|
|
57096
|
-
const content =
|
|
57489
|
+
const pyprojectTomlPath = path55.join(baseDir, "pyproject.toml");
|
|
57490
|
+
const setupCfgPath = path55.join(baseDir, "setup.cfg");
|
|
57491
|
+
const requirementsTxtPath = path55.join(baseDir, "requirements.txt");
|
|
57492
|
+
if (fs29.existsSync(pyprojectTomlPath)) {
|
|
57493
|
+
const content = fs29.readFileSync(pyprojectTomlPath, "utf-8");
|
|
57097
57494
|
if (content.includes("[tool.pytest"))
|
|
57098
57495
|
return "pytest";
|
|
57099
57496
|
if (content.includes("pytest"))
|
|
57100
57497
|
return "pytest";
|
|
57101
57498
|
}
|
|
57102
|
-
if (
|
|
57103
|
-
const content =
|
|
57499
|
+
if (fs29.existsSync(setupCfgPath)) {
|
|
57500
|
+
const content = fs29.readFileSync(setupCfgPath, "utf-8");
|
|
57104
57501
|
if (content.includes("[pytest]"))
|
|
57105
57502
|
return "pytest";
|
|
57106
57503
|
}
|
|
57107
|
-
if (
|
|
57108
|
-
const content =
|
|
57504
|
+
if (fs29.existsSync(requirementsTxtPath)) {
|
|
57505
|
+
const content = fs29.readFileSync(requirementsTxtPath, "utf-8");
|
|
57109
57506
|
if (content.includes("pytest"))
|
|
57110
57507
|
return "pytest";
|
|
57111
57508
|
}
|
|
57112
57509
|
} catch {}
|
|
57113
57510
|
try {
|
|
57114
|
-
const cargoTomlPath =
|
|
57115
|
-
if (
|
|
57116
|
-
const content =
|
|
57511
|
+
const cargoTomlPath = path55.join(baseDir, "Cargo.toml");
|
|
57512
|
+
if (fs29.existsSync(cargoTomlPath)) {
|
|
57513
|
+
const content = fs29.readFileSync(cargoTomlPath, "utf-8");
|
|
57117
57514
|
if (content.includes("[dev-dependencies]")) {
|
|
57118
57515
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
57119
57516
|
return "cargo";
|
|
@@ -57122,10 +57519,10 @@ async function detectTestFramework(cwd) {
|
|
|
57122
57519
|
}
|
|
57123
57520
|
} catch {}
|
|
57124
57521
|
try {
|
|
57125
|
-
const pesterConfigPath =
|
|
57126
|
-
const pesterConfigJsonPath =
|
|
57127
|
-
const pesterPs1Path =
|
|
57128
|
-
if (
|
|
57522
|
+
const pesterConfigPath = path55.join(baseDir, "pester.config.ps1");
|
|
57523
|
+
const pesterConfigJsonPath = path55.join(baseDir, "pester.config.ps1.json");
|
|
57524
|
+
const pesterPs1Path = path55.join(baseDir, "tests.ps1");
|
|
57525
|
+
if (fs29.existsSync(pesterConfigPath) || fs29.existsSync(pesterConfigJsonPath) || fs29.existsSync(pesterPs1Path)) {
|
|
57129
57526
|
return "pester";
|
|
57130
57527
|
}
|
|
57131
57528
|
} catch {}
|
|
@@ -57153,12 +57550,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
57153
57550
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
57154
57551
|
}
|
|
57155
57552
|
function resolveWorkspacePath(file3, workingDir) {
|
|
57156
|
-
return
|
|
57553
|
+
return path55.isAbsolute(file3) ? path55.resolve(file3) : path55.resolve(workingDir, file3);
|
|
57157
57554
|
}
|
|
57158
57555
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
57159
57556
|
if (!preferRelative)
|
|
57160
57557
|
return absolutePath;
|
|
57161
|
-
return
|
|
57558
|
+
return path55.relative(workingDir, absolutePath);
|
|
57162
57559
|
}
|
|
57163
57560
|
function dedupePush(target, value) {
|
|
57164
57561
|
if (!target.includes(value)) {
|
|
@@ -57195,18 +57592,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
57195
57592
|
}
|
|
57196
57593
|
}
|
|
57197
57594
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
57198
|
-
const relativeDir =
|
|
57595
|
+
const relativeDir = path55.dirname(relativePath);
|
|
57199
57596
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
57200
57597
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
57201
|
-
const rootDir =
|
|
57202
|
-
return nestedRelativeDir ? [rootDir,
|
|
57598
|
+
const rootDir = path55.join(workingDir, dirName);
|
|
57599
|
+
return nestedRelativeDir ? [rootDir, path55.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
57203
57600
|
});
|
|
57204
57601
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
57205
57602
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
57206
|
-
directories.push(
|
|
57603
|
+
directories.push(path55.join(workingDir, "src/test/java", path55.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
57207
57604
|
}
|
|
57208
57605
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
57209
|
-
directories.push(
|
|
57606
|
+
directories.push(path55.join(workingDir, "src/test/kotlin", path55.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
57210
57607
|
}
|
|
57211
57608
|
return [...new Set(directories)];
|
|
57212
57609
|
}
|
|
@@ -57234,23 +57631,23 @@ function isLanguageSpecificTestFile(basename9) {
|
|
|
57234
57631
|
}
|
|
57235
57632
|
function isConventionTestFilePath(filePath) {
|
|
57236
57633
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
57237
|
-
const basename9 =
|
|
57634
|
+
const basename9 = path55.basename(filePath);
|
|
57238
57635
|
return hasCompoundTestExtension(basename9) || basename9.includes(".spec.") || basename9.includes(".test.") || isLanguageSpecificTestFile(basename9) || isTestDirectoryPath(normalizedPath);
|
|
57239
57636
|
}
|
|
57240
57637
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
57241
57638
|
const testFiles = [];
|
|
57242
57639
|
for (const file3 of sourceFiles) {
|
|
57243
57640
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
57244
|
-
const relativeFile =
|
|
57245
|
-
const basename9 =
|
|
57246
|
-
const dirname31 =
|
|
57247
|
-
const preferRelativeOutput = !
|
|
57641
|
+
const relativeFile = path55.relative(workingDir, absoluteFile);
|
|
57642
|
+
const basename9 = path55.basename(absoluteFile);
|
|
57643
|
+
const dirname31 = path55.dirname(absoluteFile);
|
|
57644
|
+
const preferRelativeOutput = !path55.isAbsolute(file3);
|
|
57248
57645
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
57249
57646
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
57250
57647
|
continue;
|
|
57251
57648
|
}
|
|
57252
57649
|
const nameWithoutExt = basename9.replace(/\.[^.]+$/, "");
|
|
57253
|
-
const ext =
|
|
57650
|
+
const ext = path55.extname(basename9);
|
|
57254
57651
|
const genericTestNames = [
|
|
57255
57652
|
`${nameWithoutExt}.spec${ext}`,
|
|
57256
57653
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -57259,7 +57656,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
57259
57656
|
const colocatedCandidates = [
|
|
57260
57657
|
...genericTestNames,
|
|
57261
57658
|
...languageSpecificTestNames
|
|
57262
|
-
].map((candidateName) =>
|
|
57659
|
+
].map((candidateName) => path55.join(dirname31, candidateName));
|
|
57263
57660
|
const testDirectoryNames = [
|
|
57264
57661
|
basename9,
|
|
57265
57662
|
...genericTestNames,
|
|
@@ -57268,11 +57665,11 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
57268
57665
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
57269
57666
|
const possibleTestFiles = [
|
|
57270
57667
|
...colocatedCandidates,
|
|
57271
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
57272
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
57668
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path55.join(dirname31, dirName, candidateName))),
|
|
57669
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path55.join(candidateDir, candidateName)))
|
|
57273
57670
|
];
|
|
57274
57671
|
for (const testFile of possibleTestFiles) {
|
|
57275
|
-
if (
|
|
57672
|
+
if (fs29.existsSync(testFile)) {
|
|
57276
57673
|
dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
|
|
57277
57674
|
}
|
|
57278
57675
|
}
|
|
@@ -57289,8 +57686,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
57289
57686
|
for (const testFile of candidateTestFiles) {
|
|
57290
57687
|
try {
|
|
57291
57688
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
57292
|
-
const content =
|
|
57293
|
-
const testDir =
|
|
57689
|
+
const content = fs29.readFileSync(absoluteTestFile, "utf-8");
|
|
57690
|
+
const testDir = path55.dirname(absoluteTestFile);
|
|
57294
57691
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
57295
57692
|
let match;
|
|
57296
57693
|
match = importRegex.exec(content);
|
|
@@ -57298,8 +57695,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
57298
57695
|
const importPath = match[1];
|
|
57299
57696
|
let resolvedImport;
|
|
57300
57697
|
if (importPath.startsWith(".")) {
|
|
57301
|
-
resolvedImport =
|
|
57302
|
-
const existingExt =
|
|
57698
|
+
resolvedImport = path55.resolve(testDir, importPath);
|
|
57699
|
+
const existingExt = path55.extname(resolvedImport);
|
|
57303
57700
|
if (!existingExt) {
|
|
57304
57701
|
for (const extToTry of [
|
|
57305
57702
|
".ts",
|
|
@@ -57310,7 +57707,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
57310
57707
|
".cjs"
|
|
57311
57708
|
]) {
|
|
57312
57709
|
const withExt = resolvedImport + extToTry;
|
|
57313
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
57710
|
+
if (absoluteSourceFiles.includes(withExt) || fs29.existsSync(withExt)) {
|
|
57314
57711
|
resolvedImport = withExt;
|
|
57315
57712
|
break;
|
|
57316
57713
|
}
|
|
@@ -57319,12 +57716,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
57319
57716
|
} else {
|
|
57320
57717
|
continue;
|
|
57321
57718
|
}
|
|
57322
|
-
const importBasename =
|
|
57323
|
-
const importDir =
|
|
57719
|
+
const importBasename = path55.basename(resolvedImport, path55.extname(resolvedImport));
|
|
57720
|
+
const importDir = path55.dirname(resolvedImport);
|
|
57324
57721
|
for (const sourceFile of absoluteSourceFiles) {
|
|
57325
|
-
const sourceDir =
|
|
57326
|
-
const sourceBasename =
|
|
57327
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
57722
|
+
const sourceDir = path55.dirname(sourceFile);
|
|
57723
|
+
const sourceBasename = path55.basename(sourceFile, path55.extname(sourceFile));
|
|
57724
|
+
const isRelatedDir = importDir === sourceDir || importDir === path55.join(sourceDir, "__tests__") || importDir === path55.join(sourceDir, "tests") || importDir === path55.join(sourceDir, "test") || importDir === path55.join(sourceDir, "spec");
|
|
57328
57725
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
57329
57726
|
dedupePush(testFiles, testFile);
|
|
57330
57727
|
break;
|
|
@@ -57337,8 +57734,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
57337
57734
|
while (match !== null) {
|
|
57338
57735
|
const importPath = match[1];
|
|
57339
57736
|
if (importPath.startsWith(".")) {
|
|
57340
|
-
let resolvedImport =
|
|
57341
|
-
const existingExt =
|
|
57737
|
+
let resolvedImport = path55.resolve(testDir, importPath);
|
|
57738
|
+
const existingExt = path55.extname(resolvedImport);
|
|
57342
57739
|
if (!existingExt) {
|
|
57343
57740
|
for (const extToTry of [
|
|
57344
57741
|
".ts",
|
|
@@ -57349,18 +57746,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
57349
57746
|
".cjs"
|
|
57350
57747
|
]) {
|
|
57351
57748
|
const withExt = resolvedImport + extToTry;
|
|
57352
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
57749
|
+
if (absoluteSourceFiles.includes(withExt) || fs29.existsSync(withExt)) {
|
|
57353
57750
|
resolvedImport = withExt;
|
|
57354
57751
|
break;
|
|
57355
57752
|
}
|
|
57356
57753
|
}
|
|
57357
57754
|
}
|
|
57358
|
-
const importDir =
|
|
57359
|
-
const importBasename =
|
|
57755
|
+
const importDir = path55.dirname(resolvedImport);
|
|
57756
|
+
const importBasename = path55.basename(resolvedImport, path55.extname(resolvedImport));
|
|
57360
57757
|
for (const sourceFile of absoluteSourceFiles) {
|
|
57361
|
-
const sourceDir =
|
|
57362
|
-
const sourceBasename =
|
|
57363
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
57758
|
+
const sourceDir = path55.dirname(sourceFile);
|
|
57759
|
+
const sourceBasename = path55.basename(sourceFile, path55.extname(sourceFile));
|
|
57760
|
+
const isRelatedDir = importDir === sourceDir || importDir === path55.join(sourceDir, "__tests__") || importDir === path55.join(sourceDir, "tests") || importDir === path55.join(sourceDir, "test") || importDir === path55.join(sourceDir, "spec");
|
|
57364
57761
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
57365
57762
|
dedupePush(testFiles, testFile);
|
|
57366
57763
|
break;
|
|
@@ -57480,8 +57877,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir, bail) {
|
|
|
57480
57877
|
return ["mvn", "test"];
|
|
57481
57878
|
case "gradle": {
|
|
57482
57879
|
const isWindows = process.platform === "win32";
|
|
57483
|
-
const hasGradlewBat =
|
|
57484
|
-
const hasGradlew =
|
|
57880
|
+
const hasGradlewBat = fs29.existsSync(path55.join(baseDir, "gradlew.bat"));
|
|
57881
|
+
const hasGradlew = fs29.existsSync(path55.join(baseDir, "gradlew"));
|
|
57485
57882
|
if (hasGradlewBat && isWindows)
|
|
57486
57883
|
return ["gradlew.bat", "test"];
|
|
57487
57884
|
if (hasGradlew)
|
|
@@ -57498,7 +57895,7 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir, bail) {
|
|
|
57498
57895
|
"cmake-build-release",
|
|
57499
57896
|
"out"
|
|
57500
57897
|
];
|
|
57501
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
57898
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs29.existsSync(path55.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
57502
57899
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
57503
57900
|
}
|
|
57504
57901
|
case "swift-test":
|
|
@@ -57932,13 +58329,13 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
57932
58329
|
};
|
|
57933
58330
|
}
|
|
57934
58331
|
const startTime = Date.now();
|
|
57935
|
-
const vitestJsonOutputPath = framework === "vitest" ?
|
|
58332
|
+
const vitestJsonOutputPath = framework === "vitest" ? path55.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
|
|
57936
58333
|
try {
|
|
57937
58334
|
if (vitestJsonOutputPath) {
|
|
57938
58335
|
try {
|
|
57939
|
-
|
|
57940
|
-
if (
|
|
57941
|
-
|
|
58336
|
+
fs29.mkdirSync(path55.dirname(vitestJsonOutputPath), { recursive: true });
|
|
58337
|
+
if (fs29.existsSync(vitestJsonOutputPath)) {
|
|
58338
|
+
fs29.unlinkSync(vitestJsonOutputPath);
|
|
57942
58339
|
}
|
|
57943
58340
|
} catch {}
|
|
57944
58341
|
}
|
|
@@ -57947,9 +58344,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
57947
58344
|
stderr: "pipe",
|
|
57948
58345
|
cwd
|
|
57949
58346
|
});
|
|
57950
|
-
const timeoutPromise = new Promise((
|
|
58347
|
+
const timeoutPromise = new Promise((resolve20) => setTimeout(() => {
|
|
57951
58348
|
proc.kill();
|
|
57952
|
-
|
|
58349
|
+
resolve20(-1);
|
|
57953
58350
|
}, timeout_ms));
|
|
57954
58351
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
57955
58352
|
Promise.race([proc.exited, timeoutPromise]),
|
|
@@ -57964,8 +58361,8 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
57964
58361
|
}
|
|
57965
58362
|
if (vitestJsonOutputPath) {
|
|
57966
58363
|
try {
|
|
57967
|
-
if (
|
|
57968
|
-
const vitestJsonOutput =
|
|
58364
|
+
if (fs29.existsSync(vitestJsonOutputPath)) {
|
|
58365
|
+
const vitestJsonOutput = fs29.readFileSync(vitestJsonOutputPath, "utf-8");
|
|
57969
58366
|
if (vitestJsonOutput.trim().length > 0) {
|
|
57970
58367
|
output += (output ? `
|
|
57971
58368
|
` : "") + vitestJsonOutput;
|
|
@@ -58052,10 +58449,10 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
|
|
|
58052
58449
|
}
|
|
58053
58450
|
function normalizeHistoryTestFile(testFile, workingDir) {
|
|
58054
58451
|
const normalized = testFile.replace(/\\/g, "/");
|
|
58055
|
-
if (!
|
|
58452
|
+
if (!path55.isAbsolute(testFile))
|
|
58056
58453
|
return normalized;
|
|
58057
|
-
const relative11 =
|
|
58058
|
-
if (relative11.startsWith("..") ||
|
|
58454
|
+
const relative11 = path55.relative(workingDir, testFile);
|
|
58455
|
+
if (relative11.startsWith("..") || path55.isAbsolute(relative11)) {
|
|
58059
58456
|
return normalized;
|
|
58060
58457
|
}
|
|
58061
58458
|
return relative11.replace(/\\/g, "/");
|
|
@@ -58393,7 +58790,7 @@ var init_test_runner = __esm(() => {
|
|
|
58393
58790
|
const sourceFiles = args.files.filter((file3) => {
|
|
58394
58791
|
if (directTestFiles.includes(file3))
|
|
58395
58792
|
return false;
|
|
58396
|
-
const ext =
|
|
58793
|
+
const ext = path55.extname(file3).toLowerCase();
|
|
58397
58794
|
return SOURCE_EXTENSIONS.has(ext);
|
|
58398
58795
|
});
|
|
58399
58796
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -58439,7 +58836,7 @@ var init_test_runner = __esm(() => {
|
|
|
58439
58836
|
if (isConventionTestFilePath(f)) {
|
|
58440
58837
|
return false;
|
|
58441
58838
|
}
|
|
58442
|
-
const ext =
|
|
58839
|
+
const ext = path55.extname(f).toLowerCase();
|
|
58443
58840
|
return SOURCE_EXTENSIONS.has(ext);
|
|
58444
58841
|
});
|
|
58445
58842
|
if (sourceFiles.length === 0) {
|
|
@@ -58489,7 +58886,7 @@ var init_test_runner = __esm(() => {
|
|
|
58489
58886
|
if (isConventionTestFilePath(f)) {
|
|
58490
58887
|
return false;
|
|
58491
58888
|
}
|
|
58492
|
-
const ext =
|
|
58889
|
+
const ext = path55.extname(f).toLowerCase();
|
|
58493
58890
|
return SOURCE_EXTENSIONS.has(ext);
|
|
58494
58891
|
});
|
|
58495
58892
|
if (sourceFiles.length === 0) {
|
|
@@ -58541,8 +58938,8 @@ var init_test_runner = __esm(() => {
|
|
|
58541
58938
|
}
|
|
58542
58939
|
if (impactResult.impactedTests.length > 0) {
|
|
58543
58940
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
58544
|
-
const relativePath =
|
|
58545
|
-
return
|
|
58941
|
+
const relativePath = path55.relative(workingDir, absPath);
|
|
58942
|
+
return path55.isAbsolute(relativePath) ? absPath : relativePath;
|
|
58546
58943
|
});
|
|
58547
58944
|
} else {
|
|
58548
58945
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -58620,8 +59017,8 @@ var init_test_runner = __esm(() => {
|
|
|
58620
59017
|
});
|
|
58621
59018
|
|
|
58622
59019
|
// src/services/preflight-service.ts
|
|
58623
|
-
import * as
|
|
58624
|
-
import * as
|
|
59020
|
+
import * as fs30 from "fs";
|
|
59021
|
+
import * as path56 from "path";
|
|
58625
59022
|
function validateDirectoryPath(dir) {
|
|
58626
59023
|
if (!dir || typeof dir !== "string") {
|
|
58627
59024
|
throw new Error("Directory path is required");
|
|
@@ -58629,8 +59026,8 @@ function validateDirectoryPath(dir) {
|
|
|
58629
59026
|
if (dir.includes("..")) {
|
|
58630
59027
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
58631
59028
|
}
|
|
58632
|
-
const normalized =
|
|
58633
|
-
const absolutePath =
|
|
59029
|
+
const normalized = path56.normalize(dir);
|
|
59030
|
+
const absolutePath = path56.isAbsolute(normalized) ? normalized : path56.resolve(normalized);
|
|
58634
59031
|
return absolutePath;
|
|
58635
59032
|
}
|
|
58636
59033
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -58653,9 +59050,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
58653
59050
|
}
|
|
58654
59051
|
function getPackageVersion(dir) {
|
|
58655
59052
|
try {
|
|
58656
|
-
const packagePath =
|
|
58657
|
-
if (
|
|
58658
|
-
const content =
|
|
59053
|
+
const packagePath = path56.join(dir, "package.json");
|
|
59054
|
+
if (fs30.existsSync(packagePath)) {
|
|
59055
|
+
const content = fs30.readFileSync(packagePath, "utf-8");
|
|
58659
59056
|
const pkg = JSON.parse(content);
|
|
58660
59057
|
return pkg.version ?? null;
|
|
58661
59058
|
}
|
|
@@ -58664,9 +59061,9 @@ function getPackageVersion(dir) {
|
|
|
58664
59061
|
}
|
|
58665
59062
|
function getChangelogVersion(dir) {
|
|
58666
59063
|
try {
|
|
58667
|
-
const changelogPath =
|
|
58668
|
-
if (
|
|
58669
|
-
const content =
|
|
59064
|
+
const changelogPath = path56.join(dir, "CHANGELOG.md");
|
|
59065
|
+
if (fs30.existsSync(changelogPath)) {
|
|
59066
|
+
const content = fs30.readFileSync(changelogPath, "utf-8");
|
|
58670
59067
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
58671
59068
|
if (match) {
|
|
58672
59069
|
return match[1];
|
|
@@ -58678,10 +59075,10 @@ function getChangelogVersion(dir) {
|
|
|
58678
59075
|
function getVersionFileVersion(dir) {
|
|
58679
59076
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
58680
59077
|
for (const file3 of possibleFiles) {
|
|
58681
|
-
const filePath =
|
|
58682
|
-
if (
|
|
59078
|
+
const filePath = path56.join(dir, file3);
|
|
59079
|
+
if (fs30.existsSync(filePath)) {
|
|
58683
59080
|
try {
|
|
58684
|
-
const content =
|
|
59081
|
+
const content = fs30.readFileSync(filePath, "utf-8").trim();
|
|
58685
59082
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
58686
59083
|
if (match) {
|
|
58687
59084
|
return match[1];
|
|
@@ -58694,9 +59091,9 @@ function getVersionFileVersion(dir) {
|
|
|
58694
59091
|
async function runVersionCheck(dir, _timeoutMs) {
|
|
58695
59092
|
const startTime = Date.now();
|
|
58696
59093
|
try {
|
|
58697
|
-
const packageVersion =
|
|
58698
|
-
const changelogVersion =
|
|
58699
|
-
const versionFileVersion =
|
|
59094
|
+
const packageVersion = _internals37.getPackageVersion(dir);
|
|
59095
|
+
const changelogVersion = _internals37.getChangelogVersion(dir);
|
|
59096
|
+
const versionFileVersion = _internals37.getVersionFileVersion(dir);
|
|
58700
59097
|
const versions3 = [];
|
|
58701
59098
|
if (packageVersion)
|
|
58702
59099
|
versions3.push(`package.json: ${packageVersion}`);
|
|
@@ -59060,7 +59457,7 @@ async function runPreflight(dir, phase, config3) {
|
|
|
59060
59457
|
const reportId = `preflight-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
59061
59458
|
let validatedDir;
|
|
59062
59459
|
try {
|
|
59063
|
-
validatedDir =
|
|
59460
|
+
validatedDir = _internals37.validateDirectoryPath(dir);
|
|
59064
59461
|
} catch (error93) {
|
|
59065
59462
|
return {
|
|
59066
59463
|
id: reportId,
|
|
@@ -59080,7 +59477,7 @@ async function runPreflight(dir, phase, config3) {
|
|
|
59080
59477
|
}
|
|
59081
59478
|
let validatedTimeout;
|
|
59082
59479
|
try {
|
|
59083
|
-
validatedTimeout =
|
|
59480
|
+
validatedTimeout = _internals37.validateTimeout(config3?.checkTimeoutMs, DEFAULT_CONFIG.checkTimeoutMs);
|
|
59084
59481
|
} catch (error93) {
|
|
59085
59482
|
return {
|
|
59086
59483
|
id: reportId,
|
|
@@ -59121,12 +59518,12 @@ async function runPreflight(dir, phase, config3) {
|
|
|
59121
59518
|
});
|
|
59122
59519
|
const checks5 = [];
|
|
59123
59520
|
log("[Preflight] Running lint check...");
|
|
59124
|
-
const lintResult = await
|
|
59521
|
+
const lintResult = await _internals37.runLintCheck(validatedDir, cfg.linter, cfg.checkTimeoutMs);
|
|
59125
59522
|
checks5.push(lintResult);
|
|
59126
59523
|
log(`[Preflight] Lint check: ${lintResult.status} ${lintResult.message}`);
|
|
59127
59524
|
if (!cfg.skipTests) {
|
|
59128
59525
|
log("[Preflight] Running tests check...");
|
|
59129
|
-
const testsResult = await
|
|
59526
|
+
const testsResult = await _internals37.runTestsCheck(validatedDir, cfg.testScope, cfg.checkTimeoutMs);
|
|
59130
59527
|
checks5.push(testsResult);
|
|
59131
59528
|
log(`[Preflight] Tests check: ${testsResult.status} ${testsResult.message}`);
|
|
59132
59529
|
} else {
|
|
@@ -59138,7 +59535,7 @@ async function runPreflight(dir, phase, config3) {
|
|
|
59138
59535
|
}
|
|
59139
59536
|
if (!cfg.skipSecrets) {
|
|
59140
59537
|
log("[Preflight] Running secrets check...");
|
|
59141
|
-
const secretsResult = await
|
|
59538
|
+
const secretsResult = await _internals37.runSecretsCheck(validatedDir, cfg.checkTimeoutMs);
|
|
59142
59539
|
checks5.push(secretsResult);
|
|
59143
59540
|
log(`[Preflight] Secrets check: ${secretsResult.status} ${secretsResult.message}`);
|
|
59144
59541
|
} else {
|
|
@@ -59150,7 +59547,7 @@ async function runPreflight(dir, phase, config3) {
|
|
|
59150
59547
|
}
|
|
59151
59548
|
if (!cfg.skipEvidence) {
|
|
59152
59549
|
log("[Preflight] Running evidence check...");
|
|
59153
|
-
const evidenceResult = await
|
|
59550
|
+
const evidenceResult = await _internals37.runEvidenceCheck(validatedDir);
|
|
59154
59551
|
checks5.push(evidenceResult);
|
|
59155
59552
|
log(`[Preflight] Evidence check: ${evidenceResult.status} ${evidenceResult.message}`);
|
|
59156
59553
|
} else {
|
|
@@ -59161,12 +59558,12 @@ async function runPreflight(dir, phase, config3) {
|
|
|
59161
59558
|
});
|
|
59162
59559
|
}
|
|
59163
59560
|
log("[Preflight] Running requirement coverage check...");
|
|
59164
|
-
const reqCoverageResult = await
|
|
59561
|
+
const reqCoverageResult = await _internals37.runRequirementCoverageCheck(validatedDir, phase);
|
|
59165
59562
|
checks5.push(reqCoverageResult);
|
|
59166
59563
|
log(`[Preflight] Requirement coverage check: ${reqCoverageResult.status} ${reqCoverageResult.message}`);
|
|
59167
59564
|
if (!cfg.skipVersion) {
|
|
59168
59565
|
log("[Preflight] Running version check...");
|
|
59169
|
-
const versionResult = await
|
|
59566
|
+
const versionResult = await _internals37.runVersionCheck(validatedDir, cfg.checkTimeoutMs);
|
|
59170
59567
|
checks5.push(versionResult);
|
|
59171
59568
|
log(`[Preflight] Version check: ${versionResult.status} ${versionResult.message}`);
|
|
59172
59569
|
} else {
|
|
@@ -59229,10 +59626,10 @@ function formatPreflightMarkdown(report) {
|
|
|
59229
59626
|
async function handlePreflightCommand(directory, _args) {
|
|
59230
59627
|
const plan = await loadPlan(directory);
|
|
59231
59628
|
const phase = plan?.current_phase ?? 1;
|
|
59232
|
-
const report = await
|
|
59233
|
-
return
|
|
59629
|
+
const report = await _internals37.runPreflight(directory, phase);
|
|
59630
|
+
return _internals37.formatPreflightMarkdown(report);
|
|
59234
59631
|
}
|
|
59235
|
-
var MIN_CHECK_TIMEOUT_MS = 5000, MAX_CHECK_TIMEOUT_MS = 300000, DEFAULT_CONFIG,
|
|
59632
|
+
var MIN_CHECK_TIMEOUT_MS = 5000, MAX_CHECK_TIMEOUT_MS = 300000, DEFAULT_CONFIG, _internals37;
|
|
59236
59633
|
var init_preflight_service = __esm(() => {
|
|
59237
59634
|
init_gate_bridge();
|
|
59238
59635
|
init_manager2();
|
|
@@ -59251,7 +59648,7 @@ var init_preflight_service = __esm(() => {
|
|
|
59251
59648
|
testScope: "convention",
|
|
59252
59649
|
linter: "biome"
|
|
59253
59650
|
};
|
|
59254
|
-
|
|
59651
|
+
_internals37 = {
|
|
59255
59652
|
runPreflight,
|
|
59256
59653
|
formatPreflightMarkdown,
|
|
59257
59654
|
handlePreflightCommand,
|
|
@@ -59499,13 +59896,13 @@ class CircuitBreaker {
|
|
|
59499
59896
|
if (this.config.callTimeoutMs <= 0) {
|
|
59500
59897
|
return fn();
|
|
59501
59898
|
}
|
|
59502
|
-
return new Promise((
|
|
59899
|
+
return new Promise((resolve21, reject) => {
|
|
59503
59900
|
const timeout = setTimeout(() => {
|
|
59504
59901
|
reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
|
|
59505
59902
|
}, this.config.callTimeoutMs);
|
|
59506
59903
|
fn().then((result) => {
|
|
59507
59904
|
clearTimeout(timeout);
|
|
59508
|
-
|
|
59905
|
+
resolve21(result);
|
|
59509
59906
|
}).catch((error93) => {
|
|
59510
59907
|
clearTimeout(timeout);
|
|
59511
59908
|
reject(error93);
|
|
@@ -59792,7 +60189,7 @@ var init_queue = __esm(() => {
|
|
|
59792
60189
|
|
|
59793
60190
|
// src/background/worker.ts
|
|
59794
60191
|
function sleep(ms) {
|
|
59795
|
-
return new Promise((
|
|
60192
|
+
return new Promise((resolve21) => setTimeout(resolve21, ms));
|
|
59796
60193
|
}
|
|
59797
60194
|
|
|
59798
60195
|
class WorkerManager {
|
|
@@ -60137,8 +60534,8 @@ var init_manager3 = __esm(() => {
|
|
|
60137
60534
|
});
|
|
60138
60535
|
|
|
60139
60536
|
// src/commands/reset.ts
|
|
60140
|
-
import * as
|
|
60141
|
-
import * as
|
|
60537
|
+
import * as fs31 from "fs";
|
|
60538
|
+
import * as path57 from "path";
|
|
60142
60539
|
async function handleResetCommand(directory, args) {
|
|
60143
60540
|
const hasConfirm = args.includes("--confirm");
|
|
60144
60541
|
if (!hasConfirm) {
|
|
@@ -60166,8 +60563,8 @@ async function handleResetCommand(directory, args) {
|
|
|
60166
60563
|
for (const filename of filesToReset) {
|
|
60167
60564
|
try {
|
|
60168
60565
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
60169
|
-
if (
|
|
60170
|
-
|
|
60566
|
+
if (fs31.existsSync(resolvedPath)) {
|
|
60567
|
+
fs31.unlinkSync(resolvedPath);
|
|
60171
60568
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
60172
60569
|
} else {
|
|
60173
60570
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -60178,9 +60575,9 @@ async function handleResetCommand(directory, args) {
|
|
|
60178
60575
|
}
|
|
60179
60576
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
60180
60577
|
try {
|
|
60181
|
-
const rootPath =
|
|
60182
|
-
if (
|
|
60183
|
-
|
|
60578
|
+
const rootPath = path57.join(directory, filename);
|
|
60579
|
+
if (fs31.existsSync(rootPath)) {
|
|
60580
|
+
fs31.unlinkSync(rootPath);
|
|
60184
60581
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
60185
60582
|
}
|
|
60186
60583
|
} catch {}
|
|
@@ -60193,8 +60590,8 @@ async function handleResetCommand(directory, args) {
|
|
|
60193
60590
|
}
|
|
60194
60591
|
try {
|
|
60195
60592
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
60196
|
-
if (
|
|
60197
|
-
|
|
60593
|
+
if (fs31.existsSync(summariesPath)) {
|
|
60594
|
+
fs31.rmSync(summariesPath, { recursive: true, force: true });
|
|
60198
60595
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
60199
60596
|
} else {
|
|
60200
60597
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -60217,14 +60614,14 @@ var init_reset = __esm(() => {
|
|
|
60217
60614
|
});
|
|
60218
60615
|
|
|
60219
60616
|
// src/commands/reset-session.ts
|
|
60220
|
-
import * as
|
|
60221
|
-
import * as
|
|
60617
|
+
import * as fs32 from "fs";
|
|
60618
|
+
import * as path58 from "path";
|
|
60222
60619
|
async function handleResetSessionCommand(directory, _args) {
|
|
60223
60620
|
const results = [];
|
|
60224
60621
|
try {
|
|
60225
60622
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
60226
|
-
if (
|
|
60227
|
-
|
|
60623
|
+
if (fs32.existsSync(statePath)) {
|
|
60624
|
+
fs32.unlinkSync(statePath);
|
|
60228
60625
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
60229
60626
|
} else {
|
|
60230
60627
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -60233,15 +60630,15 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
60233
60630
|
results.push("\u274C Failed to delete state.json");
|
|
60234
60631
|
}
|
|
60235
60632
|
try {
|
|
60236
|
-
const sessionDir =
|
|
60237
|
-
if (
|
|
60238
|
-
const files =
|
|
60633
|
+
const sessionDir = path58.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
60634
|
+
if (fs32.existsSync(sessionDir)) {
|
|
60635
|
+
const files = fs32.readdirSync(sessionDir);
|
|
60239
60636
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
60240
60637
|
let deletedCount = 0;
|
|
60241
60638
|
for (const file3 of otherFiles) {
|
|
60242
|
-
const filePath =
|
|
60243
|
-
if (
|
|
60244
|
-
|
|
60639
|
+
const filePath = path58.join(sessionDir, file3);
|
|
60640
|
+
if (fs32.lstatSync(filePath).isFile()) {
|
|
60641
|
+
fs32.unlinkSync(filePath);
|
|
60245
60642
|
deletedCount++;
|
|
60246
60643
|
}
|
|
60247
60644
|
}
|
|
@@ -60271,7 +60668,7 @@ var init_reset_session = __esm(() => {
|
|
|
60271
60668
|
});
|
|
60272
60669
|
|
|
60273
60670
|
// src/summaries/manager.ts
|
|
60274
|
-
import * as
|
|
60671
|
+
import * as path59 from "path";
|
|
60275
60672
|
function sanitizeSummaryId(id) {
|
|
60276
60673
|
if (!id || id.length === 0) {
|
|
60277
60674
|
throw new Error("Invalid summary ID: empty string");
|
|
@@ -60294,7 +60691,7 @@ function sanitizeSummaryId(id) {
|
|
|
60294
60691
|
}
|
|
60295
60692
|
async function loadFullOutput(directory, id) {
|
|
60296
60693
|
const sanitizedId = sanitizeSummaryId(id);
|
|
60297
|
-
const relativePath =
|
|
60694
|
+
const relativePath = path59.join("summaries", `${sanitizedId}.json`);
|
|
60298
60695
|
validateSwarmPath(directory, relativePath);
|
|
60299
60696
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
60300
60697
|
if (content === null) {
|
|
@@ -60356,18 +60753,18 @@ var init_retrieve = __esm(() => {
|
|
|
60356
60753
|
});
|
|
60357
60754
|
|
|
60358
60755
|
// src/commands/rollback.ts
|
|
60359
|
-
import * as
|
|
60360
|
-
import * as
|
|
60756
|
+
import * as fs33 from "fs";
|
|
60757
|
+
import * as path60 from "path";
|
|
60361
60758
|
async function handleRollbackCommand(directory, args) {
|
|
60362
60759
|
const phaseArg = args[0];
|
|
60363
60760
|
if (!phaseArg) {
|
|
60364
60761
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
60365
|
-
if (!
|
|
60762
|
+
if (!fs33.existsSync(manifestPath2)) {
|
|
60366
60763
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
60367
60764
|
}
|
|
60368
60765
|
let manifest2;
|
|
60369
60766
|
try {
|
|
60370
|
-
manifest2 = JSON.parse(
|
|
60767
|
+
manifest2 = JSON.parse(fs33.readFileSync(manifestPath2, "utf-8"));
|
|
60371
60768
|
} catch {
|
|
60372
60769
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
60373
60770
|
}
|
|
@@ -60389,12 +60786,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
60389
60786
|
return "Error: Phase number must be a positive integer.";
|
|
60390
60787
|
}
|
|
60391
60788
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
60392
|
-
if (!
|
|
60789
|
+
if (!fs33.existsSync(manifestPath)) {
|
|
60393
60790
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
60394
60791
|
}
|
|
60395
60792
|
let manifest;
|
|
60396
60793
|
try {
|
|
60397
|
-
manifest = JSON.parse(
|
|
60794
|
+
manifest = JSON.parse(fs33.readFileSync(manifestPath, "utf-8"));
|
|
60398
60795
|
} catch {
|
|
60399
60796
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
60400
60797
|
}
|
|
@@ -60404,10 +60801,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
60404
60801
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
60405
60802
|
}
|
|
60406
60803
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
60407
|
-
if (!
|
|
60804
|
+
if (!fs33.existsSync(checkpointDir)) {
|
|
60408
60805
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
60409
60806
|
}
|
|
60410
|
-
const checkpointFiles =
|
|
60807
|
+
const checkpointFiles = fs33.readdirSync(checkpointDir);
|
|
60411
60808
|
if (checkpointFiles.length === 0) {
|
|
60412
60809
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
60413
60810
|
}
|
|
@@ -60422,10 +60819,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
60422
60819
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
60423
60820
|
continue;
|
|
60424
60821
|
}
|
|
60425
|
-
const src =
|
|
60426
|
-
const dest =
|
|
60822
|
+
const src = path60.join(checkpointDir, file3);
|
|
60823
|
+
const dest = path60.join(swarmDir, file3);
|
|
60427
60824
|
try {
|
|
60428
|
-
|
|
60825
|
+
fs33.cpSync(src, dest, { recursive: true, force: true });
|
|
60429
60826
|
successes.push(file3);
|
|
60430
60827
|
} catch (error93) {
|
|
60431
60828
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -60442,14 +60839,14 @@ async function handleRollbackCommand(directory, args) {
|
|
|
60442
60839
|
].join(`
|
|
60443
60840
|
`);
|
|
60444
60841
|
}
|
|
60445
|
-
const existingLedgerPath =
|
|
60446
|
-
if (
|
|
60447
|
-
|
|
60842
|
+
const existingLedgerPath = path60.join(swarmDir, "plan-ledger.jsonl");
|
|
60843
|
+
if (fs33.existsSync(existingLedgerPath)) {
|
|
60844
|
+
fs33.unlinkSync(existingLedgerPath);
|
|
60448
60845
|
}
|
|
60449
60846
|
try {
|
|
60450
|
-
const planJsonPath =
|
|
60451
|
-
if (
|
|
60452
|
-
const planRaw =
|
|
60847
|
+
const planJsonPath = path60.join(swarmDir, "plan.json");
|
|
60848
|
+
if (fs33.existsSync(planJsonPath)) {
|
|
60849
|
+
const planRaw = fs33.readFileSync(planJsonPath, "utf-8");
|
|
60453
60850
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
60454
60851
|
const planId = derivePlanId(plan);
|
|
60455
60852
|
const planHash = computePlanHash(plan);
|
|
@@ -60476,7 +60873,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
60476
60873
|
timestamp: new Date().toISOString()
|
|
60477
60874
|
};
|
|
60478
60875
|
try {
|
|
60479
|
-
|
|
60876
|
+
fs33.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
60480
60877
|
`);
|
|
60481
60878
|
} catch (error93) {
|
|
60482
60879
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -60705,11 +61102,11 @@ Ensure this is a git repository with commit history.`;
|
|
|
60705
61102
|
const report = reportLines.filter(Boolean).join(`
|
|
60706
61103
|
`);
|
|
60707
61104
|
try {
|
|
60708
|
-
const
|
|
60709
|
-
const
|
|
60710
|
-
const reportPath =
|
|
60711
|
-
await
|
|
60712
|
-
await
|
|
61105
|
+
const fs34 = await import("fs/promises");
|
|
61106
|
+
const path61 = await import("path");
|
|
61107
|
+
const reportPath = path61.join(directory, ".swarm", "simulate-report.md");
|
|
61108
|
+
await fs34.mkdir(path61.dirname(reportPath), { recursive: true });
|
|
61109
|
+
await fs34.writeFile(reportPath, report, "utf-8");
|
|
60713
61110
|
} catch (err) {
|
|
60714
61111
|
const writeErr = err instanceof Error ? err.message : String(err);
|
|
60715
61112
|
warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
|
|
@@ -60763,15 +61160,15 @@ var init_knowledge_escalator = __esm(() => {
|
|
|
60763
61160
|
});
|
|
60764
61161
|
|
|
60765
61162
|
// src/turbo/lean/state.ts
|
|
60766
|
-
import * as
|
|
60767
|
-
import * as
|
|
61163
|
+
import * as fs34 from "fs";
|
|
61164
|
+
import * as path61 from "path";
|
|
60768
61165
|
function nowISO2() {
|
|
60769
61166
|
return new Date().toISOString();
|
|
60770
61167
|
}
|
|
60771
|
-
function
|
|
60772
|
-
const swarmDir =
|
|
60773
|
-
if (!
|
|
60774
|
-
|
|
61168
|
+
function ensureSwarmDir3(directory) {
|
|
61169
|
+
const swarmDir = path61.resolve(directory, ".swarm");
|
|
61170
|
+
if (!fs34.existsSync(swarmDir)) {
|
|
61171
|
+
fs34.mkdirSync(swarmDir, { recursive: true });
|
|
60775
61172
|
}
|
|
60776
61173
|
return swarmDir;
|
|
60777
61174
|
}
|
|
@@ -60813,17 +61210,17 @@ function markStateUnreadable2(directory, reason) {
|
|
|
60813
61210
|
}
|
|
60814
61211
|
function readPersisted2(directory) {
|
|
60815
61212
|
try {
|
|
60816
|
-
const filePath =
|
|
60817
|
-
if (!
|
|
61213
|
+
const filePath = path61.join(directory, ".swarm", STATE_FILE2);
|
|
61214
|
+
if (!fs34.existsSync(filePath)) {
|
|
60818
61215
|
const seed = emptyPersisted2();
|
|
60819
61216
|
try {
|
|
60820
|
-
|
|
60821
|
-
|
|
61217
|
+
ensureSwarmDir3(directory);
|
|
61218
|
+
fs34.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
|
|
60822
61219
|
`, "utf-8");
|
|
60823
61220
|
} catch {}
|
|
60824
61221
|
return seed;
|
|
60825
61222
|
}
|
|
60826
|
-
const raw =
|
|
61223
|
+
const raw = fs34.readFileSync(filePath, "utf-8");
|
|
60827
61224
|
const parsed = JSON.parse(raw);
|
|
60828
61225
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
|
|
60829
61226
|
markStateUnreadable2(directory, `malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
|
|
@@ -60848,8 +61245,8 @@ function writePersisted2(directory, persisted) {
|
|
|
60848
61245
|
let tmpPath;
|
|
60849
61246
|
let payload;
|
|
60850
61247
|
try {
|
|
60851
|
-
|
|
60852
|
-
filePath =
|
|
61248
|
+
ensureSwarmDir3(directory);
|
|
61249
|
+
filePath = path61.join(directory, ".swarm", STATE_FILE2);
|
|
60853
61250
|
tmpPath = `${filePath}.tmp.${Date.now()}`;
|
|
60854
61251
|
persisted.updatedAt = nowISO2();
|
|
60855
61252
|
payload = `${JSON.stringify(persisted, null, 2)}
|
|
@@ -60860,14 +61257,14 @@ function writePersisted2(directory, persisted) {
|
|
|
60860
61257
|
throw new Error(`Lean Turbo state persistence prepare failed: ${msg}`);
|
|
60861
61258
|
}
|
|
60862
61259
|
try {
|
|
60863
|
-
|
|
60864
|
-
|
|
61260
|
+
fs34.writeFileSync(tmpPath, payload, "utf-8");
|
|
61261
|
+
fs34.renameSync(tmpPath, filePath);
|
|
60865
61262
|
} catch (error93) {
|
|
60866
61263
|
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
60867
61264
|
error(`[turbo/lean/state] Failed to persist ${STATE_FILE2} atomically: ${msg}`);
|
|
60868
61265
|
try {
|
|
60869
|
-
if (
|
|
60870
|
-
|
|
61266
|
+
if (fs34.existsSync(tmpPath)) {
|
|
61267
|
+
fs34.unlinkSync(tmpPath);
|
|
60871
61268
|
}
|
|
60872
61269
|
} catch {}
|
|
60873
61270
|
throw new Error(`Lean Turbo state persistence failed: ${msg}`);
|
|
@@ -60976,10 +61373,10 @@ var init_context_budget_service = __esm(() => {
|
|
|
60976
61373
|
|
|
60977
61374
|
// src/services/status-service.ts
|
|
60978
61375
|
import * as fsSync3 from "fs";
|
|
60979
|
-
import * as
|
|
61376
|
+
import * as path62 from "path";
|
|
60980
61377
|
function readSpecStalenessSnapshot(directory) {
|
|
60981
61378
|
try {
|
|
60982
|
-
const p =
|
|
61379
|
+
const p = path62.join(directory, ".swarm", "spec-staleness.json");
|
|
60983
61380
|
if (!fsSync3.existsSync(p))
|
|
60984
61381
|
return { stale: false };
|
|
60985
61382
|
const raw = fsSync3.readFileSync(p, "utf-8");
|
|
@@ -61074,7 +61471,7 @@ async function getStatusData(directory, agents) {
|
|
|
61074
61471
|
}
|
|
61075
61472
|
function enrichWithLeanTurbo(status, directory) {
|
|
61076
61473
|
const turboMode = hasActiveTurboMode();
|
|
61077
|
-
const leanActive =
|
|
61474
|
+
const leanActive = _internals38.hasActiveLeanTurbo();
|
|
61078
61475
|
let turboStrategy = "off";
|
|
61079
61476
|
if (leanActive) {
|
|
61080
61477
|
turboStrategy = "lean";
|
|
@@ -61093,7 +61490,7 @@ function enrichWithLeanTurbo(status, directory) {
|
|
|
61093
61490
|
}
|
|
61094
61491
|
}
|
|
61095
61492
|
if (leanSessionID) {
|
|
61096
|
-
const runState =
|
|
61493
|
+
const runState = _internals38.loadLeanTurboRunState(directory, leanSessionID);
|
|
61097
61494
|
if (runState) {
|
|
61098
61495
|
status.leanTurboPhase = runState.phase;
|
|
61099
61496
|
status.leanMaxParallelCoders = runState.maxParallelCoders;
|
|
@@ -61125,7 +61522,7 @@ function enrichWithLeanTurbo(status, directory) {
|
|
|
61125
61522
|
}
|
|
61126
61523
|
}
|
|
61127
61524
|
}
|
|
61128
|
-
status.fullAutoActive =
|
|
61525
|
+
status.fullAutoActive = _internals38.hasActiveFullAuto();
|
|
61129
61526
|
return status;
|
|
61130
61527
|
}
|
|
61131
61528
|
function formatStatusMarkdown(status) {
|
|
@@ -61213,7 +61610,7 @@ async function handleStatusCommand(directory, agents) {
|
|
|
61213
61610
|
}
|
|
61214
61611
|
return formatStatusMarkdown(statusData);
|
|
61215
61612
|
}
|
|
61216
|
-
var
|
|
61613
|
+
var _internals38;
|
|
61217
61614
|
var init_status_service = __esm(() => {
|
|
61218
61615
|
init_extractors();
|
|
61219
61616
|
init_knowledge_escalator();
|
|
@@ -61223,7 +61620,7 @@ var init_status_service = __esm(() => {
|
|
|
61223
61620
|
init_state3();
|
|
61224
61621
|
init_compaction_service();
|
|
61225
61622
|
init_context_budget_service();
|
|
61226
|
-
|
|
61623
|
+
_internals38 = {
|
|
61227
61624
|
loadLeanTurboRunState,
|
|
61228
61625
|
hasActiveLeanTurbo,
|
|
61229
61626
|
hasActiveFullAuto
|
|
@@ -61314,7 +61711,7 @@ async function handleTurboCommand(directory, args, sessionID) {
|
|
|
61314
61711
|
if (arg0 === "on") {
|
|
61315
61712
|
let strategy = "standard";
|
|
61316
61713
|
try {
|
|
61317
|
-
const { config: config3 } =
|
|
61714
|
+
const { config: config3 } = _internals39.loadPluginConfigWithMeta(directory);
|
|
61318
61715
|
if (config3.turbo?.strategy === "lean") {
|
|
61319
61716
|
strategy = "lean";
|
|
61320
61717
|
}
|
|
@@ -61369,7 +61766,7 @@ function enableLeanTurbo(session, directory, sessionID) {
|
|
|
61369
61766
|
let maxParallelCoders = 4;
|
|
61370
61767
|
let conflictPolicy = "serialize";
|
|
61371
61768
|
try {
|
|
61372
|
-
const { config: config3 } =
|
|
61769
|
+
const { config: config3 } = _internals39.loadPluginConfigWithMeta(directory);
|
|
61373
61770
|
const leanConfig = config3.turbo?.lean;
|
|
61374
61771
|
if (leanConfig) {
|
|
61375
61772
|
maxParallelCoders = leanConfig.max_parallel_coders ?? 4;
|
|
@@ -61439,13 +61836,13 @@ function buildStatusMessage2(session, directory, sessionID) {
|
|
|
61439
61836
|
].join(`
|
|
61440
61837
|
`);
|
|
61441
61838
|
}
|
|
61442
|
-
var
|
|
61839
|
+
var _internals39;
|
|
61443
61840
|
var init_turbo = __esm(() => {
|
|
61444
61841
|
init_config();
|
|
61445
61842
|
init_state();
|
|
61446
61843
|
init_state3();
|
|
61447
61844
|
init_logger();
|
|
61448
|
-
|
|
61845
|
+
_internals39 = {
|
|
61449
61846
|
loadPluginConfigWithMeta
|
|
61450
61847
|
};
|
|
61451
61848
|
});
|
|
@@ -61512,8 +61909,8 @@ var init_write_retro2 = __esm(() => {
|
|
|
61512
61909
|
});
|
|
61513
61910
|
|
|
61514
61911
|
// src/commands/command-dispatch.ts
|
|
61515
|
-
import
|
|
61516
|
-
import
|
|
61912
|
+
import fs35 from "fs";
|
|
61913
|
+
import path63 from "path";
|
|
61517
61914
|
function normalizeSwarmCommandInput(command, argumentText) {
|
|
61518
61915
|
if (command !== "swarm" && !command.startsWith("swarm-")) {
|
|
61519
61916
|
return { isSwarmCommand: false, tokens: [] };
|
|
@@ -61538,7 +61935,7 @@ function formatCommandNotFound(tokens) {
|
|
|
61538
61935
|
const attemptedCommand = tokens[0] || "";
|
|
61539
61936
|
const MAX_DISPLAY = 100;
|
|
61540
61937
|
const displayCommand = attemptedCommand.length > MAX_DISPLAY ? `${attemptedCommand.slice(0, MAX_DISPLAY)}...` : attemptedCommand;
|
|
61541
|
-
const similar =
|
|
61938
|
+
const similar = _internals40.findSimilarCommands(attemptedCommand);
|
|
61542
61939
|
const header = `Command \`/swarm ${displayCommand}\` not found.`;
|
|
61543
61940
|
const suggestions = similar.length > 0 ? `Did you mean:
|
|
61544
61941
|
${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
|
|
@@ -61549,11 +61946,11 @@ ${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
|
|
|
61549
61946
|
`);
|
|
61550
61947
|
}
|
|
61551
61948
|
function maybeMarkFirstRun(directory) {
|
|
61552
|
-
const sentinelPath =
|
|
61949
|
+
const sentinelPath = path63.join(directory, ".swarm", ".first-run-complete");
|
|
61553
61950
|
try {
|
|
61554
|
-
const swarmDir =
|
|
61555
|
-
|
|
61556
|
-
|
|
61951
|
+
const swarmDir = path63.join(directory, ".swarm");
|
|
61952
|
+
fs35.mkdirSync(swarmDir, { recursive: true });
|
|
61953
|
+
fs35.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
|
|
61557
61954
|
`, { flag: "wx" });
|
|
61558
61955
|
return true;
|
|
61559
61956
|
} catch {
|
|
@@ -62083,7 +62480,7 @@ async function buildSwarmCommandPrompt(args) {
|
|
|
62083
62480
|
packageRoot,
|
|
62084
62481
|
registeredAgents
|
|
62085
62482
|
} = args;
|
|
62086
|
-
const resolved =
|
|
62483
|
+
const resolved = _internals40.resolveCommand(tokens);
|
|
62087
62484
|
if (!resolved) {
|
|
62088
62485
|
if (tokens.length === 0) {
|
|
62089
62486
|
return buildHelpText();
|
|
@@ -62253,7 +62650,7 @@ function findSimilarCommands(query) {
|
|
|
62253
62650
|
}
|
|
62254
62651
|
const scored = VALID_COMMANDS.map((cmd) => {
|
|
62255
62652
|
const cmdLower = cmd.toLowerCase();
|
|
62256
|
-
const fullScore =
|
|
62653
|
+
const fullScore = _internals40.levenshteinDistance(q, cmdLower);
|
|
62257
62654
|
let tokenScore = Infinity;
|
|
62258
62655
|
if (cmd.includes(" ") || cmd.includes("-")) {
|
|
62259
62656
|
const qTokens = q.split(/[\s-]+/);
|
|
@@ -62266,7 +62663,7 @@ function findSimilarCommands(query) {
|
|
|
62266
62663
|
for (const ct of cmdTokens) {
|
|
62267
62664
|
if (ct.length === 0)
|
|
62268
62665
|
continue;
|
|
62269
|
-
const dist =
|
|
62666
|
+
const dist = _internals40.levenshteinDistance(qt, ct);
|
|
62270
62667
|
if (dist < minDist)
|
|
62271
62668
|
minDist = dist;
|
|
62272
62669
|
}
|
|
@@ -62276,7 +62673,7 @@ function findSimilarCommands(query) {
|
|
|
62276
62673
|
}
|
|
62277
62674
|
const dashStrippedQ = q.replace(/-/g, "");
|
|
62278
62675
|
const dashStrippedCmd = cmdLower.replace(/-/g, "");
|
|
62279
|
-
const dashScore =
|
|
62676
|
+
const dashScore = _internals40.levenshteinDistance(dashStrippedQ, dashStrippedCmd);
|
|
62280
62677
|
const score = Math.min(fullScore, tokenScore, dashScore);
|
|
62281
62678
|
return { cmd, score };
|
|
62282
62679
|
});
|
|
@@ -62308,11 +62705,11 @@ async function handleHelpCommand(ctx) {
|
|
|
62308
62705
|
return buildHelpText2();
|
|
62309
62706
|
}
|
|
62310
62707
|
const tokens = targetCommand.split(/\s+/);
|
|
62311
|
-
const resolved =
|
|
62708
|
+
const resolved = _internals40.resolveCommand(tokens);
|
|
62312
62709
|
if (resolved) {
|
|
62313
|
-
return
|
|
62710
|
+
return _internals40.buildDetailedHelp(resolved.key, resolved.entry);
|
|
62314
62711
|
}
|
|
62315
|
-
const similar =
|
|
62712
|
+
const similar = _internals40.findSimilarCommands(targetCommand);
|
|
62316
62713
|
const { buildHelpText: fullHelp } = await Promise.resolve().then(() => (init_commands(), exports_commands));
|
|
62317
62714
|
if (similar.length > 0) {
|
|
62318
62715
|
return `Command '/swarm ${targetCommand}' not found.
|
|
@@ -62354,24 +62751,24 @@ function validateAliases() {
|
|
|
62354
62751
|
}
|
|
62355
62752
|
aliasTargets.get(target).push(name);
|
|
62356
62753
|
const visited = new Set;
|
|
62357
|
-
const
|
|
62754
|
+
const path64 = [];
|
|
62358
62755
|
let current = target;
|
|
62359
62756
|
while (current) {
|
|
62360
62757
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
62361
62758
|
if (!currentEntry)
|
|
62362
62759
|
break;
|
|
62363
62760
|
if (visited.has(current)) {
|
|
62364
|
-
const cycleStart =
|
|
62761
|
+
const cycleStart = path64.indexOf(current);
|
|
62365
62762
|
const fullChain = [
|
|
62366
62763
|
name,
|
|
62367
|
-
...
|
|
62764
|
+
...path64.slice(0, cycleStart > 0 ? cycleStart : path64.length),
|
|
62368
62765
|
current
|
|
62369
62766
|
].join(" \u2192 ");
|
|
62370
62767
|
errors5.push(`Circular alias detected: ${fullChain}`);
|
|
62371
62768
|
break;
|
|
62372
62769
|
}
|
|
62373
62770
|
visited.add(current);
|
|
62374
|
-
|
|
62771
|
+
path64.push(current);
|
|
62375
62772
|
current = currentEntry.aliasOf || "";
|
|
62376
62773
|
}
|
|
62377
62774
|
}
|
|
@@ -62412,7 +62809,7 @@ function resolveCommand(tokens) {
|
|
|
62412
62809
|
}
|
|
62413
62810
|
return null;
|
|
62414
62811
|
}
|
|
62415
|
-
var COMMAND_REGISTRY, VALID_COMMANDS,
|
|
62812
|
+
var COMMAND_REGISTRY, VALID_COMMANDS, _internals40, validation;
|
|
62416
62813
|
var init_registry = __esm(() => {
|
|
62417
62814
|
init_bundled_skills();
|
|
62418
62815
|
init_acknowledge_spec_drift();
|
|
@@ -62442,7 +62839,10 @@ var init_registry = __esm(() => {
|
|
|
62442
62839
|
init_memory2();
|
|
62443
62840
|
init_plan();
|
|
62444
62841
|
init_pr_feedback();
|
|
62842
|
+
init_pr_monitor_status();
|
|
62445
62843
|
init_pr_review();
|
|
62844
|
+
init_pr_subscribe();
|
|
62845
|
+
init_pr_unsubscribe();
|
|
62446
62846
|
init_preflight();
|
|
62447
62847
|
init_promote();
|
|
62448
62848
|
init_qa_gates();
|
|
@@ -62490,7 +62890,7 @@ var init_registry = __esm(() => {
|
|
|
62490
62890
|
clashesWithNativeCcCommand: "/agents"
|
|
62491
62891
|
},
|
|
62492
62892
|
help: {
|
|
62493
|
-
handler: (ctx) =>
|
|
62893
|
+
handler: (ctx) => _internals40.handleHelpCommand(ctx),
|
|
62494
62894
|
description: "Show help for swarm commands",
|
|
62495
62895
|
category: "core",
|
|
62496
62896
|
args: "[command]",
|
|
@@ -62768,6 +63168,27 @@ Subcommands:
|
|
|
62768
63168
|
details: "Triggers MODE: PR_FEEDBACK \u2014 ingests existing pull-request feedback (review threads, requested changes, CI/check failures, merge conflicts, stale branch state, pasted notes), verifies every claim against source, clusters related problems, fixes confirmed items, validates the branch, and reports closure status for every ledger item. Distinct from /swarm pr-review, which discovers new findings. The PR reference is optional: with none, the architect builds the ledger from the current PR/branch; text after the reference is forwarded as extra instructions. Supports full GitHub URL, owner/repo#N shorthand, or bare PR number (resolved against origin).",
|
|
62769
63169
|
category: "agent"
|
|
62770
63170
|
},
|
|
63171
|
+
"pr subscribe": {
|
|
63172
|
+
handler: (ctx) => handlePrSubscribeCommand(ctx.directory, ctx.args, ctx.sessionID),
|
|
63173
|
+
description: "Subscribe the current session to PR state-change notifications",
|
|
63174
|
+
args: "<pr-url|owner/repo#N|N>",
|
|
63175
|
+
details: "Subscribes the current session to receive advisory notifications for the specified PR. When pr_monitor.enabled is true, the background polling worker will detect CI failures, new comments, merge conflicts, review state changes, and merge/close events. Notifications are delivered as session-scoped advisories with dedup tokens. Supports full GitHub URL, owner/repo#N shorthand, or bare PR number (resolved against origin). Requires pr_monitor.enabled: true in config.",
|
|
63176
|
+
category: "agent"
|
|
63177
|
+
},
|
|
63178
|
+
"pr unsubscribe": {
|
|
63179
|
+
handler: (ctx) => handlePrUnsubscribeCommand(ctx.directory, ctx.args, ctx.sessionID),
|
|
63180
|
+
description: "Unsubscribe the current session from PR state-change notifications",
|
|
63181
|
+
args: "<pr-url|owner/repo#N|N>",
|
|
63182
|
+
details: "Unsubscribes the current session from receiving advisory notifications for the specified PR. Removes the active subscription record. Supports full GitHub URL, owner/repo#N shorthand, or bare PR number (resolved against origin).",
|
|
63183
|
+
category: "agent"
|
|
63184
|
+
},
|
|
63185
|
+
"pr status": {
|
|
63186
|
+
handler: (ctx) => handlePrMonitorStatusCommand(ctx.directory, ctx.args, ctx.sessionID),
|
|
63187
|
+
description: "Show PR monitor subscription status for the current session",
|
|
63188
|
+
args: "",
|
|
63189
|
+
details: "Displays all active PR subscriptions for the current session. Shows PR URL, last checked time, watching status, and error count per subscription. Also shows total active subscriptions across all sessions.",
|
|
63190
|
+
category: "agent"
|
|
63191
|
+
},
|
|
62771
63192
|
"deep-dive": {
|
|
62772
63193
|
handler: (ctx) => handleModeCommandWithBundledSkills(ctx, handleDeepDiveCommand),
|
|
62773
63194
|
description: "Launch deep codebase audit with parallel explorer waves, dual reviewers, and critic challenge [scope]",
|
|
@@ -63017,7 +63438,7 @@ Subcommands:
|
|
|
63017
63438
|
}
|
|
63018
63439
|
};
|
|
63019
63440
|
VALID_COMMANDS = Object.keys(COMMAND_REGISTRY);
|
|
63020
|
-
|
|
63441
|
+
_internals40 = {
|
|
63021
63442
|
handleHelpCommand,
|
|
63022
63443
|
validateAliases,
|
|
63023
63444
|
resolveCommand,
|
|
@@ -63025,7 +63446,7 @@ Subcommands:
|
|
|
63025
63446
|
findSimilarCommands,
|
|
63026
63447
|
buildDetailedHelp
|
|
63027
63448
|
};
|
|
63028
|
-
validation =
|
|
63449
|
+
validation = _internals40.validateAliases();
|
|
63029
63450
|
if (!validation.valid) {
|
|
63030
63451
|
throw new Error(`COMMAND_REGISTRY alias validation failed:
|
|
63031
63452
|
${validation.errors.join(`
|
|
@@ -63043,72 +63464,72 @@ init_package();
|
|
|
63043
63464
|
init_registry();
|
|
63044
63465
|
init_cache_paths();
|
|
63045
63466
|
init_constants();
|
|
63046
|
-
import * as
|
|
63467
|
+
import * as fs36 from "fs";
|
|
63047
63468
|
import * as os9 from "os";
|
|
63048
|
-
import * as
|
|
63469
|
+
import * as path64 from "path";
|
|
63049
63470
|
var { version: version5 } = package_default;
|
|
63050
63471
|
var CONFIG_DIR = getPluginConfigDir();
|
|
63051
|
-
var OPENCODE_CONFIG_PATH =
|
|
63052
|
-
var PLUGIN_CONFIG_PATH =
|
|
63053
|
-
var PROMPTS_DIR =
|
|
63472
|
+
var OPENCODE_CONFIG_PATH = path64.join(CONFIG_DIR, "opencode.json");
|
|
63473
|
+
var PLUGIN_CONFIG_PATH = path64.join(CONFIG_DIR, "opencode-swarm.json");
|
|
63474
|
+
var PROMPTS_DIR = path64.join(CONFIG_DIR, "opencode-swarm");
|
|
63054
63475
|
var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
63055
63476
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
63056
63477
|
function isSafeCachePath(p) {
|
|
63057
|
-
const resolved =
|
|
63058
|
-
const home =
|
|
63478
|
+
const resolved = path64.resolve(p);
|
|
63479
|
+
const home = path64.resolve(os9.homedir());
|
|
63059
63480
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
63060
63481
|
return false;
|
|
63061
63482
|
}
|
|
63062
|
-
const segments = resolved.split(
|
|
63483
|
+
const segments = resolved.split(path64.sep).filter((s) => s.length > 0);
|
|
63063
63484
|
if (segments.length < 4) {
|
|
63064
63485
|
return false;
|
|
63065
63486
|
}
|
|
63066
|
-
const leaf =
|
|
63487
|
+
const leaf = path64.basename(resolved);
|
|
63067
63488
|
if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
|
|
63068
63489
|
return false;
|
|
63069
63490
|
}
|
|
63070
|
-
const parent =
|
|
63491
|
+
const parent = path64.basename(path64.dirname(resolved));
|
|
63071
63492
|
if (parent !== "packages" && parent !== "node_modules") {
|
|
63072
63493
|
return false;
|
|
63073
63494
|
}
|
|
63074
|
-
const grandparent =
|
|
63495
|
+
const grandparent = path64.basename(path64.dirname(path64.dirname(resolved)));
|
|
63075
63496
|
if (grandparent !== "opencode") {
|
|
63076
63497
|
return false;
|
|
63077
63498
|
}
|
|
63078
63499
|
return true;
|
|
63079
63500
|
}
|
|
63080
63501
|
function isSafeLockFilePath(p) {
|
|
63081
|
-
const resolved =
|
|
63082
|
-
const home =
|
|
63502
|
+
const resolved = path64.resolve(p);
|
|
63503
|
+
const home = path64.resolve(os9.homedir());
|
|
63083
63504
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
63084
63505
|
return false;
|
|
63085
63506
|
}
|
|
63086
|
-
const segments = resolved.split(
|
|
63507
|
+
const segments = resolved.split(path64.sep).filter((s) => s.length > 0);
|
|
63087
63508
|
if (segments.length < 4) {
|
|
63088
63509
|
return false;
|
|
63089
63510
|
}
|
|
63090
|
-
const leaf =
|
|
63511
|
+
const leaf = path64.basename(resolved);
|
|
63091
63512
|
if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
|
|
63092
63513
|
return false;
|
|
63093
63514
|
}
|
|
63094
|
-
const parent =
|
|
63515
|
+
const parent = path64.basename(path64.dirname(resolved));
|
|
63095
63516
|
if (parent !== "opencode") {
|
|
63096
63517
|
return false;
|
|
63097
63518
|
}
|
|
63098
|
-
const grandparent =
|
|
63519
|
+
const grandparent = path64.basename(path64.dirname(path64.dirname(resolved)));
|
|
63099
63520
|
if (grandparent === "opencode") {
|
|
63100
63521
|
return false;
|
|
63101
63522
|
}
|
|
63102
63523
|
return true;
|
|
63103
63524
|
}
|
|
63104
63525
|
function ensureDir(dir) {
|
|
63105
|
-
if (!
|
|
63106
|
-
|
|
63526
|
+
if (!fs36.existsSync(dir)) {
|
|
63527
|
+
fs36.mkdirSync(dir, { recursive: true });
|
|
63107
63528
|
}
|
|
63108
63529
|
}
|
|
63109
63530
|
function loadJson(filepath) {
|
|
63110
63531
|
try {
|
|
63111
|
-
const content =
|
|
63532
|
+
const content = fs36.readFileSync(filepath, "utf-8");
|
|
63112
63533
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
63113
63534
|
return JSON.parse(stripped);
|
|
63114
63535
|
} catch {
|
|
@@ -63116,14 +63537,14 @@ function loadJson(filepath) {
|
|
|
63116
63537
|
}
|
|
63117
63538
|
}
|
|
63118
63539
|
function saveJson(filepath, data) {
|
|
63119
|
-
|
|
63540
|
+
fs36.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
63120
63541
|
`, "utf-8");
|
|
63121
63542
|
}
|
|
63122
63543
|
function writeProjectConfigIfMissing(cwd) {
|
|
63123
63544
|
try {
|
|
63124
|
-
const opencodeDir =
|
|
63125
|
-
const projectConfigPath =
|
|
63126
|
-
if (
|
|
63545
|
+
const opencodeDir = path64.join(cwd, ".opencode");
|
|
63546
|
+
const projectConfigPath = path64.join(opencodeDir, "opencode-swarm.json");
|
|
63547
|
+
if (fs36.existsSync(projectConfigPath)) {
|
|
63127
63548
|
return;
|
|
63128
63549
|
}
|
|
63129
63550
|
ensureDir(opencodeDir);
|
|
@@ -63139,7 +63560,7 @@ async function install() {
|
|
|
63139
63560
|
`);
|
|
63140
63561
|
ensureDir(CONFIG_DIR);
|
|
63141
63562
|
ensureDir(PROMPTS_DIR);
|
|
63142
|
-
const LEGACY_CONFIG_PATH =
|
|
63563
|
+
const LEGACY_CONFIG_PATH = path64.join(CONFIG_DIR, "config.json");
|
|
63143
63564
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
63144
63565
|
if (!opencodeConfig) {
|
|
63145
63566
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|
|
@@ -63186,7 +63607,7 @@ async function install() {
|
|
|
63186
63607
|
console.warn(`\u26A0 Could not clear opencode lock file \u2014 you may need to delete it manually:
|
|
63187
63608
|
${failed}`);
|
|
63188
63609
|
}
|
|
63189
|
-
if (!
|
|
63610
|
+
if (!fs36.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
63190
63611
|
const defaultConfig = {
|
|
63191
63612
|
agents: { ...DEFAULT_AGENT_CONFIGS },
|
|
63192
63613
|
max_iterations: 5
|
|
@@ -63265,14 +63686,14 @@ function evictPluginCaches() {
|
|
|
63265
63686
|
const cleared = [];
|
|
63266
63687
|
const failed = [];
|
|
63267
63688
|
for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
|
|
63268
|
-
if (!
|
|
63689
|
+
if (!fs36.existsSync(cachePath))
|
|
63269
63690
|
continue;
|
|
63270
63691
|
if (!isSafeCachePath(cachePath)) {
|
|
63271
63692
|
failed.push(`${cachePath} (refused: failed safety check)`);
|
|
63272
63693
|
continue;
|
|
63273
63694
|
}
|
|
63274
63695
|
try {
|
|
63275
|
-
|
|
63696
|
+
fs36.rmSync(cachePath, { recursive: true, force: true });
|
|
63276
63697
|
cleared.push(cachePath);
|
|
63277
63698
|
} catch (err) {
|
|
63278
63699
|
failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
|
|
@@ -63284,14 +63705,14 @@ function evictLockFiles() {
|
|
|
63284
63705
|
const cleared = [];
|
|
63285
63706
|
const failed = [];
|
|
63286
63707
|
for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
|
|
63287
|
-
if (!
|
|
63708
|
+
if (!fs36.existsSync(lockPath))
|
|
63288
63709
|
continue;
|
|
63289
63710
|
if (!isSafeLockFilePath(lockPath)) {
|
|
63290
63711
|
failed.push(`${lockPath} (refused: failed safety check)`);
|
|
63291
63712
|
continue;
|
|
63292
63713
|
}
|
|
63293
63714
|
try {
|
|
63294
|
-
|
|
63715
|
+
fs36.unlinkSync(lockPath);
|
|
63295
63716
|
cleared.push(lockPath);
|
|
63296
63717
|
} catch (err) {
|
|
63297
63718
|
const code = err?.code;
|
|
@@ -63310,7 +63731,7 @@ async function uninstall() {
|
|
|
63310
63731
|
`);
|
|
63311
63732
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
63312
63733
|
if (!opencodeConfig) {
|
|
63313
|
-
if (
|
|
63734
|
+
if (fs36.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
63314
63735
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
63315
63736
|
return 1;
|
|
63316
63737
|
} else {
|
|
@@ -63342,13 +63763,13 @@ async function uninstall() {
|
|
|
63342
63763
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
63343
63764
|
if (process.argv.includes("--clean")) {
|
|
63344
63765
|
let cleaned = false;
|
|
63345
|
-
if (
|
|
63346
|
-
|
|
63766
|
+
if (fs36.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
63767
|
+
fs36.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
63347
63768
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
63348
63769
|
cleaned = true;
|
|
63349
63770
|
}
|
|
63350
|
-
if (
|
|
63351
|
-
|
|
63771
|
+
if (fs36.existsSync(PROMPTS_DIR)) {
|
|
63772
|
+
fs36.rmSync(PROMPTS_DIR, { recursive: true });
|
|
63352
63773
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
63353
63774
|
cleaned = true;
|
|
63354
63775
|
}
|