opencode-swarm 6.39.0 → 6.40.2

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.
Files changed (32) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1 -1
  3. package/dist/cli/index.js +205 -54
  4. package/dist/commands/index.d.ts +1 -1
  5. package/dist/config/plan-schema.d.ts +2 -0
  6. package/dist/config/schema.d.ts +3 -2
  7. package/dist/index.js +2815 -2383
  8. package/dist/lang/grammars/tree-sitter-bash.wasm +0 -0
  9. package/dist/lang/grammars/tree-sitter-c-sharp.wasm +0 -0
  10. package/dist/lang/grammars/tree-sitter-cpp.wasm +0 -0
  11. package/dist/lang/grammars/tree-sitter-css.wasm +0 -0
  12. package/dist/lang/grammars/tree-sitter-go.wasm +0 -0
  13. package/dist/lang/grammars/tree-sitter-ini.wasm +0 -0
  14. package/dist/lang/grammars/tree-sitter-java.wasm +0 -0
  15. package/dist/lang/grammars/tree-sitter-javascript.wasm +0 -0
  16. package/dist/lang/grammars/tree-sitter-php.wasm +0 -0
  17. package/dist/lang/grammars/tree-sitter-powershell.wasm +0 -0
  18. package/dist/lang/grammars/tree-sitter-python.wasm +0 -0
  19. package/dist/lang/grammars/tree-sitter-regex.wasm +0 -0
  20. package/dist/lang/grammars/tree-sitter-ruby.wasm +0 -0
  21. package/dist/lang/grammars/tree-sitter-rust.wasm +0 -0
  22. package/dist/lang/grammars/tree-sitter-tsx.wasm +0 -0
  23. package/dist/lang/grammars/tree-sitter-typescript.wasm +0 -0
  24. package/dist/lang/grammars/tree-sitter.wasm +0 -0
  25. package/dist/quality/index.d.ts +1 -1
  26. package/dist/quality/metrics.d.ts +5 -0
  27. package/dist/services/compaction-service.d.ts +2 -2
  28. package/dist/session/snapshot-reader.d.ts +8 -0
  29. package/dist/session/snapshot-writer.d.ts +4 -3
  30. package/dist/tools/save-plan.d.ts +1 -0
  31. package/package.json +4 -1
  32. /package/dist/commands/{write_retro.d.ts → write-retro.d.ts} +0 -0
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -27,7 +27,7 @@ Most AI coding tools let one model write code and ask that same model whether th
27
27
  ### Key Features
28
28
 
29
29
  - 🏗️ **11 specialized agents** — architect, coder, reviewer, test engineer, critic, critic_sounding_board, critic_drift_verifier, explorer, SME, docs, designer
30
- - 🔒 **Gated pipeline** — code never ships without reviewer + test engineer approval
30
+ - 🔒 **Gated pipeline** — code never ships without reviewer + test engineer approval (bypassed in turbo mode)
31
31
  - 🔄 **Phase completion gates** — completion-verify and drift verifier gates enforced before phase completion (bypassed in turbo mode)
32
32
  - 🔁 **Resumable sessions** — all state saved to `.swarm/`; pick up any project any day
33
33
  - 🌐 **11 languages** — TypeScript, Python, Go, Rust, Java, Kotlin, C#, C/C++, Swift, Dart, Ruby
package/dist/cli/index.js CHANGED
@@ -5,25 +5,43 @@ var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ function __accessProp(key) {
9
+ return this[key];
10
+ }
11
+ var __toESMCache_node;
12
+ var __toESMCache_esm;
8
13
  var __toESM = (mod, isNodeMode, target) => {
14
+ var canCache = mod != null && typeof mod === "object";
15
+ if (canCache) {
16
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
17
+ var cached = cache.get(mod);
18
+ if (cached)
19
+ return cached;
20
+ }
9
21
  target = mod != null ? __create(__getProtoOf(mod)) : {};
10
22
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
23
  for (let key of __getOwnPropNames(mod))
12
24
  if (!__hasOwnProp.call(to, key))
13
25
  __defProp(to, key, {
14
- get: () => mod[key],
26
+ get: __accessProp.bind(mod, key),
15
27
  enumerable: true
16
28
  });
29
+ if (canCache)
30
+ cache.set(mod, to);
17
31
  return to;
18
32
  };
19
33
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
34
+ var __returnValue = (v) => v;
35
+ function __exportSetter(name, newValue) {
36
+ this[name] = __returnValue.bind(null, newValue);
37
+ }
20
38
  var __export = (target, all) => {
21
39
  for (var name in all)
22
40
  __defProp(target, name, {
23
41
  get: all[name],
24
42
  enumerable: true,
25
43
  configurable: true,
26
- set: (newValue) => all[name] = () => newValue
44
+ set: __exportSetter.bind(all, name)
27
45
  });
28
46
  };
29
47
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -14572,7 +14590,8 @@ var init_plan_schema = __esm(() => {
14572
14590
  id: exports_external.number().int().min(1),
14573
14591
  name: exports_external.string().min(1),
14574
14592
  status: PhaseStatusSchema.default("pending"),
14575
- tasks: exports_external.array(TaskSchema).default([])
14593
+ tasks: exports_external.array(TaskSchema).default([]),
14594
+ required_agents: exports_external.array(exports_external.string()).optional()
14576
14595
  });
14577
14596
  PlanSchema = exports_external.object({
14578
14597
  schema_version: exports_external.literal("1.0.0"),
@@ -16652,13 +16671,21 @@ function createConfigBackup(directory) {
16652
16671
  if (fs4.existsSync(projectConfigPath)) {
16653
16672
  try {
16654
16673
  content = fs4.readFileSync(projectConfigPath, "utf-8");
16655
- } catch {}
16674
+ } catch (error93) {
16675
+ log("[ConfigDoctor] project config read failed", {
16676
+ error: error93 instanceof Error ? error93.message : String(error93)
16677
+ });
16678
+ }
16656
16679
  }
16657
16680
  if (content === null && fs4.existsSync(userConfigPath)) {
16658
16681
  configPath = userConfigPath;
16659
16682
  try {
16660
16683
  content = fs4.readFileSync(userConfigPath, "utf-8");
16661
- } catch {}
16684
+ } catch (error93) {
16685
+ log("[ConfigDoctor] user config read failed", {
16686
+ error: error93 instanceof Error ? error93.message : String(error93)
16687
+ });
16688
+ }
16662
16689
  }
16663
16690
  if (content === null) {
16664
16691
  return null;
@@ -17209,6 +17236,7 @@ async function runConfigDoctorWithFixes(directory, config3, autoFix = false) {
17209
17236
  }
17210
17237
  var VALID_CONFIG_PATTERNS, DANGEROUS_PATH_SEGMENTS;
17211
17238
  var init_config_doctor = __esm(() => {
17239
+ init_utils();
17212
17240
  VALID_CONFIG_PATTERNS = [
17213
17241
  /^\.config[\\/]opencode[\\/]opencode-swarm\.json$/,
17214
17242
  /\.opencode[\\/]opencode-swarm\.json$/
@@ -17301,8 +17329,8 @@ function getTaskBlockers(task, summary, status) {
17301
17329
  }
17302
17330
  return blockers;
17303
17331
  }
17304
- async function buildTaskSummary(task, taskId) {
17305
- const result = await loadEvidence(".", taskId);
17332
+ async function buildTaskSummary(directory, task, taskId) {
17333
+ const result = await loadEvidence(directory, taskId);
17306
17334
  const bundle = result.status === "found" ? result.bundle : null;
17307
17335
  const phase = task?.phase ?? 0;
17308
17336
  const status = getTaskStatus(task, bundle);
@@ -17331,18 +17359,18 @@ async function buildTaskSummary(task, taskId) {
17331
17359
  lastEvidenceTimestamp: lastTimestamp
17332
17360
  };
17333
17361
  }
17334
- async function buildPhaseSummary(phase) {
17335
- const taskIds = await listEvidenceTaskIds(".");
17362
+ async function buildPhaseSummary(directory, phase) {
17363
+ const taskIds = await listEvidenceTaskIds(directory);
17336
17364
  const phaseTaskIds = new Set(phase.tasks.map((t) => t.id));
17337
17365
  const taskSummaries = [];
17338
17366
  const _taskMap = new Map(phase.tasks.map((t) => [t.id, t]));
17339
17367
  for (const task of phase.tasks) {
17340
- const summary = await buildTaskSummary(task, task.id);
17368
+ const summary = await buildTaskSummary(directory, task, task.id);
17341
17369
  taskSummaries.push(summary);
17342
17370
  }
17343
17371
  const extraTaskIds = taskIds.filter((id) => !phaseTaskIds.has(id));
17344
17372
  for (const taskId of extraTaskIds) {
17345
- const summary = await buildTaskSummary(undefined, taskId);
17373
+ const summary = await buildTaskSummary(directory, undefined, taskId);
17346
17374
  if (summary.phase === phase.id) {
17347
17375
  taskSummaries.push(summary);
17348
17376
  }
@@ -17443,7 +17471,7 @@ async function buildEvidenceSummary(directory, currentPhase) {
17443
17471
  let totalTasks = 0;
17444
17472
  let completedTasks = 0;
17445
17473
  for (const phase of phasesToProcess) {
17446
- const summary = await buildPhaseSummary(phase);
17474
+ const summary = await buildPhaseSummary(directory, phase);
17447
17475
  phaseSummaries.push(summary);
17448
17476
  totalTasks += summary.totalTasks;
17449
17477
  completedTasks += summary.completedTasks;
@@ -18161,8 +18189,8 @@ var PlanCursorConfigSchema = exports_external.object({
18161
18189
  });
18162
18190
  var CheckpointConfigSchema = exports_external.object({
18163
18191
  enabled: exports_external.boolean().default(true),
18164
- auto_checkpoint_threshold: exports_external.number().min(1).max(20).default(3)
18165
- });
18192
+ auto_checkpoint_threshold: exports_external.number().int().min(1).max(20).default(3)
18193
+ }).strict();
18166
18194
  var AutomationModeSchema = exports_external.enum(["manual", "hybrid", "auto"]);
18167
18195
  var AutomationCapabilitiesSchema = exports_external.object({
18168
18196
  plan_sync: exports_external.boolean().default(true),
@@ -18282,7 +18310,8 @@ var PluginConfigSchema = exports_external.object({
18282
18310
  block_on_threshold: exports_external.boolean().default(false).describe("If true, block phase completion when threshold exceeded. Default: advisory only.")
18283
18311
  }).optional(),
18284
18312
  incremental_verify: IncrementalVerifyConfigSchema.optional(),
18285
- compaction_service: CompactionConfigSchema.optional()
18313
+ compaction_service: CompactionConfigSchema.optional(),
18314
+ turbo_mode: exports_external.boolean().default(false).optional()
18286
18315
  });
18287
18316
 
18288
18317
  // src/config/loader.ts
@@ -18385,6 +18414,15 @@ function loadPluginConfig(directory) {
18385
18414
  }
18386
18415
  return result.data;
18387
18416
  }
18417
+ function loadPluginConfigWithMeta(directory) {
18418
+ const userConfigPath = path.join(getUserConfigDir(), "opencode", CONFIG_FILENAME);
18419
+ const projectConfigPath = path.join(directory, ".opencode", CONFIG_FILENAME);
18420
+ const userResult = loadRawConfigFromPath(userConfigPath);
18421
+ const projectResult = loadRawConfigFromPath(projectConfigPath);
18422
+ const loadedFromFile = userResult.fileExisted || projectResult.fileExisted;
18423
+ const config2 = loadPluginConfig(directory);
18424
+ return { config: config2, loadedFromFile };
18425
+ }
18388
18426
 
18389
18427
  // src/commands/archive.ts
18390
18428
  init_manager();
@@ -18807,6 +18845,9 @@ async function handleBenchmarkCommand(directory, args) {
18807
18845
  `);
18808
18846
  }
18809
18847
 
18848
+ // src/commands/checkpoint.ts
18849
+ init_zod();
18850
+
18810
18851
  // src/tools/checkpoint.ts
18811
18852
  import { spawnSync } from "child_process";
18812
18853
  import * as fs3 from "fs";
@@ -31132,6 +31173,10 @@ function tool(input) {
31132
31173
  return input;
31133
31174
  }
31134
31175
  tool.schema = exports_external2;
31176
+
31177
+ // src/config/index.ts
31178
+ init_evidence_schema();
31179
+ init_plan_schema();
31135
31180
  // src/tools/create-tool.ts
31136
31181
  function createSwarmTool(opts) {
31137
31182
  return tool({
@@ -31256,6 +31301,11 @@ function isGitRepo() {
31256
31301
  }
31257
31302
  function handleSave(label, directory) {
31258
31303
  try {
31304
+ let maxCheckpoints = 20;
31305
+ try {
31306
+ const { config: config3 } = loadPluginConfigWithMeta(directory);
31307
+ maxCheckpoints = config3.checkpoint?.auto_checkpoint_threshold ?? maxCheckpoints;
31308
+ } catch {}
31259
31309
  const log2 = readCheckpointLog(directory);
31260
31310
  const existingCheckpoint = log2.checkpoints.find((c) => c.label === label);
31261
31311
  if (existingCheckpoint) {
@@ -31375,7 +31425,7 @@ var checkpoint = createSwarmTool({
31375
31425
  let label;
31376
31426
  try {
31377
31427
  action = String(args.action);
31378
- label = args.label !== undefined ? String(args.label) : undefined;
31428
+ label = args.label !== undefined && args.label !== null ? String(args.label) : undefined;
31379
31429
  } catch {
31380
31430
  return JSON.stringify({
31381
31431
  action: "unknown",
@@ -31428,6 +31478,22 @@ var checkpoint = createSwarmTool({
31428
31478
  });
31429
31479
 
31430
31480
  // src/commands/checkpoint.ts
31481
+ var CheckpointResultSchema = exports_external.object({
31482
+ action: exports_external.string().optional(),
31483
+ success: exports_external.boolean(),
31484
+ error: exports_external.string().optional(),
31485
+ checkpoints: exports_external.array(exports_external.unknown()).optional()
31486
+ }).passthrough();
31487
+ function safeParseResult(result) {
31488
+ const parsed = CheckpointResultSchema.safeParse(JSON.parse(result));
31489
+ if (!parsed.success) {
31490
+ return {
31491
+ success: false,
31492
+ error: `Invalid response: ${parsed.error.message}`
31493
+ };
31494
+ }
31495
+ return parsed.data;
31496
+ }
31431
31497
  async function handleCheckpointCommand(directory, args) {
31432
31498
  const subcommand = args[0] || "list";
31433
31499
  const label = args[1];
@@ -31450,7 +31516,7 @@ async function handleSave2(directory, label) {
31450
31516
  const result = await checkpoint.execute({ action: "save", label }, {
31451
31517
  directory
31452
31518
  });
31453
- const parsed = JSON.parse(result);
31519
+ const parsed = safeParseResult(result);
31454
31520
  if (parsed.success) {
31455
31521
  return `\u2713 Checkpoint saved: "${label}"`;
31456
31522
  } else {
@@ -31469,7 +31535,7 @@ async function handleRestore2(directory, label) {
31469
31535
  const result = await checkpoint.execute({ action: "restore", label }, {
31470
31536
  directory
31471
31537
  });
31472
- const parsed = JSON.parse(result);
31538
+ const parsed = safeParseResult(result);
31473
31539
  if (parsed.success) {
31474
31540
  return `\u2713 Restored to checkpoint: "${label}"`;
31475
31541
  } else {
@@ -31488,7 +31554,7 @@ async function handleDelete2(directory, label) {
31488
31554
  const result = await checkpoint.execute({ action: "delete", label }, {
31489
31555
  directory
31490
31556
  });
31491
- const parsed = JSON.parse(result);
31557
+ const parsed = safeParseResult(result);
31492
31558
  if (parsed.success) {
31493
31559
  return `\u2713 Checkpoint deleted: "${label}"`;
31494
31560
  } else {
@@ -31504,7 +31570,7 @@ async function handleList2(directory) {
31504
31570
  const result = await checkpoint.execute({ action: "list" }, {
31505
31571
  directory
31506
31572
  });
31507
- const parsed = JSON.parse(result);
31573
+ const parsed = safeParseResult(result);
31508
31574
  if (!parsed.success) {
31509
31575
  return `Error: ${parsed.error || "Failed to list checkpoints"}`;
31510
31576
  }
@@ -33713,6 +33779,7 @@ import { renameSync as renameSync4 } from "fs";
33713
33779
  // src/services/handoff-service.ts
33714
33780
  init_utils2();
33715
33781
  init_manager2();
33782
+ init_utils();
33716
33783
  var RTL_OVERRIDE_PATTERN = /[\u202e\u202d\u202c\u200f]/g;
33717
33784
  var MAX_TASK_ID_LENGTH = 100;
33718
33785
  var MAX_DECISION_LENGTH = 500;
@@ -33829,7 +33896,10 @@ function parseSessionState(content) {
33829
33896
  }
33830
33897
  }
33831
33898
  return { activeAgent, delegationState, pendingQA };
33832
- } catch {
33899
+ } catch (error93) {
33900
+ log("[HandoffService] state extraction failed", {
33901
+ error: error93 instanceof Error ? error93.message : String(error93)
33902
+ });
33833
33903
  return null;
33834
33904
  }
33835
33905
  }
@@ -34011,8 +34081,8 @@ function formatHandoffMarkdown(data) {
34011
34081
  init_utils2();
34012
34082
  import { mkdirSync as mkdirSync4, renameSync as renameSync3 } from "fs";
34013
34083
  import * as path14 from "path";
34014
- var pendingWrite = null;
34015
- var lastWritePromise = Promise.resolve();
34084
+ init_utils();
34085
+ var _writeInFlight = Promise.resolve();
34016
34086
  function serializeAgentSession(s) {
34017
34087
  const gateLog = {};
34018
34088
  const rawGateLog = s.gateLog ?? new Map;
@@ -34102,19 +34172,14 @@ async function writeSnapshot(directory, state) {
34102
34172
  await Bun.write(tempPath, content);
34103
34173
  renameSync3(tempPath, resolvedPath);
34104
34174
  } catch (error93) {
34105
- if (process.env.DEBUG_SWARM) {
34106
- console.warn("[snapshot-writer] write failed:", error93 instanceof Error ? error93.message : String(error93));
34107
- }
34175
+ log("[snapshot-writer] write failed", {
34176
+ error: error93 instanceof Error ? error93.message : String(error93)
34177
+ });
34108
34178
  }
34109
34179
  }
34110
34180
  async function flushPendingSnapshot(directory) {
34111
- if (pendingWrite) {
34112
- clearTimeout(pendingWrite);
34113
- pendingWrite = null;
34114
- await writeSnapshot(directory, swarmState).catch(() => {});
34115
- } else {
34116
- await lastWritePromise;
34117
- }
34181
+ _writeInFlight = _writeInFlight.then(() => writeSnapshot(directory, swarmState), () => writeSnapshot(directory, swarmState));
34182
+ await _writeInFlight;
34118
34183
  }
34119
34184
 
34120
34185
  // src/commands/handoff.ts
@@ -34202,7 +34267,8 @@ async function extractFromLegacy(directory) {
34202
34267
  mappedStatus = "complete";
34203
34268
  else if (status === "IN PROGRESS")
34204
34269
  mappedStatus = "in_progress";
34205
- const headerLineIndex = lines.indexOf(match[0]);
34270
+ const headerLineIndex = planContent.substring(0, match.index).split(`
34271
+ `).length - 1;
34206
34272
  let completed = 0;
34207
34273
  let total = 0;
34208
34274
  if (headerLineIndex !== -1) {
@@ -34597,9 +34663,9 @@ async function getPlanData(directory, phaseArg) {
34597
34663
  return {
34598
34664
  hasPlan: true,
34599
34665
  fullMarkdown,
34600
- requestedPhase: NaN,
34666
+ requestedPhase: null,
34601
34667
  phaseMarkdown: null,
34602
- errorMessage: null,
34668
+ errorMessage: `Invalid phase number: "${phaseArg}"`,
34603
34669
  isLegacy: false
34604
34670
  };
34605
34671
  }
@@ -34650,9 +34716,9 @@ async function getPlanData(directory, phaseArg) {
34650
34716
  return {
34651
34717
  hasPlan: true,
34652
34718
  fullMarkdown: planContent,
34653
- requestedPhase: NaN,
34719
+ requestedPhase: null,
34654
34720
  phaseMarkdown: null,
34655
- errorMessage: null,
34721
+ errorMessage: `Invalid phase number: "${phaseArg}"`,
34656
34722
  isLegacy: true
34657
34723
  };
34658
34724
  }
@@ -35591,6 +35657,59 @@ LANGUAGE_REGISTRY.register({
35591
35657
  ]
35592
35658
  }
35593
35659
  });
35660
+ LANGUAGE_REGISTRY.register({
35661
+ id: "php",
35662
+ displayName: "PHP",
35663
+ tier: 3,
35664
+ extensions: [".php", ".phtml"],
35665
+ treeSitter: { grammarId: "php", wasmFile: "tree-sitter-php.wasm" },
35666
+ build: {
35667
+ detectFiles: ["composer.json"],
35668
+ commands: []
35669
+ },
35670
+ test: {
35671
+ detectFiles: ["phpunit.xml", "phpunit.xml.dist"],
35672
+ frameworks: [
35673
+ {
35674
+ name: "PHPUnit",
35675
+ detect: "phpunit.xml",
35676
+ cmd: "vendor/bin/phpunit",
35677
+ priority: 1
35678
+ }
35679
+ ]
35680
+ },
35681
+ lint: {
35682
+ detectFiles: [".php-cs-fixer.php", "phpcs.xml"],
35683
+ linters: [
35684
+ {
35685
+ name: "PHP-CS-Fixer",
35686
+ detect: ".php-cs-fixer.php",
35687
+ cmd: "vendor/bin/php-cs-fixer fix --dry-run --diff",
35688
+ priority: 1
35689
+ }
35690
+ ]
35691
+ },
35692
+ audit: {
35693
+ detectFiles: ["composer.lock"],
35694
+ command: "composer audit --format=json",
35695
+ outputFormat: "json"
35696
+ },
35697
+ sast: { nativeRuleSet: "php", semgrepSupport: "ga" },
35698
+ prompts: {
35699
+ coderConstraints: [
35700
+ "Follow PSR-12 coding standards",
35701
+ "Use strict types declaration: declare(strict_types=1)",
35702
+ "Prefer type hints and return type declarations on all functions",
35703
+ "Use dependency injection over static methods and singletons"
35704
+ ],
35705
+ reviewerChecklist: [
35706
+ "Verify no user input reaches SQL queries without parameterised binding",
35707
+ "Check for XSS \u2014 all output must be escaped with htmlspecialchars()",
35708
+ "Confirm no eval(), exec(), or shell_exec() with user-controlled input",
35709
+ "Validate proper error handling \u2014 no bare catch blocks that swallow errors"
35710
+ ]
35711
+ }
35712
+ });
35594
35713
 
35595
35714
  // src/lang/detector.ts
35596
35715
  async function detectProjectLanguages(projectDir) {
@@ -36174,7 +36293,7 @@ async function detectAvailableLinter(directory) {
36174
36293
  async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
36175
36294
  const DETECT_TIMEOUT = 2000;
36176
36295
  try {
36177
- const biomeProc = Bun.spawn(["npx", "biome", "--version"], {
36296
+ const biomeProc = Bun.spawn([biomeBin, "--version"], {
36178
36297
  stdout: "pipe",
36179
36298
  stderr: "pipe"
36180
36299
  });
@@ -36188,7 +36307,7 @@ async function _detectAvailableLinter(_projectDir, biomeBin, eslintBin) {
36188
36307
  }
36189
36308
  } catch {}
36190
36309
  try {
36191
- const eslintProc = Bun.spawn(["npx", "eslint", "--version"], {
36310
+ const eslintProc = Bun.spawn([eslintBin, "--version"], {
36192
36311
  stdout: "pipe",
36193
36312
  stderr: "pipe"
36194
36313
  });
@@ -38205,12 +38324,13 @@ async function runLintCheck(dir, linter, timeoutMs) {
38205
38324
  const startTime = Date.now();
38206
38325
  try {
38207
38326
  const lintPromise = runLint(linter, "check", dir);
38327
+ let timeoutId;
38208
38328
  const timeoutPromise = new Promise((_, reject) => {
38209
- setTimeout(() => {
38329
+ timeoutId = setTimeout(() => {
38210
38330
  reject(new Error(`Lint check timed out after ${timeoutMs}ms`));
38211
38331
  }, timeoutMs);
38212
38332
  });
38213
- const result = await Promise.race([lintPromise, timeoutPromise]);
38333
+ const result = await Promise.race([lintPromise, timeoutPromise]).finally(() => clearTimeout(timeoutId));
38214
38334
  if (!result.success) {
38215
38335
  return {
38216
38336
  type: "lint",
@@ -38774,17 +38894,19 @@ class CircuitBreaker {
38774
38894
  this.successCount = 0;
38775
38895
  this.onStateChange?.("closed", {
38776
38896
  timestamp: Date.now(),
38777
- successCount: 0
38897
+ successCount: 0,
38898
+ oldState
38778
38899
  });
38779
38900
  } else if (newState === "open") {
38780
38901
  this.successCount = 0;
38781
38902
  this.onStateChange?.("opened", {
38782
38903
  timestamp: Date.now(),
38783
- failureCount: this.failureCount
38904
+ failureCount: this.failureCount,
38905
+ oldState
38784
38906
  });
38785
38907
  } else if (newState === "half-open") {
38786
38908
  this.successCount = 0;
38787
- this.onStateChange?.("half-open", { timestamp: Date.now() });
38909
+ this.onStateChange?.("half-open", { timestamp: Date.now(), oldState });
38788
38910
  }
38789
38911
  }
38790
38912
  reset() {
@@ -39720,12 +39842,32 @@ function makeInitialState() {
39720
39842
  lastSnapshotAt: null
39721
39843
  };
39722
39844
  }
39723
- var state = makeInitialState();
39724
- function getCompactionMetrics() {
39725
- return {
39726
- compactionCount: state.observationCount + state.reflectionCount + state.emergencyCount,
39727
- lastSnapshotAt: state.lastSnapshotAt
39728
- };
39845
+ var sessionStates = new Map;
39846
+ function getSessionState(sessionId) {
39847
+ let state = sessionStates.get(sessionId);
39848
+ if (!state) {
39849
+ state = makeInitialState();
39850
+ sessionStates.set(sessionId, state);
39851
+ }
39852
+ return state;
39853
+ }
39854
+ function getCompactionMetrics(sessionId) {
39855
+ if (sessionId) {
39856
+ const state = getSessionState(sessionId);
39857
+ return {
39858
+ compactionCount: state.observationCount + state.reflectionCount + state.emergencyCount,
39859
+ lastSnapshotAt: state.lastSnapshotAt
39860
+ };
39861
+ }
39862
+ let total = 0;
39863
+ let lastSnapshot = null;
39864
+ for (const state of sessionStates.values()) {
39865
+ total += state.observationCount + state.reflectionCount + state.emergencyCount;
39866
+ if (state.lastSnapshotAt && (!lastSnapshot || state.lastSnapshotAt > lastSnapshot)) {
39867
+ lastSnapshot = state.lastSnapshotAt;
39868
+ }
39869
+ }
39870
+ return { compactionCount: total, lastSnapshotAt: lastSnapshot };
39729
39871
  }
39730
39872
 
39731
39873
  // src/services/context-budget-service.ts
@@ -39888,6 +40030,7 @@ async function handleTurboCommand(_directory, args, sessionID) {
39888
40030
  }
39889
40031
 
39890
40032
  // src/tools/write-retro.ts
40033
+ init_evidence_schema();
39891
40034
  init_manager();
39892
40035
  async function executeWriteRetro(args, directory) {
39893
40036
  const phase = args.phase;
@@ -40121,8 +40264,9 @@ async function executeWriteRetro(args, directory) {
40121
40264
  };
40122
40265
  const taxonomy = [];
40123
40266
  try {
40124
- for (const taskSuffix of ["1", "2", "3", "4", "5"]) {
40125
- const phaseTaskId = `${phase}.${taskSuffix}`;
40267
+ const allTaskIds = await listEvidenceTaskIds(directory);
40268
+ const phaseTaskIds = allTaskIds.filter((id) => id.startsWith(`${phase}.`));
40269
+ for (const phaseTaskId of phaseTaskIds) {
40126
40270
  const result = await loadEvidence(directory, phaseTaskId);
40127
40271
  if (result.status !== "found")
40128
40272
  continue;
@@ -40156,6 +40300,13 @@ async function executeWriteRetro(args, directory) {
40156
40300
  }
40157
40301
  } catch {}
40158
40302
  retroEntry.error_taxonomy = [...new Set(taxonomy)];
40303
+ const validationResult = RetrospectiveEvidenceSchema.safeParse(retroEntry);
40304
+ if (!validationResult.success) {
40305
+ return JSON.stringify({
40306
+ success: false,
40307
+ error: `Retrospective entry failed validation: ${validationResult.error.message}`
40308
+ }, null, 2);
40309
+ }
40159
40310
  try {
40160
40311
  await saveEvidence(directory, taskId, retroEntry);
40161
40312
  return JSON.stringify({
@@ -40220,7 +40371,7 @@ var write_retro = createSwarmTool({
40220
40371
  }
40221
40372
  });
40222
40373
 
40223
- // src/commands/write_retro.ts
40374
+ // src/commands/write-retro.ts
40224
40375
  async function handleWriteRetroCommand(directory, args) {
40225
40376
  if (args.length === 0 || !args[0] || args[0].trim() === "") {
40226
40377
  return `## Usage: /swarm write-retro <json>
@@ -29,7 +29,7 @@ export { handleSpecifyCommand } from './specify';
29
29
  export { handleStatusCommand } from './status';
30
30
  export { handleSyncPlanCommand } from './sync-plan';
31
31
  export { handleTurboCommand } from './turbo';
32
- export { handleWriteRetroCommand } from './write_retro';
32
+ export { handleWriteRetroCommand } from './write-retro';
33
33
  /**
34
34
  * Creates a command.execute.before handler for /swarm commands.
35
35
  * Uses factory pattern to close over directory and agents.
@@ -91,6 +91,7 @@ export declare const PhaseSchema: z.ZodObject<{
91
91
  evidence_path: z.ZodOptional<z.ZodString>;
92
92
  blocked_reason: z.ZodOptional<z.ZodString>;
93
93
  }, z.core.$strip>>>;
94
+ required_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
94
95
  }, z.core.$strip>;
95
96
  export type Phase = z.infer<typeof PhaseSchema>;
96
97
  export declare const PlanSchema: z.ZodObject<{
@@ -129,6 +130,7 @@ export declare const PlanSchema: z.ZodObject<{
129
130
  evidence_path: z.ZodOptional<z.ZodString>;
130
131
  blocked_reason: z.ZodOptional<z.ZodString>;
131
132
  }, z.core.$strip>>>;
133
+ required_agents: z.ZodOptional<z.ZodArray<z.ZodString>>;
132
134
  }, z.core.$strip>>;
133
135
  migration_status: z.ZodOptional<z.ZodEnum<{
134
136
  native: "native";
@@ -375,7 +375,7 @@ export type PlanCursorConfig = z.infer<typeof PlanCursorConfigSchema>;
375
375
  export declare const CheckpointConfigSchema: z.ZodObject<{
376
376
  enabled: z.ZodDefault<z.ZodBoolean>;
377
377
  auto_checkpoint_threshold: z.ZodDefault<z.ZodNumber>;
378
- }, z.core.$strip>;
378
+ }, z.core.$strict>;
379
379
  export type CheckpointConfig = z.infer<typeof CheckpointConfigSchema>;
380
380
  export declare const AutomationModeSchema: z.ZodEnum<{
381
381
  auto: "auto";
@@ -699,7 +699,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
699
699
  checkpoint: z.ZodOptional<z.ZodObject<{
700
700
  enabled: z.ZodDefault<z.ZodBoolean>;
701
701
  auto_checkpoint_threshold: z.ZodDefault<z.ZodNumber>;
702
- }, z.core.$strip>>;
702
+ }, z.core.$strict>>;
703
703
  automation: z.ZodOptional<z.ZodType<{
704
704
  mode: "auto" | "manual" | "hybrid";
705
705
  capabilities: {
@@ -785,6 +785,7 @@ export declare const PluginConfigSchema: z.ZodObject<{
785
785
  emergencyThreshold: z.ZodDefault<z.ZodNumber>;
786
786
  preserveLastNTurns: z.ZodDefault<z.ZodNumber>;
787
787
  }, z.core.$strip>>;
788
+ turbo_mode: z.ZodOptional<z.ZodDefault<z.ZodBoolean>>;
788
789
  }, z.core.$strip>;
789
790
  export type PluginConfig = z.infer<typeof PluginConfigSchema>;
790
791
  export type { AgentName, PipelineAgentName, QAAgentName, } from './constants';