opencode-swarm 7.6.0 → 7.8.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 +3 -1
- package/dist/__tests__/qa-gate-hardening.test.d.ts +1 -1
- package/dist/agents/index.d.ts +11 -3
- package/dist/cli/index.js +810 -378
- package/dist/commands/full-auto.d.ts +13 -2
- package/dist/config/evidence-schema.d.ts +3 -3
- package/dist/config/schema.d.ts +82 -19
- package/dist/db/qa-gate-profile.d.ts +2 -1
- package/dist/full-auto/cadence.d.ts +64 -0
- package/dist/full-auto/input-probe.d.ts +22 -0
- package/dist/full-auto/oversight.d.ts +93 -0
- package/dist/full-auto/phase-approval.d.ts +7 -0
- package/dist/full-auto/policy.d.ts +85 -0
- package/dist/full-auto/state.d.ts +121 -0
- package/dist/hooks/full-auto-delegation.d.ts +28 -0
- package/dist/hooks/full-auto-input-probe.d.ts +27 -0
- package/dist/hooks/full-auto-intercept.d.ts +1 -1
- package/dist/hooks/full-auto-permission.d.ts +39 -0
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/utils.d.ts +40 -0
- package/dist/index.js +4276 -1342
- package/dist/plan/index.d.ts +1 -0
- package/dist/plan/utils.d.ts +8 -0
- package/dist/state.d.ts +9 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/set-qa-gates.d.ts +1 -0
- package/dist/tools/tool-names.d.ts +1 -1
- package/dist/tools/update-task-status.d.ts +1 -1
- package/dist/tools/write-final-council-evidence.d.ts +29 -0
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -34,7 +34,7 @@ var package_default;
|
|
|
34
34
|
var init_package = __esm(() => {
|
|
35
35
|
package_default = {
|
|
36
36
|
name: "opencode-swarm",
|
|
37
|
-
version: "7.
|
|
37
|
+
version: "7.8.0",
|
|
38
38
|
description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
|
|
39
39
|
main: "dist/index.js",
|
|
40
40
|
types: "dist/index.d.ts",
|
|
@@ -142,6 +142,14 @@ function warn(message, data) {
|
|
|
142
142
|
console.warn(`[opencode-swarm ${timestamp}] WARN: ${message}`);
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
|
+
function error(message, data) {
|
|
146
|
+
const timestamp = new Date().toISOString();
|
|
147
|
+
if (data !== undefined) {
|
|
148
|
+
console.error(`[opencode-swarm ${timestamp}] ERROR: ${message}`, data);
|
|
149
|
+
} else {
|
|
150
|
+
console.error(`[opencode-swarm ${timestamp}] ERROR: ${message}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
145
153
|
var init_logger = () => {};
|
|
146
154
|
|
|
147
155
|
// src/utils/merge.ts
|
|
@@ -14589,6 +14597,11 @@ var init_spec_hash = __esm(() => {
|
|
|
14589
14597
|
};
|
|
14590
14598
|
});
|
|
14591
14599
|
|
|
14600
|
+
// src/plan/utils.ts
|
|
14601
|
+
function derivePlanId(plan) {
|
|
14602
|
+
return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
14603
|
+
}
|
|
14604
|
+
|
|
14592
14605
|
// src/plan/ledger.ts
|
|
14593
14606
|
import * as crypto2 from "crypto";
|
|
14594
14607
|
import * as fs from "fs";
|
|
@@ -14777,7 +14790,7 @@ async function takeSnapshotEvent(directory, plan, options) {
|
|
|
14777
14790
|
if (options?.approvalMetadata) {
|
|
14778
14791
|
snapshotPayload.approval = options.approvalMetadata;
|
|
14779
14792
|
}
|
|
14780
|
-
const planId =
|
|
14793
|
+
const planId = derivePlanId(plan);
|
|
14781
14794
|
return appendLedgerEvent(directory, {
|
|
14782
14795
|
event_type: "snapshot",
|
|
14783
14796
|
source: options?.source ?? "takeSnapshotEvent",
|
|
@@ -14972,7 +14985,7 @@ async function loadLastApprovedPlan(directory, expectedPlanId) {
|
|
|
14972
14985
|
continue;
|
|
14973
14986
|
}
|
|
14974
14987
|
if (expectedPlanId !== undefined) {
|
|
14975
|
-
const payloadPlanId =
|
|
14988
|
+
const payloadPlanId = derivePlanId(payload.plan);
|
|
14976
14989
|
if (payloadPlanId !== expectedPlanId) {
|
|
14977
14990
|
continue;
|
|
14978
14991
|
}
|
|
@@ -15173,7 +15186,7 @@ async function loadPlan(directory) {
|
|
|
15173
15186
|
if (!startupLedgerCheckedWorkspaces.has(resolvedWorkspace)) {
|
|
15174
15187
|
startupLedgerCheckedWorkspaces.add(resolvedWorkspace);
|
|
15175
15188
|
if (ledgerHash !== "" && planHash !== ledgerHash) {
|
|
15176
|
-
const currentPlanId =
|
|
15189
|
+
const currentPlanId = derivePlanId(validated);
|
|
15177
15190
|
const ledgerEvents = await readLedgerEvents(directory);
|
|
15178
15191
|
const firstEvent = ledgerEvents.length > 0 ? ledgerEvents[0] : null;
|
|
15179
15192
|
if (firstEvent && firstEvent.plan_id !== currentPlanId) {
|
|
@@ -15256,7 +15269,7 @@ async function loadPlan(directory) {
|
|
|
15256
15269
|
try {
|
|
15257
15270
|
const rawParsed = JSON.parse(planJsonContent);
|
|
15258
15271
|
if (typeof rawParsed?.swarm === "string" && typeof rawParsed?.title === "string") {
|
|
15259
|
-
rawPlanId =
|
|
15272
|
+
rawPlanId = derivePlanId(rawParsed);
|
|
15260
15273
|
}
|
|
15261
15274
|
} catch {}
|
|
15262
15275
|
if (await ledgerExists(directory)) {
|
|
@@ -15382,7 +15395,7 @@ async function savePlan(directory, plan, options) {
|
|
|
15382
15395
|
}
|
|
15383
15396
|
}
|
|
15384
15397
|
const currentPlan = await _internals3.loadPlanJsonOnly(directory);
|
|
15385
|
-
const planId =
|
|
15398
|
+
const planId = derivePlanId(validated);
|
|
15386
15399
|
const planHashForInit = computePlanHash(validated);
|
|
15387
15400
|
if (!await ledgerExists(directory)) {
|
|
15388
15401
|
try {
|
|
@@ -15483,7 +15496,7 @@ async function savePlan(directory, plan, options) {
|
|
|
15483
15496
|
const oldTask = oldTaskMap.get(task.id);
|
|
15484
15497
|
if (oldTask && oldTask.status !== task.status) {
|
|
15485
15498
|
const eventInput = {
|
|
15486
|
-
plan_id:
|
|
15499
|
+
plan_id: derivePlanId(validated),
|
|
15487
15500
|
event_type: "task_status_changed",
|
|
15488
15501
|
task_id: task.id,
|
|
15489
15502
|
phase_id: phase.id,
|
|
@@ -16040,7 +16053,8 @@ var init_tool_names = __esm(() => {
|
|
|
16040
16053
|
"get_qa_gate_profile",
|
|
16041
16054
|
"set_qa_gates",
|
|
16042
16055
|
"web_search",
|
|
16043
|
-
"convene_general_council"
|
|
16056
|
+
"convene_general_council",
|
|
16057
|
+
"write_final_council_evidence"
|
|
16044
16058
|
];
|
|
16045
16059
|
TOOL_NAME_SET = new Set(TOOL_NAMES);
|
|
16046
16060
|
});
|
|
@@ -16277,7 +16291,8 @@ var init_constants = __esm(() => {
|
|
|
16277
16291
|
"get_qa_gate_profile",
|
|
16278
16292
|
"set_qa_gates",
|
|
16279
16293
|
"convene_general_council",
|
|
16280
|
-
"web_search"
|
|
16294
|
+
"web_search",
|
|
16295
|
+
"write_final_council_evidence"
|
|
16281
16296
|
],
|
|
16282
16297
|
explorer: [
|
|
16283
16298
|
"complexity_hotspots",
|
|
@@ -16403,12 +16418,26 @@ var init_constants = __esm(() => {
|
|
|
16403
16418
|
"repo_map"
|
|
16404
16419
|
],
|
|
16405
16420
|
critic_oversight: [
|
|
16406
|
-
"
|
|
16407
|
-
"
|
|
16408
|
-
"
|
|
16421
|
+
"diff",
|
|
16422
|
+
"diff_summary",
|
|
16423
|
+
"evidence_check",
|
|
16424
|
+
"check_gate_status",
|
|
16425
|
+
"completion_verify",
|
|
16426
|
+
"get_approved_plan",
|
|
16427
|
+
"req_coverage",
|
|
16428
|
+
"test_impact",
|
|
16429
|
+
"pkg_audit",
|
|
16430
|
+
"secretscan",
|
|
16431
|
+
"sast_scan",
|
|
16432
|
+
"repo_map",
|
|
16409
16433
|
"retrieve_summary",
|
|
16434
|
+
"knowledge_recall",
|
|
16410
16435
|
"symbols",
|
|
16411
|
-
"
|
|
16436
|
+
"batch_symbols",
|
|
16437
|
+
"search",
|
|
16438
|
+
"imports",
|
|
16439
|
+
"complexity_hotspots",
|
|
16440
|
+
"detect_domains"
|
|
16412
16441
|
],
|
|
16413
16442
|
docs: [
|
|
16414
16443
|
"detect_domains",
|
|
@@ -16502,60 +16531,43 @@ var init_constants = __esm(() => {
|
|
|
16502
16531
|
});
|
|
16503
16532
|
|
|
16504
16533
|
// src/config/schema.ts
|
|
16505
|
-
function
|
|
16534
|
+
function getCanonicalAgentRole(agentName, generatedAgentNames) {
|
|
16506
16535
|
if (!agentName)
|
|
16507
16536
|
return agentName;
|
|
16508
16537
|
const normalized = agentName.toLowerCase();
|
|
16509
|
-
|
|
16510
|
-
|
|
16511
|
-
while (stripped !== previous) {
|
|
16512
|
-
previous = stripped;
|
|
16513
|
-
for (const prefix of KNOWN_SWARM_PREFIXES) {
|
|
16514
|
-
for (const sep2 of SEPARATORS) {
|
|
16515
|
-
const prefixWithSep = prefix + sep2;
|
|
16516
|
-
if (stripped.startsWith(prefixWithSep)) {
|
|
16517
|
-
stripped = stripped.slice(prefixWithSep.length);
|
|
16518
|
-
break;
|
|
16519
|
-
}
|
|
16520
|
-
}
|
|
16521
|
-
if (stripped !== previous)
|
|
16522
|
-
break;
|
|
16523
|
-
}
|
|
16538
|
+
if (CANONICAL_ROLES_SET.has(normalized)) {
|
|
16539
|
+
return normalized;
|
|
16524
16540
|
}
|
|
16525
|
-
if (
|
|
16526
|
-
|
|
16541
|
+
if (generatedAgentNames) {
|
|
16542
|
+
const registry2 = new Set;
|
|
16543
|
+
for (const n of generatedAgentNames)
|
|
16544
|
+
registry2.add(n.toLowerCase());
|
|
16545
|
+
if (!registry2.has(normalized)) {
|
|
16546
|
+
return agentName;
|
|
16547
|
+
}
|
|
16527
16548
|
}
|
|
16528
|
-
for (const
|
|
16549
|
+
for (const role of CANONICAL_ROLES_LONGEST_FIRST) {
|
|
16529
16550
|
for (const sep2 of SEPARATORS) {
|
|
16530
|
-
const suffix = sep2 +
|
|
16551
|
+
const suffix = sep2 + role;
|
|
16531
16552
|
if (normalized.endsWith(suffix)) {
|
|
16532
|
-
return
|
|
16553
|
+
return role;
|
|
16533
16554
|
}
|
|
16534
16555
|
}
|
|
16535
|
-
if (normalized === agent) {
|
|
16536
|
-
return agent;
|
|
16537
|
-
}
|
|
16538
16556
|
}
|
|
16539
16557
|
return agentName;
|
|
16540
16558
|
}
|
|
16541
|
-
|
|
16559
|
+
function stripKnownSwarmPrefix(agentName) {
|
|
16560
|
+
return getCanonicalAgentRole(agentName);
|
|
16561
|
+
}
|
|
16562
|
+
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, UIReviewConfigSchema, CompactionAdvisoryConfigSchema, LintConfigSchema, SecretscanConfigSchema, GuardrailsProfileSchema, DEFAULT_AGENT_PROFILES, DEFAULT_ARCHITECT_PROFILE, GuardrailsConfigSchema, WatchdogConfigSchema, SelfReviewConfigSchema, ToolFilterConfigSchema, PlanCursorConfigSchema, CheckpointConfigSchema, AutomationModeSchema, AutomationCapabilitiesSchema, AutomationConfigSchemaBase, AutomationConfigSchema, KnowledgeConfigSchema, CuratorConfigSchema, SlopDetectorConfigSchema, IncrementalVerifyConfigSchema, CompactionConfigSchema, PrmConfigSchema, AgentAuthorityRuleSchema, AuthorityConfigSchema, GeneralCouncilMemberConfigSchema, GeneralCouncilConfigSchema, CouncilConfigSchema, ParallelizationConfigSchema, PluginConfigSchema;
|
|
16542
16563
|
var init_schema = __esm(() => {
|
|
16543
16564
|
init_zod();
|
|
16544
16565
|
init_constants();
|
|
16545
|
-
KNOWN_SWARM_PREFIXES = [
|
|
16546
|
-
"paid",
|
|
16547
|
-
"local",
|
|
16548
|
-
"cloud",
|
|
16549
|
-
"enterprise",
|
|
16550
|
-
"mega",
|
|
16551
|
-
"default",
|
|
16552
|
-
"custom",
|
|
16553
|
-
"team",
|
|
16554
|
-
"project",
|
|
16555
|
-
"swarm",
|
|
16556
|
-
"synthetic"
|
|
16557
|
-
];
|
|
16558
16566
|
SEPARATORS = ["_", "-", " "];
|
|
16567
|
+
CANONICAL_ROLES_LONGEST_FIRST = [
|
|
16568
|
+
...ALL_AGENT_NAMES
|
|
16569
|
+
].sort((a, b) => b.length - a.length);
|
|
16570
|
+
CANONICAL_ROLES_SET = new Set(ALL_AGENT_NAMES);
|
|
16559
16571
|
AgentOverrideConfigSchema = exports_external.object({
|
|
16560
16572
|
model: exports_external.string().optional(),
|
|
16561
16573
|
variant: exports_external.string().min(1).optional(),
|
|
@@ -17102,12 +17114,7 @@ var init_schema = __esm(() => {
|
|
|
17102
17114
|
maxConcurrentTasks: exports_external.number().int().min(1).max(64).default(1),
|
|
17103
17115
|
evidenceLockTimeoutMs: exports_external.number().int().min(1000).max(300000).default(60000),
|
|
17104
17116
|
max_coders: exports_external.number().int().min(1).max(16).default(3),
|
|
17105
|
-
max_reviewers: exports_external.number().int().min(1).max(16).default(2)
|
|
17106
|
-
stageB: exports_external.object({
|
|
17107
|
-
parallel: exports_external.object({
|
|
17108
|
-
enabled: exports_external.boolean().default(false)
|
|
17109
|
-
}).default({ enabled: false })
|
|
17110
|
-
}).default({ parallel: { enabled: false } })
|
|
17117
|
+
max_reviewers: exports_external.number().int().min(1).max(16).default(2)
|
|
17111
17118
|
});
|
|
17112
17119
|
PluginConfigSchema = exports_external.object({
|
|
17113
17120
|
agents: exports_external.record(exports_external.string(), AgentOverrideConfigSchema).optional(),
|
|
@@ -17173,13 +17180,143 @@ var init_schema = __esm(() => {
|
|
|
17173
17180
|
critic_model: exports_external.string().optional(),
|
|
17174
17181
|
max_interactions_per_phase: exports_external.number().int().min(5).max(200).default(50),
|
|
17175
17182
|
deadlock_threshold: exports_external.number().int().min(2).max(10).default(3),
|
|
17176
|
-
escalation_mode: exports_external.enum(["pause", "terminate"]).default("pause")
|
|
17177
|
-
|
|
17183
|
+
escalation_mode: exports_external.enum(["pause", "terminate"]).default("pause"),
|
|
17184
|
+
mode: exports_external.enum(["assisted", "supervised", "strict"]).default("supervised"),
|
|
17185
|
+
fail_closed: exports_external.boolean().default(true),
|
|
17186
|
+
permission_policy: exports_external.object({
|
|
17187
|
+
enabled: exports_external.boolean().default(true),
|
|
17188
|
+
trusted_roots: exports_external.array(exports_external.string()).default(["."]),
|
|
17189
|
+
trusted_domains: exports_external.array(exports_external.string()).default([]),
|
|
17190
|
+
protected_paths: exports_external.array(exports_external.string()).default([
|
|
17191
|
+
".git",
|
|
17192
|
+
".github/workflows",
|
|
17193
|
+
".swarm",
|
|
17194
|
+
"package.json",
|
|
17195
|
+
"package-lock.json",
|
|
17196
|
+
"bun.lock",
|
|
17197
|
+
"CHANGELOG.md",
|
|
17198
|
+
".release-please-manifest.json",
|
|
17199
|
+
"release-please-config.json",
|
|
17200
|
+
"src/index.ts",
|
|
17201
|
+
"src/hooks/guardrails.ts",
|
|
17202
|
+
"src/hooks/delegation-gate.ts",
|
|
17203
|
+
"src/hooks/scope-guard.ts",
|
|
17204
|
+
"src/hooks/full-auto-permission.ts",
|
|
17205
|
+
"src/hooks/full-auto-intercept.ts",
|
|
17206
|
+
"src/full-auto",
|
|
17207
|
+
"src/config/schema.ts",
|
|
17208
|
+
"src/config/constants.ts",
|
|
17209
|
+
"src/tools/phase-complete.ts",
|
|
17210
|
+
"dist"
|
|
17211
|
+
]),
|
|
17212
|
+
allow_defaults: exports_external.boolean().default(true)
|
|
17213
|
+
}).default(() => ({
|
|
17214
|
+
enabled: true,
|
|
17215
|
+
trusted_roots: ["."],
|
|
17216
|
+
trusted_domains: [],
|
|
17217
|
+
protected_paths: [
|
|
17218
|
+
".git",
|
|
17219
|
+
".github/workflows",
|
|
17220
|
+
".swarm",
|
|
17221
|
+
"package.json",
|
|
17222
|
+
"package-lock.json",
|
|
17223
|
+
"bun.lock",
|
|
17224
|
+
"CHANGELOG.md",
|
|
17225
|
+
".release-please-manifest.json",
|
|
17226
|
+
"release-please-config.json",
|
|
17227
|
+
"src/index.ts",
|
|
17228
|
+
"src/hooks/guardrails.ts",
|
|
17229
|
+
"src/hooks/delegation-gate.ts",
|
|
17230
|
+
"src/hooks/scope-guard.ts",
|
|
17231
|
+
"src/hooks/full-auto-permission.ts",
|
|
17232
|
+
"src/hooks/full-auto-intercept.ts",
|
|
17233
|
+
"src/full-auto",
|
|
17234
|
+
"src/config/schema.ts",
|
|
17235
|
+
"src/config/constants.ts",
|
|
17236
|
+
"src/tools/phase-complete.ts",
|
|
17237
|
+
"dist"
|
|
17238
|
+
],
|
|
17239
|
+
allow_defaults: true
|
|
17240
|
+
})),
|
|
17241
|
+
denials: exports_external.object({
|
|
17242
|
+
max_consecutive: exports_external.number().int().min(1).max(50).default(3),
|
|
17243
|
+
max_total: exports_external.number().int().min(1).max(500).default(20),
|
|
17244
|
+
on_limit: exports_external.enum(["pause", "terminate"]).default("pause")
|
|
17245
|
+
}).default(() => ({
|
|
17246
|
+
max_consecutive: 3,
|
|
17247
|
+
max_total: 20,
|
|
17248
|
+
on_limit: "pause"
|
|
17249
|
+
})),
|
|
17250
|
+
oversight: exports_external.object({
|
|
17251
|
+
on_plan_change: exports_external.boolean().default(true),
|
|
17252
|
+
on_task_completion: exports_external.boolean().default(false),
|
|
17253
|
+
on_phase_boundary: exports_external.boolean().default(true),
|
|
17254
|
+
on_high_risk_action: exports_external.boolean().default(true),
|
|
17255
|
+
on_subagent_return_warning: exports_external.boolean().default(true),
|
|
17256
|
+
every_tool_calls: exports_external.number().int().min(0).max(1e4).default(25),
|
|
17257
|
+
every_architect_turns: exports_external.number().int().min(0).max(1000).default(5),
|
|
17258
|
+
every_minutes: exports_external.number().int().min(0).max(1440).default(20)
|
|
17259
|
+
}).default(() => ({
|
|
17260
|
+
on_plan_change: true,
|
|
17261
|
+
on_task_completion: false,
|
|
17262
|
+
on_phase_boundary: true,
|
|
17263
|
+
on_high_risk_action: true,
|
|
17264
|
+
on_subagent_return_warning: true,
|
|
17265
|
+
every_tool_calls: 25,
|
|
17266
|
+
every_architect_turns: 5,
|
|
17267
|
+
every_minutes: 20
|
|
17268
|
+
}))
|
|
17269
|
+
}).optional().default(() => ({
|
|
17178
17270
|
enabled: false,
|
|
17179
17271
|
max_interactions_per_phase: 50,
|
|
17180
17272
|
deadlock_threshold: 3,
|
|
17181
|
-
escalation_mode: "pause"
|
|
17182
|
-
|
|
17273
|
+
escalation_mode: "pause",
|
|
17274
|
+
mode: "supervised",
|
|
17275
|
+
fail_closed: true,
|
|
17276
|
+
permission_policy: {
|
|
17277
|
+
enabled: true,
|
|
17278
|
+
trusted_roots: ["."],
|
|
17279
|
+
trusted_domains: [],
|
|
17280
|
+
protected_paths: [
|
|
17281
|
+
".git",
|
|
17282
|
+
".github/workflows",
|
|
17283
|
+
".swarm",
|
|
17284
|
+
"package.json",
|
|
17285
|
+
"package-lock.json",
|
|
17286
|
+
"bun.lock",
|
|
17287
|
+
"CHANGELOG.md",
|
|
17288
|
+
".release-please-manifest.json",
|
|
17289
|
+
"release-please-config.json",
|
|
17290
|
+
"src/index.ts",
|
|
17291
|
+
"src/hooks/guardrails.ts",
|
|
17292
|
+
"src/hooks/delegation-gate.ts",
|
|
17293
|
+
"src/hooks/scope-guard.ts",
|
|
17294
|
+
"src/hooks/full-auto-permission.ts",
|
|
17295
|
+
"src/hooks/full-auto-intercept.ts",
|
|
17296
|
+
"src/full-auto",
|
|
17297
|
+
"src/config/schema.ts",
|
|
17298
|
+
"src/config/constants.ts",
|
|
17299
|
+
"src/tools/phase-complete.ts",
|
|
17300
|
+
"dist"
|
|
17301
|
+
],
|
|
17302
|
+
allow_defaults: true
|
|
17303
|
+
},
|
|
17304
|
+
denials: {
|
|
17305
|
+
max_consecutive: 3,
|
|
17306
|
+
max_total: 20,
|
|
17307
|
+
on_limit: "pause"
|
|
17308
|
+
},
|
|
17309
|
+
oversight: {
|
|
17310
|
+
on_plan_change: true,
|
|
17311
|
+
on_task_completion: false,
|
|
17312
|
+
on_phase_boundary: true,
|
|
17313
|
+
on_high_risk_action: true,
|
|
17314
|
+
on_subagent_return_warning: true,
|
|
17315
|
+
every_tool_calls: 25,
|
|
17316
|
+
every_architect_turns: 5,
|
|
17317
|
+
every_minutes: 20
|
|
17318
|
+
}
|
|
17319
|
+
}))
|
|
17183
17320
|
});
|
|
17184
17321
|
});
|
|
17185
17322
|
|
|
@@ -19870,7 +20007,8 @@ var init_qa_gate_profile = __esm(() => {
|
|
|
19870
20007
|
sast_enabled: true,
|
|
19871
20008
|
mutation_test: false,
|
|
19872
20009
|
council_general_review: false,
|
|
19873
|
-
drift_check: true
|
|
20010
|
+
drift_check: true,
|
|
20011
|
+
final_council: false
|
|
19874
20012
|
};
|
|
19875
20013
|
});
|
|
19876
20014
|
// node_modules/quick-lru/index.js
|
|
@@ -20520,6 +20658,7 @@ var init_delegation_gate = __esm(() => {
|
|
|
20520
20658
|
init_state();
|
|
20521
20659
|
init_telemetry();
|
|
20522
20660
|
init_logger();
|
|
20661
|
+
init_task_id();
|
|
20523
20662
|
init_guardrails();
|
|
20524
20663
|
init_normalize_tool_name();
|
|
20525
20664
|
init_utils2();
|
|
@@ -20559,6 +20698,7 @@ function resetSwarmState() {
|
|
|
20559
20698
|
swarmState.opencodeClient = null;
|
|
20560
20699
|
swarmState.curatorInitAgentNames = [];
|
|
20561
20700
|
swarmState.curatorPhaseAgentNames = [];
|
|
20701
|
+
swarmState.generatedAgentNames = [];
|
|
20562
20702
|
_rehydrationCache = null;
|
|
20563
20703
|
swarmState.fullAutoEnabledInConfig = false;
|
|
20564
20704
|
swarmState.environmentProfiles.clear();
|
|
@@ -20603,6 +20743,7 @@ var init_state = __esm(() => {
|
|
|
20603
20743
|
opencodeClient: null,
|
|
20604
20744
|
curatorInitAgentNames: [],
|
|
20605
20745
|
curatorPhaseAgentNames: [],
|
|
20746
|
+
generatedAgentNames: [],
|
|
20606
20747
|
lastBudgetPct: 0,
|
|
20607
20748
|
agentSessions: defaultRunContext.agentSessions,
|
|
20608
20749
|
pendingRehydrations: new Set,
|
|
@@ -40758,8 +40899,254 @@ var init_export = __esm(() => {
|
|
|
40758
40899
|
init_export_service();
|
|
40759
40900
|
});
|
|
40760
40901
|
|
|
40902
|
+
// src/full-auto/state.ts
|
|
40903
|
+
import * as fs11 from "fs";
|
|
40904
|
+
import * as path24 from "path";
|
|
40905
|
+
function nowISO() {
|
|
40906
|
+
return new Date().toISOString();
|
|
40907
|
+
}
|
|
40908
|
+
function ensureSwarmDir(directory) {
|
|
40909
|
+
const swarmDir = path24.resolve(directory, ".swarm");
|
|
40910
|
+
if (!fs11.existsSync(swarmDir)) {
|
|
40911
|
+
fs11.mkdirSync(swarmDir, { recursive: true });
|
|
40912
|
+
}
|
|
40913
|
+
return swarmDir;
|
|
40914
|
+
}
|
|
40915
|
+
function emptyCounters() {
|
|
40916
|
+
return {
|
|
40917
|
+
architectTurns: 0,
|
|
40918
|
+
toolCalls: 0,
|
|
40919
|
+
coderDelegations: 0,
|
|
40920
|
+
reviewerRejections: 0,
|
|
40921
|
+
testFailures: 0,
|
|
40922
|
+
oversightChecks: 0,
|
|
40923
|
+
consecutiveNoProgressTurns: 0
|
|
40924
|
+
};
|
|
40925
|
+
}
|
|
40926
|
+
function emptyState(sessionID, mode = "supervised") {
|
|
40927
|
+
const now = nowISO();
|
|
40928
|
+
return {
|
|
40929
|
+
status: "idle",
|
|
40930
|
+
sessionID,
|
|
40931
|
+
mode,
|
|
40932
|
+
startedAt: now,
|
|
40933
|
+
updatedAt: now,
|
|
40934
|
+
denialCounters: { consecutive: 0, total: 0 },
|
|
40935
|
+
denialHistory: [],
|
|
40936
|
+
counters: emptyCounters()
|
|
40937
|
+
};
|
|
40938
|
+
}
|
|
40939
|
+
function withStateLock(directory, fn) {
|
|
40940
|
+
let release;
|
|
40941
|
+
try {
|
|
40942
|
+
const lockTarget = validateSwarmPath(directory, STATE_FILE);
|
|
40943
|
+
if (!fs11.existsSync(lockTarget)) {
|
|
40944
|
+
ensureSwarmDir(directory);
|
|
40945
|
+
const seed = {
|
|
40946
|
+
version: 2,
|
|
40947
|
+
updatedAt: nowISO(),
|
|
40948
|
+
oversightSequence: 0,
|
|
40949
|
+
sessions: {}
|
|
40950
|
+
};
|
|
40951
|
+
fs11.writeFileSync(lockTarget, `${JSON.stringify(seed, null, 2)}
|
|
40952
|
+
`, "utf-8");
|
|
40953
|
+
}
|
|
40954
|
+
release = lockfile5.lockSync(lockTarget, {
|
|
40955
|
+
retries: { retries: 5, minTimeout: 5, maxTimeout: 50 },
|
|
40956
|
+
stale: 5000
|
|
40957
|
+
});
|
|
40958
|
+
} catch (error93) {
|
|
40959
|
+
warn(`[full-auto/state] cross-process lock unavailable; proceeding unlocked: ${error93 instanceof Error ? error93.message : String(error93)}`);
|
|
40960
|
+
}
|
|
40961
|
+
try {
|
|
40962
|
+
return fn();
|
|
40963
|
+
} finally {
|
|
40964
|
+
if (release) {
|
|
40965
|
+
try {
|
|
40966
|
+
release();
|
|
40967
|
+
} catch (releaseError) {
|
|
40968
|
+
warn(`[full-auto/state] lock release failed: ${releaseError instanceof Error ? releaseError.message : String(releaseError)}`);
|
|
40969
|
+
}
|
|
40970
|
+
}
|
|
40971
|
+
}
|
|
40972
|
+
}
|
|
40973
|
+
function emptyPersisted() {
|
|
40974
|
+
return {
|
|
40975
|
+
version: 2,
|
|
40976
|
+
updatedAt: nowISO(),
|
|
40977
|
+
oversightSequence: 0,
|
|
40978
|
+
sessions: {}
|
|
40979
|
+
};
|
|
40980
|
+
}
|
|
40981
|
+
function markStateUnreadable(reason) {
|
|
40982
|
+
stateUnreadable = true;
|
|
40983
|
+
stateUnreadableReason = reason;
|
|
40984
|
+
error(`[full-auto/state] state file unreadable: ${reason} \u2014 failing closed`);
|
|
40985
|
+
}
|
|
40986
|
+
function clearStateUnreadable() {
|
|
40987
|
+
stateUnreadable = false;
|
|
40988
|
+
stateUnreadableReason = "";
|
|
40989
|
+
}
|
|
40990
|
+
function readPersisted(directory) {
|
|
40991
|
+
try {
|
|
40992
|
+
const filePath = validateSwarmPath(directory, STATE_FILE);
|
|
40993
|
+
if (!fs11.existsSync(filePath)) {
|
|
40994
|
+
clearStateUnreadable();
|
|
40995
|
+
return emptyPersisted();
|
|
40996
|
+
}
|
|
40997
|
+
const raw = fs11.readFileSync(filePath, "utf-8");
|
|
40998
|
+
const parsed = JSON.parse(raw);
|
|
40999
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 2 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
|
|
41000
|
+
markStateUnreadable(`malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
|
|
41001
|
+
return emptyPersisted();
|
|
41002
|
+
}
|
|
41003
|
+
clearStateUnreadable();
|
|
41004
|
+
return {
|
|
41005
|
+
version: 2,
|
|
41006
|
+
updatedAt: parsed.updatedAt ?? nowISO(),
|
|
41007
|
+
oversightSequence: typeof parsed.oversightSequence === "number" ? parsed.oversightSequence : 0,
|
|
41008
|
+
sessions: parsed.sessions
|
|
41009
|
+
};
|
|
41010
|
+
} catch (error93) {
|
|
41011
|
+
const reason = error93 instanceof Error ? error93.message : String(error93);
|
|
41012
|
+
error(`[full-auto/state] Failed to read ${STATE_FILE}: ${reason} \u2014 attempting .bak recovery`);
|
|
41013
|
+
try {
|
|
41014
|
+
const bakPath = validateSwarmPath(directory, `${STATE_FILE}.bak`);
|
|
41015
|
+
if (fs11.existsSync(bakPath)) {
|
|
41016
|
+
const raw = fs11.readFileSync(bakPath, "utf-8");
|
|
41017
|
+
const parsed = JSON.parse(raw);
|
|
41018
|
+
if (parsed?.version === 2 && parsed.sessions && !Array.isArray(parsed.sessions)) {
|
|
41019
|
+
warn(`[full-auto/state] Recovered from ${STATE_FILE}.bak`);
|
|
41020
|
+
clearStateUnreadable();
|
|
41021
|
+
return {
|
|
41022
|
+
version: 2,
|
|
41023
|
+
updatedAt: parsed.updatedAt ?? nowISO(),
|
|
41024
|
+
oversightSequence: typeof parsed.oversightSequence === "number" ? parsed.oversightSequence : 0,
|
|
41025
|
+
sessions: parsed.sessions
|
|
41026
|
+
};
|
|
41027
|
+
}
|
|
41028
|
+
}
|
|
41029
|
+
} catch (bakError) {
|
|
41030
|
+
error(`[full-auto/state] .bak recovery also failed: ${bakError instanceof Error ? bakError.message : String(bakError)}`);
|
|
41031
|
+
}
|
|
41032
|
+
markStateUnreadable(`canonical=${reason}; .bak=missing-or-corrupt`);
|
|
41033
|
+
return emptyPersisted();
|
|
41034
|
+
}
|
|
41035
|
+
}
|
|
41036
|
+
function writePersisted(directory, persisted) {
|
|
41037
|
+
let filePath;
|
|
41038
|
+
let tmpPath;
|
|
41039
|
+
let bakPath;
|
|
41040
|
+
let payload;
|
|
41041
|
+
try {
|
|
41042
|
+
ensureSwarmDir(directory);
|
|
41043
|
+
filePath = validateSwarmPath(directory, STATE_FILE);
|
|
41044
|
+
tmpPath = validateSwarmPath(directory, `${STATE_FILE}.tmp`);
|
|
41045
|
+
bakPath = validateSwarmPath(directory, `${STATE_FILE}.bak`);
|
|
41046
|
+
persisted.updatedAt = nowISO();
|
|
41047
|
+
payload = `${JSON.stringify(persisted, null, 2)}
|
|
41048
|
+
`;
|
|
41049
|
+
} catch (error93) {
|
|
41050
|
+
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
41051
|
+
error(`[full-auto/state] Failed to prepare ${STATE_FILE} write: ${msg}`);
|
|
41052
|
+
throw new Error(`Full-Auto state persistence prepare failed: ${msg}`);
|
|
41053
|
+
}
|
|
41054
|
+
try {
|
|
41055
|
+
if (fs11.existsSync(filePath)) {
|
|
41056
|
+
fs11.copyFileSync(filePath, bakPath);
|
|
41057
|
+
}
|
|
41058
|
+
} catch {}
|
|
41059
|
+
try {
|
|
41060
|
+
fs11.writeFileSync(tmpPath, payload, "utf-8");
|
|
41061
|
+
try {
|
|
41062
|
+
const fd = fs11.openSync(tmpPath, "r+");
|
|
41063
|
+
try {
|
|
41064
|
+
fs11.fsyncSync(fd);
|
|
41065
|
+
} finally {
|
|
41066
|
+
fs11.closeSync(fd);
|
|
41067
|
+
}
|
|
41068
|
+
} catch {}
|
|
41069
|
+
fs11.renameSync(tmpPath, filePath);
|
|
41070
|
+
const readback = fs11.readFileSync(filePath, "utf-8");
|
|
41071
|
+
const parsed = JSON.parse(readback);
|
|
41072
|
+
if (parsed?.version !== 2) {
|
|
41073
|
+
throw new Error("Round-trip readback returned wrong version");
|
|
41074
|
+
}
|
|
41075
|
+
} catch (error93) {
|
|
41076
|
+
const msg = error93 instanceof Error ? error93.message : String(error93);
|
|
41077
|
+
error(`[full-auto/state] Failed to persist ${STATE_FILE} atomically: ${msg}`);
|
|
41078
|
+
throw new Error(`Full-Auto state persistence failed: ${msg}`);
|
|
41079
|
+
}
|
|
41080
|
+
}
|
|
41081
|
+
function startFullAutoRun(directory, sessionID, config3, options = {}) {
|
|
41082
|
+
return withStateLock(directory, () => {
|
|
41083
|
+
const persisted = readPersisted(directory);
|
|
41084
|
+
const existing = persisted.sessions[sessionID];
|
|
41085
|
+
const mode = config3?.mode ?? existing?.mode ?? "supervised";
|
|
41086
|
+
const state = existing ? {
|
|
41087
|
+
...existing,
|
|
41088
|
+
status: "running",
|
|
41089
|
+
mode,
|
|
41090
|
+
planID: options.planID ?? existing.planID,
|
|
41091
|
+
currentPhase: options.phase ?? existing.currentPhase,
|
|
41092
|
+
currentTaskID: options.taskID ?? existing.currentTaskID,
|
|
41093
|
+
pauseReason: undefined,
|
|
41094
|
+
terminateReason: undefined,
|
|
41095
|
+
updatedAt: nowISO(),
|
|
41096
|
+
denialCounters: {
|
|
41097
|
+
consecutive: 0,
|
|
41098
|
+
total: existing.denialCounters.total
|
|
41099
|
+
}
|
|
41100
|
+
} : {
|
|
41101
|
+
...emptyState(sessionID, mode),
|
|
41102
|
+
status: "running",
|
|
41103
|
+
planID: options.planID,
|
|
41104
|
+
currentPhase: options.phase,
|
|
41105
|
+
currentTaskID: options.taskID
|
|
41106
|
+
};
|
|
41107
|
+
persisted.sessions[sessionID] = state;
|
|
41108
|
+
writePersisted(directory, persisted);
|
|
41109
|
+
return state;
|
|
41110
|
+
});
|
|
41111
|
+
}
|
|
41112
|
+
function pauseFullAutoRun(directory, sessionID, reason) {
|
|
41113
|
+
return withStateLock(directory, () => {
|
|
41114
|
+
const persisted = readPersisted(directory);
|
|
41115
|
+
const state = persisted.sessions[sessionID];
|
|
41116
|
+
if (!state)
|
|
41117
|
+
return;
|
|
41118
|
+
state.status = "paused";
|
|
41119
|
+
state.pauseReason = reason;
|
|
41120
|
+
state.updatedAt = nowISO();
|
|
41121
|
+
persisted.sessions[sessionID] = state;
|
|
41122
|
+
writePersisted(directory, persisted);
|
|
41123
|
+
return state;
|
|
41124
|
+
});
|
|
41125
|
+
}
|
|
41126
|
+
function terminateFullAutoRun(directory, sessionID, reason) {
|
|
41127
|
+
return withStateLock(directory, () => {
|
|
41128
|
+
const persisted = readPersisted(directory);
|
|
41129
|
+
const state = persisted.sessions[sessionID];
|
|
41130
|
+
if (!state)
|
|
41131
|
+
return;
|
|
41132
|
+
state.status = "terminated";
|
|
41133
|
+
state.terminateReason = reason;
|
|
41134
|
+
state.updatedAt = nowISO();
|
|
41135
|
+
persisted.sessions[sessionID] = state;
|
|
41136
|
+
writePersisted(directory, persisted);
|
|
41137
|
+
return state;
|
|
41138
|
+
});
|
|
41139
|
+
}
|
|
41140
|
+
var import_proper_lockfile5, lockfile5, STATE_FILE = "full-auto-state.json", stateUnreadable = false, stateUnreadableReason = "";
|
|
41141
|
+
var init_state2 = __esm(() => {
|
|
41142
|
+
init_utils2();
|
|
41143
|
+
init_logger();
|
|
41144
|
+
import_proper_lockfile5 = __toESM(require_proper_lockfile(), 1);
|
|
41145
|
+
lockfile5 = import_proper_lockfile5.default;
|
|
41146
|
+
});
|
|
41147
|
+
|
|
40761
41148
|
// src/commands/full-auto.ts
|
|
40762
|
-
async function handleFullAutoCommand(
|
|
41149
|
+
async function handleFullAutoCommand(directory, args, sessionID) {
|
|
40763
41150
|
if (!sessionID || sessionID.trim() === "") {
|
|
40764
41151
|
return "Error: No active session context. Full-Auto Mode requires an active session. Use /swarm-full-auto from within an OpenCode session, or start a session first.";
|
|
40765
41152
|
}
|
|
@@ -40779,16 +41166,63 @@ async function handleFullAutoCommand(_directory, args, sessionID) {
|
|
|
40779
41166
|
if (newFullAutoMode && !swarmState.fullAutoEnabledInConfig) {
|
|
40780
41167
|
return "Error: Full-Auto Mode cannot be enabled because full_auto.enabled is not set to true in the swarm plugin config. The autonomous oversight hook is inactive without config-level enablement. Set full_auto.enabled = true in your opencode-swarm config and restart.";
|
|
40781
41168
|
}
|
|
41169
|
+
let v2Status = "unavailable";
|
|
41170
|
+
let modeLabel = "supervised";
|
|
41171
|
+
let denialMaxConsecutive = 3;
|
|
41172
|
+
let denialMaxTotal = 20;
|
|
41173
|
+
let failClosed = true;
|
|
41174
|
+
let durableError;
|
|
41175
|
+
try {
|
|
41176
|
+
const { config: config3 } = loadPluginConfigWithMeta(directory);
|
|
41177
|
+
const fullAutoConfig = config3.full_auto;
|
|
41178
|
+
modeLabel = fullAutoConfig?.mode ?? "supervised";
|
|
41179
|
+
denialMaxConsecutive = fullAutoConfig?.denials?.max_consecutive ?? 3;
|
|
41180
|
+
denialMaxTotal = fullAutoConfig?.denials?.max_total ?? 20;
|
|
41181
|
+
failClosed = fullAutoConfig?.fail_closed !== false;
|
|
41182
|
+
if (newFullAutoMode) {
|
|
41183
|
+
startFullAutoRun(directory, sessionID, fullAutoConfig);
|
|
41184
|
+
v2Status = "running";
|
|
41185
|
+
} else {
|
|
41186
|
+
const paused = pauseFullAutoRun(directory, sessionID, "/swarm full-auto off");
|
|
41187
|
+
if (!paused) {
|
|
41188
|
+
terminateFullAutoRun(directory, sessionID, "never started");
|
|
41189
|
+
}
|
|
41190
|
+
v2Status = "paused";
|
|
41191
|
+
}
|
|
41192
|
+
} catch (error93) {
|
|
41193
|
+
durableError = error93 instanceof Error ? error93.message : String(error93);
|
|
41194
|
+
error(`[full-auto] durable run-state write failed: ${durableError}`);
|
|
41195
|
+
}
|
|
41196
|
+
if (newFullAutoMode && durableError) {
|
|
41197
|
+
return [
|
|
41198
|
+
"Error: Full-Auto Mode could NOT be enabled \u2014 durable run-state write failed.",
|
|
41199
|
+
`Reason: ${durableError}.`,
|
|
41200
|
+
"Inspect .swarm/ permissions and disk space, then retry."
|
|
41201
|
+
].join(" ");
|
|
41202
|
+
}
|
|
40782
41203
|
session.fullAutoMode = newFullAutoMode;
|
|
40783
41204
|
if (!newFullAutoMode) {
|
|
40784
41205
|
session.fullAutoInteractionCount = 0;
|
|
40785
41206
|
session.fullAutoDeadlockCount = 0;
|
|
40786
41207
|
session.fullAutoLastQuestionHash = null;
|
|
40787
41208
|
}
|
|
40788
|
-
|
|
41209
|
+
if (!newFullAutoMode) {
|
|
41210
|
+
return [
|
|
41211
|
+
"Full-Auto Mode disabled",
|
|
41212
|
+
`(v2 run-state: ${v2Status}; mode=${modeLabel})`
|
|
41213
|
+
].join(" ");
|
|
41214
|
+
}
|
|
41215
|
+
return [
|
|
41216
|
+
"Full-Auto Mode enabled",
|
|
41217
|
+
`(v2 mode=${modeLabel}, fail_closed=${failClosed},`,
|
|
41218
|
+
`denials max ${denialMaxConsecutive} consecutive / ${denialMaxTotal} total)`
|
|
41219
|
+
].join(" ");
|
|
40789
41220
|
}
|
|
40790
41221
|
var init_full_auto = __esm(() => {
|
|
41222
|
+
init_config();
|
|
41223
|
+
init_state2();
|
|
40791
41224
|
init_state();
|
|
41225
|
+
init_logger();
|
|
40792
41226
|
});
|
|
40793
41227
|
|
|
40794
41228
|
// src/services/handoff-service.ts
|
|
@@ -41173,19 +41607,19 @@ var init_handoff_service = __esm(() => {
|
|
|
41173
41607
|
|
|
41174
41608
|
// src/commands/handoff.ts
|
|
41175
41609
|
import crypto4 from "crypto";
|
|
41176
|
-
import { renameSync as
|
|
41610
|
+
import { renameSync as renameSync7 } from "fs";
|
|
41177
41611
|
async function handleHandoffCommand(directory, _args) {
|
|
41178
41612
|
const handoffData = await getHandoffData(directory);
|
|
41179
41613
|
const markdown = formatHandoffMarkdown(handoffData);
|
|
41180
41614
|
const resolvedPath = validateSwarmPath(directory, "handoff.md");
|
|
41181
41615
|
const tempPath = `${resolvedPath}.tmp.${crypto4.randomUUID()}`;
|
|
41182
41616
|
await bunWrite(tempPath, markdown);
|
|
41183
|
-
|
|
41617
|
+
renameSync7(tempPath, resolvedPath);
|
|
41184
41618
|
const continuationPrompt = formatContinuationPrompt(handoffData);
|
|
41185
41619
|
const promptPath = validateSwarmPath(directory, "handoff-prompt.md");
|
|
41186
41620
|
const promptTempPath = `${promptPath}.tmp.${crypto4.randomUUID()}`;
|
|
41187
41621
|
await bunWrite(promptTempPath, continuationPrompt);
|
|
41188
|
-
|
|
41622
|
+
renameSync7(promptTempPath, promptPath);
|
|
41189
41623
|
await writeSnapshot(directory, swarmState);
|
|
41190
41624
|
await flushPendingSnapshot(directory);
|
|
41191
41625
|
return `## Handoff Brief Written
|
|
@@ -41560,9 +41994,9 @@ var init_issue = __esm(() => {
|
|
|
41560
41994
|
|
|
41561
41995
|
// src/hooks/knowledge-migrator.ts
|
|
41562
41996
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
41563
|
-
import { existsSync as
|
|
41997
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11 } from "fs";
|
|
41564
41998
|
import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile6 } from "fs/promises";
|
|
41565
|
-
import * as
|
|
41999
|
+
import * as path25 from "path";
|
|
41566
42000
|
async function migrateKnowledgeToExternal(_directory, _config) {
|
|
41567
42001
|
return {
|
|
41568
42002
|
migrated: false,
|
|
@@ -41573,10 +42007,10 @@ async function migrateKnowledgeToExternal(_directory, _config) {
|
|
|
41573
42007
|
};
|
|
41574
42008
|
}
|
|
41575
42009
|
async function migrateContextToKnowledge(directory, config3) {
|
|
41576
|
-
const sentinelPath =
|
|
41577
|
-
const contextPath =
|
|
42010
|
+
const sentinelPath = path25.join(directory, ".swarm", ".knowledge-migrated");
|
|
42011
|
+
const contextPath = path25.join(directory, ".swarm", "context.md");
|
|
41578
42012
|
const knowledgePath = resolveSwarmKnowledgePath(directory);
|
|
41579
|
-
if (
|
|
42013
|
+
if (existsSync15(sentinelPath)) {
|
|
41580
42014
|
return {
|
|
41581
42015
|
migrated: false,
|
|
41582
42016
|
entriesMigrated: 0,
|
|
@@ -41585,7 +42019,7 @@ async function migrateContextToKnowledge(directory, config3) {
|
|
|
41585
42019
|
skippedReason: "sentinel-exists"
|
|
41586
42020
|
};
|
|
41587
42021
|
}
|
|
41588
|
-
if (!
|
|
42022
|
+
if (!existsSync15(contextPath)) {
|
|
41589
42023
|
return {
|
|
41590
42024
|
migrated: false,
|
|
41591
42025
|
entriesMigrated: 0,
|
|
@@ -41770,16 +42204,16 @@ function truncateLesson(text) {
|
|
|
41770
42204
|
return `${text.slice(0, 277)}...`;
|
|
41771
42205
|
}
|
|
41772
42206
|
function inferProjectName(directory) {
|
|
41773
|
-
const packageJsonPath =
|
|
41774
|
-
if (
|
|
42207
|
+
const packageJsonPath = path25.join(directory, "package.json");
|
|
42208
|
+
if (existsSync15(packageJsonPath)) {
|
|
41775
42209
|
try {
|
|
41776
|
-
const pkg = JSON.parse(
|
|
42210
|
+
const pkg = JSON.parse(readFileSync11(packageJsonPath, "utf-8"));
|
|
41777
42211
|
if (pkg.name && typeof pkg.name === "string") {
|
|
41778
42212
|
return pkg.name;
|
|
41779
42213
|
}
|
|
41780
42214
|
} catch {}
|
|
41781
42215
|
}
|
|
41782
|
-
return
|
|
42216
|
+
return path25.basename(directory);
|
|
41783
42217
|
}
|
|
41784
42218
|
async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
41785
42219
|
const sentinel = {
|
|
@@ -41791,7 +42225,7 @@ async function writeSentinel(sentinelPath, migrated, dropped) {
|
|
|
41791
42225
|
schema_version: 1,
|
|
41792
42226
|
migration_tool: "knowledge-migrator.ts"
|
|
41793
42227
|
};
|
|
41794
|
-
await mkdir5(
|
|
42228
|
+
await mkdir5(path25.dirname(sentinelPath), { recursive: true });
|
|
41795
42229
|
await writeFile6(sentinelPath, JSON.stringify(sentinel, null, 2), "utf-8");
|
|
41796
42230
|
}
|
|
41797
42231
|
var _internals14;
|
|
@@ -42312,8 +42746,8 @@ function containsControlChars(str) {
|
|
|
42312
42746
|
var init_path_security = () => {};
|
|
42313
42747
|
|
|
42314
42748
|
// src/tools/lint.ts
|
|
42315
|
-
import * as
|
|
42316
|
-
import * as
|
|
42749
|
+
import * as fs12 from "fs";
|
|
42750
|
+
import * as path26 from "path";
|
|
42317
42751
|
function validateArgs(args) {
|
|
42318
42752
|
if (typeof args !== "object" || args === null)
|
|
42319
42753
|
return false;
|
|
@@ -42324,9 +42758,9 @@ function validateArgs(args) {
|
|
|
42324
42758
|
}
|
|
42325
42759
|
function getLinterCommand(linter, mode, projectDir) {
|
|
42326
42760
|
const isWindows = process.platform === "win32";
|
|
42327
|
-
const binDir =
|
|
42328
|
-
const biomeBin = isWindows ?
|
|
42329
|
-
const eslintBin = isWindows ?
|
|
42761
|
+
const binDir = path26.join(projectDir, "node_modules", ".bin");
|
|
42762
|
+
const biomeBin = isWindows ? path26.join(binDir, "biome.EXE") : path26.join(binDir, "biome");
|
|
42763
|
+
const eslintBin = isWindows ? path26.join(binDir, "eslint.cmd") : path26.join(binDir, "eslint");
|
|
42330
42764
|
switch (linter) {
|
|
42331
42765
|
case "biome":
|
|
42332
42766
|
if (mode === "fix") {
|
|
@@ -42342,7 +42776,7 @@ function getLinterCommand(linter, mode, projectDir) {
|
|
|
42342
42776
|
}
|
|
42343
42777
|
function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
42344
42778
|
const gradlewName = process.platform === "win32" ? "gradlew.bat" : "gradlew";
|
|
42345
|
-
const gradlew =
|
|
42779
|
+
const gradlew = fs12.existsSync(path26.join(cwd, gradlewName)) ? path26.join(cwd, gradlewName) : null;
|
|
42346
42780
|
switch (linter) {
|
|
42347
42781
|
case "ruff":
|
|
42348
42782
|
return mode === "fix" ? ["ruff", "check", "--fix", "."] : ["ruff", "check", "."];
|
|
@@ -42376,12 +42810,12 @@ function getAdditionalLinterCommand(linter, mode, cwd) {
|
|
|
42376
42810
|
}
|
|
42377
42811
|
}
|
|
42378
42812
|
function detectRuff(cwd) {
|
|
42379
|
-
if (
|
|
42813
|
+
if (fs12.existsSync(path26.join(cwd, "ruff.toml")))
|
|
42380
42814
|
return isCommandAvailable("ruff");
|
|
42381
42815
|
try {
|
|
42382
|
-
const pyproject =
|
|
42383
|
-
if (
|
|
42384
|
-
const content =
|
|
42816
|
+
const pyproject = path26.join(cwd, "pyproject.toml");
|
|
42817
|
+
if (fs12.existsSync(pyproject)) {
|
|
42818
|
+
const content = fs12.readFileSync(pyproject, "utf-8");
|
|
42385
42819
|
if (content.includes("[tool.ruff]"))
|
|
42386
42820
|
return isCommandAvailable("ruff");
|
|
42387
42821
|
}
|
|
@@ -42389,21 +42823,21 @@ function detectRuff(cwd) {
|
|
|
42389
42823
|
return false;
|
|
42390
42824
|
}
|
|
42391
42825
|
function detectClippy(cwd) {
|
|
42392
|
-
return
|
|
42826
|
+
return fs12.existsSync(path26.join(cwd, "Cargo.toml")) && isCommandAvailable("cargo");
|
|
42393
42827
|
}
|
|
42394
42828
|
function detectGolangciLint(cwd) {
|
|
42395
|
-
return
|
|
42829
|
+
return fs12.existsSync(path26.join(cwd, "go.mod")) && isCommandAvailable("golangci-lint");
|
|
42396
42830
|
}
|
|
42397
42831
|
function detectCheckstyle(cwd) {
|
|
42398
|
-
const hasMaven =
|
|
42399
|
-
const hasGradle =
|
|
42400
|
-
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (
|
|
42832
|
+
const hasMaven = fs12.existsSync(path26.join(cwd, "pom.xml"));
|
|
42833
|
+
const hasGradle = fs12.existsSync(path26.join(cwd, "build.gradle")) || fs12.existsSync(path26.join(cwd, "build.gradle.kts"));
|
|
42834
|
+
const hasBinary = hasMaven && isCommandAvailable("mvn") || hasGradle && (fs12.existsSync(path26.join(cwd, "gradlew")) || isCommandAvailable("gradle"));
|
|
42401
42835
|
return (hasMaven || hasGradle) && hasBinary;
|
|
42402
42836
|
}
|
|
42403
42837
|
function detectKtlint(cwd) {
|
|
42404
|
-
const hasKotlin =
|
|
42838
|
+
const hasKotlin = fs12.existsSync(path26.join(cwd, "build.gradle.kts")) || fs12.existsSync(path26.join(cwd, "build.gradle")) || (() => {
|
|
42405
42839
|
try {
|
|
42406
|
-
return
|
|
42840
|
+
return fs12.readdirSync(cwd).some((f) => f.endsWith(".kt") || f.endsWith(".kts"));
|
|
42407
42841
|
} catch {
|
|
42408
42842
|
return false;
|
|
42409
42843
|
}
|
|
@@ -42412,7 +42846,7 @@ function detectKtlint(cwd) {
|
|
|
42412
42846
|
}
|
|
42413
42847
|
function detectDotnetFormat(cwd) {
|
|
42414
42848
|
try {
|
|
42415
|
-
const files =
|
|
42849
|
+
const files = fs12.readdirSync(cwd);
|
|
42416
42850
|
const hasCsproj = files.some((f) => f.endsWith(".csproj") || f.endsWith(".sln"));
|
|
42417
42851
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
42418
42852
|
} catch {
|
|
@@ -42420,14 +42854,14 @@ function detectDotnetFormat(cwd) {
|
|
|
42420
42854
|
}
|
|
42421
42855
|
}
|
|
42422
42856
|
function detectCppcheck(cwd) {
|
|
42423
|
-
if (
|
|
42857
|
+
if (fs12.existsSync(path26.join(cwd, "CMakeLists.txt"))) {
|
|
42424
42858
|
return isCommandAvailable("cppcheck");
|
|
42425
42859
|
}
|
|
42426
42860
|
try {
|
|
42427
|
-
const dirsToCheck = [cwd,
|
|
42861
|
+
const dirsToCheck = [cwd, path26.join(cwd, "src")];
|
|
42428
42862
|
const hasCpp = dirsToCheck.some((dir) => {
|
|
42429
42863
|
try {
|
|
42430
|
-
return
|
|
42864
|
+
return fs12.readdirSync(dir).some((f) => /\.(c|cpp|cc|cxx|h|hpp)$/.test(f));
|
|
42431
42865
|
} catch {
|
|
42432
42866
|
return false;
|
|
42433
42867
|
}
|
|
@@ -42438,13 +42872,13 @@ function detectCppcheck(cwd) {
|
|
|
42438
42872
|
}
|
|
42439
42873
|
}
|
|
42440
42874
|
function detectSwiftlint(cwd) {
|
|
42441
|
-
return
|
|
42875
|
+
return fs12.existsSync(path26.join(cwd, "Package.swift")) && isCommandAvailable("swiftlint");
|
|
42442
42876
|
}
|
|
42443
42877
|
function detectDartAnalyze(cwd) {
|
|
42444
|
-
return
|
|
42878
|
+
return fs12.existsSync(path26.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
42445
42879
|
}
|
|
42446
42880
|
function detectRubocop(cwd) {
|
|
42447
|
-
return (
|
|
42881
|
+
return (fs12.existsSync(path26.join(cwd, "Gemfile")) || fs12.existsSync(path26.join(cwd, "gems.rb")) || fs12.existsSync(path26.join(cwd, ".rubocop.yml"))) && (isCommandAvailable("rubocop") || isCommandAvailable("bundle"));
|
|
42448
42882
|
}
|
|
42449
42883
|
function detectAdditionalLinter(cwd) {
|
|
42450
42884
|
if (detectRuff(cwd))
|
|
@@ -42472,10 +42906,10 @@ function detectAdditionalLinter(cwd) {
|
|
|
42472
42906
|
function findBinInAncestors(startDir, binName) {
|
|
42473
42907
|
let dir = startDir;
|
|
42474
42908
|
while (true) {
|
|
42475
|
-
const candidate =
|
|
42476
|
-
if (
|
|
42909
|
+
const candidate = path26.join(dir, "node_modules", ".bin", binName);
|
|
42910
|
+
if (fs12.existsSync(candidate))
|
|
42477
42911
|
return candidate;
|
|
42478
|
-
const parent =
|
|
42912
|
+
const parent = path26.dirname(dir);
|
|
42479
42913
|
if (parent === dir)
|
|
42480
42914
|
break;
|
|
42481
42915
|
dir = parent;
|
|
@@ -42484,11 +42918,11 @@ function findBinInAncestors(startDir, binName) {
|
|
|
42484
42918
|
}
|
|
42485
42919
|
function findBinInEnvPath(binName) {
|
|
42486
42920
|
const searchPath = process.env.PATH ?? "";
|
|
42487
|
-
for (const dir of searchPath.split(
|
|
42921
|
+
for (const dir of searchPath.split(path26.delimiter)) {
|
|
42488
42922
|
if (!dir)
|
|
42489
42923
|
continue;
|
|
42490
|
-
const candidate =
|
|
42491
|
-
if (
|
|
42924
|
+
const candidate = path26.join(dir, binName);
|
|
42925
|
+
if (fs12.existsSync(candidate))
|
|
42492
42926
|
return candidate;
|
|
42493
42927
|
}
|
|
42494
42928
|
return null;
|
|
@@ -42496,17 +42930,17 @@ function findBinInEnvPath(binName) {
|
|
|
42496
42930
|
async function detectAvailableLinter(directory) {
|
|
42497
42931
|
if (!directory)
|
|
42498
42932
|
return null;
|
|
42499
|
-
if (!
|
|
42933
|
+
if (!fs12.existsSync(directory))
|
|
42500
42934
|
return null;
|
|
42501
42935
|
const projectDir = directory;
|
|
42502
42936
|
const isWindows = process.platform === "win32";
|
|
42503
|
-
const biomeBin = isWindows ?
|
|
42504
|
-
const eslintBin = isWindows ?
|
|
42937
|
+
const biomeBin = isWindows ? path26.join(projectDir, "node_modules", ".bin", "biome.EXE") : path26.join(projectDir, "node_modules", ".bin", "biome");
|
|
42938
|
+
const eslintBin = isWindows ? path26.join(projectDir, "node_modules", ".bin", "eslint.cmd") : path26.join(projectDir, "node_modules", ".bin", "eslint");
|
|
42505
42939
|
const localResult = await _detectAvailableLinter(projectDir, biomeBin, eslintBin);
|
|
42506
42940
|
if (localResult)
|
|
42507
42941
|
return localResult;
|
|
42508
|
-
const biomeAncestor = findBinInAncestors(
|
|
42509
|
-
const eslintAncestor = findBinInAncestors(
|
|
42942
|
+
const biomeAncestor = findBinInAncestors(path26.dirname(projectDir), isWindows ? "biome.EXE" : "biome");
|
|
42943
|
+
const eslintAncestor = findBinInAncestors(path26.dirname(projectDir), isWindows ? "eslint.cmd" : "eslint");
|
|
42510
42944
|
if (biomeAncestor || eslintAncestor) {
|
|
42511
42945
|
return _detectAvailableLinter(projectDir, biomeAncestor ?? biomeBin, eslintAncestor ?? eslintBin);
|
|
42512
42946
|
}
|
|
@@ -42525,11 +42959,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
42525
42959
|
stderr: "pipe"
|
|
42526
42960
|
});
|
|
42527
42961
|
const biomeExit = biomeProc.exited;
|
|
42528
|
-
const timeout = new Promise((
|
|
42962
|
+
const timeout = new Promise((resolve10) => setTimeout(() => resolve10("timeout"), DETECT_TIMEOUT));
|
|
42529
42963
|
const result = await Promise.race([biomeExit, timeout]);
|
|
42530
42964
|
if (result === "timeout") {
|
|
42531
42965
|
biomeProc.kill();
|
|
42532
|
-
} else if (biomeProc.exitCode === 0 &&
|
|
42966
|
+
} else if (biomeProc.exitCode === 0 && fs12.existsSync(biomeBin)) {
|
|
42533
42967
|
return "biome";
|
|
42534
42968
|
}
|
|
42535
42969
|
} catch {}
|
|
@@ -42539,11 +42973,11 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
|
|
|
42539
42973
|
stderr: "pipe"
|
|
42540
42974
|
});
|
|
42541
42975
|
const eslintExit = eslintProc.exited;
|
|
42542
|
-
const timeout = new Promise((
|
|
42976
|
+
const timeout = new Promise((resolve10) => setTimeout(() => resolve10("timeout"), DETECT_TIMEOUT));
|
|
42543
42977
|
const result = await Promise.race([eslintExit, timeout]);
|
|
42544
42978
|
if (result === "timeout") {
|
|
42545
42979
|
eslintProc.kill();
|
|
42546
|
-
} else if (eslintProc.exitCode === 0 &&
|
|
42980
|
+
} else if (eslintProc.exitCode === 0 && fs12.existsSync(eslintBin)) {
|
|
42547
42981
|
return "eslint";
|
|
42548
42982
|
}
|
|
42549
42983
|
} catch {}
|
|
@@ -42728,8 +43162,8 @@ For Rust: rustup component add clippy`
|
|
|
42728
43162
|
});
|
|
42729
43163
|
|
|
42730
43164
|
// src/tools/secretscan.ts
|
|
42731
|
-
import * as
|
|
42732
|
-
import * as
|
|
43165
|
+
import * as fs13 from "fs";
|
|
43166
|
+
import * as path27 from "path";
|
|
42733
43167
|
function calculateShannonEntropy(str) {
|
|
42734
43168
|
if (str.length === 0)
|
|
42735
43169
|
return 0;
|
|
@@ -42777,11 +43211,11 @@ function isGlobOrPathPattern(pattern) {
|
|
|
42777
43211
|
return pattern.includes("/") || pattern.includes("\\") || /[*?[\]{}]/.test(pattern);
|
|
42778
43212
|
}
|
|
42779
43213
|
function loadSecretScanIgnore(scanDir) {
|
|
42780
|
-
const ignorePath =
|
|
43214
|
+
const ignorePath = path27.join(scanDir, ".secretscanignore");
|
|
42781
43215
|
try {
|
|
42782
|
-
if (!
|
|
43216
|
+
if (!fs13.existsSync(ignorePath))
|
|
42783
43217
|
return [];
|
|
42784
|
-
const content =
|
|
43218
|
+
const content = fs13.readFileSync(ignorePath, "utf8");
|
|
42785
43219
|
const patterns = [];
|
|
42786
43220
|
for (const rawLine of content.split(/\r?\n/)) {
|
|
42787
43221
|
const line = rawLine.trim();
|
|
@@ -42800,7 +43234,7 @@ function isExcluded(entry, relPath, exactNames, globPatterns) {
|
|
|
42800
43234
|
if (exactNames.has(entry))
|
|
42801
43235
|
return true;
|
|
42802
43236
|
for (const pattern of globPatterns) {
|
|
42803
|
-
if (
|
|
43237
|
+
if (path27.matchesGlob(relPath, pattern))
|
|
42804
43238
|
return true;
|
|
42805
43239
|
}
|
|
42806
43240
|
return false;
|
|
@@ -42821,7 +43255,7 @@ function validateDirectoryInput(dir) {
|
|
|
42821
43255
|
return null;
|
|
42822
43256
|
}
|
|
42823
43257
|
function isBinaryFile(filePath, buffer) {
|
|
42824
|
-
const ext =
|
|
43258
|
+
const ext = path27.extname(filePath).toLowerCase();
|
|
42825
43259
|
if (DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
42826
43260
|
return true;
|
|
42827
43261
|
}
|
|
@@ -42899,7 +43333,7 @@ function createRedactedContext(line, findings) {
|
|
|
42899
43333
|
function scanFileForSecrets(filePath) {
|
|
42900
43334
|
const findings = [];
|
|
42901
43335
|
try {
|
|
42902
|
-
const lstat =
|
|
43336
|
+
const lstat = fs13.lstatSync(filePath);
|
|
42903
43337
|
if (lstat.isSymbolicLink()) {
|
|
42904
43338
|
return findings;
|
|
42905
43339
|
}
|
|
@@ -42908,14 +43342,14 @@ function scanFileForSecrets(filePath) {
|
|
|
42908
43342
|
}
|
|
42909
43343
|
let buffer;
|
|
42910
43344
|
if (O_NOFOLLOW !== undefined) {
|
|
42911
|
-
const fd =
|
|
43345
|
+
const fd = fs13.openSync(filePath, "r", O_NOFOLLOW);
|
|
42912
43346
|
try {
|
|
42913
|
-
buffer =
|
|
43347
|
+
buffer = fs13.readFileSync(fd);
|
|
42914
43348
|
} finally {
|
|
42915
|
-
|
|
43349
|
+
fs13.closeSync(fd);
|
|
42916
43350
|
}
|
|
42917
43351
|
} else {
|
|
42918
|
-
buffer =
|
|
43352
|
+
buffer = fs13.readFileSync(filePath);
|
|
42919
43353
|
}
|
|
42920
43354
|
if (isBinaryFile(filePath, buffer)) {
|
|
42921
43355
|
return findings;
|
|
@@ -42957,9 +43391,9 @@ function isSymlinkLoop(realPath, visited) {
|
|
|
42957
43391
|
return false;
|
|
42958
43392
|
}
|
|
42959
43393
|
function isPathWithinScope(realPath, scanDir) {
|
|
42960
|
-
const resolvedScanDir =
|
|
42961
|
-
const resolvedRealPath =
|
|
42962
|
-
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir +
|
|
43394
|
+
const resolvedScanDir = path27.resolve(scanDir);
|
|
43395
|
+
const resolvedRealPath = path27.resolve(realPath);
|
|
43396
|
+
return resolvedRealPath === resolvedScanDir || resolvedRealPath.startsWith(resolvedScanDir + path27.sep) || resolvedRealPath.startsWith(`${resolvedScanDir}/`) || resolvedRealPath.startsWith(`${resolvedScanDir}\\`);
|
|
42963
43397
|
}
|
|
42964
43398
|
function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, stats = {
|
|
42965
43399
|
skippedDirs: 0,
|
|
@@ -42970,7 +43404,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
42970
43404
|
const files = [];
|
|
42971
43405
|
let entries;
|
|
42972
43406
|
try {
|
|
42973
|
-
entries =
|
|
43407
|
+
entries = fs13.readdirSync(dir);
|
|
42974
43408
|
} catch {
|
|
42975
43409
|
stats.fileErrors++;
|
|
42976
43410
|
return files;
|
|
@@ -42985,15 +43419,15 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
42985
43419
|
return a.localeCompare(b);
|
|
42986
43420
|
});
|
|
42987
43421
|
for (const entry of entries) {
|
|
42988
|
-
const fullPath =
|
|
42989
|
-
const relPath =
|
|
43422
|
+
const fullPath = path27.join(dir, entry);
|
|
43423
|
+
const relPath = path27.relative(scanDir, fullPath).replace(/\\/g, "/");
|
|
42990
43424
|
if (isExcluded(entry, relPath, excludeExact, excludeGlobs)) {
|
|
42991
43425
|
stats.skippedDirs++;
|
|
42992
43426
|
continue;
|
|
42993
43427
|
}
|
|
42994
43428
|
let lstat;
|
|
42995
43429
|
try {
|
|
42996
|
-
lstat =
|
|
43430
|
+
lstat = fs13.lstatSync(fullPath);
|
|
42997
43431
|
} catch {
|
|
42998
43432
|
stats.fileErrors++;
|
|
42999
43433
|
continue;
|
|
@@ -43005,7 +43439,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
43005
43439
|
if (lstat.isDirectory()) {
|
|
43006
43440
|
let realPath;
|
|
43007
43441
|
try {
|
|
43008
|
-
realPath =
|
|
43442
|
+
realPath = fs13.realpathSync(fullPath);
|
|
43009
43443
|
} catch {
|
|
43010
43444
|
stats.fileErrors++;
|
|
43011
43445
|
continue;
|
|
@@ -43021,7 +43455,7 @@ function findScannableFiles(dir, excludeExact, excludeGlobs, scanDir, visited, s
|
|
|
43021
43455
|
const subFiles = findScannableFiles(fullPath, excludeExact, excludeGlobs, scanDir, visited, stats);
|
|
43022
43456
|
files.push(...subFiles);
|
|
43023
43457
|
} else if (lstat.isFile()) {
|
|
43024
|
-
const ext =
|
|
43458
|
+
const ext = path27.extname(fullPath).toLowerCase();
|
|
43025
43459
|
if (!DEFAULT_EXCLUDE_EXTENSIONS.has(ext)) {
|
|
43026
43460
|
files.push(fullPath);
|
|
43027
43461
|
} else {
|
|
@@ -43224,7 +43658,7 @@ var init_secretscan = __esm(() => {
|
|
|
43224
43658
|
redactTemplate: () => "SK[REDACTED]"
|
|
43225
43659
|
}
|
|
43226
43660
|
];
|
|
43227
|
-
O_NOFOLLOW = process.platform !== "win32" ?
|
|
43661
|
+
O_NOFOLLOW = process.platform !== "win32" ? fs13.constants.O_NOFOLLOW : undefined;
|
|
43228
43662
|
secretscan = createSwarmTool({
|
|
43229
43663
|
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.",
|
|
43230
43664
|
args: {
|
|
@@ -43281,15 +43715,15 @@ var init_secretscan = __esm(() => {
|
|
|
43281
43715
|
}
|
|
43282
43716
|
}
|
|
43283
43717
|
try {
|
|
43284
|
-
const _scanDirRaw =
|
|
43718
|
+
const _scanDirRaw = path27.resolve(directory);
|
|
43285
43719
|
const scanDir = (() => {
|
|
43286
43720
|
try {
|
|
43287
|
-
return
|
|
43721
|
+
return fs13.realpathSync(_scanDirRaw);
|
|
43288
43722
|
} catch {
|
|
43289
43723
|
return _scanDirRaw;
|
|
43290
43724
|
}
|
|
43291
43725
|
})();
|
|
43292
|
-
if (!
|
|
43726
|
+
if (!fs13.existsSync(scanDir)) {
|
|
43293
43727
|
const errorResult = {
|
|
43294
43728
|
error: "directory not found",
|
|
43295
43729
|
scan_dir: directory,
|
|
@@ -43300,7 +43734,7 @@ var init_secretscan = __esm(() => {
|
|
|
43300
43734
|
};
|
|
43301
43735
|
return JSON.stringify(errorResult, null, 2);
|
|
43302
43736
|
}
|
|
43303
|
-
const dirStat =
|
|
43737
|
+
const dirStat = fs13.statSync(scanDir);
|
|
43304
43738
|
if (!dirStat.isDirectory()) {
|
|
43305
43739
|
const errorResult = {
|
|
43306
43740
|
error: "target must be a directory, not a file",
|
|
@@ -43351,7 +43785,7 @@ var init_secretscan = __esm(() => {
|
|
|
43351
43785
|
break;
|
|
43352
43786
|
const fileFindings = scanFileForSecrets(filePath);
|
|
43353
43787
|
try {
|
|
43354
|
-
const stat3 =
|
|
43788
|
+
const stat3 = fs13.statSync(filePath);
|
|
43355
43789
|
if (stat3.size > MAX_FILE_SIZE_BYTES) {
|
|
43356
43790
|
skippedFiles++;
|
|
43357
43791
|
continue;
|
|
@@ -43427,15 +43861,15 @@ var init_secretscan = __esm(() => {
|
|
|
43427
43861
|
});
|
|
43428
43862
|
|
|
43429
43863
|
// src/test-impact/analyzer.ts
|
|
43430
|
-
import
|
|
43431
|
-
import
|
|
43864
|
+
import fs14 from "fs";
|
|
43865
|
+
import path28 from "path";
|
|
43432
43866
|
function normalizePath(p) {
|
|
43433
43867
|
return p.replace(/\\/g, "/");
|
|
43434
43868
|
}
|
|
43435
43869
|
function isCacheStale(impactMap, generatedAtMs) {
|
|
43436
43870
|
for (const sourcePath of Object.keys(impactMap)) {
|
|
43437
43871
|
try {
|
|
43438
|
-
const stat3 =
|
|
43872
|
+
const stat3 = fs14.statSync(sourcePath);
|
|
43439
43873
|
if (stat3.mtimeMs > generatedAtMs) {
|
|
43440
43874
|
return true;
|
|
43441
43875
|
}
|
|
@@ -43449,15 +43883,15 @@ function resolveRelativeImport(fromDir, importPath) {
|
|
|
43449
43883
|
if (!importPath.startsWith(".")) {
|
|
43450
43884
|
return null;
|
|
43451
43885
|
}
|
|
43452
|
-
const resolved =
|
|
43453
|
-
if (
|
|
43454
|
-
if (
|
|
43886
|
+
const resolved = path28.resolve(fromDir, importPath);
|
|
43887
|
+
if (path28.extname(resolved)) {
|
|
43888
|
+
if (fs14.existsSync(resolved) && fs14.statSync(resolved).isFile()) {
|
|
43455
43889
|
return normalizePath(resolved);
|
|
43456
43890
|
}
|
|
43457
43891
|
} else {
|
|
43458
43892
|
for (const ext of EXTENSIONS_TO_TRY) {
|
|
43459
43893
|
const withExt = resolved + ext;
|
|
43460
|
-
if (
|
|
43894
|
+
if (fs14.existsSync(withExt) && fs14.statSync(withExt).isFile()) {
|
|
43461
43895
|
return normalizePath(withExt);
|
|
43462
43896
|
}
|
|
43463
43897
|
}
|
|
@@ -43476,13 +43910,13 @@ function findTestFilesSync(cwd) {
|
|
|
43476
43910
|
function walk(dir, visitedInodes) {
|
|
43477
43911
|
let entries;
|
|
43478
43912
|
try {
|
|
43479
|
-
entries =
|
|
43913
|
+
entries = fs14.readdirSync(dir, { withFileTypes: true });
|
|
43480
43914
|
} catch {
|
|
43481
43915
|
return;
|
|
43482
43916
|
}
|
|
43483
43917
|
let dirInode;
|
|
43484
43918
|
try {
|
|
43485
|
-
dirInode =
|
|
43919
|
+
dirInode = fs14.statSync(dir).ino;
|
|
43486
43920
|
} catch {
|
|
43487
43921
|
return;
|
|
43488
43922
|
}
|
|
@@ -43495,12 +43929,12 @@ function findTestFilesSync(cwd) {
|
|
|
43495
43929
|
for (const entry of entries) {
|
|
43496
43930
|
if (entry.isDirectory()) {
|
|
43497
43931
|
if (!skipDirs.has(entry.name)) {
|
|
43498
|
-
walk(
|
|
43932
|
+
walk(path28.join(dir, entry.name), visitedInodes);
|
|
43499
43933
|
}
|
|
43500
43934
|
} else if (entry.isFile()) {
|
|
43501
43935
|
const name = entry.name;
|
|
43502
43936
|
if (/\.(test|spec)\.(ts|tsx|js|jsx)$/.test(name) || dir.includes("__tests__") && /\.(ts|tsx|js|jsx)$/.test(name)) {
|
|
43503
|
-
testFiles.push(normalizePath(
|
|
43937
|
+
testFiles.push(normalizePath(path28.join(dir, entry.name)));
|
|
43504
43938
|
}
|
|
43505
43939
|
}
|
|
43506
43940
|
}
|
|
@@ -43530,7 +43964,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
43530
43964
|
for (const testFile of testFiles) {
|
|
43531
43965
|
let content;
|
|
43532
43966
|
try {
|
|
43533
|
-
content =
|
|
43967
|
+
content = fs14.readFileSync(testFile, "utf-8");
|
|
43534
43968
|
} catch {
|
|
43535
43969
|
continue;
|
|
43536
43970
|
}
|
|
@@ -43538,7 +43972,7 @@ async function buildImpactMapInternal(cwd) {
|
|
|
43538
43972
|
continue;
|
|
43539
43973
|
}
|
|
43540
43974
|
const imports = extractImports(content);
|
|
43541
|
-
const testDir =
|
|
43975
|
+
const testDir = path28.dirname(testFile);
|
|
43542
43976
|
for (const importPath of imports) {
|
|
43543
43977
|
const resolvedSource = resolveRelativeImport(testDir, importPath);
|
|
43544
43978
|
if (resolvedSource === null) {
|
|
@@ -43560,10 +43994,10 @@ async function buildImpactMap(cwd) {
|
|
|
43560
43994
|
return impactMap;
|
|
43561
43995
|
}
|
|
43562
43996
|
async function loadImpactMap(cwd) {
|
|
43563
|
-
const cachePath =
|
|
43564
|
-
if (
|
|
43997
|
+
const cachePath = path28.join(cwd, ".swarm", "cache", "impact-map.json");
|
|
43998
|
+
if (fs14.existsSync(cachePath)) {
|
|
43565
43999
|
try {
|
|
43566
|
-
const content =
|
|
44000
|
+
const content = fs14.readFileSync(cachePath, "utf-8");
|
|
43567
44001
|
const data = JSON.parse(content);
|
|
43568
44002
|
const map3 = data.map;
|
|
43569
44003
|
const generatedAt = new Date(data.generatedAt).getTime();
|
|
@@ -43575,17 +44009,17 @@ async function loadImpactMap(cwd) {
|
|
|
43575
44009
|
return _internals17.buildImpactMap(cwd);
|
|
43576
44010
|
}
|
|
43577
44011
|
async function saveImpactMap(cwd, impactMap) {
|
|
43578
|
-
const cacheDir2 =
|
|
43579
|
-
const cachePath =
|
|
43580
|
-
if (!
|
|
43581
|
-
|
|
44012
|
+
const cacheDir2 = path28.join(cwd, ".swarm", "cache");
|
|
44013
|
+
const cachePath = path28.join(cacheDir2, "impact-map.json");
|
|
44014
|
+
if (!fs14.existsSync(cacheDir2)) {
|
|
44015
|
+
fs14.mkdirSync(cacheDir2, { recursive: true });
|
|
43582
44016
|
}
|
|
43583
44017
|
const data = {
|
|
43584
44018
|
generatedAt: new Date().toISOString(),
|
|
43585
44019
|
fileCount: Object.keys(impactMap).length,
|
|
43586
44020
|
map: impactMap
|
|
43587
44021
|
};
|
|
43588
|
-
|
|
44022
|
+
fs14.writeFileSync(cachePath, JSON.stringify(data, null, 2), "utf-8");
|
|
43589
44023
|
}
|
|
43590
44024
|
async function analyzeImpact(changedFiles, cwd) {
|
|
43591
44025
|
if (!Array.isArray(changedFiles)) {
|
|
@@ -43602,7 +44036,7 @@ async function analyzeImpact(changedFiles, cwd) {
|
|
|
43602
44036
|
const impactedTestsSet = new Set;
|
|
43603
44037
|
const untestedFiles = [];
|
|
43604
44038
|
for (const changedFile of validFiles) {
|
|
43605
|
-
const normalizedChanged = normalizePath(
|
|
44039
|
+
const normalizedChanged = normalizePath(path28.resolve(changedFile));
|
|
43606
44040
|
const tests = impactMap[normalizedChanged];
|
|
43607
44041
|
if (tests && tests.length > 0) {
|
|
43608
44042
|
for (const test of tests) {
|
|
@@ -43865,10 +44299,10 @@ function detectFlakyTests(allHistory) {
|
|
|
43865
44299
|
var FLAKY_THRESHOLD = 0.3, MIN_RUNS_FOR_QUARANTINE = 5, MAX_HISTORY_RUNS = 20;
|
|
43866
44300
|
|
|
43867
44301
|
// src/test-impact/history-store.ts
|
|
43868
|
-
import
|
|
43869
|
-
import
|
|
44302
|
+
import fs15 from "fs";
|
|
44303
|
+
import path29 from "path";
|
|
43870
44304
|
function getHistoryPath(workingDir) {
|
|
43871
|
-
return
|
|
44305
|
+
return path29.join(workingDir || process.cwd(), ".swarm", "cache", "test-history.jsonl");
|
|
43872
44306
|
}
|
|
43873
44307
|
function sanitizeErrorMessage(errorMessage) {
|
|
43874
44308
|
if (errorMessage === undefined) {
|
|
@@ -43923,9 +44357,9 @@ function appendTestRun(record3, workingDir) {
|
|
|
43923
44357
|
changedFiles: sanitizeChangedFiles(record3.changedFiles || [])
|
|
43924
44358
|
};
|
|
43925
44359
|
const historyPath = getHistoryPath(workingDir);
|
|
43926
|
-
const historyDir =
|
|
43927
|
-
if (!
|
|
43928
|
-
|
|
44360
|
+
const historyDir = path29.dirname(historyPath);
|
|
44361
|
+
if (!fs15.existsSync(historyDir)) {
|
|
44362
|
+
fs15.mkdirSync(historyDir, { recursive: true });
|
|
43929
44363
|
}
|
|
43930
44364
|
const existingRecords = readAllRecords(historyPath);
|
|
43931
44365
|
existingRecords.push(sanitizedRecord);
|
|
@@ -43950,24 +44384,24 @@ function appendTestRun(record3, workingDir) {
|
|
|
43950
44384
|
`)}
|
|
43951
44385
|
`;
|
|
43952
44386
|
const tempPath = `${historyPath}.tmp`;
|
|
43953
|
-
|
|
43954
|
-
|
|
44387
|
+
fs15.writeFileSync(tempPath, content, "utf-8");
|
|
44388
|
+
fs15.renameSync(tempPath, historyPath);
|
|
43955
44389
|
} catch (err) {
|
|
43956
44390
|
try {
|
|
43957
44391
|
const tempPath = `${historyPath}.tmp`;
|
|
43958
|
-
if (
|
|
43959
|
-
|
|
44392
|
+
if (fs15.existsSync(tempPath)) {
|
|
44393
|
+
fs15.unlinkSync(tempPath);
|
|
43960
44394
|
}
|
|
43961
44395
|
} catch {}
|
|
43962
44396
|
throw new Error(`Failed to write test history: ${err instanceof Error ? err.message : String(err)}`);
|
|
43963
44397
|
}
|
|
43964
44398
|
}
|
|
43965
44399
|
function readAllRecords(historyPath) {
|
|
43966
|
-
if (!
|
|
44400
|
+
if (!fs15.existsSync(historyPath)) {
|
|
43967
44401
|
return [];
|
|
43968
44402
|
}
|
|
43969
44403
|
try {
|
|
43970
|
-
const content =
|
|
44404
|
+
const content = fs15.readFileSync(historyPath, "utf-8");
|
|
43971
44405
|
const lines = content.split(`
|
|
43972
44406
|
`);
|
|
43973
44407
|
const records = [];
|
|
@@ -44004,8 +44438,8 @@ var init_history_store = __esm(() => {
|
|
|
44004
44438
|
});
|
|
44005
44439
|
|
|
44006
44440
|
// src/tools/resolve-working-directory.ts
|
|
44007
|
-
import * as
|
|
44008
|
-
import * as
|
|
44441
|
+
import * as fs16 from "fs";
|
|
44442
|
+
import * as path30 from "path";
|
|
44009
44443
|
function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
44010
44444
|
if (workingDirectory == null || workingDirectory === "") {
|
|
44011
44445
|
return { success: true, directory: fallbackDirectory };
|
|
@@ -44025,18 +44459,18 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
44025
44459
|
};
|
|
44026
44460
|
}
|
|
44027
44461
|
}
|
|
44028
|
-
const normalizedDir =
|
|
44029
|
-
const pathParts = normalizedDir.split(
|
|
44462
|
+
const normalizedDir = path30.normalize(workingDirectory);
|
|
44463
|
+
const pathParts = normalizedDir.split(path30.sep);
|
|
44030
44464
|
if (pathParts.includes("..")) {
|
|
44031
44465
|
return {
|
|
44032
44466
|
success: false,
|
|
44033
44467
|
message: "Invalid working_directory: path traversal sequences (..) are not allowed"
|
|
44034
44468
|
};
|
|
44035
44469
|
}
|
|
44036
|
-
const resolvedDir =
|
|
44470
|
+
const resolvedDir = path30.resolve(normalizedDir);
|
|
44037
44471
|
let statResult;
|
|
44038
44472
|
try {
|
|
44039
|
-
statResult =
|
|
44473
|
+
statResult = fs16.statSync(resolvedDir);
|
|
44040
44474
|
} catch {
|
|
44041
44475
|
return {
|
|
44042
44476
|
success: false,
|
|
@@ -44049,17 +44483,17 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
44049
44483
|
message: `Invalid working_directory: path "${resolvedDir}" is not a directory`
|
|
44050
44484
|
};
|
|
44051
44485
|
}
|
|
44052
|
-
const resolvedFallback =
|
|
44486
|
+
const resolvedFallback = path30.resolve(fallbackDirectory);
|
|
44053
44487
|
let fallbackExists = false;
|
|
44054
44488
|
try {
|
|
44055
|
-
|
|
44489
|
+
fs16.statSync(resolvedFallback);
|
|
44056
44490
|
fallbackExists = true;
|
|
44057
44491
|
} catch {
|
|
44058
44492
|
fallbackExists = false;
|
|
44059
44493
|
}
|
|
44060
44494
|
if (workingDirectory != null && workingDirectory !== "") {
|
|
44061
44495
|
if (fallbackExists) {
|
|
44062
|
-
const isSubdirectory = resolvedDir.startsWith(resolvedFallback +
|
|
44496
|
+
const isSubdirectory = resolvedDir.startsWith(resolvedFallback + path30.sep);
|
|
44063
44497
|
if (isSubdirectory) {
|
|
44064
44498
|
return {
|
|
44065
44499
|
success: false,
|
|
@@ -44080,8 +44514,8 @@ function resolveWorkingDirectory(workingDirectory, fallbackDirectory) {
|
|
|
44080
44514
|
var init_resolve_working_directory = () => {};
|
|
44081
44515
|
|
|
44082
44516
|
// src/tools/test-runner.ts
|
|
44083
|
-
import * as
|
|
44084
|
-
import * as
|
|
44517
|
+
import * as fs17 from "fs";
|
|
44518
|
+
import * as path31 from "path";
|
|
44085
44519
|
function isAbsolutePath(str) {
|
|
44086
44520
|
if (str.startsWith("/"))
|
|
44087
44521
|
return true;
|
|
@@ -44146,19 +44580,19 @@ function hasDevDependency(devDeps, ...patterns) {
|
|
|
44146
44580
|
return hasPackageJsonDependency(devDeps, ...patterns);
|
|
44147
44581
|
}
|
|
44148
44582
|
function detectGoTest(cwd) {
|
|
44149
|
-
return
|
|
44583
|
+
return fs17.existsSync(path31.join(cwd, "go.mod")) && isCommandAvailable("go");
|
|
44150
44584
|
}
|
|
44151
44585
|
function detectJavaMaven(cwd) {
|
|
44152
|
-
return
|
|
44586
|
+
return fs17.existsSync(path31.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
|
|
44153
44587
|
}
|
|
44154
44588
|
function detectGradle(cwd) {
|
|
44155
|
-
const hasBuildFile =
|
|
44156
|
-
const hasGradlew =
|
|
44589
|
+
const hasBuildFile = fs17.existsSync(path31.join(cwd, "build.gradle")) || fs17.existsSync(path31.join(cwd, "build.gradle.kts"));
|
|
44590
|
+
const hasGradlew = fs17.existsSync(path31.join(cwd, "gradlew")) || fs17.existsSync(path31.join(cwd, "gradlew.bat"));
|
|
44157
44591
|
return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
|
|
44158
44592
|
}
|
|
44159
44593
|
function detectDotnetTest(cwd) {
|
|
44160
44594
|
try {
|
|
44161
|
-
const files =
|
|
44595
|
+
const files = fs17.readdirSync(cwd);
|
|
44162
44596
|
const hasCsproj = files.some((f) => f.endsWith(".csproj"));
|
|
44163
44597
|
return hasCsproj && isCommandAvailable("dotnet");
|
|
44164
44598
|
} catch {
|
|
@@ -44166,32 +44600,32 @@ function detectDotnetTest(cwd) {
|
|
|
44166
44600
|
}
|
|
44167
44601
|
}
|
|
44168
44602
|
function detectCTest(cwd) {
|
|
44169
|
-
const hasSource =
|
|
44170
|
-
const hasBuildCache =
|
|
44603
|
+
const hasSource = fs17.existsSync(path31.join(cwd, "CMakeLists.txt"));
|
|
44604
|
+
const hasBuildCache = fs17.existsSync(path31.join(cwd, "CMakeCache.txt")) || fs17.existsSync(path31.join(cwd, "build", "CMakeCache.txt"));
|
|
44171
44605
|
return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
|
|
44172
44606
|
}
|
|
44173
44607
|
function detectSwiftTest(cwd) {
|
|
44174
|
-
return
|
|
44608
|
+
return fs17.existsSync(path31.join(cwd, "Package.swift")) && isCommandAvailable("swift");
|
|
44175
44609
|
}
|
|
44176
44610
|
function detectDartTest(cwd) {
|
|
44177
|
-
return
|
|
44611
|
+
return fs17.existsSync(path31.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
|
|
44178
44612
|
}
|
|
44179
44613
|
function detectRSpec(cwd) {
|
|
44180
|
-
const hasRSpecFile =
|
|
44181
|
-
const hasGemfile =
|
|
44182
|
-
const hasSpecDir =
|
|
44614
|
+
const hasRSpecFile = fs17.existsSync(path31.join(cwd, ".rspec"));
|
|
44615
|
+
const hasGemfile = fs17.existsSync(path31.join(cwd, "Gemfile"));
|
|
44616
|
+
const hasSpecDir = fs17.existsSync(path31.join(cwd, "spec"));
|
|
44183
44617
|
const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
|
|
44184
44618
|
return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
|
|
44185
44619
|
}
|
|
44186
44620
|
function detectMinitest(cwd) {
|
|
44187
|
-
return
|
|
44621
|
+
return fs17.existsSync(path31.join(cwd, "test")) && (fs17.existsSync(path31.join(cwd, "Gemfile")) || fs17.existsSync(path31.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
|
|
44188
44622
|
}
|
|
44189
44623
|
async function detectTestFramework(cwd) {
|
|
44190
44624
|
const baseDir = cwd;
|
|
44191
44625
|
try {
|
|
44192
|
-
const packageJsonPath =
|
|
44193
|
-
if (
|
|
44194
|
-
const content =
|
|
44626
|
+
const packageJsonPath = path31.join(baseDir, "package.json");
|
|
44627
|
+
if (fs17.existsSync(packageJsonPath)) {
|
|
44628
|
+
const content = fs17.readFileSync(packageJsonPath, "utf-8");
|
|
44195
44629
|
const pkg = JSON.parse(content);
|
|
44196
44630
|
const _deps = pkg.dependencies || {};
|
|
44197
44631
|
const devDeps = pkg.devDependencies || {};
|
|
@@ -44210,38 +44644,38 @@ async function detectTestFramework(cwd) {
|
|
|
44210
44644
|
return "jest";
|
|
44211
44645
|
if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
|
|
44212
44646
|
return "mocha";
|
|
44213
|
-
if (
|
|
44647
|
+
if (fs17.existsSync(path31.join(baseDir, "bun.lockb")) || fs17.existsSync(path31.join(baseDir, "bun.lock"))) {
|
|
44214
44648
|
if (scripts.test?.includes("bun"))
|
|
44215
44649
|
return "bun";
|
|
44216
44650
|
}
|
|
44217
44651
|
}
|
|
44218
44652
|
} catch {}
|
|
44219
44653
|
try {
|
|
44220
|
-
const pyprojectTomlPath =
|
|
44221
|
-
const setupCfgPath =
|
|
44222
|
-
const requirementsTxtPath =
|
|
44223
|
-
if (
|
|
44224
|
-
const content =
|
|
44654
|
+
const pyprojectTomlPath = path31.join(baseDir, "pyproject.toml");
|
|
44655
|
+
const setupCfgPath = path31.join(baseDir, "setup.cfg");
|
|
44656
|
+
const requirementsTxtPath = path31.join(baseDir, "requirements.txt");
|
|
44657
|
+
if (fs17.existsSync(pyprojectTomlPath)) {
|
|
44658
|
+
const content = fs17.readFileSync(pyprojectTomlPath, "utf-8");
|
|
44225
44659
|
if (content.includes("[tool.pytest"))
|
|
44226
44660
|
return "pytest";
|
|
44227
44661
|
if (content.includes("pytest"))
|
|
44228
44662
|
return "pytest";
|
|
44229
44663
|
}
|
|
44230
|
-
if (
|
|
44231
|
-
const content =
|
|
44664
|
+
if (fs17.existsSync(setupCfgPath)) {
|
|
44665
|
+
const content = fs17.readFileSync(setupCfgPath, "utf-8");
|
|
44232
44666
|
if (content.includes("[pytest]"))
|
|
44233
44667
|
return "pytest";
|
|
44234
44668
|
}
|
|
44235
|
-
if (
|
|
44236
|
-
const content =
|
|
44669
|
+
if (fs17.existsSync(requirementsTxtPath)) {
|
|
44670
|
+
const content = fs17.readFileSync(requirementsTxtPath, "utf-8");
|
|
44237
44671
|
if (content.includes("pytest"))
|
|
44238
44672
|
return "pytest";
|
|
44239
44673
|
}
|
|
44240
44674
|
} catch {}
|
|
44241
44675
|
try {
|
|
44242
|
-
const cargoTomlPath =
|
|
44243
|
-
if (
|
|
44244
|
-
const content =
|
|
44676
|
+
const cargoTomlPath = path31.join(baseDir, "Cargo.toml");
|
|
44677
|
+
if (fs17.existsSync(cargoTomlPath)) {
|
|
44678
|
+
const content = fs17.readFileSync(cargoTomlPath, "utf-8");
|
|
44245
44679
|
if (content.includes("[dev-dependencies]")) {
|
|
44246
44680
|
if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
|
|
44247
44681
|
return "cargo";
|
|
@@ -44250,10 +44684,10 @@ async function detectTestFramework(cwd) {
|
|
|
44250
44684
|
}
|
|
44251
44685
|
} catch {}
|
|
44252
44686
|
try {
|
|
44253
|
-
const pesterConfigPath =
|
|
44254
|
-
const pesterConfigJsonPath =
|
|
44255
|
-
const pesterPs1Path =
|
|
44256
|
-
if (
|
|
44687
|
+
const pesterConfigPath = path31.join(baseDir, "pester.config.ps1");
|
|
44688
|
+
const pesterConfigJsonPath = path31.join(baseDir, "pester.config.ps1.json");
|
|
44689
|
+
const pesterPs1Path = path31.join(baseDir, "tests.ps1");
|
|
44690
|
+
if (fs17.existsSync(pesterConfigPath) || fs17.existsSync(pesterConfigJsonPath) || fs17.existsSync(pesterPs1Path)) {
|
|
44257
44691
|
return "pester";
|
|
44258
44692
|
}
|
|
44259
44693
|
} catch {}
|
|
@@ -44281,12 +44715,12 @@ function isTestDirectoryPath(normalizedPath) {
|
|
|
44281
44715
|
return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
|
|
44282
44716
|
}
|
|
44283
44717
|
function resolveWorkspacePath(file3, workingDir) {
|
|
44284
|
-
return
|
|
44718
|
+
return path31.isAbsolute(file3) ? path31.resolve(file3) : path31.resolve(workingDir, file3);
|
|
44285
44719
|
}
|
|
44286
44720
|
function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
|
|
44287
44721
|
if (!preferRelative)
|
|
44288
44722
|
return absolutePath;
|
|
44289
|
-
return
|
|
44723
|
+
return path31.relative(workingDir, absolutePath);
|
|
44290
44724
|
}
|
|
44291
44725
|
function dedupePush(target, value) {
|
|
44292
44726
|
if (!target.includes(value)) {
|
|
@@ -44323,18 +44757,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
|
|
|
44323
44757
|
}
|
|
44324
44758
|
}
|
|
44325
44759
|
function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
|
|
44326
|
-
const relativeDir =
|
|
44760
|
+
const relativeDir = path31.dirname(relativePath);
|
|
44327
44761
|
const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
|
|
44328
44762
|
const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
|
|
44329
|
-
const rootDir =
|
|
44330
|
-
return nestedRelativeDir ? [rootDir,
|
|
44763
|
+
const rootDir = path31.join(workingDir, dirName);
|
|
44764
|
+
return nestedRelativeDir ? [rootDir, path31.join(rootDir, nestedRelativeDir)] : [rootDir];
|
|
44331
44765
|
});
|
|
44332
44766
|
const normalizedRelativePath = relativePath.replace(/\\/g, "/");
|
|
44333
44767
|
if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
|
|
44334
|
-
directories.push(
|
|
44768
|
+
directories.push(path31.join(workingDir, "src/test/java", path31.dirname(normalizedRelativePath.slice("src/main/java/".length))));
|
|
44335
44769
|
}
|
|
44336
44770
|
if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
|
|
44337
|
-
directories.push(
|
|
44771
|
+
directories.push(path31.join(workingDir, "src/test/kotlin", path31.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
|
|
44338
44772
|
}
|
|
44339
44773
|
return [...new Set(directories)];
|
|
44340
44774
|
}
|
|
@@ -44362,23 +44796,23 @@ function isLanguageSpecificTestFile(basename5) {
|
|
|
44362
44796
|
}
|
|
44363
44797
|
function isConventionTestFilePath(filePath) {
|
|
44364
44798
|
const normalizedPath = filePath.replace(/\\/g, "/");
|
|
44365
|
-
const basename5 =
|
|
44799
|
+
const basename5 = path31.basename(filePath);
|
|
44366
44800
|
return hasCompoundTestExtension(basename5) || basename5.includes(".spec.") || basename5.includes(".test.") || isLanguageSpecificTestFile(basename5) || isTestDirectoryPath(normalizedPath);
|
|
44367
44801
|
}
|
|
44368
44802
|
function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
44369
44803
|
const testFiles = [];
|
|
44370
44804
|
for (const file3 of sourceFiles) {
|
|
44371
44805
|
const absoluteFile = resolveWorkspacePath(file3, workingDir);
|
|
44372
|
-
const relativeFile =
|
|
44373
|
-
const basename5 =
|
|
44374
|
-
const dirname13 =
|
|
44375
|
-
const preferRelativeOutput = !
|
|
44806
|
+
const relativeFile = path31.relative(workingDir, absoluteFile);
|
|
44807
|
+
const basename5 = path31.basename(absoluteFile);
|
|
44808
|
+
const dirname13 = path31.dirname(absoluteFile);
|
|
44809
|
+
const preferRelativeOutput = !path31.isAbsolute(file3);
|
|
44376
44810
|
if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
|
|
44377
44811
|
dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
|
|
44378
44812
|
continue;
|
|
44379
44813
|
}
|
|
44380
44814
|
const nameWithoutExt = basename5.replace(/\.[^.]+$/, "");
|
|
44381
|
-
const ext =
|
|
44815
|
+
const ext = path31.extname(basename5);
|
|
44382
44816
|
const genericTestNames = [
|
|
44383
44817
|
`${nameWithoutExt}.spec${ext}`,
|
|
44384
44818
|
`${nameWithoutExt}.test${ext}`
|
|
@@ -44387,7 +44821,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
44387
44821
|
const colocatedCandidates = [
|
|
44388
44822
|
...genericTestNames,
|
|
44389
44823
|
...languageSpecificTestNames
|
|
44390
|
-
].map((candidateName) =>
|
|
44824
|
+
].map((candidateName) => path31.join(dirname13, candidateName));
|
|
44391
44825
|
const testDirectoryNames = [
|
|
44392
44826
|
basename5,
|
|
44393
44827
|
...genericTestNames,
|
|
@@ -44396,11 +44830,11 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
|
|
|
44396
44830
|
const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
|
|
44397
44831
|
const possibleTestFiles = [
|
|
44398
44832
|
...colocatedCandidates,
|
|
44399
|
-
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) =>
|
|
44400
|
-
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) =>
|
|
44833
|
+
...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path31.join(dirname13, dirName, candidateName))),
|
|
44834
|
+
...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path31.join(candidateDir, candidateName)))
|
|
44401
44835
|
];
|
|
44402
44836
|
for (const testFile of possibleTestFiles) {
|
|
44403
|
-
if (
|
|
44837
|
+
if (fs17.existsSync(testFile)) {
|
|
44404
44838
|
dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
|
|
44405
44839
|
}
|
|
44406
44840
|
}
|
|
@@ -44417,8 +44851,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
44417
44851
|
for (const testFile of candidateTestFiles) {
|
|
44418
44852
|
try {
|
|
44419
44853
|
const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
|
|
44420
|
-
const content =
|
|
44421
|
-
const testDir =
|
|
44854
|
+
const content = fs17.readFileSync(absoluteTestFile, "utf-8");
|
|
44855
|
+
const testDir = path31.dirname(absoluteTestFile);
|
|
44422
44856
|
const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
|
|
44423
44857
|
let match;
|
|
44424
44858
|
match = importRegex.exec(content);
|
|
@@ -44426,8 +44860,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
44426
44860
|
const importPath = match[1];
|
|
44427
44861
|
let resolvedImport;
|
|
44428
44862
|
if (importPath.startsWith(".")) {
|
|
44429
|
-
resolvedImport =
|
|
44430
|
-
const existingExt =
|
|
44863
|
+
resolvedImport = path31.resolve(testDir, importPath);
|
|
44864
|
+
const existingExt = path31.extname(resolvedImport);
|
|
44431
44865
|
if (!existingExt) {
|
|
44432
44866
|
for (const extToTry of [
|
|
44433
44867
|
".ts",
|
|
@@ -44438,7 +44872,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
44438
44872
|
".cjs"
|
|
44439
44873
|
]) {
|
|
44440
44874
|
const withExt = resolvedImport + extToTry;
|
|
44441
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
44875
|
+
if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
|
|
44442
44876
|
resolvedImport = withExt;
|
|
44443
44877
|
break;
|
|
44444
44878
|
}
|
|
@@ -44447,12 +44881,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
44447
44881
|
} else {
|
|
44448
44882
|
continue;
|
|
44449
44883
|
}
|
|
44450
|
-
const importBasename =
|
|
44451
|
-
const importDir =
|
|
44884
|
+
const importBasename = path31.basename(resolvedImport, path31.extname(resolvedImport));
|
|
44885
|
+
const importDir = path31.dirname(resolvedImport);
|
|
44452
44886
|
for (const sourceFile of absoluteSourceFiles) {
|
|
44453
|
-
const sourceDir =
|
|
44454
|
-
const sourceBasename =
|
|
44455
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
44887
|
+
const sourceDir = path31.dirname(sourceFile);
|
|
44888
|
+
const sourceBasename = path31.basename(sourceFile, path31.extname(sourceFile));
|
|
44889
|
+
const isRelatedDir = importDir === sourceDir || importDir === path31.join(sourceDir, "__tests__") || importDir === path31.join(sourceDir, "tests") || importDir === path31.join(sourceDir, "test") || importDir === path31.join(sourceDir, "spec");
|
|
44456
44890
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
44457
44891
|
dedupePush(testFiles, testFile);
|
|
44458
44892
|
break;
|
|
@@ -44465,8 +44899,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
44465
44899
|
while (match !== null) {
|
|
44466
44900
|
const importPath = match[1];
|
|
44467
44901
|
if (importPath.startsWith(".")) {
|
|
44468
|
-
let resolvedImport =
|
|
44469
|
-
const existingExt =
|
|
44902
|
+
let resolvedImport = path31.resolve(testDir, importPath);
|
|
44903
|
+
const existingExt = path31.extname(resolvedImport);
|
|
44470
44904
|
if (!existingExt) {
|
|
44471
44905
|
for (const extToTry of [
|
|
44472
44906
|
".ts",
|
|
@@ -44477,18 +44911,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
|
|
|
44477
44911
|
".cjs"
|
|
44478
44912
|
]) {
|
|
44479
44913
|
const withExt = resolvedImport + extToTry;
|
|
44480
|
-
if (absoluteSourceFiles.includes(withExt) ||
|
|
44914
|
+
if (absoluteSourceFiles.includes(withExt) || fs17.existsSync(withExt)) {
|
|
44481
44915
|
resolvedImport = withExt;
|
|
44482
44916
|
break;
|
|
44483
44917
|
}
|
|
44484
44918
|
}
|
|
44485
44919
|
}
|
|
44486
|
-
const importDir =
|
|
44487
|
-
const importBasename =
|
|
44920
|
+
const importDir = path31.dirname(resolvedImport);
|
|
44921
|
+
const importBasename = path31.basename(resolvedImport, path31.extname(resolvedImport));
|
|
44488
44922
|
for (const sourceFile of absoluteSourceFiles) {
|
|
44489
|
-
const sourceDir =
|
|
44490
|
-
const sourceBasename =
|
|
44491
|
-
const isRelatedDir = importDir === sourceDir || importDir ===
|
|
44923
|
+
const sourceDir = path31.dirname(sourceFile);
|
|
44924
|
+
const sourceBasename = path31.basename(sourceFile, path31.extname(sourceFile));
|
|
44925
|
+
const isRelatedDir = importDir === sourceDir || importDir === path31.join(sourceDir, "__tests__") || importDir === path31.join(sourceDir, "tests") || importDir === path31.join(sourceDir, "test") || importDir === path31.join(sourceDir, "spec");
|
|
44492
44926
|
if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
|
|
44493
44927
|
dedupePush(testFiles, testFile);
|
|
44494
44928
|
break;
|
|
@@ -44591,8 +45025,8 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
44591
45025
|
return ["mvn", "test"];
|
|
44592
45026
|
case "gradle": {
|
|
44593
45027
|
const isWindows = process.platform === "win32";
|
|
44594
|
-
const hasGradlewBat =
|
|
44595
|
-
const hasGradlew =
|
|
45028
|
+
const hasGradlewBat = fs17.existsSync(path31.join(baseDir, "gradlew.bat"));
|
|
45029
|
+
const hasGradlew = fs17.existsSync(path31.join(baseDir, "gradlew"));
|
|
44596
45030
|
if (hasGradlewBat && isWindows)
|
|
44597
45031
|
return ["gradlew.bat", "test"];
|
|
44598
45032
|
if (hasGradlew)
|
|
@@ -44609,7 +45043,7 @@ function buildTestCommand(framework, scope, files, coverage, baseDir) {
|
|
|
44609
45043
|
"cmake-build-release",
|
|
44610
45044
|
"out"
|
|
44611
45045
|
];
|
|
44612
|
-
const actualBuildDir = buildDirCandidates.find((d) =>
|
|
45046
|
+
const actualBuildDir = buildDirCandidates.find((d) => fs17.existsSync(path31.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
|
|
44613
45047
|
return ["ctest", "--test-dir", actualBuildDir];
|
|
44614
45048
|
}
|
|
44615
45049
|
case "swift-test":
|
|
@@ -44930,9 +45364,9 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd) {
|
|
|
44930
45364
|
stderr: "pipe",
|
|
44931
45365
|
cwd
|
|
44932
45366
|
});
|
|
44933
|
-
const timeoutPromise = new Promise((
|
|
45367
|
+
const timeoutPromise = new Promise((resolve13) => setTimeout(() => {
|
|
44934
45368
|
proc.kill();
|
|
44935
|
-
|
|
45369
|
+
resolve13(-1);
|
|
44936
45370
|
}, timeout_ms));
|
|
44937
45371
|
const [exitCode, stdoutResult, stderrResult] = await Promise.all([
|
|
44938
45372
|
Promise.race([proc.exited, timeoutPromise]),
|
|
@@ -45262,7 +45696,7 @@ var init_test_runner = __esm(() => {
|
|
|
45262
45696
|
const sourceFiles = args.files.filter((file3) => {
|
|
45263
45697
|
if (directTestFiles.includes(file3))
|
|
45264
45698
|
return false;
|
|
45265
|
-
const ext =
|
|
45699
|
+
const ext = path31.extname(file3).toLowerCase();
|
|
45266
45700
|
return SOURCE_EXTENSIONS.has(ext);
|
|
45267
45701
|
});
|
|
45268
45702
|
const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
|
|
@@ -45297,7 +45731,7 @@ var init_test_runner = __esm(() => {
|
|
|
45297
45731
|
if (isConventionTestFilePath(f)) {
|
|
45298
45732
|
return false;
|
|
45299
45733
|
}
|
|
45300
|
-
const ext =
|
|
45734
|
+
const ext = path31.extname(f).toLowerCase();
|
|
45301
45735
|
return SOURCE_EXTENSIONS.has(ext);
|
|
45302
45736
|
});
|
|
45303
45737
|
if (sourceFiles.length === 0) {
|
|
@@ -45324,7 +45758,7 @@ var init_test_runner = __esm(() => {
|
|
|
45324
45758
|
if (isConventionTestFilePath(f)) {
|
|
45325
45759
|
return false;
|
|
45326
45760
|
}
|
|
45327
|
-
const ext =
|
|
45761
|
+
const ext = path31.extname(f).toLowerCase();
|
|
45328
45762
|
return SOURCE_EXTENSIONS.has(ext);
|
|
45329
45763
|
});
|
|
45330
45764
|
if (sourceFiles.length === 0) {
|
|
@@ -45342,8 +45776,8 @@ var init_test_runner = __esm(() => {
|
|
|
45342
45776
|
const impactResult = await analyzeImpact(sourceFiles, workingDir);
|
|
45343
45777
|
if (impactResult.impactedTests.length > 0) {
|
|
45344
45778
|
testFiles = impactResult.impactedTests.map((absPath) => {
|
|
45345
|
-
const relativePath =
|
|
45346
|
-
return
|
|
45779
|
+
const relativePath = path31.relative(workingDir, absPath);
|
|
45780
|
+
return path31.isAbsolute(relativePath) ? absPath : relativePath;
|
|
45347
45781
|
});
|
|
45348
45782
|
} else {
|
|
45349
45783
|
graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
|
|
@@ -45418,8 +45852,8 @@ var init_test_runner = __esm(() => {
|
|
|
45418
45852
|
});
|
|
45419
45853
|
|
|
45420
45854
|
// src/services/preflight-service.ts
|
|
45421
|
-
import * as
|
|
45422
|
-
import * as
|
|
45855
|
+
import * as fs18 from "fs";
|
|
45856
|
+
import * as path32 from "path";
|
|
45423
45857
|
function validateDirectoryPath(dir) {
|
|
45424
45858
|
if (!dir || typeof dir !== "string") {
|
|
45425
45859
|
throw new Error("Directory path is required");
|
|
@@ -45427,8 +45861,8 @@ function validateDirectoryPath(dir) {
|
|
|
45427
45861
|
if (dir.includes("..")) {
|
|
45428
45862
|
throw new Error("Directory path must not contain path traversal sequences");
|
|
45429
45863
|
}
|
|
45430
|
-
const normalized =
|
|
45431
|
-
const absolutePath =
|
|
45864
|
+
const normalized = path32.normalize(dir);
|
|
45865
|
+
const absolutePath = path32.isAbsolute(normalized) ? normalized : path32.resolve(normalized);
|
|
45432
45866
|
return absolutePath;
|
|
45433
45867
|
}
|
|
45434
45868
|
function validateTimeout(timeoutMs, defaultValue) {
|
|
@@ -45451,9 +45885,9 @@ function validateTimeout(timeoutMs, defaultValue) {
|
|
|
45451
45885
|
}
|
|
45452
45886
|
function getPackageVersion(dir) {
|
|
45453
45887
|
try {
|
|
45454
|
-
const packagePath =
|
|
45455
|
-
if (
|
|
45456
|
-
const content =
|
|
45888
|
+
const packagePath = path32.join(dir, "package.json");
|
|
45889
|
+
if (fs18.existsSync(packagePath)) {
|
|
45890
|
+
const content = fs18.readFileSync(packagePath, "utf-8");
|
|
45457
45891
|
const pkg = JSON.parse(content);
|
|
45458
45892
|
return pkg.version ?? null;
|
|
45459
45893
|
}
|
|
@@ -45462,9 +45896,9 @@ function getPackageVersion(dir) {
|
|
|
45462
45896
|
}
|
|
45463
45897
|
function getChangelogVersion(dir) {
|
|
45464
45898
|
try {
|
|
45465
|
-
const changelogPath =
|
|
45466
|
-
if (
|
|
45467
|
-
const content =
|
|
45899
|
+
const changelogPath = path32.join(dir, "CHANGELOG.md");
|
|
45900
|
+
if (fs18.existsSync(changelogPath)) {
|
|
45901
|
+
const content = fs18.readFileSync(changelogPath, "utf-8");
|
|
45468
45902
|
const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
|
|
45469
45903
|
if (match) {
|
|
45470
45904
|
return match[1];
|
|
@@ -45476,10 +45910,10 @@ function getChangelogVersion(dir) {
|
|
|
45476
45910
|
function getVersionFileVersion(dir) {
|
|
45477
45911
|
const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
|
|
45478
45912
|
for (const file3 of possibleFiles) {
|
|
45479
|
-
const filePath =
|
|
45480
|
-
if (
|
|
45913
|
+
const filePath = path32.join(dir, file3);
|
|
45914
|
+
if (fs18.existsSync(filePath)) {
|
|
45481
45915
|
try {
|
|
45482
|
-
const content =
|
|
45916
|
+
const content = fs18.readFileSync(filePath, "utf-8").trim();
|
|
45483
45917
|
const match = content.match(/(\d+\.\d+\.\d+)/);
|
|
45484
45918
|
if (match) {
|
|
45485
45919
|
return match[1];
|
|
@@ -45803,8 +46237,8 @@ async function runEvidenceCheck(dir) {
|
|
|
45803
46237
|
async function runRequirementCoverageCheck(dir, currentPhase) {
|
|
45804
46238
|
const startTime = Date.now();
|
|
45805
46239
|
try {
|
|
45806
|
-
const specPath =
|
|
45807
|
-
if (!
|
|
46240
|
+
const specPath = path32.join(dir, ".swarm", "spec.md");
|
|
46241
|
+
if (!fs18.existsSync(specPath)) {
|
|
45808
46242
|
return {
|
|
45809
46243
|
type: "req_coverage",
|
|
45810
46244
|
status: "skip",
|
|
@@ -46101,9 +46535,6 @@ var init_promote = __esm(() => {
|
|
|
46101
46535
|
});
|
|
46102
46536
|
|
|
46103
46537
|
// src/commands/qa-gates.ts
|
|
46104
|
-
function derivePlanId(plan) {
|
|
46105
|
-
return `${plan.swarm}-${plan.title}`.replace(/[^a-zA-Z0-9-_]/g, "_");
|
|
46106
|
-
}
|
|
46107
46538
|
function isGateName(name) {
|
|
46108
46539
|
return ALL_GATE_NAMES.includes(name);
|
|
46109
46540
|
}
|
|
@@ -46229,7 +46660,8 @@ var init_qa_gates = __esm(() => {
|
|
|
46229
46660
|
"sast_enabled",
|
|
46230
46661
|
"mutation_test",
|
|
46231
46662
|
"council_general_review",
|
|
46232
|
-
"drift_check"
|
|
46663
|
+
"drift_check",
|
|
46664
|
+
"final_council"
|
|
46233
46665
|
];
|
|
46234
46666
|
});
|
|
46235
46667
|
|
|
@@ -46283,13 +46715,13 @@ class CircuitBreaker {
|
|
|
46283
46715
|
if (this.config.callTimeoutMs <= 0) {
|
|
46284
46716
|
return fn();
|
|
46285
46717
|
}
|
|
46286
|
-
return new Promise((
|
|
46718
|
+
return new Promise((resolve14, reject) => {
|
|
46287
46719
|
const timeout = setTimeout(() => {
|
|
46288
46720
|
reject(new Error(`Call timeout after ${this.config.callTimeoutMs}ms`));
|
|
46289
46721
|
}, this.config.callTimeoutMs);
|
|
46290
46722
|
fn().then((result) => {
|
|
46291
46723
|
clearTimeout(timeout);
|
|
46292
|
-
|
|
46724
|
+
resolve14(result);
|
|
46293
46725
|
}).catch((error93) => {
|
|
46294
46726
|
clearTimeout(timeout);
|
|
46295
46727
|
reject(error93);
|
|
@@ -46576,7 +47008,7 @@ var init_queue = __esm(() => {
|
|
|
46576
47008
|
|
|
46577
47009
|
// src/background/worker.ts
|
|
46578
47010
|
function sleep(ms) {
|
|
46579
|
-
return new Promise((
|
|
47011
|
+
return new Promise((resolve14) => setTimeout(resolve14, ms));
|
|
46580
47012
|
}
|
|
46581
47013
|
|
|
46582
47014
|
class WorkerManager {
|
|
@@ -46921,8 +47353,8 @@ var init_manager3 = __esm(() => {
|
|
|
46921
47353
|
});
|
|
46922
47354
|
|
|
46923
47355
|
// src/commands/reset.ts
|
|
46924
|
-
import * as
|
|
46925
|
-
import * as
|
|
47356
|
+
import * as fs19 from "fs";
|
|
47357
|
+
import * as path33 from "path";
|
|
46926
47358
|
async function handleResetCommand(directory, args) {
|
|
46927
47359
|
const hasConfirm = args.includes("--confirm");
|
|
46928
47360
|
if (!hasConfirm) {
|
|
@@ -46950,8 +47382,8 @@ async function handleResetCommand(directory, args) {
|
|
|
46950
47382
|
for (const filename of filesToReset) {
|
|
46951
47383
|
try {
|
|
46952
47384
|
const resolvedPath = validateSwarmPath(directory, filename);
|
|
46953
|
-
if (
|
|
46954
|
-
|
|
47385
|
+
if (fs19.existsSync(resolvedPath)) {
|
|
47386
|
+
fs19.unlinkSync(resolvedPath);
|
|
46955
47387
|
results.push(`- \u2705 Deleted ${filename}`);
|
|
46956
47388
|
} else {
|
|
46957
47389
|
results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
|
|
@@ -46962,9 +47394,9 @@ async function handleResetCommand(directory, args) {
|
|
|
46962
47394
|
}
|
|
46963
47395
|
for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
|
|
46964
47396
|
try {
|
|
46965
|
-
const rootPath =
|
|
46966
|
-
if (
|
|
46967
|
-
|
|
47397
|
+
const rootPath = path33.join(directory, filename);
|
|
47398
|
+
if (fs19.existsSync(rootPath)) {
|
|
47399
|
+
fs19.unlinkSync(rootPath);
|
|
46968
47400
|
results.push(`- \u2705 Deleted ${filename} (root)`);
|
|
46969
47401
|
}
|
|
46970
47402
|
} catch {}
|
|
@@ -46977,8 +47409,8 @@ async function handleResetCommand(directory, args) {
|
|
|
46977
47409
|
}
|
|
46978
47410
|
try {
|
|
46979
47411
|
const summariesPath = validateSwarmPath(directory, "summaries");
|
|
46980
|
-
if (
|
|
46981
|
-
|
|
47412
|
+
if (fs19.existsSync(summariesPath)) {
|
|
47413
|
+
fs19.rmSync(summariesPath, { recursive: true, force: true });
|
|
46982
47414
|
results.push("- \u2705 Deleted summaries/ directory");
|
|
46983
47415
|
} else {
|
|
46984
47416
|
results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
|
|
@@ -47001,14 +47433,14 @@ var init_reset = __esm(() => {
|
|
|
47001
47433
|
});
|
|
47002
47434
|
|
|
47003
47435
|
// src/commands/reset-session.ts
|
|
47004
|
-
import * as
|
|
47005
|
-
import * as
|
|
47436
|
+
import * as fs20 from "fs";
|
|
47437
|
+
import * as path34 from "path";
|
|
47006
47438
|
async function handleResetSessionCommand(directory, _args) {
|
|
47007
47439
|
const results = [];
|
|
47008
47440
|
try {
|
|
47009
47441
|
const statePath = validateSwarmPath(directory, "session/state.json");
|
|
47010
|
-
if (
|
|
47011
|
-
|
|
47442
|
+
if (fs20.existsSync(statePath)) {
|
|
47443
|
+
fs20.unlinkSync(statePath);
|
|
47012
47444
|
results.push("\u2705 Deleted .swarm/session/state.json");
|
|
47013
47445
|
} else {
|
|
47014
47446
|
results.push("\u23ED\uFE0F state.json not found (already clean)");
|
|
@@ -47017,15 +47449,15 @@ async function handleResetSessionCommand(directory, _args) {
|
|
|
47017
47449
|
results.push("\u274C Failed to delete state.json");
|
|
47018
47450
|
}
|
|
47019
47451
|
try {
|
|
47020
|
-
const sessionDir =
|
|
47021
|
-
if (
|
|
47022
|
-
const files =
|
|
47452
|
+
const sessionDir = path34.dirname(validateSwarmPath(directory, "session/state.json"));
|
|
47453
|
+
if (fs20.existsSync(sessionDir)) {
|
|
47454
|
+
const files = fs20.readdirSync(sessionDir);
|
|
47023
47455
|
const otherFiles = files.filter((f) => f !== "state.json");
|
|
47024
47456
|
let deletedCount = 0;
|
|
47025
47457
|
for (const file3 of otherFiles) {
|
|
47026
|
-
const filePath =
|
|
47027
|
-
if (
|
|
47028
|
-
|
|
47458
|
+
const filePath = path34.join(sessionDir, file3);
|
|
47459
|
+
if (fs20.lstatSync(filePath).isFile()) {
|
|
47460
|
+
fs20.unlinkSync(filePath);
|
|
47029
47461
|
deletedCount++;
|
|
47030
47462
|
}
|
|
47031
47463
|
}
|
|
@@ -47055,7 +47487,7 @@ var init_reset_session = __esm(() => {
|
|
|
47055
47487
|
});
|
|
47056
47488
|
|
|
47057
47489
|
// src/summaries/manager.ts
|
|
47058
|
-
import * as
|
|
47490
|
+
import * as path35 from "path";
|
|
47059
47491
|
function sanitizeSummaryId(id) {
|
|
47060
47492
|
if (!id || id.length === 0) {
|
|
47061
47493
|
throw new Error("Invalid summary ID: empty string");
|
|
@@ -47078,7 +47510,7 @@ function sanitizeSummaryId(id) {
|
|
|
47078
47510
|
}
|
|
47079
47511
|
async function loadFullOutput(directory, id) {
|
|
47080
47512
|
const sanitizedId = sanitizeSummaryId(id);
|
|
47081
|
-
const relativePath =
|
|
47513
|
+
const relativePath = path35.join("summaries", `${sanitizedId}.json`);
|
|
47082
47514
|
validateSwarmPath(directory, relativePath);
|
|
47083
47515
|
const content = await readSwarmFileAsync(directory, relativePath);
|
|
47084
47516
|
if (content === null) {
|
|
@@ -47140,18 +47572,18 @@ var init_retrieve = __esm(() => {
|
|
|
47140
47572
|
});
|
|
47141
47573
|
|
|
47142
47574
|
// src/commands/rollback.ts
|
|
47143
|
-
import * as
|
|
47144
|
-
import * as
|
|
47575
|
+
import * as fs21 from "fs";
|
|
47576
|
+
import * as path36 from "path";
|
|
47145
47577
|
async function handleRollbackCommand(directory, args) {
|
|
47146
47578
|
const phaseArg = args[0];
|
|
47147
47579
|
if (!phaseArg) {
|
|
47148
47580
|
const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
47149
|
-
if (!
|
|
47581
|
+
if (!fs21.existsSync(manifestPath2)) {
|
|
47150
47582
|
return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
|
|
47151
47583
|
}
|
|
47152
47584
|
let manifest2;
|
|
47153
47585
|
try {
|
|
47154
|
-
manifest2 = JSON.parse(
|
|
47586
|
+
manifest2 = JSON.parse(fs21.readFileSync(manifestPath2, "utf-8"));
|
|
47155
47587
|
} catch {
|
|
47156
47588
|
return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
|
|
47157
47589
|
}
|
|
@@ -47173,12 +47605,12 @@ async function handleRollbackCommand(directory, args) {
|
|
|
47173
47605
|
return "Error: Phase number must be a positive integer.";
|
|
47174
47606
|
}
|
|
47175
47607
|
const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
|
|
47176
|
-
if (!
|
|
47608
|
+
if (!fs21.existsSync(manifestPath)) {
|
|
47177
47609
|
return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
|
|
47178
47610
|
}
|
|
47179
47611
|
let manifest;
|
|
47180
47612
|
try {
|
|
47181
|
-
manifest = JSON.parse(
|
|
47613
|
+
manifest = JSON.parse(fs21.readFileSync(manifestPath, "utf-8"));
|
|
47182
47614
|
} catch {
|
|
47183
47615
|
return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
|
|
47184
47616
|
}
|
|
@@ -47188,10 +47620,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
47188
47620
|
return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
|
|
47189
47621
|
}
|
|
47190
47622
|
const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
|
|
47191
|
-
if (!
|
|
47623
|
+
if (!fs21.existsSync(checkpointDir)) {
|
|
47192
47624
|
return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
|
|
47193
47625
|
}
|
|
47194
|
-
const checkpointFiles =
|
|
47626
|
+
const checkpointFiles = fs21.readdirSync(checkpointDir);
|
|
47195
47627
|
if (checkpointFiles.length === 0) {
|
|
47196
47628
|
return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
|
|
47197
47629
|
}
|
|
@@ -47206,10 +47638,10 @@ async function handleRollbackCommand(directory, args) {
|
|
|
47206
47638
|
if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
|
|
47207
47639
|
continue;
|
|
47208
47640
|
}
|
|
47209
|
-
const src =
|
|
47210
|
-
const dest =
|
|
47641
|
+
const src = path36.join(checkpointDir, file3);
|
|
47642
|
+
const dest = path36.join(swarmDir, file3);
|
|
47211
47643
|
try {
|
|
47212
|
-
|
|
47644
|
+
fs21.cpSync(src, dest, { recursive: true, force: true });
|
|
47213
47645
|
successes.push(file3);
|
|
47214
47646
|
} catch (error93) {
|
|
47215
47647
|
failures.push({ file: file3, error: error93.message });
|
|
@@ -47226,16 +47658,16 @@ async function handleRollbackCommand(directory, args) {
|
|
|
47226
47658
|
].join(`
|
|
47227
47659
|
`);
|
|
47228
47660
|
}
|
|
47229
|
-
const existingLedgerPath =
|
|
47230
|
-
if (
|
|
47231
|
-
|
|
47661
|
+
const existingLedgerPath = path36.join(swarmDir, "plan-ledger.jsonl");
|
|
47662
|
+
if (fs21.existsSync(existingLedgerPath)) {
|
|
47663
|
+
fs21.unlinkSync(existingLedgerPath);
|
|
47232
47664
|
}
|
|
47233
47665
|
try {
|
|
47234
|
-
const planJsonPath =
|
|
47235
|
-
if (
|
|
47236
|
-
const planRaw =
|
|
47666
|
+
const planJsonPath = path36.join(swarmDir, "plan.json");
|
|
47667
|
+
if (fs21.existsSync(planJsonPath)) {
|
|
47668
|
+
const planRaw = fs21.readFileSync(planJsonPath, "utf-8");
|
|
47237
47669
|
const plan = PlanSchema.parse(JSON.parse(planRaw));
|
|
47238
|
-
const planId =
|
|
47670
|
+
const planId = derivePlanId(plan);
|
|
47239
47671
|
const planHash = computePlanHash(plan);
|
|
47240
47672
|
await initLedger(directory, planId, planHash, plan);
|
|
47241
47673
|
await appendLedgerEvent(directory, {
|
|
@@ -47260,7 +47692,7 @@ async function handleRollbackCommand(directory, args) {
|
|
|
47260
47692
|
timestamp: new Date().toISOString()
|
|
47261
47693
|
};
|
|
47262
47694
|
try {
|
|
47263
|
-
|
|
47695
|
+
fs21.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
|
|
47264
47696
|
`);
|
|
47265
47697
|
} catch (error93) {
|
|
47266
47698
|
console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
|
|
@@ -47308,11 +47740,11 @@ async function handleSimulateCommand(directory, args) {
|
|
|
47308
47740
|
];
|
|
47309
47741
|
const report = reportLines.filter(Boolean).join(`
|
|
47310
47742
|
`);
|
|
47311
|
-
const
|
|
47312
|
-
const
|
|
47313
|
-
const reportPath =
|
|
47314
|
-
await
|
|
47315
|
-
await
|
|
47743
|
+
const fs22 = await import("fs/promises");
|
|
47744
|
+
const path37 = await import("path");
|
|
47745
|
+
const reportPath = path37.join(directory, ".swarm", "simulate-report.md");
|
|
47746
|
+
await fs22.mkdir(path37.dirname(reportPath), { recursive: true });
|
|
47747
|
+
await fs22.writeFile(reportPath, report, "utf-8");
|
|
47316
47748
|
return `${darkMatterPairs.length} hidden coupling pairs detected`;
|
|
47317
47749
|
}
|
|
47318
47750
|
var init_simulate = __esm(() => {
|
|
@@ -47665,8 +48097,8 @@ __export(exports_commands, {
|
|
|
47665
48097
|
VALID_COMMANDS: () => VALID_COMMANDS,
|
|
47666
48098
|
COMMAND_REGISTRY: () => COMMAND_REGISTRY
|
|
47667
48099
|
});
|
|
47668
|
-
import
|
|
47669
|
-
import
|
|
48100
|
+
import fs22 from "fs";
|
|
48101
|
+
import path37 from "path";
|
|
47670
48102
|
function buildHelpText() {
|
|
47671
48103
|
const lines = ["## Swarm Commands", ""];
|
|
47672
48104
|
const CATEGORIES = [
|
|
@@ -47775,11 +48207,11 @@ function createSwarmCommandHandler(directory, agents) {
|
|
|
47775
48207
|
return;
|
|
47776
48208
|
}
|
|
47777
48209
|
let isFirstRun = false;
|
|
47778
|
-
const sentinelPath =
|
|
48210
|
+
const sentinelPath = path37.join(directory, ".swarm", ".first-run-complete");
|
|
47779
48211
|
try {
|
|
47780
|
-
const swarmDir =
|
|
47781
|
-
|
|
47782
|
-
|
|
48212
|
+
const swarmDir = path37.join(directory, ".swarm");
|
|
48213
|
+
fs22.mkdirSync(swarmDir, { recursive: true });
|
|
48214
|
+
fs22.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
|
|
47783
48215
|
`, { flag: "wx" });
|
|
47784
48216
|
isFirstRun = true;
|
|
47785
48217
|
} catch (_err) {}
|
|
@@ -47962,24 +48394,24 @@ function validateAliases() {
|
|
|
47962
48394
|
}
|
|
47963
48395
|
aliasTargets.get(target).push(name);
|
|
47964
48396
|
const visited = new Set;
|
|
47965
|
-
const
|
|
48397
|
+
const path38 = [];
|
|
47966
48398
|
let current = target;
|
|
47967
48399
|
while (current) {
|
|
47968
48400
|
const currentEntry = COMMAND_REGISTRY[current];
|
|
47969
48401
|
if (!currentEntry)
|
|
47970
48402
|
break;
|
|
47971
48403
|
if (visited.has(current)) {
|
|
47972
|
-
const cycleStart =
|
|
48404
|
+
const cycleStart = path38.indexOf(current);
|
|
47973
48405
|
const fullChain = [
|
|
47974
48406
|
name,
|
|
47975
|
-
...
|
|
48407
|
+
...path38.slice(0, cycleStart > 0 ? cycleStart : path38.length),
|
|
47976
48408
|
current
|
|
47977
48409
|
].join(" \u2192 ");
|
|
47978
48410
|
errors5.push(`Circular alias detected: ${fullChain}`);
|
|
47979
48411
|
break;
|
|
47980
48412
|
}
|
|
47981
48413
|
visited.add(current);
|
|
47982
|
-
|
|
48414
|
+
path38.push(current);
|
|
47983
48415
|
current = currentEntry.aliasOf || "";
|
|
47984
48416
|
}
|
|
47985
48417
|
}
|
|
@@ -48437,68 +48869,68 @@ init_package();
|
|
|
48437
48869
|
init_registry();
|
|
48438
48870
|
init_cache_paths();
|
|
48439
48871
|
init_constants();
|
|
48440
|
-
import * as
|
|
48872
|
+
import * as fs23 from "fs";
|
|
48441
48873
|
import * as os7 from "os";
|
|
48442
|
-
import * as
|
|
48874
|
+
import * as path38 from "path";
|
|
48443
48875
|
var { version: version4 } = package_default;
|
|
48444
48876
|
var CONFIG_DIR = getPluginConfigDir();
|
|
48445
|
-
var OPENCODE_CONFIG_PATH =
|
|
48446
|
-
var PLUGIN_CONFIG_PATH =
|
|
48447
|
-
var PROMPTS_DIR =
|
|
48877
|
+
var OPENCODE_CONFIG_PATH = path38.join(CONFIG_DIR, "opencode.json");
|
|
48878
|
+
var PLUGIN_CONFIG_PATH = path38.join(CONFIG_DIR, "opencode-swarm.json");
|
|
48879
|
+
var PROMPTS_DIR = path38.join(CONFIG_DIR, "opencode-swarm");
|
|
48448
48880
|
var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
|
|
48449
48881
|
var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
|
|
48450
48882
|
function isSafeCachePath(p) {
|
|
48451
|
-
const resolved =
|
|
48452
|
-
const home =
|
|
48883
|
+
const resolved = path38.resolve(p);
|
|
48884
|
+
const home = path38.resolve(os7.homedir());
|
|
48453
48885
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
48454
48886
|
return false;
|
|
48455
48887
|
}
|
|
48456
|
-
const segments = resolved.split(
|
|
48888
|
+
const segments = resolved.split(path38.sep).filter((s) => s.length > 0);
|
|
48457
48889
|
if (segments.length < 4) {
|
|
48458
48890
|
return false;
|
|
48459
48891
|
}
|
|
48460
|
-
const leaf =
|
|
48892
|
+
const leaf = path38.basename(resolved);
|
|
48461
48893
|
if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
|
|
48462
48894
|
return false;
|
|
48463
48895
|
}
|
|
48464
|
-
const parent =
|
|
48896
|
+
const parent = path38.basename(path38.dirname(resolved));
|
|
48465
48897
|
if (parent !== "packages" && parent !== "node_modules") {
|
|
48466
48898
|
return false;
|
|
48467
48899
|
}
|
|
48468
|
-
const grandparent =
|
|
48900
|
+
const grandparent = path38.basename(path38.dirname(path38.dirname(resolved)));
|
|
48469
48901
|
if (grandparent !== "opencode") {
|
|
48470
48902
|
return false;
|
|
48471
48903
|
}
|
|
48472
48904
|
return true;
|
|
48473
48905
|
}
|
|
48474
48906
|
function isSafeLockFilePath(p) {
|
|
48475
|
-
const resolved =
|
|
48476
|
-
const home =
|
|
48907
|
+
const resolved = path38.resolve(p);
|
|
48908
|
+
const home = path38.resolve(os7.homedir());
|
|
48477
48909
|
if (resolved === "/" || resolved === home || resolved.length <= home.length) {
|
|
48478
48910
|
return false;
|
|
48479
48911
|
}
|
|
48480
|
-
const segments = resolved.split(
|
|
48912
|
+
const segments = resolved.split(path38.sep).filter((s) => s.length > 0);
|
|
48481
48913
|
if (segments.length < 4) {
|
|
48482
48914
|
return false;
|
|
48483
48915
|
}
|
|
48484
|
-
const leaf =
|
|
48916
|
+
const leaf = path38.basename(resolved);
|
|
48485
48917
|
if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
|
|
48486
48918
|
return false;
|
|
48487
48919
|
}
|
|
48488
|
-
const parent =
|
|
48920
|
+
const parent = path38.basename(path38.dirname(resolved));
|
|
48489
48921
|
if (parent !== "opencode") {
|
|
48490
48922
|
return false;
|
|
48491
48923
|
}
|
|
48492
48924
|
return true;
|
|
48493
48925
|
}
|
|
48494
48926
|
function ensureDir(dir) {
|
|
48495
|
-
if (!
|
|
48496
|
-
|
|
48927
|
+
if (!fs23.existsSync(dir)) {
|
|
48928
|
+
fs23.mkdirSync(dir, { recursive: true });
|
|
48497
48929
|
}
|
|
48498
48930
|
}
|
|
48499
48931
|
function loadJson(filepath) {
|
|
48500
48932
|
try {
|
|
48501
|
-
const content =
|
|
48933
|
+
const content = fs23.readFileSync(filepath, "utf-8");
|
|
48502
48934
|
const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
|
|
48503
48935
|
return JSON.parse(stripped);
|
|
48504
48936
|
} catch {
|
|
@@ -48506,14 +48938,14 @@ function loadJson(filepath) {
|
|
|
48506
48938
|
}
|
|
48507
48939
|
}
|
|
48508
48940
|
function saveJson(filepath, data) {
|
|
48509
|
-
|
|
48941
|
+
fs23.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
|
|
48510
48942
|
`, "utf-8");
|
|
48511
48943
|
}
|
|
48512
48944
|
function writeProjectConfigIfMissing(cwd) {
|
|
48513
48945
|
try {
|
|
48514
|
-
const opencodeDir =
|
|
48515
|
-
const projectConfigPath =
|
|
48516
|
-
if (
|
|
48946
|
+
const opencodeDir = path38.join(cwd, ".opencode");
|
|
48947
|
+
const projectConfigPath = path38.join(opencodeDir, "opencode-swarm.json");
|
|
48948
|
+
if (fs23.existsSync(projectConfigPath)) {
|
|
48517
48949
|
return;
|
|
48518
48950
|
}
|
|
48519
48951
|
ensureDir(opencodeDir);
|
|
@@ -48533,7 +48965,7 @@ async function install() {
|
|
|
48533
48965
|
`);
|
|
48534
48966
|
ensureDir(CONFIG_DIR);
|
|
48535
48967
|
ensureDir(PROMPTS_DIR);
|
|
48536
|
-
const LEGACY_CONFIG_PATH =
|
|
48968
|
+
const LEGACY_CONFIG_PATH = path38.join(CONFIG_DIR, "config.json");
|
|
48537
48969
|
let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
48538
48970
|
if (!opencodeConfig) {
|
|
48539
48971
|
const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
|
|
@@ -48580,7 +49012,7 @@ async function install() {
|
|
|
48580
49012
|
console.warn(`\u26A0 Could not clear opencode lock file \u2014 you may need to delete it manually:
|
|
48581
49013
|
${failed}`);
|
|
48582
49014
|
}
|
|
48583
|
-
if (!
|
|
49015
|
+
if (!fs23.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
48584
49016
|
const defaultConfig = {
|
|
48585
49017
|
agents: { ...DEFAULT_AGENT_CONFIGS },
|
|
48586
49018
|
max_iterations: 5
|
|
@@ -48659,14 +49091,14 @@ function evictPluginCaches() {
|
|
|
48659
49091
|
const cleared = [];
|
|
48660
49092
|
const failed = [];
|
|
48661
49093
|
for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
|
|
48662
|
-
if (!
|
|
49094
|
+
if (!fs23.existsSync(cachePath))
|
|
48663
49095
|
continue;
|
|
48664
49096
|
if (!isSafeCachePath(cachePath)) {
|
|
48665
49097
|
failed.push(`${cachePath} (refused: failed safety check)`);
|
|
48666
49098
|
continue;
|
|
48667
49099
|
}
|
|
48668
49100
|
try {
|
|
48669
|
-
|
|
49101
|
+
fs23.rmSync(cachePath, { recursive: true, force: true });
|
|
48670
49102
|
cleared.push(cachePath);
|
|
48671
49103
|
} catch (err) {
|
|
48672
49104
|
failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
|
|
@@ -48678,14 +49110,14 @@ function evictLockFiles() {
|
|
|
48678
49110
|
const cleared = [];
|
|
48679
49111
|
const failed = [];
|
|
48680
49112
|
for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
|
|
48681
|
-
if (!
|
|
49113
|
+
if (!fs23.existsSync(lockPath))
|
|
48682
49114
|
continue;
|
|
48683
49115
|
if (!isSafeLockFilePath(lockPath)) {
|
|
48684
49116
|
failed.push(`${lockPath} (refused: failed safety check)`);
|
|
48685
49117
|
continue;
|
|
48686
49118
|
}
|
|
48687
49119
|
try {
|
|
48688
|
-
|
|
49120
|
+
fs23.unlinkSync(lockPath);
|
|
48689
49121
|
cleared.push(lockPath);
|
|
48690
49122
|
} catch (err) {
|
|
48691
49123
|
const code = err?.code;
|
|
@@ -48704,7 +49136,7 @@ async function uninstall() {
|
|
|
48704
49136
|
`);
|
|
48705
49137
|
const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
|
|
48706
49138
|
if (!opencodeConfig) {
|
|
48707
|
-
if (
|
|
49139
|
+
if (fs23.existsSync(OPENCODE_CONFIG_PATH)) {
|
|
48708
49140
|
console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
|
|
48709
49141
|
return 1;
|
|
48710
49142
|
} else {
|
|
@@ -48736,13 +49168,13 @@ async function uninstall() {
|
|
|
48736
49168
|
console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
|
|
48737
49169
|
if (process.argv.includes("--clean")) {
|
|
48738
49170
|
let cleaned = false;
|
|
48739
|
-
if (
|
|
48740
|
-
|
|
49171
|
+
if (fs23.existsSync(PLUGIN_CONFIG_PATH)) {
|
|
49172
|
+
fs23.unlinkSync(PLUGIN_CONFIG_PATH);
|
|
48741
49173
|
console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
|
|
48742
49174
|
cleaned = true;
|
|
48743
49175
|
}
|
|
48744
|
-
if (
|
|
48745
|
-
|
|
49176
|
+
if (fs23.existsSync(PROMPTS_DIR)) {
|
|
49177
|
+
fs23.rmSync(PROMPTS_DIR, { recursive: true });
|
|
48746
49178
|
console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
|
|
48747
49179
|
cleaned = true;
|
|
48748
49180
|
}
|