opencode-swarm 7.55.0 → 7.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "opencode-swarm",
55
- version: "7.55.0",
55
+ version: "7.56.1",
56
56
  description: "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
57
57
  main: "dist/index.js",
58
58
  types: "dist/index.d.ts",
@@ -36811,7 +36811,7 @@ function clusterEntries(entries) {
36811
36811
  function uniqueStrings(arr) {
36812
36812
  return [...new Set(arr.filter((s) => typeof s === "string" && s.length > 0))];
36813
36813
  }
36814
- function renderSkillMarkdown(cluster, mode = "active") {
36814
+ function renderSkillMarkdown(cluster, mode = "active", generatedAt = new Date().toISOString()) {
36815
36815
  const description = cluster.title.length > 200 ? `${cluster.title.slice(0, 197)}\u2026` : cluster.title;
36816
36816
  const ids = cluster.entries.map((e) => ` - ${e.id}`).join(`
36817
36817
  `);
@@ -36821,6 +36821,9 @@ function renderSkillMarkdown(cluster, mode = "active") {
36821
36821
  lines.push(`description: ${escapeYaml(description)}`);
36822
36822
  lines.push("generated_from_knowledge:");
36823
36823
  lines.push(ids);
36824
+ lines.push("source_knowledge_ids:");
36825
+ lines.push(ids);
36826
+ lines.push(`generated_at: ${generatedAt}`);
36824
36827
  lines.push(`confidence: ${cluster.avgConfidence.toFixed(2)}`);
36825
36828
  lines.push(`status: ${mode === "active" ? "active" : "draft"}`);
36826
36829
  lines.push("---");
@@ -37009,6 +37012,62 @@ async function stampSourceEntries(directory, slug, ids) {
37009
37012
  if (touchedHive)
37010
37013
  await rewriteKnowledge(hivePath, hive);
37011
37014
  }
37015
+ function parseDraftFrontmatter(content) {
37016
+ const stripped = content.charCodeAt(0) === 65279 ? content.slice(1) : content;
37017
+ const openFence = stripped.match(/^---[ \t]*\r?\n/);
37018
+ if (!openFence)
37019
+ return null;
37020
+ const fenceLen = openFence[0].length;
37021
+ const closeFence = stripped.slice(fenceLen).match(/\n---[ \t]*(\r?\n|$)/);
37022
+ if (!closeFence)
37023
+ return null;
37024
+ const closeStart = fenceLen + (closeFence.index ?? 0);
37025
+ const body = stripped.slice(fenceLen, closeStart).replace(/\r\n/g, `
37026
+ `);
37027
+ const lines = body.split(`
37028
+ `);
37029
+ const out = {
37030
+ sourceKnowledgeIds: []
37031
+ };
37032
+ let inLegacyIdsList = false;
37033
+ let inSourceIdsList = false;
37034
+ for (const raw of lines) {
37035
+ const line = raw;
37036
+ if (inLegacyIdsList || inSourceIdsList) {
37037
+ const m = line.match(/^\s+-\s+(\S{1,64})\s*$/);
37038
+ if (m) {
37039
+ out.sourceKnowledgeIds.push(m[1]);
37040
+ continue;
37041
+ }
37042
+ inLegacyIdsList = false;
37043
+ inSourceIdsList = false;
37044
+ }
37045
+ const nm = line.match(/^name:\s*(\S+)\s*$/);
37046
+ if (nm) {
37047
+ out.name = nm[1];
37048
+ continue;
37049
+ }
37050
+ const st = line.match(/^status:\s*(\S+)\s*$/);
37051
+ if (st) {
37052
+ out.status = st[1];
37053
+ continue;
37054
+ }
37055
+ const ga = line.match(/^generated_at:\s*(\S+)\s*$/);
37056
+ if (ga) {
37057
+ out.generatedAt = ga[1];
37058
+ continue;
37059
+ }
37060
+ if (/^generated_from_knowledge:\s*$/.test(line)) {
37061
+ inLegacyIdsList = true;
37062
+ continue;
37063
+ }
37064
+ if (/^source_knowledge_ids:\s*$/.test(line)) {
37065
+ out.sourceKnowledgeIds = [];
37066
+ inSourceIdsList = true;
37067
+ }
37068
+ }
37069
+ return out;
37070
+ }
37012
37071
  async function listSkills(directory) {
37013
37072
  const result = {
37014
37073
  proposals: [],
@@ -38338,7 +38397,7 @@ var init_skill_improver_quota = __esm(() => {
38338
38397
 
38339
38398
  // src/services/skill-improver.ts
38340
38399
  import { existsSync as existsSync12 } from "fs";
38341
- import { mkdir as mkdir7, rename as rename5, writeFile as writeFile6 } from "fs/promises";
38400
+ import { mkdir as mkdir7, readFile as readFile7, rename as rename5, writeFile as writeFile6 } from "fs/promises";
38342
38401
  import * as path18 from "path";
38343
38402
  function timestampSlug(d) {
38344
38403
  return d.toISOString().replace(/[:.]/g, "-");
@@ -38355,15 +38414,63 @@ async function gatherInventory(directory) {
38355
38414
  const hive = existsSync12(hivePath) ? await readKnowledge(hivePath) : [];
38356
38415
  const archived = [...swarm, ...hive].filter((e) => e.status === "archived").length;
38357
38416
  const skills = await listSkills(directory);
38417
+ const knowledgeById = new Map([...swarm, ...hive].map((entry) => [entry.id, entry]));
38418
+ const staleActiveSkills = [];
38419
+ let metadataReadable = 0;
38420
+ for (const skill of skills.active) {
38421
+ let content;
38422
+ try {
38423
+ content = await readFile7(skill.path, "utf-8");
38424
+ } catch {
38425
+ continue;
38426
+ }
38427
+ const fm = parseDraftFrontmatter(content);
38428
+ if (!fm)
38429
+ continue;
38430
+ metadataReadable += 1;
38431
+ const reasons = [];
38432
+ if (fm.sourceKnowledgeIds.length === 0) {
38433
+ reasons.push("missing_source_knowledge_ids");
38434
+ }
38435
+ if (!fm.generatedAt) {
38436
+ reasons.push("missing_generated_at");
38437
+ } else {
38438
+ const generatedAtMs = Date.parse(fm.generatedAt);
38439
+ if (!Number.isFinite(generatedAtMs)) {
38440
+ reasons.push("invalid_generated_at");
38441
+ } else {
38442
+ for (const id of fm.sourceKnowledgeIds) {
38443
+ const source = knowledgeById.get(id);
38444
+ if (!source) {
38445
+ reasons.push(`missing_source:${id}`);
38446
+ continue;
38447
+ }
38448
+ const updatedAtMs = Date.parse(source.updated_at);
38449
+ if (Number.isFinite(updatedAtMs) && updatedAtMs > generatedAtMs) {
38450
+ reasons.push(`updated_after_generation:${id}`);
38451
+ }
38452
+ }
38453
+ }
38454
+ }
38455
+ if (reasons.length > 0) {
38456
+ staleActiveSkills.push({
38457
+ slug: skill.slug,
38458
+ reasons: reasons.slice(0, 6)
38459
+ });
38460
+ }
38461
+ }
38358
38462
  const matureCandidates = swarm.concat(hive).filter((e) => e.status !== "archived" && e.confidence >= 0.85 && !e.generated_skill_slug && (e.confirmed_by ?? []).length >= 2);
38359
38463
  return {
38360
38464
  knowledge: { swarm: swarm.length, hive: hive.length, archived },
38361
38465
  skills: {
38362
38466
  proposals: skills.proposals.length,
38363
- active: skills.active.length
38467
+ active: skills.active.length,
38468
+ stale: staleActiveSkills.length,
38469
+ metadataReadable
38364
38470
  },
38365
38471
  highConfidenceClusters: matureCandidates.length,
38366
- matureCandidates
38472
+ matureCandidates,
38473
+ staleActiveSkills
38367
38474
  };
38368
38475
  }
38369
38476
  function buildSystemPrompt(targets, cfg) {
@@ -38387,10 +38494,16 @@ hive_entries: ${inv.knowledge.hive}
38387
38494
  archived: ${inv.knowledge.archived}
38388
38495
  draft_skills: ${inv.skills.proposals}
38389
38496
  active_skills: ${inv.skills.active}
38497
+ active_skills_with_readable_metadata: ${inv.skills.metadataReadable}
38498
+ stale_active_skills: ${inv.skills.stale}
38390
38499
  mature_uncompiled_clusters: ${inv.highConfidenceClusters}
38391
38500
 
38392
38501
  TOP MATURE CANDIDATES (first 25):
38393
38502
  ${matureRows || "(none)"}
38503
+
38504
+ STALE ACTIVE SKILLS (first 10):
38505
+ ${inv.staleActiveSkills.slice(0, 10).map((s) => `- ${s.slug} | ${s.reasons.join(", ")}`).join(`
38506
+ `) || "(none)"}
38394
38507
  `;
38395
38508
  }
38396
38509
  function isAbortError(err) {
@@ -38419,7 +38532,11 @@ function buildDeterministicProposal(args) {
38419
38532
  lines.push("## Inventory snapshot");
38420
38533
  lines.push(`- Knowledge entries: swarm=${args.inventory.knowledge.swarm}, hive=${args.inventory.knowledge.hive}, archived=${args.inventory.knowledge.archived}`);
38421
38534
  lines.push(`- Generated skills: proposals=${args.inventory.skills.proposals}, active=${args.inventory.skills.active}`);
38535
+ lines.push(`- Active skills with readable metadata: ${args.inventory.skills.metadataReadable} (stale=${args.inventory.skills.stale})`);
38422
38536
  lines.push(`- High-confidence un-skill'd clusters: ${args.inventory.highConfidenceClusters}`);
38537
+ if (args.inventory.staleActiveSkills.length > 0) {
38538
+ lines.push(`- Stale active skills: ${args.inventory.staleActiveSkills.map((s) => s.slug).join(", ")}`);
38539
+ }
38423
38540
  lines.push("");
38424
38541
  lines.push("## Recommendations");
38425
38542
  if (args.inventory.highConfidenceClusters > 0) {
@@ -39914,7 +40031,7 @@ var init_curate = __esm(() => {
39914
40031
  // src/tools/co-change-analyzer.ts
39915
40032
  import * as child_process3 from "child_process";
39916
40033
  import { randomUUID as randomUUID2 } from "crypto";
39917
- import { readdir, readFile as readFile7, stat as stat2 } from "fs/promises";
40034
+ import { readdir, readFile as readFile8, stat as stat2 } from "fs/promises";
39918
40035
  import * as path21 from "path";
39919
40036
  import { promisify } from "util";
39920
40037
  function getExecFileAsync() {
@@ -40041,7 +40158,7 @@ async function getStaticEdges(directory) {
40041
40158
  const sourceFiles = await scanSourceFiles(directory);
40042
40159
  for (const sourceFile of sourceFiles) {
40043
40160
  try {
40044
- const content = await readFile7(sourceFile, "utf-8");
40161
+ const content = await readFile8(sourceFile, "utf-8");
40045
40162
  const importRegex = /(?:import|require)\s*(?:\(?\s*['"`]|.*?from\s+['"`])([^'"`]+)['"`]/g;
40046
40163
  for (let match = importRegex.exec(content);match !== null; match = importRegex.exec(content)) {
40047
40164
  const importPath = match[1].trim();
@@ -40825,11 +40942,11 @@ var init_version_check = __esm(() => {
40825
40942
 
40826
40943
  // src/services/knowledge-diagnostics.ts
40827
40944
  import { existsSync as existsSync14 } from "fs";
40828
- import { readFile as readFile8 } from "fs/promises";
40945
+ import { readFile as readFile9 } from "fs/promises";
40829
40946
  async function readRawLines(filePath) {
40830
40947
  if (!existsSync14(filePath))
40831
40948
  return { entries: [], corrupt: 0 };
40832
- const content = await readFile8(filePath, "utf-8");
40949
+ const content = await readFile9(filePath, "utf-8");
40833
40950
  const entries = [];
40834
40951
  let corrupt = 0;
40835
40952
  for (const line of content.split(`
@@ -42803,7 +42920,7 @@ var init_profiles = __esm(() => {
42803
42920
  detectFiles: ["Cargo.toml"],
42804
42921
  frameworks: [
42805
42922
  {
42806
- name: "cargo test",
42923
+ name: "cargo",
42807
42924
  detect: "Cargo.toml",
42808
42925
  cmd: "cargo test",
42809
42926
  priority: 10
@@ -42875,7 +42992,7 @@ var init_profiles = __esm(() => {
42875
42992
  test: {
42876
42993
  detectFiles: ["go.mod"],
42877
42994
  frameworks: [
42878
- { name: "go test", detect: "go.mod", cmd: "go test ./...", priority: 10 }
42995
+ { name: "go-test", detect: "go.mod", cmd: "go test ./...", priority: 10 }
42879
42996
  ]
42880
42997
  },
42881
42998
  lint: {
@@ -42950,13 +43067,13 @@ var init_profiles = __esm(() => {
42950
43067
  detectFiles: ["pom.xml", "build.gradle", "build.gradle.kts"],
42951
43068
  frameworks: [
42952
43069
  {
42953
- name: "maven-test",
43070
+ name: "maven",
42954
43071
  detect: "pom.xml",
42955
43072
  cmd: "mvn test -q",
42956
43073
  priority: 10
42957
43074
  },
42958
43075
  {
42959
- name: "gradle-test",
43076
+ name: "gradle",
42960
43077
  detect: "build.gradle",
42961
43078
  cmd: "gradle test -q",
42962
43079
  priority: 9
@@ -43034,13 +43151,13 @@ var init_profiles = __esm(() => {
43034
43151
  detectFiles: ["build.gradle.kts", "build.gradle"],
43035
43152
  frameworks: [
43036
43153
  {
43037
- name: "gradle-test",
43154
+ name: "gradle",
43038
43155
  detect: "build.gradle.kts",
43039
43156
  cmd: "gradle test -q",
43040
43157
  priority: 10
43041
43158
  },
43042
43159
  {
43043
- name: "gradle-test-groovy",
43160
+ name: "gradle",
43044
43161
  detect: "build.gradle",
43045
43162
  cmd: "gradle test -q",
43046
43163
  priority: 9
@@ -43048,11 +43165,11 @@ var init_profiles = __esm(() => {
43048
43165
  ]
43049
43166
  },
43050
43167
  lint: {
43051
- detectFiles: [".editorconfig", "build.gradle.kts"],
43168
+ detectFiles: ["build.gradle.kts", "build.gradle"],
43052
43169
  linters: [
43053
43170
  {
43054
43171
  name: "ktlint",
43055
- detect: ".editorconfig",
43172
+ detect: "build.gradle.kts",
43056
43173
  cmd: "ktlint --format",
43057
43174
  priority: 10
43058
43175
  }
@@ -43112,7 +43229,7 @@ var init_profiles = __esm(() => {
43112
43229
  detectFiles: ["*.csproj", "*.sln"],
43113
43230
  frameworks: [
43114
43231
  {
43115
- name: "dotnet test",
43232
+ name: "dotnet-test",
43116
43233
  detect: "*.csproj",
43117
43234
  cmd: "dotnet test",
43118
43235
  priority: 10
@@ -43263,7 +43380,7 @@ var init_profiles = __esm(() => {
43263
43380
  detectFiles: ["Package.swift", "*.xcodeproj"],
43264
43381
  frameworks: [
43265
43382
  {
43266
- name: "swift test",
43383
+ name: "swift-test",
43267
43384
  detect: "Package.swift",
43268
43385
  cmd: "swift test",
43269
43386
  priority: 10
@@ -43590,8 +43707,14 @@ async function detectProjectLanguages(projectDir) {
43590
43707
  }
43591
43708
  for (const profile of LANGUAGE_REGISTRY.getAll()) {
43592
43709
  for (const detectFile of profile.build.detectFiles) {
43593
- if (detectFile.includes("*") || detectFile.includes("?"))
43710
+ if (detectFile.includes("*") || detectFile.includes("?")) {
43711
+ const regex = new RegExp(`^${detectFile.replace(/\./g, "\\.").replace(/\*/g, ".*").replace(/\?/g, ".")}$`);
43712
+ if (entries.some((name) => regex.test(name))) {
43713
+ detected.add(profile.id);
43714
+ break;
43715
+ }
43594
43716
  continue;
43717
+ }
43595
43718
  try {
43596
43719
  await access3(join24(dir, detectFile));
43597
43720
  detected.add(profile.id);
@@ -46049,7 +46172,7 @@ var KNOWLEDGE_SCHEMA_VERSION = 2;
46049
46172
  // src/hooks/knowledge-migrator.ts
46050
46173
  import { randomUUID as randomUUID3 } from "crypto";
46051
46174
  import { existsSync as existsSync19, readFileSync as readFileSync13 } from "fs";
46052
- import { mkdir as mkdir8, readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
46175
+ import { mkdir as mkdir8, readFile as readFile10, writeFile as writeFile7 } from "fs/promises";
46053
46176
  import * as path29 from "path";
46054
46177
  async function migrateKnowledgeToExternal(_directory, _config) {
46055
46178
  return {
@@ -46082,7 +46205,7 @@ async function migrateContextToKnowledge(directory, config3) {
46082
46205
  skippedReason: "no-context-file"
46083
46206
  };
46084
46207
  }
46085
- const contextContent = await readFile9(contextPath, "utf-8");
46208
+ const contextContent = await readFile10(contextPath, "utf-8");
46086
46209
  if (contextContent.trim().length === 0) {
46087
46210
  return {
46088
46211
  migrated: false,
@@ -47331,7 +47454,7 @@ import { existsSync as existsSync20 } from "fs";
47331
47454
  import {
47332
47455
  appendFile as appendFile5,
47333
47456
  mkdir as mkdir9,
47334
- readFile as readFile10,
47457
+ readFile as readFile11,
47335
47458
  rename as rename6,
47336
47459
  writeFile as writeFile8
47337
47460
  } from "fs/promises";
@@ -47680,7 +47803,7 @@ function validateLoadedProposals(values, config3) {
47680
47803
  async function readJsonl(filePath) {
47681
47804
  if (!existsSync20(filePath))
47682
47805
  return [];
47683
- const content = await readFile10(filePath, "utf-8");
47806
+ const content = await readFile11(filePath, "utf-8");
47684
47807
  const records = [];
47685
47808
  for (const line of content.split(`
47686
47809
  `)) {
@@ -47765,7 +47888,7 @@ var init_prompt_block = __esm(() => {
47765
47888
 
47766
47889
  // src/memory/jsonl-migration.ts
47767
47890
  import { existsSync as existsSync21 } from "fs";
47768
- import { copyFile, mkdir as mkdir10, readFile as readFile11, stat as stat3, writeFile as writeFile9 } from "fs/promises";
47891
+ import { copyFile, mkdir as mkdir10, readFile as readFile12, stat as stat3, writeFile as writeFile9 } from "fs/promises";
47769
47892
  import * as path31 from "path";
47770
47893
  function resolveMemoryStorageDir(rootDirectory, config3 = {}) {
47771
47894
  const resolved = resolveConfig(config3);
@@ -47829,7 +47952,7 @@ async function readMigrationReport(rootDirectory, config3 = {}) {
47829
47952
  if (!existsSync21(reportPath))
47830
47953
  return null;
47831
47954
  try {
47832
- return JSON.parse(await readFile11(reportPath, "utf-8"));
47955
+ return JSON.parse(await readFile12(reportPath, "utf-8"));
47833
47956
  } catch {
47834
47957
  return null;
47835
47958
  }
@@ -47930,7 +48053,7 @@ async function readJsonlRows(filePath) {
47930
48053
  if (!existsSync21(filePath)) {
47931
48054
  return { rows: [], invalidRows: [], totalRows: 0 };
47932
48055
  }
47933
- const content = await readFile11(filePath, "utf-8");
48056
+ const content = await readFile12(filePath, "utf-8");
47934
48057
  const rows = [];
47935
48058
  const invalidRows = [];
47936
48059
  let totalRows = 0;
@@ -53044,12 +53167,85 @@ var init_registry_backend = __esm(() => {
53044
53167
  LANGUAGE_BACKEND_REGISTRY = new LanguageBackendRegistry;
53045
53168
  });
53046
53169
 
53047
- // src/lang/backends/typescript.ts
53170
+ // src/lang/framework-detector.ts
53048
53171
  import * as fs21 from "fs";
53049
53172
  import * as path43 from "path";
53173
+ function detectLaravelProject(directory) {
53174
+ const signals = getLaravelSignals(directory);
53175
+ const signalCount = [
53176
+ signals.hasArtisanFile,
53177
+ signals.hasLaravelFrameworkDep,
53178
+ signals.hasConfigApp
53179
+ ].filter(Boolean).length;
53180
+ return signalCount >= 2;
53181
+ }
53182
+ function getLaravelSignals(directory) {
53183
+ const hasArtisanFile = checkArtisanFile(directory);
53184
+ const hasLaravelFrameworkDep = checkLaravelFrameworkDep(directory);
53185
+ const hasConfigApp = checkConfigApp(directory);
53186
+ return { hasArtisanFile, hasLaravelFrameworkDep, hasConfigApp };
53187
+ }
53188
+ function checkArtisanFile(directory) {
53189
+ const artisanPath = path43.join(directory, "artisan");
53190
+ if (!fs21.existsSync(artisanPath))
53191
+ return false;
53192
+ try {
53193
+ return fs21.statSync(artisanPath).isFile();
53194
+ } catch {
53195
+ return false;
53196
+ }
53197
+ }
53198
+ function checkLaravelFrameworkDep(directory) {
53199
+ const composerPath = path43.join(directory, "composer.json");
53200
+ if (!fs21.existsSync(composerPath))
53201
+ return false;
53202
+ try {
53203
+ const content = fs21.readFileSync(composerPath, "utf-8");
53204
+ const parsed = JSON.parse(content);
53205
+ const require2 = parsed?.require ?? {};
53206
+ return typeof require2["laravel/framework"] === "string";
53207
+ } catch {
53208
+ return false;
53209
+ }
53210
+ }
53211
+ function checkConfigApp(directory) {
53212
+ return fs21.existsSync(path43.join(directory, "config", "app.php"));
53213
+ }
53214
+ var init_framework_detector = () => {};
53215
+
53216
+ // src/lang/backends/php.ts
53217
+ async function selectFramework3(dir) {
53218
+ if (detectLaravelProject(dir)) {
53219
+ return {
53220
+ name: "laravel",
53221
+ detectedVia: "Laravel signals (artisan / composer.json / config/app.php)"
53222
+ };
53223
+ }
53224
+ return null;
53225
+ }
53226
+ function buildPhpBackend() {
53227
+ const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
53228
+ if (!profile) {
53229
+ throw new Error("buildPhpBackend: php profile not in LANGUAGE_REGISTRY. " + "profiles.ts must be imported before this backend.");
53230
+ }
53231
+ return {
53232
+ ...defaultBackendFor(profile),
53233
+ selectFramework: selectFramework3
53234
+ };
53235
+ }
53236
+ var PROFILE_ID3 = "php";
53237
+ var init_php = __esm(() => {
53238
+ init_default_backend();
53239
+ init_framework_detector();
53240
+ init_profiles();
53241
+ });
53242
+
53243
+ // src/lang/backends/typescript.ts
53244
+ import * as fs22 from "fs";
53245
+ import * as path44 from "path";
53050
53246
  function readPackageJsonRaw(dir) {
53051
53247
  try {
53052
- const content = fs21.readFileSync(path43.join(dir, "package.json"), "utf-8");
53248
+ const content = fs22.readFileSync(path44.join(dir, "package.json"), "utf-8");
53053
53249
  return JSON.parse(content);
53054
53250
  } catch {
53055
53251
  return null;
@@ -53099,7 +53295,7 @@ function selectionFromFramework(profile, fwName, dir, detectedVia) {
53099
53295
  };
53100
53296
  }
53101
53297
  async function selectTestFramework(dir) {
53102
- const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
53298
+ const profile = LANGUAGE_REGISTRY.get(PROFILE_ID4);
53103
53299
  if (!profile)
53104
53300
  return null;
53105
53301
  const pkg = readPackageJson(dir);
@@ -53121,7 +53317,7 @@ async function selectTestFramework(dir) {
53121
53317
  return defaultSelectTestFramework(profile, dir);
53122
53318
  }
53123
53319
  function buildTestCommand(framework, files, dir, opts) {
53124
- const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
53320
+ const profile = LANGUAGE_REGISTRY.get(PROFILE_ID4);
53125
53321
  if (!profile)
53126
53322
  return null;
53127
53323
  return defaultBuildTestCommand(profile, framework, files, dir, opts);
@@ -53129,7 +53325,7 @@ function buildTestCommand(framework, files, dir, opts) {
53129
53325
  function parseTestOutput(framework, stdout, stderr, exitCode) {
53130
53326
  return defaultParseTestOutput(framework, stdout, stderr, exitCode);
53131
53327
  }
53132
- async function selectFramework3(dir) {
53328
+ async function selectFramework4(dir) {
53133
53329
  const pkg = readPackageJson(dir);
53134
53330
  if (!pkg)
53135
53331
  return null;
@@ -53198,19 +53394,19 @@ function extractImports4(_sourceFile, source) {
53198
53394
  return [...out];
53199
53395
  }
53200
53396
  async function selectBuildCommand(dir) {
53201
- const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
53397
+ const profile = LANGUAGE_REGISTRY.get(PROFILE_ID4);
53202
53398
  if (!profile)
53203
53399
  return null;
53204
53400
  return defaultSelectBuildCommand(profile, dir);
53205
53401
  }
53206
53402
  async function testFilesFor(sourceFile, dir) {
53207
- const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
53403
+ const profile = LANGUAGE_REGISTRY.get(PROFILE_ID4);
53208
53404
  if (!profile)
53209
53405
  return [];
53210
53406
  return defaultTestFilesFor(profile, sourceFile, dir);
53211
53407
  }
53212
53408
  function buildTypescriptBackend() {
53213
- const profile = LANGUAGE_REGISTRY.get(PROFILE_ID3);
53409
+ const profile = LANGUAGE_REGISTRY.get(PROFILE_ID4);
53214
53410
  if (!profile) {
53215
53411
  throw new Error("buildTypescriptBackend: typescript profile not in LANGUAGE_REGISTRY. " + "profiles.ts must be imported before this backend.");
53216
53412
  }
@@ -53222,11 +53418,11 @@ function buildTypescriptBackend() {
53222
53418
  extractImports: extractImports4,
53223
53419
  selectBuildCommand,
53224
53420
  testFilesFor,
53225
- selectFramework: selectFramework3,
53421
+ selectFramework: selectFramework4,
53226
53422
  selectEntryPoints: selectEntryPoints3
53227
53423
  };
53228
53424
  }
53229
- var PROFILE_ID3 = "typescript", IMPORT_REGEX_ES2, IMPORT_REGEX_BARE, IMPORT_REGEX_REQUIRE2, IMPORT_REGEX_DYNAMIC, IMPORT_REGEX_REEXPORT2, _internals28;
53425
+ var PROFILE_ID4 = "typescript", IMPORT_REGEX_ES2, IMPORT_REGEX_BARE, IMPORT_REGEX_REQUIRE2, IMPORT_REGEX_DYNAMIC, IMPORT_REGEX_REEXPORT2, _internals28;
53230
53426
  var init_typescript = __esm(() => {
53231
53427
  init_default_backend();
53232
53428
  init_profiles();
@@ -53249,12 +53445,14 @@ function registerAllBackends() {
53249
53445
  LANGUAGE_BACKEND_REGISTRY.register(buildTypescriptBackend());
53250
53446
  LANGUAGE_BACKEND_REGISTRY.register(buildPythonBackend());
53251
53447
  LANGUAGE_BACKEND_REGISTRY.register(buildGoBackend());
53448
+ LANGUAGE_BACKEND_REGISTRY.register(buildPhpBackend());
53252
53449
  registered = true;
53253
53450
  }
53254
53451
  var registered = false;
53255
53452
  var init_backends = __esm(() => {
53256
53453
  init_registry_backend();
53257
53454
  init_go();
53455
+ init_php();
53258
53456
  init_python();
53259
53457
  init_typescript();
53260
53458
  registerAllBackends();
@@ -53268,11 +53466,11 @@ __export(exports_dispatch, {
53268
53466
  clearDispatchCache: () => clearDispatchCache,
53269
53467
  _internals: () => _internals29
53270
53468
  });
53271
- import * as fs22 from "fs";
53272
- import * as path44 from "path";
53469
+ import * as fs23 from "fs";
53470
+ import * as path45 from "path";
53273
53471
  function safeReaddirSet(dir) {
53274
53472
  try {
53275
- return new Set(fs22.readdirSync(dir));
53473
+ return new Set(fs23.readdirSync(dir));
53276
53474
  } catch {
53277
53475
  return new Set;
53278
53476
  }
@@ -53286,14 +53484,14 @@ function manifestHash(dir) {
53286
53484
  if (!entries.has(name))
53287
53485
  continue;
53288
53486
  try {
53289
- const stat4 = fs22.statSync(path44.join(dir, name));
53487
+ const stat4 = fs23.statSync(path45.join(dir, name));
53290
53488
  parts.push(`${name}:${stat4.size}:${stat4.mtimeMs}:${stat4.ino}`);
53291
53489
  } catch {}
53292
53490
  }
53293
53491
  return parts.join("|");
53294
53492
  }
53295
53493
  function findManifestRoot(start) {
53296
- const resolved = path44.resolve(start);
53494
+ const resolved = path45.resolve(start);
53297
53495
  const cached3 = manifestRootCache.get(resolved);
53298
53496
  if (cached3 !== undefined)
53299
53497
  return cached3;
@@ -53312,7 +53510,7 @@ function findManifestRoot(start) {
53312
53510
  return cur;
53313
53511
  }
53314
53512
  }
53315
- const parent = path44.dirname(cur);
53513
+ const parent = path45.dirname(cur);
53316
53514
  if (parent === cur)
53317
53515
  break;
53318
53516
  cur = parent;
@@ -53421,14 +53619,14 @@ var init_dispatch = __esm(() => {
53421
53619
  });
53422
53620
 
53423
53621
  // src/tools/test-runner.ts
53424
- import * as fs23 from "fs";
53425
- import * as path45 from "path";
53622
+ import * as fs24 from "fs";
53623
+ import * as path46 from "path";
53426
53624
  async function estimateFanOut(sourceFiles, cwd) {
53427
53625
  try {
53428
53626
  const impactMap = await loadImpactMap(cwd, { skipRebuild: true });
53429
53627
  const uniqueTestFiles = new Set;
53430
53628
  for (const sourceFile of sourceFiles) {
53431
- const resolvedPath = path45.resolve(cwd, sourceFile);
53629
+ const resolvedPath = path46.resolve(cwd, sourceFile);
53432
53630
  const normalizedPath = resolvedPath.replace(/\\/g, "/");
53433
53631
  const testFiles = impactMap[normalizedPath];
53434
53632
  if (testFiles) {
@@ -53510,19 +53708,19 @@ function hasDevDependency(devDeps, ...patterns) {
53510
53708
  return hasPackageJsonDependency(devDeps, ...patterns);
53511
53709
  }
53512
53710
  function detectGoTest(cwd) {
53513
- return fs23.existsSync(path45.join(cwd, "go.mod")) && isCommandAvailable("go");
53711
+ return fs24.existsSync(path46.join(cwd, "go.mod")) && isCommandAvailable("go");
53514
53712
  }
53515
53713
  function detectJavaMaven(cwd) {
53516
- return fs23.existsSync(path45.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
53714
+ return fs24.existsSync(path46.join(cwd, "pom.xml")) && isCommandAvailable("mvn");
53517
53715
  }
53518
53716
  function detectGradle(cwd) {
53519
- const hasBuildFile = fs23.existsSync(path45.join(cwd, "build.gradle")) || fs23.existsSync(path45.join(cwd, "build.gradle.kts"));
53520
- const hasGradlew = fs23.existsSync(path45.join(cwd, "gradlew")) || fs23.existsSync(path45.join(cwd, "gradlew.bat"));
53717
+ const hasBuildFile = fs24.existsSync(path46.join(cwd, "build.gradle")) || fs24.existsSync(path46.join(cwd, "build.gradle.kts"));
53718
+ const hasGradlew = fs24.existsSync(path46.join(cwd, "gradlew")) || fs24.existsSync(path46.join(cwd, "gradlew.bat"));
53521
53719
  return hasBuildFile && (hasGradlew || isCommandAvailable("gradle"));
53522
53720
  }
53523
53721
  function detectDotnetTest(cwd) {
53524
53722
  try {
53525
- const files = fs23.readdirSync(cwd);
53723
+ const files = fs24.readdirSync(cwd);
53526
53724
  const hasCsproj = files.some((f) => f.endsWith(".csproj"));
53527
53725
  return hasCsproj && isCommandAvailable("dotnet");
53528
53726
  } catch {
@@ -53530,25 +53728,25 @@ function detectDotnetTest(cwd) {
53530
53728
  }
53531
53729
  }
53532
53730
  function detectCTest(cwd) {
53533
- const hasSource = fs23.existsSync(path45.join(cwd, "CMakeLists.txt"));
53534
- const hasBuildCache = fs23.existsSync(path45.join(cwd, "CMakeCache.txt")) || fs23.existsSync(path45.join(cwd, "build", "CMakeCache.txt"));
53731
+ const hasSource = fs24.existsSync(path46.join(cwd, "CMakeLists.txt"));
53732
+ const hasBuildCache = fs24.existsSync(path46.join(cwd, "CMakeCache.txt")) || fs24.existsSync(path46.join(cwd, "build", "CMakeCache.txt"));
53535
53733
  return (hasSource || hasBuildCache) && isCommandAvailable("ctest");
53536
53734
  }
53537
53735
  function detectSwiftTest(cwd) {
53538
- return fs23.existsSync(path45.join(cwd, "Package.swift")) && isCommandAvailable("swift");
53736
+ return fs24.existsSync(path46.join(cwd, "Package.swift")) && isCommandAvailable("swift");
53539
53737
  }
53540
53738
  function detectDartTest(cwd) {
53541
- return fs23.existsSync(path45.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
53739
+ return fs24.existsSync(path46.join(cwd, "pubspec.yaml")) && (isCommandAvailable("dart") || isCommandAvailable("flutter"));
53542
53740
  }
53543
53741
  function detectRSpec(cwd) {
53544
- const hasRSpecFile = fs23.existsSync(path45.join(cwd, ".rspec"));
53545
- const hasGemfile = fs23.existsSync(path45.join(cwd, "Gemfile"));
53546
- const hasSpecDir = fs23.existsSync(path45.join(cwd, "spec"));
53742
+ const hasRSpecFile = fs24.existsSync(path46.join(cwd, ".rspec"));
53743
+ const hasGemfile = fs24.existsSync(path46.join(cwd, "Gemfile"));
53744
+ const hasSpecDir = fs24.existsSync(path46.join(cwd, "spec"));
53547
53745
  const hasRSpec = hasRSpecFile || hasGemfile && hasSpecDir;
53548
53746
  return hasRSpec && (isCommandAvailable("bundle") || isCommandAvailable("rspec"));
53549
53747
  }
53550
53748
  function detectMinitest(cwd) {
53551
- return fs23.existsSync(path45.join(cwd, "test")) && (fs23.existsSync(path45.join(cwd, "Gemfile")) || fs23.existsSync(path45.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
53749
+ return fs24.existsSync(path46.join(cwd, "test")) && (fs24.existsSync(path46.join(cwd, "Gemfile")) || fs24.existsSync(path46.join(cwd, "Rakefile"))) && isCommandAvailable("ruby");
53552
53750
  }
53553
53751
  async function detectTestFrameworkViaDispatch(cwd) {
53554
53752
  try {
@@ -53611,9 +53809,9 @@ async function parseTestOutputViaDispatch(framework, output, baseDir) {
53611
53809
  async function detectTestFramework(cwd) {
53612
53810
  const baseDir = cwd;
53613
53811
  try {
53614
- const packageJsonPath = path45.join(baseDir, "package.json");
53615
- if (fs23.existsSync(packageJsonPath)) {
53616
- const content = fs23.readFileSync(packageJsonPath, "utf-8");
53812
+ const packageJsonPath = path46.join(baseDir, "package.json");
53813
+ if (fs24.existsSync(packageJsonPath)) {
53814
+ const content = fs24.readFileSync(packageJsonPath, "utf-8");
53617
53815
  const pkg = JSON.parse(content);
53618
53816
  const _deps = pkg.dependencies || {};
53619
53817
  const devDeps = pkg.devDependencies || {};
@@ -53632,38 +53830,38 @@ async function detectTestFramework(cwd) {
53632
53830
  return "jest";
53633
53831
  if (hasDevDependency(devDeps, "mocha", "@types/mocha"))
53634
53832
  return "mocha";
53635
- if (fs23.existsSync(path45.join(baseDir, "bun.lockb")) || fs23.existsSync(path45.join(baseDir, "bun.lock"))) {
53833
+ if (fs24.existsSync(path46.join(baseDir, "bun.lockb")) || fs24.existsSync(path46.join(baseDir, "bun.lock"))) {
53636
53834
  if (scripts.test?.includes("bun"))
53637
53835
  return "bun";
53638
53836
  }
53639
53837
  }
53640
53838
  } catch {}
53641
53839
  try {
53642
- const pyprojectTomlPath = path45.join(baseDir, "pyproject.toml");
53643
- const setupCfgPath = path45.join(baseDir, "setup.cfg");
53644
- const requirementsTxtPath = path45.join(baseDir, "requirements.txt");
53645
- if (fs23.existsSync(pyprojectTomlPath)) {
53646
- const content = fs23.readFileSync(pyprojectTomlPath, "utf-8");
53840
+ const pyprojectTomlPath = path46.join(baseDir, "pyproject.toml");
53841
+ const setupCfgPath = path46.join(baseDir, "setup.cfg");
53842
+ const requirementsTxtPath = path46.join(baseDir, "requirements.txt");
53843
+ if (fs24.existsSync(pyprojectTomlPath)) {
53844
+ const content = fs24.readFileSync(pyprojectTomlPath, "utf-8");
53647
53845
  if (content.includes("[tool.pytest"))
53648
53846
  return "pytest";
53649
53847
  if (content.includes("pytest"))
53650
53848
  return "pytest";
53651
53849
  }
53652
- if (fs23.existsSync(setupCfgPath)) {
53653
- const content = fs23.readFileSync(setupCfgPath, "utf-8");
53850
+ if (fs24.existsSync(setupCfgPath)) {
53851
+ const content = fs24.readFileSync(setupCfgPath, "utf-8");
53654
53852
  if (content.includes("[pytest]"))
53655
53853
  return "pytest";
53656
53854
  }
53657
- if (fs23.existsSync(requirementsTxtPath)) {
53658
- const content = fs23.readFileSync(requirementsTxtPath, "utf-8");
53855
+ if (fs24.existsSync(requirementsTxtPath)) {
53856
+ const content = fs24.readFileSync(requirementsTxtPath, "utf-8");
53659
53857
  if (content.includes("pytest"))
53660
53858
  return "pytest";
53661
53859
  }
53662
53860
  } catch {}
53663
53861
  try {
53664
- const cargoTomlPath = path45.join(baseDir, "Cargo.toml");
53665
- if (fs23.existsSync(cargoTomlPath)) {
53666
- const content = fs23.readFileSync(cargoTomlPath, "utf-8");
53862
+ const cargoTomlPath = path46.join(baseDir, "Cargo.toml");
53863
+ if (fs24.existsSync(cargoTomlPath)) {
53864
+ const content = fs24.readFileSync(cargoTomlPath, "utf-8");
53667
53865
  if (content.includes("[dev-dependencies]")) {
53668
53866
  if (content.includes("tokio") || content.includes("mockall") || content.includes("pretty_assertions")) {
53669
53867
  return "cargo";
@@ -53672,10 +53870,10 @@ async function detectTestFramework(cwd) {
53672
53870
  }
53673
53871
  } catch {}
53674
53872
  try {
53675
- const pesterConfigPath = path45.join(baseDir, "pester.config.ps1");
53676
- const pesterConfigJsonPath = path45.join(baseDir, "pester.config.ps1.json");
53677
- const pesterPs1Path = path45.join(baseDir, "tests.ps1");
53678
- if (fs23.existsSync(pesterConfigPath) || fs23.existsSync(pesterConfigJsonPath) || fs23.existsSync(pesterPs1Path)) {
53873
+ const pesterConfigPath = path46.join(baseDir, "pester.config.ps1");
53874
+ const pesterConfigJsonPath = path46.join(baseDir, "pester.config.ps1.json");
53875
+ const pesterPs1Path = path46.join(baseDir, "tests.ps1");
53876
+ if (fs24.existsSync(pesterConfigPath) || fs24.existsSync(pesterConfigJsonPath) || fs24.existsSync(pesterPs1Path)) {
53679
53877
  return "pester";
53680
53878
  }
53681
53879
  } catch {}
@@ -53703,12 +53901,12 @@ function isTestDirectoryPath(normalizedPath) {
53703
53901
  return normalizedPath.split("/").some((segment) => TEST_DIRECTORY_NAMES.includes(segment));
53704
53902
  }
53705
53903
  function resolveWorkspacePath(file3, workingDir) {
53706
- return path45.isAbsolute(file3) ? path45.resolve(file3) : path45.resolve(workingDir, file3);
53904
+ return path46.isAbsolute(file3) ? path46.resolve(file3) : path46.resolve(workingDir, file3);
53707
53905
  }
53708
53906
  function toWorkspaceOutputPath(absolutePath, workingDir, preferRelative) {
53709
53907
  if (!preferRelative)
53710
53908
  return absolutePath;
53711
- return path45.relative(workingDir, absolutePath);
53909
+ return path46.relative(workingDir, absolutePath);
53712
53910
  }
53713
53911
  function dedupePush(target, value) {
53714
53912
  if (!target.includes(value)) {
@@ -53745,18 +53943,18 @@ function buildLanguageSpecificTestNames(nameWithoutExt, ext) {
53745
53943
  }
53746
53944
  }
53747
53945
  function getRepoLevelCandidateDirectories(workingDir, relativePath, ext) {
53748
- const relativeDir = path45.dirname(relativePath);
53946
+ const relativeDir = path46.dirname(relativePath);
53749
53947
  const nestedRelativeDir = relativeDir === "." ? "" : relativeDir;
53750
53948
  const directories = TEST_DIRECTORY_NAMES.flatMap((dirName) => {
53751
- const rootDir = path45.join(workingDir, dirName);
53752
- return nestedRelativeDir ? [rootDir, path45.join(rootDir, nestedRelativeDir)] : [rootDir];
53949
+ const rootDir = path46.join(workingDir, dirName);
53950
+ return nestedRelativeDir ? [rootDir, path46.join(rootDir, nestedRelativeDir)] : [rootDir];
53753
53951
  });
53754
53952
  const normalizedRelativePath = relativePath.replace(/\\/g, "/");
53755
53953
  if (ext === ".java" && normalizedRelativePath.startsWith("src/main/java/")) {
53756
- directories.push(path45.join(workingDir, "src/test/java", path45.dirname(normalizedRelativePath.slice("src/main/java/".length))));
53954
+ directories.push(path46.join(workingDir, "src/test/java", path46.dirname(normalizedRelativePath.slice("src/main/java/".length))));
53757
53955
  }
53758
53956
  if ((ext === ".kt" || ext === ".java") && normalizedRelativePath.startsWith("src/main/kotlin/")) {
53759
- directories.push(path45.join(workingDir, "src/test/kotlin", path45.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
53957
+ directories.push(path46.join(workingDir, "src/test/kotlin", path46.dirname(normalizedRelativePath.slice("src/main/kotlin/".length))));
53760
53958
  }
53761
53959
  return [...new Set(directories)];
53762
53960
  }
@@ -53784,23 +53982,23 @@ function isLanguageSpecificTestFile(basename7) {
53784
53982
  }
53785
53983
  function isConventionTestFilePath(filePath) {
53786
53984
  const normalizedPath = filePath.replace(/\\/g, "/");
53787
- const basename7 = path45.basename(filePath);
53985
+ const basename7 = path46.basename(filePath);
53788
53986
  return hasCompoundTestExtension(basename7) || basename7.includes(".spec.") || basename7.includes(".test.") || isLanguageSpecificTestFile(basename7) || isTestDirectoryPath(normalizedPath);
53789
53987
  }
53790
53988
  function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
53791
53989
  const testFiles = [];
53792
53990
  for (const file3 of sourceFiles) {
53793
53991
  const absoluteFile = resolveWorkspacePath(file3, workingDir);
53794
- const relativeFile = path45.relative(workingDir, absoluteFile);
53795
- const basename7 = path45.basename(absoluteFile);
53796
- const dirname23 = path45.dirname(absoluteFile);
53797
- const preferRelativeOutput = !path45.isAbsolute(file3);
53992
+ const relativeFile = path46.relative(workingDir, absoluteFile);
53993
+ const basename7 = path46.basename(absoluteFile);
53994
+ const dirname23 = path46.dirname(absoluteFile);
53995
+ const preferRelativeOutput = !path46.isAbsolute(file3);
53798
53996
  if (isConventionTestFilePath(relativeFile) || isConventionTestFilePath(file3)) {
53799
53997
  dedupePush(testFiles, toWorkspaceOutputPath(absoluteFile, workingDir, preferRelativeOutput));
53800
53998
  continue;
53801
53999
  }
53802
54000
  const nameWithoutExt = basename7.replace(/\.[^.]+$/, "");
53803
- const ext = path45.extname(basename7);
54001
+ const ext = path46.extname(basename7);
53804
54002
  const genericTestNames = [
53805
54003
  `${nameWithoutExt}.spec${ext}`,
53806
54004
  `${nameWithoutExt}.test${ext}`
@@ -53809,7 +54007,7 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
53809
54007
  const colocatedCandidates = [
53810
54008
  ...genericTestNames,
53811
54009
  ...languageSpecificTestNames
53812
- ].map((candidateName) => path45.join(dirname23, candidateName));
54010
+ ].map((candidateName) => path46.join(dirname23, candidateName));
53813
54011
  const testDirectoryNames = [
53814
54012
  basename7,
53815
54013
  ...genericTestNames,
@@ -53818,11 +54016,11 @@ function getTestFilesFromConvention(sourceFiles, workingDir = process.cwd()) {
53818
54016
  const repoLevelDirectories = getRepoLevelCandidateDirectories(workingDir, relativeFile, ext);
53819
54017
  const possibleTestFiles = [
53820
54018
  ...colocatedCandidates,
53821
- ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path45.join(dirname23, dirName, candidateName))),
53822
- ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path45.join(candidateDir, candidateName)))
54019
+ ...TEST_DIRECTORY_NAMES.flatMap((dirName) => testDirectoryNames.map((candidateName) => path46.join(dirname23, dirName, candidateName))),
54020
+ ...repoLevelDirectories.flatMap((candidateDir) => testDirectoryNames.map((candidateName) => path46.join(candidateDir, candidateName)))
53823
54021
  ];
53824
54022
  for (const testFile of possibleTestFiles) {
53825
- if (fs23.existsSync(testFile)) {
54023
+ if (fs24.existsSync(testFile)) {
53826
54024
  dedupePush(testFiles, toWorkspaceOutputPath(testFile, workingDir, preferRelativeOutput));
53827
54025
  }
53828
54026
  }
@@ -53839,8 +54037,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
53839
54037
  for (const testFile of candidateTestFiles) {
53840
54038
  try {
53841
54039
  const absoluteTestFile = resolveWorkspacePath(testFile, workingDir);
53842
- const content = fs23.readFileSync(absoluteTestFile, "utf-8");
53843
- const testDir = path45.dirname(absoluteTestFile);
54040
+ const content = fs24.readFileSync(absoluteTestFile, "utf-8");
54041
+ const testDir = path46.dirname(absoluteTestFile);
53844
54042
  const importRegex = /import\s+.*?\s+from\s+['"]([^'"]+)['"]/g;
53845
54043
  let match;
53846
54044
  match = importRegex.exec(content);
@@ -53848,8 +54046,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
53848
54046
  const importPath = match[1];
53849
54047
  let resolvedImport;
53850
54048
  if (importPath.startsWith(".")) {
53851
- resolvedImport = path45.resolve(testDir, importPath);
53852
- const existingExt = path45.extname(resolvedImport);
54049
+ resolvedImport = path46.resolve(testDir, importPath);
54050
+ const existingExt = path46.extname(resolvedImport);
53853
54051
  if (!existingExt) {
53854
54052
  for (const extToTry of [
53855
54053
  ".ts",
@@ -53860,7 +54058,7 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
53860
54058
  ".cjs"
53861
54059
  ]) {
53862
54060
  const withExt = resolvedImport + extToTry;
53863
- if (absoluteSourceFiles.includes(withExt) || fs23.existsSync(withExt)) {
54061
+ if (absoluteSourceFiles.includes(withExt) || fs24.existsSync(withExt)) {
53864
54062
  resolvedImport = withExt;
53865
54063
  break;
53866
54064
  }
@@ -53869,12 +54067,12 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
53869
54067
  } else {
53870
54068
  continue;
53871
54069
  }
53872
- const importBasename = path45.basename(resolvedImport, path45.extname(resolvedImport));
53873
- const importDir = path45.dirname(resolvedImport);
54070
+ const importBasename = path46.basename(resolvedImport, path46.extname(resolvedImport));
54071
+ const importDir = path46.dirname(resolvedImport);
53874
54072
  for (const sourceFile of absoluteSourceFiles) {
53875
- const sourceDir = path45.dirname(sourceFile);
53876
- const sourceBasename = path45.basename(sourceFile, path45.extname(sourceFile));
53877
- const isRelatedDir = importDir === sourceDir || importDir === path45.join(sourceDir, "__tests__") || importDir === path45.join(sourceDir, "tests") || importDir === path45.join(sourceDir, "test") || importDir === path45.join(sourceDir, "spec");
54073
+ const sourceDir = path46.dirname(sourceFile);
54074
+ const sourceBasename = path46.basename(sourceFile, path46.extname(sourceFile));
54075
+ const isRelatedDir = importDir === sourceDir || importDir === path46.join(sourceDir, "__tests__") || importDir === path46.join(sourceDir, "tests") || importDir === path46.join(sourceDir, "test") || importDir === path46.join(sourceDir, "spec");
53878
54076
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
53879
54077
  dedupePush(testFiles, testFile);
53880
54078
  break;
@@ -53887,8 +54085,8 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
53887
54085
  while (match !== null) {
53888
54086
  const importPath = match[1];
53889
54087
  if (importPath.startsWith(".")) {
53890
- let resolvedImport = path45.resolve(testDir, importPath);
53891
- const existingExt = path45.extname(resolvedImport);
54088
+ let resolvedImport = path46.resolve(testDir, importPath);
54089
+ const existingExt = path46.extname(resolvedImport);
53892
54090
  if (!existingExt) {
53893
54091
  for (const extToTry of [
53894
54092
  ".ts",
@@ -53899,18 +54097,18 @@ async function getTestFilesFromGraph(sourceFiles, workingDir) {
53899
54097
  ".cjs"
53900
54098
  ]) {
53901
54099
  const withExt = resolvedImport + extToTry;
53902
- if (absoluteSourceFiles.includes(withExt) || fs23.existsSync(withExt)) {
54100
+ if (absoluteSourceFiles.includes(withExt) || fs24.existsSync(withExt)) {
53903
54101
  resolvedImport = withExt;
53904
54102
  break;
53905
54103
  }
53906
54104
  }
53907
54105
  }
53908
- const importDir = path45.dirname(resolvedImport);
53909
- const importBasename = path45.basename(resolvedImport, path45.extname(resolvedImport));
54106
+ const importDir = path46.dirname(resolvedImport);
54107
+ const importBasename = path46.basename(resolvedImport, path46.extname(resolvedImport));
53910
54108
  for (const sourceFile of absoluteSourceFiles) {
53911
- const sourceDir = path45.dirname(sourceFile);
53912
- const sourceBasename = path45.basename(sourceFile, path45.extname(sourceFile));
53913
- const isRelatedDir = importDir === sourceDir || importDir === path45.join(sourceDir, "__tests__") || importDir === path45.join(sourceDir, "tests") || importDir === path45.join(sourceDir, "test") || importDir === path45.join(sourceDir, "spec");
54109
+ const sourceDir = path46.dirname(sourceFile);
54110
+ const sourceBasename = path46.basename(sourceFile, path46.extname(sourceFile));
54111
+ const isRelatedDir = importDir === sourceDir || importDir === path46.join(sourceDir, "__tests__") || importDir === path46.join(sourceDir, "tests") || importDir === path46.join(sourceDir, "test") || importDir === path46.join(sourceDir, "spec");
53914
54112
  if (resolvedImport === sourceFile || importBasename === sourceBasename && isRelatedDir) {
53915
54113
  dedupePush(testFiles, testFile);
53916
54114
  break;
@@ -54030,8 +54228,8 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir, bail) {
54030
54228
  return ["mvn", "test"];
54031
54229
  case "gradle": {
54032
54230
  const isWindows = process.platform === "win32";
54033
- const hasGradlewBat = fs23.existsSync(path45.join(baseDir, "gradlew.bat"));
54034
- const hasGradlew = fs23.existsSync(path45.join(baseDir, "gradlew"));
54231
+ const hasGradlewBat = fs24.existsSync(path46.join(baseDir, "gradlew.bat"));
54232
+ const hasGradlew = fs24.existsSync(path46.join(baseDir, "gradlew"));
54035
54233
  if (hasGradlewBat && isWindows)
54036
54234
  return ["gradlew.bat", "test"];
54037
54235
  if (hasGradlew)
@@ -54048,7 +54246,7 @@ function buildTestCommand2(framework, scope, files, coverage, baseDir, bail) {
54048
54246
  "cmake-build-release",
54049
54247
  "out"
54050
54248
  ];
54051
- const actualBuildDir = buildDirCandidates.find((d) => fs23.existsSync(path45.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
54249
+ const actualBuildDir = buildDirCandidates.find((d) => fs24.existsSync(path46.join(baseDir, d, "CMakeCache.txt"))) ?? "build";
54052
54250
  return ["ctest", "--test-dir", actualBuildDir];
54053
54251
  }
54054
54252
  case "swift-test":
@@ -54482,13 +54680,13 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
54482
54680
  };
54483
54681
  }
54484
54682
  const startTime = Date.now();
54485
- const vitestJsonOutputPath = framework === "vitest" ? path45.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
54683
+ const vitestJsonOutputPath = framework === "vitest" ? path46.join(cwd, ".swarm", "cache", "test-runner-vitest.json") : undefined;
54486
54684
  try {
54487
54685
  if (vitestJsonOutputPath) {
54488
54686
  try {
54489
- fs23.mkdirSync(path45.dirname(vitestJsonOutputPath), { recursive: true });
54490
- if (fs23.existsSync(vitestJsonOutputPath)) {
54491
- fs23.unlinkSync(vitestJsonOutputPath);
54687
+ fs24.mkdirSync(path46.dirname(vitestJsonOutputPath), { recursive: true });
54688
+ if (fs24.existsSync(vitestJsonOutputPath)) {
54689
+ fs24.unlinkSync(vitestJsonOutputPath);
54492
54690
  }
54493
54691
  } catch {}
54494
54692
  }
@@ -54514,8 +54712,8 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
54514
54712
  }
54515
54713
  if (vitestJsonOutputPath) {
54516
54714
  try {
54517
- if (fs23.existsSync(vitestJsonOutputPath)) {
54518
- const vitestJsonOutput = fs23.readFileSync(vitestJsonOutputPath, "utf-8");
54715
+ if (fs24.existsSync(vitestJsonOutputPath)) {
54716
+ const vitestJsonOutput = fs24.readFileSync(vitestJsonOutputPath, "utf-8");
54519
54717
  if (vitestJsonOutput.trim().length > 0) {
54520
54718
  output += (output ? `
54521
54719
  ` : "") + vitestJsonOutput;
@@ -54602,10 +54800,10 @@ async function runTests(framework, scope, files, coverage, timeout_ms, cwd, bail
54602
54800
  }
54603
54801
  function normalizeHistoryTestFile(testFile, workingDir) {
54604
54802
  const normalized = testFile.replace(/\\/g, "/");
54605
- if (!path45.isAbsolute(testFile))
54803
+ if (!path46.isAbsolute(testFile))
54606
54804
  return normalized;
54607
- const relative9 = path45.relative(workingDir, testFile);
54608
- if (relative9.startsWith("..") || path45.isAbsolute(relative9)) {
54805
+ const relative9 = path46.relative(workingDir, testFile);
54806
+ if (relative9.startsWith("..") || path46.isAbsolute(relative9)) {
54609
54807
  return normalized;
54610
54808
  }
54611
54809
  return relative9.replace(/\\/g, "/");
@@ -54712,28 +54910,26 @@ var init_test_runner = __esm(() => {
54712
54910
  init_resolve_working_directory();
54713
54911
  POWERSHELL_METACHARACTERS = /[|;&`$(){}[\]<>"'#*?\x00-\x1f]/;
54714
54912
  DISPATCH_FRAMEWORK_MAP = {
54715
- "bun:test": "bun",
54716
54913
  bun: "bun",
54717
54914
  vitest: "vitest",
54718
54915
  jest: "jest",
54719
54916
  mocha: "mocha",
54720
54917
  pytest: "pytest",
54721
- "cargo test": "cargo",
54722
54918
  cargo: "cargo",
54723
54919
  pester: "pester",
54724
- "go test": "go-test",
54725
- "maven-test": "maven",
54726
- "gradle-test": "gradle",
54727
- "gradle-test-groovy": "gradle",
54728
- "gradle-kts": "gradle",
54729
- "dotnet test": "dotnet-test",
54920
+ "go-test": "go-test",
54921
+ maven: "maven",
54922
+ gradle: "gradle",
54923
+ "dotnet-test": "dotnet-test",
54730
54924
  ctest: "ctest",
54731
- "swift test": "swift-test",
54925
+ "swift-test": "swift-test",
54926
+ "dart-test": "dart-test",
54927
+ rspec: "rspec",
54928
+ minitest: "minitest",
54929
+ "bun:test": "bun",
54732
54930
  "xcodebuild-test": "swift-test",
54733
54931
  "flutter test": "dart-test",
54734
- "dart test": "dart-test",
54735
- rspec: "rspec",
54736
- minitest: "minitest"
54932
+ "dart test": "dart-test"
54737
54933
  };
54738
54934
  COMPOUND_TEST_EXTENSIONS = [
54739
54935
  ".test.ts",
@@ -54945,7 +55141,7 @@ var init_test_runner = __esm(() => {
54945
55141
  const sourceFiles = args.files.filter((file3) => {
54946
55142
  if (directTestFiles.includes(file3))
54947
55143
  return false;
54948
- const ext = path45.extname(file3).toLowerCase();
55144
+ const ext = path46.extname(file3).toLowerCase();
54949
55145
  return SOURCE_EXTENSIONS.has(ext);
54950
55146
  });
54951
55147
  const invalidFiles = args.files.filter((file3) => !directTestFiles.includes(file3) && !sourceFiles.includes(file3));
@@ -54991,7 +55187,7 @@ var init_test_runner = __esm(() => {
54991
55187
  if (isConventionTestFilePath(f)) {
54992
55188
  return false;
54993
55189
  }
54994
- const ext = path45.extname(f).toLowerCase();
55190
+ const ext = path46.extname(f).toLowerCase();
54995
55191
  return SOURCE_EXTENSIONS.has(ext);
54996
55192
  });
54997
55193
  if (sourceFiles.length === 0) {
@@ -55041,7 +55237,7 @@ var init_test_runner = __esm(() => {
55041
55237
  if (isConventionTestFilePath(f)) {
55042
55238
  return false;
55043
55239
  }
55044
- const ext = path45.extname(f).toLowerCase();
55240
+ const ext = path46.extname(f).toLowerCase();
55045
55241
  return SOURCE_EXTENSIONS.has(ext);
55046
55242
  });
55047
55243
  if (sourceFiles.length === 0) {
@@ -55093,8 +55289,8 @@ var init_test_runner = __esm(() => {
55093
55289
  }
55094
55290
  if (impactResult.impactedTests.length > 0) {
55095
55291
  testFiles = impactResult.impactedTests.map((absPath) => {
55096
- const relativePath = path45.relative(workingDir, absPath);
55097
- return path45.isAbsolute(relativePath) ? absPath : relativePath;
55292
+ const relativePath = path46.relative(workingDir, absPath);
55293
+ return path46.isAbsolute(relativePath) ? absPath : relativePath;
55098
55294
  });
55099
55295
  } else {
55100
55296
  graphFallbackReason = "no impacted tests found via impact analysis, falling back to graph";
@@ -55172,8 +55368,8 @@ var init_test_runner = __esm(() => {
55172
55368
  });
55173
55369
 
55174
55370
  // src/services/preflight-service.ts
55175
- import * as fs24 from "fs";
55176
- import * as path46 from "path";
55371
+ import * as fs25 from "fs";
55372
+ import * as path47 from "path";
55177
55373
  function validateDirectoryPath(dir) {
55178
55374
  if (!dir || typeof dir !== "string") {
55179
55375
  throw new Error("Directory path is required");
@@ -55181,8 +55377,8 @@ function validateDirectoryPath(dir) {
55181
55377
  if (dir.includes("..")) {
55182
55378
  throw new Error("Directory path must not contain path traversal sequences");
55183
55379
  }
55184
- const normalized = path46.normalize(dir);
55185
- const absolutePath = path46.isAbsolute(normalized) ? normalized : path46.resolve(normalized);
55380
+ const normalized = path47.normalize(dir);
55381
+ const absolutePath = path47.isAbsolute(normalized) ? normalized : path47.resolve(normalized);
55186
55382
  return absolutePath;
55187
55383
  }
55188
55384
  function validateTimeout(timeoutMs, defaultValue) {
@@ -55205,9 +55401,9 @@ function validateTimeout(timeoutMs, defaultValue) {
55205
55401
  }
55206
55402
  function getPackageVersion(dir) {
55207
55403
  try {
55208
- const packagePath = path46.join(dir, "package.json");
55209
- if (fs24.existsSync(packagePath)) {
55210
- const content = fs24.readFileSync(packagePath, "utf-8");
55404
+ const packagePath = path47.join(dir, "package.json");
55405
+ if (fs25.existsSync(packagePath)) {
55406
+ const content = fs25.readFileSync(packagePath, "utf-8");
55211
55407
  const pkg = JSON.parse(content);
55212
55408
  return pkg.version ?? null;
55213
55409
  }
@@ -55216,9 +55412,9 @@ function getPackageVersion(dir) {
55216
55412
  }
55217
55413
  function getChangelogVersion(dir) {
55218
55414
  try {
55219
- const changelogPath = path46.join(dir, "CHANGELOG.md");
55220
- if (fs24.existsSync(changelogPath)) {
55221
- const content = fs24.readFileSync(changelogPath, "utf-8");
55415
+ const changelogPath = path47.join(dir, "CHANGELOG.md");
55416
+ if (fs25.existsSync(changelogPath)) {
55417
+ const content = fs25.readFileSync(changelogPath, "utf-8");
55222
55418
  const match = content.match(/^##\s*\[?(\d+\.\d+\.\d+)\]?/m);
55223
55419
  if (match) {
55224
55420
  return match[1];
@@ -55230,10 +55426,10 @@ function getChangelogVersion(dir) {
55230
55426
  function getVersionFileVersion(dir) {
55231
55427
  const possibleFiles = ["VERSION.txt", "version.txt", "VERSION", "version"];
55232
55428
  for (const file3 of possibleFiles) {
55233
- const filePath = path46.join(dir, file3);
55234
- if (fs24.existsSync(filePath)) {
55429
+ const filePath = path47.join(dir, file3);
55430
+ if (fs25.existsSync(filePath)) {
55235
55431
  try {
55236
- const content = fs24.readFileSync(filePath, "utf-8").trim();
55432
+ const content = fs25.readFileSync(filePath, "utf-8").trim();
55237
55433
  const match = content.match(/(\d+\.\d+\.\d+)/);
55238
55434
  if (match) {
55239
55435
  return match[1];
@@ -55572,8 +55768,8 @@ async function runEvidenceCheck(dir) {
55572
55768
  async function runRequirementCoverageCheck(dir, currentPhase) {
55573
55769
  const startTime = Date.now();
55574
55770
  try {
55575
- const specPath = path46.join(dir, ".swarm", "spec.md");
55576
- if (!fs24.existsSync(specPath)) {
55771
+ const specPath = path47.join(dir, ".swarm", "spec.md");
55772
+ if (!fs25.existsSync(specPath)) {
55577
55773
  return {
55578
55774
  type: "req_coverage",
55579
55775
  status: "skip",
@@ -56689,8 +56885,8 @@ var init_manager3 = __esm(() => {
56689
56885
  });
56690
56886
 
56691
56887
  // src/commands/reset.ts
56692
- import * as fs25 from "fs";
56693
- import * as path47 from "path";
56888
+ import * as fs26 from "fs";
56889
+ import * as path48 from "path";
56694
56890
  async function handleResetCommand(directory, args) {
56695
56891
  const hasConfirm = args.includes("--confirm");
56696
56892
  if (!hasConfirm) {
@@ -56718,8 +56914,8 @@ async function handleResetCommand(directory, args) {
56718
56914
  for (const filename of filesToReset) {
56719
56915
  try {
56720
56916
  const resolvedPath = validateSwarmPath(directory, filename);
56721
- if (fs25.existsSync(resolvedPath)) {
56722
- fs25.unlinkSync(resolvedPath);
56917
+ if (fs26.existsSync(resolvedPath)) {
56918
+ fs26.unlinkSync(resolvedPath);
56723
56919
  results.push(`- \u2705 Deleted ${filename}`);
56724
56920
  } else {
56725
56921
  results.push(`- \u23ED\uFE0F ${filename} not found (skipped)`);
@@ -56730,9 +56926,9 @@ async function handleResetCommand(directory, args) {
56730
56926
  }
56731
56927
  for (const filename of ["SWARM_PLAN.md", "SWARM_PLAN.json"]) {
56732
56928
  try {
56733
- const rootPath = path47.join(directory, filename);
56734
- if (fs25.existsSync(rootPath)) {
56735
- fs25.unlinkSync(rootPath);
56929
+ const rootPath = path48.join(directory, filename);
56930
+ if (fs26.existsSync(rootPath)) {
56931
+ fs26.unlinkSync(rootPath);
56736
56932
  results.push(`- \u2705 Deleted ${filename} (root)`);
56737
56933
  }
56738
56934
  } catch {}
@@ -56745,8 +56941,8 @@ async function handleResetCommand(directory, args) {
56745
56941
  }
56746
56942
  try {
56747
56943
  const summariesPath = validateSwarmPath(directory, "summaries");
56748
- if (fs25.existsSync(summariesPath)) {
56749
- fs25.rmSync(summariesPath, { recursive: true, force: true });
56944
+ if (fs26.existsSync(summariesPath)) {
56945
+ fs26.rmSync(summariesPath, { recursive: true, force: true });
56750
56946
  results.push("- \u2705 Deleted summaries/ directory");
56751
56947
  } else {
56752
56948
  results.push("- \u23ED\uFE0F summaries/ not found (skipped)");
@@ -56769,14 +56965,14 @@ var init_reset = __esm(() => {
56769
56965
  });
56770
56966
 
56771
56967
  // src/commands/reset-session.ts
56772
- import * as fs26 from "fs";
56773
- import * as path48 from "path";
56968
+ import * as fs27 from "fs";
56969
+ import * as path49 from "path";
56774
56970
  async function handleResetSessionCommand(directory, _args) {
56775
56971
  const results = [];
56776
56972
  try {
56777
56973
  const statePath = validateSwarmPath(directory, "session/state.json");
56778
- if (fs26.existsSync(statePath)) {
56779
- fs26.unlinkSync(statePath);
56974
+ if (fs27.existsSync(statePath)) {
56975
+ fs27.unlinkSync(statePath);
56780
56976
  results.push("\u2705 Deleted .swarm/session/state.json");
56781
56977
  } else {
56782
56978
  results.push("\u23ED\uFE0F state.json not found (already clean)");
@@ -56785,15 +56981,15 @@ async function handleResetSessionCommand(directory, _args) {
56785
56981
  results.push("\u274C Failed to delete state.json");
56786
56982
  }
56787
56983
  try {
56788
- const sessionDir = path48.dirname(validateSwarmPath(directory, "session/state.json"));
56789
- if (fs26.existsSync(sessionDir)) {
56790
- const files = fs26.readdirSync(sessionDir);
56984
+ const sessionDir = path49.dirname(validateSwarmPath(directory, "session/state.json"));
56985
+ if (fs27.existsSync(sessionDir)) {
56986
+ const files = fs27.readdirSync(sessionDir);
56791
56987
  const otherFiles = files.filter((f) => f !== "state.json");
56792
56988
  let deletedCount = 0;
56793
56989
  for (const file3 of otherFiles) {
56794
- const filePath = path48.join(sessionDir, file3);
56795
- if (fs26.lstatSync(filePath).isFile()) {
56796
- fs26.unlinkSync(filePath);
56990
+ const filePath = path49.join(sessionDir, file3);
56991
+ if (fs27.lstatSync(filePath).isFile()) {
56992
+ fs27.unlinkSync(filePath);
56797
56993
  deletedCount++;
56798
56994
  }
56799
56995
  }
@@ -56823,7 +57019,7 @@ var init_reset_session = __esm(() => {
56823
57019
  });
56824
57020
 
56825
57021
  // src/summaries/manager.ts
56826
- import * as path49 from "path";
57022
+ import * as path50 from "path";
56827
57023
  function sanitizeSummaryId(id) {
56828
57024
  if (!id || id.length === 0) {
56829
57025
  throw new Error("Invalid summary ID: empty string");
@@ -56846,7 +57042,7 @@ function sanitizeSummaryId(id) {
56846
57042
  }
56847
57043
  async function loadFullOutput(directory, id) {
56848
57044
  const sanitizedId = sanitizeSummaryId(id);
56849
- const relativePath = path49.join("summaries", `${sanitizedId}.json`);
57045
+ const relativePath = path50.join("summaries", `${sanitizedId}.json`);
56850
57046
  validateSwarmPath(directory, relativePath);
56851
57047
  const content = await readSwarmFileAsync(directory, relativePath);
56852
57048
  if (content === null) {
@@ -56908,18 +57104,18 @@ var init_retrieve = __esm(() => {
56908
57104
  });
56909
57105
 
56910
57106
  // src/commands/rollback.ts
56911
- import * as fs27 from "fs";
56912
- import * as path50 from "path";
57107
+ import * as fs28 from "fs";
57108
+ import * as path51 from "path";
56913
57109
  async function handleRollbackCommand(directory, args) {
56914
57110
  const phaseArg = args[0];
56915
57111
  if (!phaseArg) {
56916
57112
  const manifestPath2 = validateSwarmPath(directory, "checkpoints/manifest.json");
56917
- if (!fs27.existsSync(manifestPath2)) {
57113
+ if (!fs28.existsSync(manifestPath2)) {
56918
57114
  return "No checkpoints found. Use `/swarm checkpoint` to create checkpoints.";
56919
57115
  }
56920
57116
  let manifest2;
56921
57117
  try {
56922
- manifest2 = JSON.parse(fs27.readFileSync(manifestPath2, "utf-8"));
57118
+ manifest2 = JSON.parse(fs28.readFileSync(manifestPath2, "utf-8"));
56923
57119
  } catch {
56924
57120
  return "Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.";
56925
57121
  }
@@ -56941,12 +57137,12 @@ async function handleRollbackCommand(directory, args) {
56941
57137
  return "Error: Phase number must be a positive integer.";
56942
57138
  }
56943
57139
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
56944
- if (!fs27.existsSync(manifestPath)) {
57140
+ if (!fs28.existsSync(manifestPath)) {
56945
57141
  return `Error: No checkpoints found. Cannot rollback to phase ${targetPhase}.`;
56946
57142
  }
56947
57143
  let manifest;
56948
57144
  try {
56949
- manifest = JSON.parse(fs27.readFileSync(manifestPath, "utf-8"));
57145
+ manifest = JSON.parse(fs28.readFileSync(manifestPath, "utf-8"));
56950
57146
  } catch {
56951
57147
  return `Error: Checkpoint manifest is corrupted. Delete .swarm/checkpoints/manifest.json and re-checkpoint.`;
56952
57148
  }
@@ -56956,10 +57152,10 @@ async function handleRollbackCommand(directory, args) {
56956
57152
  return `Error: Checkpoint for phase ${targetPhase} not found. Available phases: ${available}`;
56957
57153
  }
56958
57154
  const checkpointDir = validateSwarmPath(directory, `checkpoints/phase-${targetPhase}`);
56959
- if (!fs27.existsSync(checkpointDir)) {
57155
+ if (!fs28.existsSync(checkpointDir)) {
56960
57156
  return `Error: Checkpoint directory for phase ${targetPhase} does not exist.`;
56961
57157
  }
56962
- const checkpointFiles = fs27.readdirSync(checkpointDir);
57158
+ const checkpointFiles = fs28.readdirSync(checkpointDir);
56963
57159
  if (checkpointFiles.length === 0) {
56964
57160
  return `Error: Checkpoint for phase ${targetPhase} is empty. Cannot rollback.`;
56965
57161
  }
@@ -56974,10 +57170,10 @@ async function handleRollbackCommand(directory, args) {
56974
57170
  if (EXCLUDE_FILES.has(file3) || file3.startsWith("plan-ledger.archived-")) {
56975
57171
  continue;
56976
57172
  }
56977
- const src = path50.join(checkpointDir, file3);
56978
- const dest = path50.join(swarmDir, file3);
57173
+ const src = path51.join(checkpointDir, file3);
57174
+ const dest = path51.join(swarmDir, file3);
56979
57175
  try {
56980
- fs27.cpSync(src, dest, { recursive: true, force: true });
57176
+ fs28.cpSync(src, dest, { recursive: true, force: true });
56981
57177
  successes.push(file3);
56982
57178
  } catch (error93) {
56983
57179
  failures.push({ file: file3, error: error93.message });
@@ -56994,14 +57190,14 @@ async function handleRollbackCommand(directory, args) {
56994
57190
  ].join(`
56995
57191
  `);
56996
57192
  }
56997
- const existingLedgerPath = path50.join(swarmDir, "plan-ledger.jsonl");
56998
- if (fs27.existsSync(existingLedgerPath)) {
56999
- fs27.unlinkSync(existingLedgerPath);
57193
+ const existingLedgerPath = path51.join(swarmDir, "plan-ledger.jsonl");
57194
+ if (fs28.existsSync(existingLedgerPath)) {
57195
+ fs28.unlinkSync(existingLedgerPath);
57000
57196
  }
57001
57197
  try {
57002
- const planJsonPath = path50.join(swarmDir, "plan.json");
57003
- if (fs27.existsSync(planJsonPath)) {
57004
- const planRaw = fs27.readFileSync(planJsonPath, "utf-8");
57198
+ const planJsonPath = path51.join(swarmDir, "plan.json");
57199
+ if (fs28.existsSync(planJsonPath)) {
57200
+ const planRaw = fs28.readFileSync(planJsonPath, "utf-8");
57005
57201
  const plan = PlanSchema.parse(JSON.parse(planRaw));
57006
57202
  const planId = derivePlanId(plan);
57007
57203
  const planHash = computePlanHash(plan);
@@ -57028,7 +57224,7 @@ async function handleRollbackCommand(directory, args) {
57028
57224
  timestamp: new Date().toISOString()
57029
57225
  };
57030
57226
  try {
57031
- fs27.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
57227
+ fs28.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
57032
57228
  `);
57033
57229
  } catch (error93) {
57034
57230
  console.error("Failed to write rollback event:", error93 instanceof Error ? error93.message : String(error93));
@@ -57089,11 +57285,11 @@ Ensure this is a git repository with commit history.`;
57089
57285
  const report = reportLines.filter(Boolean).join(`
57090
57286
  `);
57091
57287
  try {
57092
- const fs28 = await import("fs/promises");
57093
- const path51 = await import("path");
57094
- const reportPath = path51.join(directory, ".swarm", "simulate-report.md");
57095
- await fs28.mkdir(path51.dirname(reportPath), { recursive: true });
57096
- await fs28.writeFile(reportPath, report, "utf-8");
57288
+ const fs29 = await import("fs/promises");
57289
+ const path52 = await import("path");
57290
+ const reportPath = path52.join(directory, ".swarm", "simulate-report.md");
57291
+ await fs29.mkdir(path52.dirname(reportPath), { recursive: true });
57292
+ await fs29.writeFile(reportPath, report, "utf-8");
57097
57293
  } catch (err) {
57098
57294
  const writeErr = err instanceof Error ? err.message : String(err);
57099
57295
  warn(`simulate: failed to write report to ${directory}/.swarm/simulate-report.md`, writeErr);
@@ -57115,15 +57311,15 @@ async function handleSpecifyCommand(_directory, args) {
57115
57311
  }
57116
57312
 
57117
57313
  // src/turbo/lean/state.ts
57118
- import * as fs28 from "fs";
57119
- import * as path51 from "path";
57314
+ import * as fs29 from "fs";
57315
+ import * as path52 from "path";
57120
57316
  function nowISO2() {
57121
57317
  return new Date().toISOString();
57122
57318
  }
57123
57319
  function ensureSwarmDir2(directory) {
57124
- const swarmDir = path51.resolve(directory, ".swarm");
57125
- if (!fs28.existsSync(swarmDir)) {
57126
- fs28.mkdirSync(swarmDir, { recursive: true });
57320
+ const swarmDir = path52.resolve(directory, ".swarm");
57321
+ if (!fs29.existsSync(swarmDir)) {
57322
+ fs29.mkdirSync(swarmDir, { recursive: true });
57127
57323
  }
57128
57324
  return swarmDir;
57129
57325
  }
@@ -57165,17 +57361,17 @@ function markStateUnreadable2(directory, reason) {
57165
57361
  }
57166
57362
  function readPersisted2(directory) {
57167
57363
  try {
57168
- const filePath = path51.join(directory, ".swarm", STATE_FILE2);
57169
- if (!fs28.existsSync(filePath)) {
57364
+ const filePath = path52.join(directory, ".swarm", STATE_FILE2);
57365
+ if (!fs29.existsSync(filePath)) {
57170
57366
  const seed = emptyPersisted2();
57171
57367
  try {
57172
57368
  ensureSwarmDir2(directory);
57173
- fs28.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
57369
+ fs29.writeFileSync(filePath, `${JSON.stringify(seed, null, 2)}
57174
57370
  `, "utf-8");
57175
57371
  } catch {}
57176
57372
  return seed;
57177
57373
  }
57178
- const raw = fs28.readFileSync(filePath, "utf-8");
57374
+ const raw = fs29.readFileSync(filePath, "utf-8");
57179
57375
  const parsed = JSON.parse(raw);
57180
57376
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || parsed.version !== 1 || !parsed.sessions || typeof parsed.sessions !== "object" || Array.isArray(parsed.sessions)) {
57181
57377
  markStateUnreadable2(directory, `malformed shape (version=${parsed?.version}, sessions type=${Array.isArray(parsed?.sessions) ? "array" : typeof parsed?.sessions})`);
@@ -57201,7 +57397,7 @@ function writePersisted2(directory, persisted) {
57201
57397
  let payload;
57202
57398
  try {
57203
57399
  ensureSwarmDir2(directory);
57204
- filePath = path51.join(directory, ".swarm", STATE_FILE2);
57400
+ filePath = path52.join(directory, ".swarm", STATE_FILE2);
57205
57401
  tmpPath = `${filePath}.tmp.${Date.now()}`;
57206
57402
  persisted.updatedAt = nowISO2();
57207
57403
  payload = `${JSON.stringify(persisted, null, 2)}
@@ -57212,14 +57408,14 @@ function writePersisted2(directory, persisted) {
57212
57408
  throw new Error(`Lean Turbo state persistence prepare failed: ${msg}`);
57213
57409
  }
57214
57410
  try {
57215
- fs28.writeFileSync(tmpPath, payload, "utf-8");
57216
- fs28.renameSync(tmpPath, filePath);
57411
+ fs29.writeFileSync(tmpPath, payload, "utf-8");
57412
+ fs29.renameSync(tmpPath, filePath);
57217
57413
  } catch (error93) {
57218
57414
  const msg = error93 instanceof Error ? error93.message : String(error93);
57219
57415
  error(`[turbo/lean/state] Failed to persist ${STATE_FILE2} atomically: ${msg}`);
57220
57416
  try {
57221
- if (fs28.existsSync(tmpPath)) {
57222
- fs28.unlinkSync(tmpPath);
57417
+ if (fs29.existsSync(tmpPath)) {
57418
+ fs29.unlinkSync(tmpPath);
57223
57419
  }
57224
57420
  } catch {}
57225
57421
  throw new Error(`Lean Turbo state persistence failed: ${msg}`);
@@ -57328,10 +57524,10 @@ var init_context_budget_service = __esm(() => {
57328
57524
 
57329
57525
  // src/services/status-service.ts
57330
57526
  import * as fsSync2 from "fs";
57331
- import * as path52 from "path";
57527
+ import * as path53 from "path";
57332
57528
  function readSpecStalenessSnapshot(directory) {
57333
57529
  try {
57334
- const p = path52.join(directory, ".swarm", "spec-staleness.json");
57530
+ const p = path53.join(directory, ".swarm", "spec-staleness.json");
57335
57531
  if (!fsSync2.existsSync(p))
57336
57532
  return { stale: false };
57337
57533
  const raw = fsSync2.readFileSync(p, "utf-8");
@@ -57856,8 +58052,8 @@ var init_write_retro2 = __esm(() => {
57856
58052
  });
57857
58053
 
57858
58054
  // src/commands/command-dispatch.ts
57859
- import fs29 from "fs";
57860
- import path53 from "path";
58055
+ import fs30 from "fs";
58056
+ import path54 from "path";
57861
58057
  function normalizeSwarmCommandInput(command, argumentText) {
57862
58058
  if (command !== "swarm" && !command.startsWith("swarm-")) {
57863
58059
  return { isSwarmCommand: false, tokens: [] };
@@ -57893,11 +58089,11 @@ ${similar.map((cmd) => ` - /swarm ${cmd}`).join(`
57893
58089
  `);
57894
58090
  }
57895
58091
  function maybeMarkFirstRun(directory) {
57896
- const sentinelPath = path53.join(directory, ".swarm", ".first-run-complete");
58092
+ const sentinelPath = path54.join(directory, ".swarm", ".first-run-complete");
57897
58093
  try {
57898
- const swarmDir = path53.join(directory, ".swarm");
57899
- fs29.mkdirSync(swarmDir, { recursive: true });
57900
- fs29.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
58094
+ const swarmDir = path54.join(directory, ".swarm");
58095
+ fs30.mkdirSync(swarmDir, { recursive: true });
58096
+ fs30.writeFileSync(sentinelPath, `first-run-complete: ${new Date().toISOString()}
57901
58097
  `, { flag: "wx" });
57902
58098
  return true;
57903
58099
  } catch {
@@ -58645,24 +58841,24 @@ function validateAliases() {
58645
58841
  }
58646
58842
  aliasTargets.get(target).push(name);
58647
58843
  const visited = new Set;
58648
- const path54 = [];
58844
+ const path55 = [];
58649
58845
  let current = target;
58650
58846
  while (current) {
58651
58847
  const currentEntry = COMMAND_REGISTRY[current];
58652
58848
  if (!currentEntry)
58653
58849
  break;
58654
58850
  if (visited.has(current)) {
58655
- const cycleStart = path54.indexOf(current);
58851
+ const cycleStart = path55.indexOf(current);
58656
58852
  const fullChain = [
58657
58853
  name,
58658
- ...path54.slice(0, cycleStart > 0 ? cycleStart : path54.length),
58854
+ ...path55.slice(0, cycleStart > 0 ? cycleStart : path55.length),
58659
58855
  current
58660
58856
  ].join(" \u2192 ");
58661
58857
  errors5.push(`Circular alias detected: ${fullChain}`);
58662
58858
  break;
58663
58859
  }
58664
58860
  visited.add(current);
58665
- path54.push(current);
58861
+ path55.push(current);
58666
58862
  current = currentEntry.aliasOf || "";
58667
58863
  }
58668
58864
  }
@@ -59281,68 +59477,68 @@ init_package();
59281
59477
  init_registry();
59282
59478
  init_cache_paths();
59283
59479
  init_constants();
59284
- import * as fs30 from "fs";
59480
+ import * as fs31 from "fs";
59285
59481
  import * as os8 from "os";
59286
- import * as path54 from "path";
59482
+ import * as path55 from "path";
59287
59483
  var { version: version5 } = package_default;
59288
59484
  var CONFIG_DIR = getPluginConfigDir();
59289
- var OPENCODE_CONFIG_PATH = path54.join(CONFIG_DIR, "opencode.json");
59290
- var PLUGIN_CONFIG_PATH = path54.join(CONFIG_DIR, "opencode-swarm.json");
59291
- var PROMPTS_DIR = path54.join(CONFIG_DIR, "opencode-swarm");
59485
+ var OPENCODE_CONFIG_PATH = path55.join(CONFIG_DIR, "opencode.json");
59486
+ var PLUGIN_CONFIG_PATH = path55.join(CONFIG_DIR, "opencode-swarm.json");
59487
+ var PROMPTS_DIR = path55.join(CONFIG_DIR, "opencode-swarm");
59292
59488
  var OPENCODE_PLUGIN_CACHE_PATHS = getPluginCachePaths();
59293
59489
  var OPENCODE_PLUGIN_LOCK_FILE_PATHS = getPluginLockFilePaths();
59294
59490
  function isSafeCachePath(p) {
59295
- const resolved = path54.resolve(p);
59296
- const home = path54.resolve(os8.homedir());
59491
+ const resolved = path55.resolve(p);
59492
+ const home = path55.resolve(os8.homedir());
59297
59493
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
59298
59494
  return false;
59299
59495
  }
59300
- const segments = resolved.split(path54.sep).filter((s) => s.length > 0);
59496
+ const segments = resolved.split(path55.sep).filter((s) => s.length > 0);
59301
59497
  if (segments.length < 4) {
59302
59498
  return false;
59303
59499
  }
59304
- const leaf = path54.basename(resolved);
59500
+ const leaf = path55.basename(resolved);
59305
59501
  if (leaf !== "opencode-swarm@latest" && leaf !== "opencode-swarm") {
59306
59502
  return false;
59307
59503
  }
59308
- const parent = path54.basename(path54.dirname(resolved));
59504
+ const parent = path55.basename(path55.dirname(resolved));
59309
59505
  if (parent !== "packages" && parent !== "node_modules") {
59310
59506
  return false;
59311
59507
  }
59312
- const grandparent = path54.basename(path54.dirname(path54.dirname(resolved)));
59508
+ const grandparent = path55.basename(path55.dirname(path55.dirname(resolved)));
59313
59509
  if (grandparent !== "opencode") {
59314
59510
  return false;
59315
59511
  }
59316
59512
  return true;
59317
59513
  }
59318
59514
  function isSafeLockFilePath(p) {
59319
- const resolved = path54.resolve(p);
59320
- const home = path54.resolve(os8.homedir());
59515
+ const resolved = path55.resolve(p);
59516
+ const home = path55.resolve(os8.homedir());
59321
59517
  if (resolved === "/" || resolved === home || resolved.length <= home.length) {
59322
59518
  return false;
59323
59519
  }
59324
- const segments = resolved.split(path54.sep).filter((s) => s.length > 0);
59520
+ const segments = resolved.split(path55.sep).filter((s) => s.length > 0);
59325
59521
  if (segments.length < 4) {
59326
59522
  return false;
59327
59523
  }
59328
- const leaf = path54.basename(resolved);
59524
+ const leaf = path55.basename(resolved);
59329
59525
  if (leaf !== "bun.lock" && leaf !== "bun.lockb" && leaf !== "package-lock.json") {
59330
59526
  return false;
59331
59527
  }
59332
- const parent = path54.basename(path54.dirname(resolved));
59528
+ const parent = path55.basename(path55.dirname(resolved));
59333
59529
  if (parent !== "opencode") {
59334
59530
  return false;
59335
59531
  }
59336
59532
  return true;
59337
59533
  }
59338
59534
  function ensureDir(dir) {
59339
- if (!fs30.existsSync(dir)) {
59340
- fs30.mkdirSync(dir, { recursive: true });
59535
+ if (!fs31.existsSync(dir)) {
59536
+ fs31.mkdirSync(dir, { recursive: true });
59341
59537
  }
59342
59538
  }
59343
59539
  function loadJson(filepath) {
59344
59540
  try {
59345
- const content = fs30.readFileSync(filepath, "utf-8");
59541
+ const content = fs31.readFileSync(filepath, "utf-8");
59346
59542
  const stripped = content.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (match, comment) => comment ? "" : match).replace(/,(\s*[}\]])/g, "$1");
59347
59543
  return JSON.parse(stripped);
59348
59544
  } catch {
@@ -59350,14 +59546,14 @@ function loadJson(filepath) {
59350
59546
  }
59351
59547
  }
59352
59548
  function saveJson(filepath, data) {
59353
- fs30.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
59549
+ fs31.writeFileSync(filepath, `${JSON.stringify(data, null, 2)}
59354
59550
  `, "utf-8");
59355
59551
  }
59356
59552
  function writeProjectConfigIfMissing(cwd) {
59357
59553
  try {
59358
- const opencodeDir = path54.join(cwd, ".opencode");
59359
- const projectConfigPath = path54.join(opencodeDir, "opencode-swarm.json");
59360
- if (fs30.existsSync(projectConfigPath)) {
59554
+ const opencodeDir = path55.join(cwd, ".opencode");
59555
+ const projectConfigPath = path55.join(opencodeDir, "opencode-swarm.json");
59556
+ if (fs31.existsSync(projectConfigPath)) {
59361
59557
  return;
59362
59558
  }
59363
59559
  ensureDir(opencodeDir);
@@ -59373,7 +59569,7 @@ async function install() {
59373
59569
  `);
59374
59570
  ensureDir(CONFIG_DIR);
59375
59571
  ensureDir(PROMPTS_DIR);
59376
- const LEGACY_CONFIG_PATH = path54.join(CONFIG_DIR, "config.json");
59572
+ const LEGACY_CONFIG_PATH = path55.join(CONFIG_DIR, "config.json");
59377
59573
  let opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
59378
59574
  if (!opencodeConfig) {
59379
59575
  const legacyConfig = loadJson(LEGACY_CONFIG_PATH);
@@ -59420,7 +59616,7 @@ async function install() {
59420
59616
  console.warn(`\u26A0 Could not clear opencode lock file \u2014 you may need to delete it manually:
59421
59617
  ${failed}`);
59422
59618
  }
59423
- if (!fs30.existsSync(PLUGIN_CONFIG_PATH)) {
59619
+ if (!fs31.existsSync(PLUGIN_CONFIG_PATH)) {
59424
59620
  const defaultConfig = {
59425
59621
  agents: { ...DEFAULT_AGENT_CONFIGS },
59426
59622
  max_iterations: 5
@@ -59499,14 +59695,14 @@ function evictPluginCaches() {
59499
59695
  const cleared = [];
59500
59696
  const failed = [];
59501
59697
  for (const cachePath of OPENCODE_PLUGIN_CACHE_PATHS) {
59502
- if (!fs30.existsSync(cachePath))
59698
+ if (!fs31.existsSync(cachePath))
59503
59699
  continue;
59504
59700
  if (!isSafeCachePath(cachePath)) {
59505
59701
  failed.push(`${cachePath} (refused: failed safety check)`);
59506
59702
  continue;
59507
59703
  }
59508
59704
  try {
59509
- fs30.rmSync(cachePath, { recursive: true, force: true });
59705
+ fs31.rmSync(cachePath, { recursive: true, force: true });
59510
59706
  cleared.push(cachePath);
59511
59707
  } catch (err) {
59512
59708
  failed.push(`${cachePath} (${err instanceof Error ? err.message : String(err)})`);
@@ -59518,14 +59714,14 @@ function evictLockFiles() {
59518
59714
  const cleared = [];
59519
59715
  const failed = [];
59520
59716
  for (const lockPath of OPENCODE_PLUGIN_LOCK_FILE_PATHS) {
59521
- if (!fs30.existsSync(lockPath))
59717
+ if (!fs31.existsSync(lockPath))
59522
59718
  continue;
59523
59719
  if (!isSafeLockFilePath(lockPath)) {
59524
59720
  failed.push(`${lockPath} (refused: failed safety check)`);
59525
59721
  continue;
59526
59722
  }
59527
59723
  try {
59528
- fs30.unlinkSync(lockPath);
59724
+ fs31.unlinkSync(lockPath);
59529
59725
  cleared.push(lockPath);
59530
59726
  } catch (err) {
59531
59727
  const code = err?.code;
@@ -59544,7 +59740,7 @@ async function uninstall() {
59544
59740
  `);
59545
59741
  const opencodeConfig = loadJson(OPENCODE_CONFIG_PATH);
59546
59742
  if (!opencodeConfig) {
59547
- if (fs30.existsSync(OPENCODE_CONFIG_PATH)) {
59743
+ if (fs31.existsSync(OPENCODE_CONFIG_PATH)) {
59548
59744
  console.log(`\u2717 Could not parse opencode config at: ${OPENCODE_CONFIG_PATH}`);
59549
59745
  return 1;
59550
59746
  } else {
@@ -59576,13 +59772,13 @@ async function uninstall() {
59576
59772
  console.log("\u2713 Re-enabled default OpenCode agents (explore, general)");
59577
59773
  if (process.argv.includes("--clean")) {
59578
59774
  let cleaned = false;
59579
- if (fs30.existsSync(PLUGIN_CONFIG_PATH)) {
59580
- fs30.unlinkSync(PLUGIN_CONFIG_PATH);
59775
+ if (fs31.existsSync(PLUGIN_CONFIG_PATH)) {
59776
+ fs31.unlinkSync(PLUGIN_CONFIG_PATH);
59581
59777
  console.log(`\u2713 Removed plugin config: ${PLUGIN_CONFIG_PATH}`);
59582
59778
  cleaned = true;
59583
59779
  }
59584
- if (fs30.existsSync(PROMPTS_DIR)) {
59585
- fs30.rmSync(PROMPTS_DIR, { recursive: true });
59780
+ if (fs31.existsSync(PROMPTS_DIR)) {
59781
+ fs31.rmSync(PROMPTS_DIR, { recursive: true });
59586
59782
  console.log(`\u2713 Removed custom prompts: ${PROMPTS_DIR}`);
59587
59783
  cleaned = true;
59588
59784
  }