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