opencode-swarm 6.19.8 → 6.20.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/README.md CHANGED
@@ -852,7 +852,7 @@ This release adds runtime detection hooks to catch and warn about architect work
852
852
  - **Partial gate tracking**: Detects when QA gates are skipped
853
853
  - **Self-fix detection**: Warns when an agent fixes its own gate failure (should delegate to fresh agent)
854
854
  - **Batch detection**: Catches "implement X and add Y" batching in task requests
855
- - **Zero-delegation detection**: Warns when tasks complete without any coder delegation
855
+ - **Zero-delegation detection**: Warns when tasks complete without any coder delegation; supports parsing delegation envelopes from JSON or KEY: VALUE text format for validation.
856
856
 
857
857
  These hooks are advisory (warnings only) and help maintain workflow discipline during long sessions.
858
858
 
package/dist/cli/index.js CHANGED
@@ -32646,9 +32646,9 @@ function validateArgs(args) {
32646
32646
  return false;
32647
32647
  return true;
32648
32648
  }
32649
- function getLinterCommand(linter, mode) {
32649
+ function getLinterCommand(linter, mode, projectDir) {
32650
32650
  const isWindows = process.platform === "win32";
32651
- const binDir = path11.join(process.cwd(), "node_modules", ".bin");
32651
+ const binDir = path11.join(projectDir, "node_modules", ".bin");
32652
32652
  const biomeBin = isWindows ? path11.join(binDir, "biome.EXE") : path11.join(binDir, "biome");
32653
32653
  const eslintBin = isWindows ? path11.join(binDir, "eslint.cmd") : path11.join(binDir, "eslint");
32654
32654
  switch (linter) {
@@ -32825,8 +32825,8 @@ async function detectAvailableLinter() {
32825
32825
  } catch {}
32826
32826
  return null;
32827
32827
  }
32828
- async function runLint(linter, mode) {
32829
- const command = getLinterCommand(linter, mode);
32828
+ async function runLint(linter, mode, directory) {
32829
+ const command = getLinterCommand(linter, mode, directory);
32830
32830
  const commandStr = command.join(" ");
32831
32831
  if (commandStr.length > MAX_COMMAND_LENGTH) {
32832
32832
  return {
@@ -32840,7 +32840,8 @@ async function runLint(linter, mode) {
32840
32840
  try {
32841
32841
  const proc = Bun.spawn(command, {
32842
32842
  stdout: "pipe",
32843
- stderr: "pipe"
32843
+ stderr: "pipe",
32844
+ cwd: directory
32844
32845
  });
32845
32846
  const [stdout, stderr] = await Promise.all([
32846
32847
  new Response(proc.stdout).text(),
@@ -32954,11 +32955,19 @@ var lint = createSwarmTool({
32954
32955
  };
32955
32956
  return JSON.stringify(errorResult2, null, 2);
32956
32957
  }
32958
+ if (!directory || typeof directory !== "string" || directory.trim() === "") {
32959
+ const errorResult2 = {
32960
+ success: false,
32961
+ mode: "check",
32962
+ error: "project directory is required but was not provided"
32963
+ };
32964
+ return JSON.stringify(errorResult2, null, 2);
32965
+ }
32957
32966
  const { mode } = args;
32958
32967
  const cwd = directory;
32959
32968
  const linter = await detectAvailableLinter();
32960
32969
  if (linter) {
32961
- const result = await runLint(linter, mode);
32970
+ const result = await runLint(linter, mode, directory);
32962
32971
  return JSON.stringify(result, null, 2);
32963
32972
  }
32964
32973
  const additionalLinter = detectAdditionalLinter(cwd);
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Handle /swarm checkpoint command
3
+ * Creates, lists, restores, or deletes checkpoints with optional label
4
+ */
5
+ export declare function handleCheckpointCommand(directory: string, args: string[]): Promise<string>;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Role-Scoped Context Injection Filter
3
+ * Filters context entries based on [FOR: ...] tags for role-based context delivery.
4
+ */
5
+ /**
6
+ * Context entry with role metadata
7
+ */
8
+ export interface ContextEntry {
9
+ role: 'user' | 'assistant' | 'system';
10
+ content: string;
11
+ name?: string;
12
+ }
13
+ /**
14
+ * Filter context entries based on target role and [FOR: ...] tags.
15
+ *
16
+ * Filtering rules:
17
+ * - Entries with [FOR: ALL] are included for all agents
18
+ * - Entries with [FOR: specific_agents] are included only for named agents
19
+ * - Entries without [FOR: ...] tag are included for all agents (backward compatibility)
20
+ * - System prompts, delegation envelopes, plan content, and knowledge entries are never filtered
21
+ *
22
+ * @param entries - Array of context entries to filter
23
+ * @param targetRole - The target agent role to filter for
24
+ * @param directory - Optional project directory for metrics logging (defaults to cwd)
25
+ * @returns Filtered array of context entries
26
+ */
27
+ export declare function filterByRole(entries: ContextEntry[], targetRole: string, directory?: string): ContextEntry[];
@@ -0,0 +1,17 @@
1
+ export type FileZone = 'production' | 'test' | 'config' | 'generated' | 'docs' | 'build';
2
+ export interface ZoneClassification {
3
+ filePath: string;
4
+ zone: FileZone;
5
+ confidence: 'high' | 'medium';
6
+ reason: string;
7
+ }
8
+ export interface ZonePolicy {
9
+ qaDepth: 'full' | 'standard' | 'light' | 'skip';
10
+ lintRequired: boolean;
11
+ testRequired: boolean;
12
+ reviewRequired: boolean;
13
+ securityReviewRequired: boolean;
14
+ }
15
+ export declare function classifyFile(filePath: string): ZoneClassification;
16
+ export declare function classifyFiles(filePaths: string[]): ZoneClassification[];
17
+ export declare function getZonePolicy(zone: FileZone): ZonePolicy;
@@ -0,0 +1,20 @@
1
+ export interface ASTChange {
2
+ type: 'added' | 'modified' | 'removed';
3
+ category: 'function' | 'class' | 'type' | 'export' | 'import' | 'variable' | 'other';
4
+ name: string;
5
+ lineStart: number;
6
+ lineEnd: number;
7
+ signature?: string;
8
+ }
9
+ export interface ASTDiffResult {
10
+ filePath: string;
11
+ language: string | null;
12
+ changes: ASTChange[];
13
+ durationMs: number;
14
+ usedAST: boolean;
15
+ error?: string;
16
+ }
17
+ /**
18
+ * Compute AST-level diff between old and new file content
19
+ */
20
+ export declare function computeASTDiff(filePath: string, oldContent: string, newContent: string): Promise<ASTDiffResult>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Check if we're in a git repository
3
+ */
4
+ export declare function isGitRepo(cwd: string): boolean;
5
+ /**
6
+ * Get current branch name
7
+ */
8
+ export declare function getCurrentBranch(cwd: string): string;
9
+ /**
10
+ * Create a new branch
11
+ * @param cwd - Working directory
12
+ * @param branchName - Name of the branch to create
13
+ * @param remote - Remote name (default: 'origin')
14
+ */
15
+ export declare function createBranch(cwd: string, branchName: string, remote?: string): void;
16
+ /**
17
+ * Get list of changed files compared to main/master
18
+ * @param cwd - Working directory
19
+ * @param branch - Base branch to compare against (optional, auto-detected if not provided)
20
+ * @returns Array of changed file paths, or empty array if error occurs
21
+ */
22
+ export declare function getChangedFiles(cwd: string, branch?: string): string[];
23
+ /**
24
+ * Get default base branch (main or master)
25
+ */
26
+ export declare function getDefaultBaseBranch(cwd: string): string;
27
+ /**
28
+ * Stage specific files for commit
29
+ * @param cwd - Working directory
30
+ * @param files - Array of file paths to stage (must not be empty)
31
+ * @throws Error if files array is empty
32
+ */
33
+ export declare function stageFiles(cwd: string, files: string[]): void;
34
+ /**
35
+ * Stage all files in the working directory
36
+ * @param cwd - Working directory
37
+ */
38
+ export declare function stageAll(cwd: string): void;
39
+ /**
40
+ * Commit changes
41
+ */
42
+ export declare function commitChanges(cwd: string, message: string): void;
43
+ /**
44
+ * Get current commit SHA
45
+ */
46
+ export declare function getCurrentSha(cwd: string): string;
47
+ /**
48
+ * Check if there are uncommitted changes
49
+ */
50
+ export declare function hasUncommittedChanges(cwd: string): boolean;
@@ -0,0 +1,22 @@
1
+ import { createBranch, isGitRepo } from './branch.js';
2
+ import { isAuthenticated, isGhAvailable } from './pr.js';
3
+ export interface PRWorkflowOptions {
4
+ title: string;
5
+ body?: string;
6
+ branch?: string;
7
+ }
8
+ export interface PRWorkflowResult {
9
+ success: boolean;
10
+ url?: string;
11
+ number?: number;
12
+ error?: string;
13
+ }
14
+ /**
15
+ * Full PR workflow: create branch → commit → push → create PR
16
+ */
17
+ export declare function runPRWorkflow(cwd: string, options: PRWorkflowOptions): Promise<PRWorkflowResult>;
18
+ /**
19
+ * Generate evidence summary without creating PR
20
+ */
21
+ export declare function prepareEvidence(cwd: string): string;
22
+ export { isGhAvailable, isAuthenticated, isGitRepo, createBranch };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Sanitize input string to prevent command injection
3
+ * Removes or escapes shell metacharacters
4
+ */
5
+ export declare function sanitizeInput(input: string): string;
6
+ /**
7
+ * Check if gh CLI is available
8
+ */
9
+ export declare function isGhAvailable(cwd: string): boolean;
10
+ /**
11
+ * Check if authenticated with gh
12
+ */
13
+ export declare function isAuthenticated(cwd: string): boolean;
14
+ /**
15
+ * Create evidence.md summary
16
+ */
17
+ export declare function generateEvidenceMd(cwd: string): string;
18
+ /**
19
+ * Create a pull request
20
+ */
21
+ export declare function createPullRequest(cwd: string, title: string, body?: string, baseBranch?: string): Promise<{
22
+ url: string;
23
+ number: number;
24
+ }>;
25
+ /**
26
+ * Commit and push current changes
27
+ */
28
+ export declare function commitAndPush(cwd: string, message: string): void;
@@ -5,6 +5,22 @@
5
5
  * Uses experimental.chat.messages.transform to provide non-blocking guidance.
6
6
  */
7
7
  import type { PluginConfig } from '../config';
8
+ import type { DelegationEnvelope, EnvelopeValidationResult } from '../types/delegation.js';
9
+ /**
10
+ * Parses a string to extract a DelegationEnvelope.
11
+ * Returns null if no valid envelope is found.
12
+ * Never throws - all errors are caught and result in null.
13
+ */
14
+ export declare function parseDelegationEnvelope(content: string): DelegationEnvelope | null;
15
+ interface ValidationContext {
16
+ planTasks: string[];
17
+ validAgents: string[];
18
+ }
19
+ /**
20
+ * Validates a DelegationEnvelope against the current plan and agent list.
21
+ * Returns { valid: true } on success, or { valid: false; reason: string } on failure.
22
+ */
23
+ export declare function validateDelegationEnvelope(envelope: unknown, context: ValidationContext): EnvelopeValidationResult;
8
24
  interface MessageInfo {
9
25
  role: string;
10
26
  agent?: string;
@@ -1,5 +1,6 @@
1
1
  /** Core storage layer for the opencode-swarm v6.17 two-tier knowledge system. */
2
2
  import type { RejectedLesson } from './knowledge-types.js';
3
+ export declare function getPlatformConfigDir(): string;
3
4
  export declare function resolveSwarmKnowledgePath(directory: string): string;
4
5
  export declare function resolveSwarmRejectedPath(directory: string): string;
5
6
  export declare function resolveHiveKnowledgePath(): string;
package/dist/index.js CHANGED
@@ -32236,9 +32236,9 @@ function validateArgs(args2) {
32236
32236
  return false;
32237
32237
  return true;
32238
32238
  }
32239
- function getLinterCommand(linter, mode) {
32239
+ function getLinterCommand(linter, mode, projectDir) {
32240
32240
  const isWindows = process.platform === "win32";
32241
- const binDir = path18.join(process.cwd(), "node_modules", ".bin");
32241
+ const binDir = path18.join(projectDir, "node_modules", ".bin");
32242
32242
  const biomeBin = isWindows ? path18.join(binDir, "biome.EXE") : path18.join(binDir, "biome");
32243
32243
  const eslintBin = isWindows ? path18.join(binDir, "eslint.cmd") : path18.join(binDir, "eslint");
32244
32244
  switch (linter) {
@@ -32415,8 +32415,8 @@ async function detectAvailableLinter() {
32415
32415
  } catch {}
32416
32416
  return null;
32417
32417
  }
32418
- async function runLint(linter, mode) {
32419
- const command = getLinterCommand(linter, mode);
32418
+ async function runLint(linter, mode, directory) {
32419
+ const command = getLinterCommand(linter, mode, directory);
32420
32420
  const commandStr = command.join(" ");
32421
32421
  if (commandStr.length > MAX_COMMAND_LENGTH) {
32422
32422
  return {
@@ -32430,7 +32430,8 @@ async function runLint(linter, mode) {
32430
32430
  try {
32431
32431
  const proc = Bun.spawn(command, {
32432
32432
  stdout: "pipe",
32433
- stderr: "pipe"
32433
+ stderr: "pipe",
32434
+ cwd: directory
32434
32435
  });
32435
32436
  const [stdout, stderr] = await Promise.all([
32436
32437
  new Response(proc.stdout).text(),
@@ -32550,11 +32551,19 @@ var init_lint = __esm(() => {
32550
32551
  };
32551
32552
  return JSON.stringify(errorResult2, null, 2);
32552
32553
  }
32554
+ if (!directory || typeof directory !== "string" || directory.trim() === "") {
32555
+ const errorResult2 = {
32556
+ success: false,
32557
+ mode: "check",
32558
+ error: "project directory is required but was not provided"
32559
+ };
32560
+ return JSON.stringify(errorResult2, null, 2);
32561
+ }
32553
32562
  const { mode } = args2;
32554
32563
  const cwd = directory;
32555
32564
  const linter = await detectAvailableLinter();
32556
32565
  if (linter) {
32557
- const result = await runLint(linter, mode);
32566
+ const result = await runLint(linter, mode, directory);
32558
32567
  return JSON.stringify(result, null, 2);
32559
32568
  }
32560
32569
  const additionalLinter = detectAdditionalLinter(cwd);
@@ -34357,10 +34366,10 @@ async function runVersionCheck(dir, _timeoutMs) {
34357
34366
  };
34358
34367
  }
34359
34368
  }
34360
- async function runLintCheck(_dir, linter, timeoutMs) {
34369
+ async function runLintCheck(dir, linter, timeoutMs) {
34361
34370
  const startTime = Date.now();
34362
34371
  try {
34363
- const lintPromise = runLint(linter, "check");
34372
+ const lintPromise = runLint(linter, "check", dir);
34364
34373
  const timeoutPromise = new Promise((_, reject) => {
34365
34374
  setTimeout(() => {
34366
34375
  reject(new Error(`Lint check timed out after ${timeoutMs}ms`));
@@ -44993,7 +45002,7 @@ async function handleKnowledgeListCommand(directory, _args) {
44993
45002
  "|------|----------|------------|---------------------|"
44994
45003
  ];
44995
45004
  for (const entry of entries) {
44996
- const truncatedLesson = entry.lesson.length > 60 ? entry.lesson.slice(0, 57) + "..." : entry.lesson;
45005
+ const truncatedLesson = entry.lesson.length > 60 ? `${entry.lesson.slice(0, 57)}...` : entry.lesson;
44997
45006
  const confidencePct = Math.round(entry.confidence * 100);
44998
45007
  lines.push(`| ${entry.id.slice(0, 8)}... | ${entry.category} | ${confidencePct}% | ${truncatedLesson} |`);
44999
45008
  }
@@ -45605,7 +45614,7 @@ async function handleRollbackCommand(directory, args2) {
45605
45614
  `);
45606
45615
  }
45607
45616
  const targetPhase = parseInt(phaseArg, 10);
45608
- if (isNaN(targetPhase) || targetPhase < 1) {
45617
+ if (Number.isNaN(targetPhase) || targetPhase < 1) {
45609
45618
  return "Error: Phase number must be a positive integer.";
45610
45619
  }
45611
45620
  const manifestPath = validateSwarmPath(directory, "checkpoints/manifest.json");
@@ -45650,7 +45659,7 @@ async function handleRollbackCommand(directory, args2) {
45650
45659
  timestamp: new Date().toISOString()
45651
45660
  };
45652
45661
  try {
45653
- fs12.appendFileSync(eventsPath, JSON.stringify(rollbackEvent) + `
45662
+ fs12.appendFileSync(eventsPath, `${JSON.stringify(rollbackEvent)}
45654
45663
  `);
45655
45664
  } catch (error93) {
45656
45665
  console.error("Failed to write rollback event:", error93);
@@ -51240,7 +51249,7 @@ function validateExtensions(extensions) {
51240
51249
  }
51241
51250
  return { valid: true, value: extensions, error: null };
51242
51251
  }
51243
- async function getGitChurn(days) {
51252
+ async function getGitChurn(days, directory) {
51244
51253
  const churnMap = new Map;
51245
51254
  const proc = Bun.spawn([
51246
51255
  "git",
@@ -51250,7 +51259,8 @@ async function getGitChurn(days) {
51250
51259
  "--pretty=format:"
51251
51260
  ], {
51252
51261
  stdout: "pipe",
51253
- stderr: "pipe"
51262
+ stderr: "pipe",
51263
+ cwd: directory
51254
51264
  });
51255
51265
  const stdout = await new Response(proc.stdout).text();
51256
51266
  await proc.exited;
@@ -51315,8 +51325,8 @@ function getComplexityForFile(filePath) {
51315
51325
  return null;
51316
51326
  }
51317
51327
  }
51318
- async function analyzeHotspots(days, topN, extensions) {
51319
- const churnMap = await getGitChurn(days);
51328
+ async function analyzeHotspots(days, topN, extensions, directory) {
51329
+ const churnMap = await getGitChurn(days, directory);
51320
51330
  const extSet = new Set(extensions.map((e) => e.startsWith(".") ? e : `.${e}`));
51321
51331
  const filteredChurn = new Map;
51322
51332
  for (const [file3, count] of churnMap) {
@@ -51326,7 +51336,7 @@ async function analyzeHotspots(days, topN, extensions) {
51326
51336
  }
51327
51337
  }
51328
51338
  const hotspots = [];
51329
- const cwd = process.cwd();
51339
+ const cwd = directory;
51330
51340
  let analyzedFiles = 0;
51331
51341
  for (const [file3, churnCount] of filteredChurn) {
51332
51342
  let fullPath = file3;
@@ -51378,7 +51388,22 @@ var complexity_hotspots = createSwarmTool({
51378
51388
  top_n: tool.schema.number().optional().describe("Number of top hotspots to return (default: 20, valid range: 1-100)"),
51379
51389
  extensions: tool.schema.string().optional().describe('Comma-separated extensions to include (default: "ts,tsx,js,jsx,py,rs,ps1")')
51380
51390
  },
51381
- async execute(args2, _directory) {
51391
+ async execute(args2, directory) {
51392
+ if (!directory || typeof directory !== "string" || directory.trim() === "") {
51393
+ const errorResult = {
51394
+ error: "project directory is required but was not provided",
51395
+ analyzedFiles: 0,
51396
+ period: "0 days",
51397
+ hotspots: [],
51398
+ summary: {
51399
+ fullGates: 0,
51400
+ securityReview: 0,
51401
+ enhancedReview: 0,
51402
+ standard: 0
51403
+ }
51404
+ };
51405
+ return JSON.stringify(errorResult, null, 2);
51406
+ }
51382
51407
  let daysInput;
51383
51408
  let topNInput;
51384
51409
  let extensionsInput;
@@ -51442,7 +51467,7 @@ var complexity_hotspots = createSwarmTool({
51442
51467
  const topN = topNValidation.value;
51443
51468
  const extensions = extensionsValidation.value.split(",").map((e) => e.trim());
51444
51469
  try {
51445
- const result = await analyzeHotspots(days, topN, extensions);
51470
+ const result = await analyzeHotspots(days, topN, extensions, directory);
51446
51471
  return JSON.stringify(result, null, 2);
51447
51472
  } catch (e) {
51448
51473
  const errorResult = {
@@ -51477,7 +51502,7 @@ var SAFE_REF_PATTERN = /^[a-zA-Z0-9._\-/~^@{}]+$/;
51477
51502
  var MAX_REF_LENGTH = 256;
51478
51503
  var MAX_PATH_LENGTH = 500;
51479
51504
  var SHELL_METACHARACTERS2 = /[;|&$`(){}<>!'"]/;
51480
- var CONTROL_CHAR_PATTERN2 = new RegExp("[\\u0000-\\u001F\\u007F]");
51505
+ var CONTROL_CHAR_PATTERN2 = /[\u0000-\u001F\u007F]/;
51481
51506
  function validateBase(base) {
51482
51507
  if (base.length > MAX_REF_LENGTH) {
51483
51508
  return `base ref exceeds maximum length of ${MAX_REF_LENGTH}`;
@@ -51515,8 +51540,17 @@ var diff = tool({
51515
51540
  base: tool.schema.string().optional().describe('Base ref to diff against (default: HEAD). Use "staged" for staged changes, "unstaged" for working tree changes.'),
51516
51541
  paths: tool.schema.array(tool.schema.string()).optional().describe("Optional file paths to restrict diff scope.")
51517
51542
  },
51518
- async execute(args2, _context) {
51543
+ async execute(args2, context) {
51519
51544
  try {
51545
+ if (!context.directory || typeof context.directory !== "string" || context.directory.trim() === "") {
51546
+ const errorResult = {
51547
+ error: "project directory is required but was not provided",
51548
+ files: [],
51549
+ contractChanges: [],
51550
+ hasContractChanges: false
51551
+ };
51552
+ return JSON.stringify(errorResult, null, 2);
51553
+ }
51520
51554
  const base = args2.base ?? "HEAD";
51521
51555
  const baseValidationError = validateBase(base);
51522
51556
  if (baseValidationError) {
@@ -51555,12 +51589,14 @@ var diff = tool({
51555
51589
  const numstatOutput = execFileSync("git", numstatArgs, {
51556
51590
  encoding: "utf-8",
51557
51591
  timeout: DIFF_TIMEOUT_MS,
51558
- maxBuffer: MAX_BUFFER_BYTES
51592
+ maxBuffer: MAX_BUFFER_BYTES,
51593
+ cwd: context.directory
51559
51594
  });
51560
51595
  const fullDiffOutput = execFileSync("git", fullDiffArgs, {
51561
51596
  encoding: "utf-8",
51562
51597
  timeout: DIFF_TIMEOUT_MS,
51563
- maxBuffer: MAX_BUFFER_BYTES
51598
+ maxBuffer: MAX_BUFFER_BYTES,
51599
+ cwd: context.directory
51564
51600
  });
51565
51601
  const files = [];
51566
51602
  const numstatLines = numstatOutput.split(`
@@ -51610,7 +51646,7 @@ var diff = tool({
51610
51646
  return JSON.stringify(result, null, 2);
51611
51647
  } catch (e) {
51612
51648
  const errorResult = {
51613
- error: e instanceof Error ? `git diff failed: ${e.constructor.name}` : "git diff failed: unknown error",
51649
+ error: e instanceof Error ? `git diff failed: ${e.message}` : "git diff failed: unknown error",
51614
51650
  files: [],
51615
51651
  contractChanges: [],
51616
51652
  hasContractChanges: false
@@ -52906,9 +52942,9 @@ function validateArgs3(args2) {
52906
52942
  }
52907
52943
  return true;
52908
52944
  }
52909
- function detectEcosystems() {
52945
+ function detectEcosystems(directory) {
52910
52946
  const ecosystems = [];
52911
- const cwd = process.cwd();
52947
+ const cwd = directory;
52912
52948
  if (fs23.existsSync(path34.join(cwd, "package.json"))) {
52913
52949
  ecosystems.push("npm");
52914
52950
  }
@@ -52935,13 +52971,13 @@ function detectEcosystems() {
52935
52971
  }
52936
52972
  return ecosystems;
52937
52973
  }
52938
- async function runNpmAudit() {
52974
+ async function runNpmAudit(directory) {
52939
52975
  const command = ["npm", "audit", "--json"];
52940
52976
  try {
52941
52977
  const proc = Bun.spawn(command, {
52942
52978
  stdout: "pipe",
52943
52979
  stderr: "pipe",
52944
- cwd: process.cwd()
52980
+ cwd: directory
52945
52981
  });
52946
52982
  const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
52947
52983
  const result = await Promise.race([
@@ -53058,13 +53094,13 @@ function mapNpmSeverity(severity) {
53058
53094
  return "info";
53059
53095
  }
53060
53096
  }
53061
- async function runPipAudit() {
53097
+ async function runPipAudit(directory) {
53062
53098
  const command = ["pip-audit", "--format=json"];
53063
53099
  try {
53064
53100
  const proc = Bun.spawn(command, {
53065
53101
  stdout: "pipe",
53066
53102
  stderr: "pipe",
53067
- cwd: process.cwd()
53103
+ cwd: directory
53068
53104
  });
53069
53105
  const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
53070
53106
  const result = await Promise.race([
@@ -53189,13 +53225,13 @@ async function runPipAudit() {
53189
53225
  };
53190
53226
  }
53191
53227
  }
53192
- async function runCargoAudit() {
53228
+ async function runCargoAudit(directory) {
53193
53229
  const command = ["cargo", "audit", "--json"];
53194
53230
  try {
53195
53231
  const proc = Bun.spawn(command, {
53196
53232
  stdout: "pipe",
53197
53233
  stderr: "pipe",
53198
- cwd: process.cwd()
53234
+ cwd: directory
53199
53235
  });
53200
53236
  const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
53201
53237
  const result = await Promise.race([
@@ -53303,7 +53339,7 @@ function mapCargoSeverity(cvss) {
53303
53339
  return "moderate";
53304
53340
  return "low";
53305
53341
  }
53306
- async function runGoAudit() {
53342
+ async function runGoAudit(directory) {
53307
53343
  const command = ["govulncheck", "-json", "./..."];
53308
53344
  if (!isCommandAvailable("govulncheck")) {
53309
53345
  warn("[pkg-audit] govulncheck not found, skipping Go audit");
@@ -53322,7 +53358,7 @@ async function runGoAudit() {
53322
53358
  const proc = Bun.spawn(command, {
53323
53359
  stdout: "pipe",
53324
53360
  stderr: "pipe",
53325
- cwd: process.cwd()
53361
+ cwd: directory
53326
53362
  });
53327
53363
  const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
53328
53364
  const result = await Promise.race([
@@ -53433,7 +53469,7 @@ async function runGoAudit() {
53433
53469
  };
53434
53470
  }
53435
53471
  }
53436
- async function runDotnetAudit() {
53472
+ async function runDotnetAudit(directory) {
53437
53473
  const command = [
53438
53474
  "dotnet",
53439
53475
  "list",
@@ -53458,7 +53494,7 @@ async function runDotnetAudit() {
53458
53494
  const proc = Bun.spawn(command, {
53459
53495
  stdout: "pipe",
53460
53496
  stderr: "pipe",
53461
- cwd: process.cwd()
53497
+ cwd: directory
53462
53498
  });
53463
53499
  const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
53464
53500
  const result = await Promise.race([
@@ -53557,7 +53593,7 @@ function mapDotnetSeverity(severity) {
53557
53593
  return "info";
53558
53594
  }
53559
53595
  }
53560
- async function runBundleAudit() {
53596
+ async function runBundleAudit(directory) {
53561
53597
  const useBundleExec = !isCommandAvailable("bundle-audit") && isCommandAvailable("bundle");
53562
53598
  if (!isCommandAvailable("bundle-audit") && !isCommandAvailable("bundle")) {
53563
53599
  warn("[pkg-audit] bundle-audit not found, skipping Ruby audit");
@@ -53577,7 +53613,7 @@ async function runBundleAudit() {
53577
53613
  const proc = Bun.spawn(command, {
53578
53614
  stdout: "pipe",
53579
53615
  stderr: "pipe",
53580
- cwd: process.cwd()
53616
+ cwd: directory
53581
53617
  });
53582
53618
  const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
53583
53619
  const result = await Promise.race([
@@ -53704,7 +53740,7 @@ function mapBundleSeverity(adv) {
53704
53740
  return "moderate";
53705
53741
  return "low";
53706
53742
  }
53707
- async function runDartAudit() {
53743
+ async function runDartAudit(directory) {
53708
53744
  const dartBin = isCommandAvailable("dart") ? "dart" : isCommandAvailable("flutter") ? "flutter" : null;
53709
53745
  if (!dartBin) {
53710
53746
  warn("[pkg-audit] dart/flutter not found, skipping Dart audit");
@@ -53724,7 +53760,7 @@ async function runDartAudit() {
53724
53760
  const proc = Bun.spawn(command, {
53725
53761
  stdout: "pipe",
53726
53762
  stderr: "pipe",
53727
- cwd: process.cwd()
53763
+ cwd: directory
53728
53764
  });
53729
53765
  const timeoutPromise = new Promise((resolve12) => setTimeout(() => resolve12("timeout"), AUDIT_TIMEOUT_MS));
53730
53766
  const result = await Promise.race([
@@ -53823,8 +53859,8 @@ async function runDartAudit() {
53823
53859
  };
53824
53860
  }
53825
53861
  }
53826
- async function runAutoAudit() {
53827
- const ecosystems = detectEcosystems();
53862
+ async function runAutoAudit(directory) {
53863
+ const ecosystems = detectEcosystems(directory);
53828
53864
  if (ecosystems.length === 0) {
53829
53865
  return {
53830
53866
  ecosystems: [],
@@ -53839,25 +53875,25 @@ async function runAutoAudit() {
53839
53875
  for (const eco of ecosystems) {
53840
53876
  switch (eco) {
53841
53877
  case "npm":
53842
- results.push(await runNpmAudit());
53878
+ results.push(await runNpmAudit(directory));
53843
53879
  break;
53844
53880
  case "pip":
53845
- results.push(await runPipAudit());
53881
+ results.push(await runPipAudit(directory));
53846
53882
  break;
53847
53883
  case "cargo":
53848
- results.push(await runCargoAudit());
53884
+ results.push(await runCargoAudit(directory));
53849
53885
  break;
53850
53886
  case "go":
53851
- results.push(await runGoAudit());
53887
+ results.push(await runGoAudit(directory));
53852
53888
  break;
53853
53889
  case "dotnet":
53854
- results.push(await runDotnetAudit());
53890
+ results.push(await runDotnetAudit(directory));
53855
53891
  break;
53856
53892
  case "ruby":
53857
- results.push(await runBundleAudit());
53893
+ results.push(await runBundleAudit(directory));
53858
53894
  break;
53859
53895
  case "dart":
53860
- results.push(await runDartAudit());
53896
+ results.push(await runDartAudit(directory));
53861
53897
  break;
53862
53898
  }
53863
53899
  }
@@ -53883,40 +53919,46 @@ var pkg_audit = createSwarmTool({
53883
53919
  args: {
53884
53920
  ecosystem: tool.schema.enum(["auto", "npm", "pip", "cargo", "go", "dotnet", "ruby", "dart"]).default("auto").describe('Package ecosystem to audit: "auto" (detect from project files), "npm", "pip", "cargo", "go" (govulncheck), "dotnet" (dotnet list package), "ruby" (bundle-audit), or "dart" (dart pub outdated)')
53885
53921
  },
53886
- async execute(args2, _directory) {
53922
+ async execute(args2, directory) {
53887
53923
  if (!validateArgs3(args2)) {
53888
53924
  const errorResult = {
53889
53925
  error: 'Invalid arguments: ecosystem must be "auto", "npm", "pip", "cargo", "go", "dotnet", "ruby", or "dart"'
53890
53926
  };
53891
53927
  return JSON.stringify(errorResult, null, 2);
53892
53928
  }
53929
+ if (!directory || typeof directory !== "string" || directory.trim() === "") {
53930
+ const errorResult = {
53931
+ error: "project directory is required but was not provided"
53932
+ };
53933
+ return JSON.stringify(errorResult, null, 2);
53934
+ }
53893
53935
  const obj = args2;
53894
53936
  const ecosystem = obj.ecosystem || "auto";
53895
53937
  let result;
53896
53938
  switch (ecosystem) {
53897
53939
  case "auto":
53898
- result = await runAutoAudit();
53940
+ result = await runAutoAudit(directory);
53899
53941
  break;
53900
53942
  case "npm":
53901
- result = await runNpmAudit();
53943
+ result = await runNpmAudit(directory);
53902
53944
  break;
53903
53945
  case "pip":
53904
- result = await runPipAudit();
53946
+ result = await runPipAudit(directory);
53905
53947
  break;
53906
53948
  case "cargo":
53907
- result = await runCargoAudit();
53949
+ result = await runCargoAudit(directory);
53908
53950
  break;
53909
53951
  case "go":
53910
- result = await runGoAudit();
53952
+ result = await runGoAudit(directory);
53911
53953
  break;
53912
53954
  case "dotnet":
53913
- result = await runDotnetAudit();
53955
+ result = await runDotnetAudit(directory);
53914
53956
  break;
53915
53957
  case "ruby":
53916
- result = await runBundleAudit();
53958
+ result = await runBundleAudit(directory);
53917
53959
  break;
53918
53960
  case "dart":
53919
- result = await runDartAudit();
53961
+ result = await runDartAudit(directory);
53920
53962
  break;
53921
53963
  }
53922
53964
  return JSON.stringify(result, null, 2);
@@ -56088,7 +56130,7 @@ async function runLintWrapped(files, directory, _config) {
56088
56130
  duration_ms: Number(process.hrtime.bigint() - start2) / 1e6
56089
56131
  };
56090
56132
  }
56091
- const result = await runWithTimeout(runLint(linter, "check"), TOOL_TIMEOUT_MS);
56133
+ const result = await runWithTimeout(runLint(linter, "check", directory), TOOL_TIMEOUT_MS);
56092
56134
  return {
56093
56135
  ran: true,
56094
56136
  result,
@@ -56104,7 +56146,7 @@ async function runLintWrapped(files, directory, _config) {
56104
56146
  }
56105
56147
  async function runLintOnFiles(linter, files, workspaceDir) {
56106
56148
  const isWindows = process.platform === "win32";
56107
- const binDir = path37.join(process.cwd(), "node_modules", ".bin");
56149
+ const binDir = path37.join(workspaceDir, "node_modules", ".bin");
56108
56150
  const validatedFiles = [];
56109
56151
  for (const file3 of files) {
56110
56152
  if (typeof file3 !== "string") {
@@ -56137,7 +56179,8 @@ async function runLintOnFiles(linter, files, workspaceDir) {
56137
56179
  try {
56138
56180
  const proc = Bun.spawn(command, {
56139
56181
  stdout: "pipe",
56140
- stderr: "pipe"
56182
+ stderr: "pipe",
56183
+ cwd: workspaceDir
56141
56184
  });
56142
56185
  const [stdout, stderr] = await Promise.all([
56143
56186
  new Response(proc.stdout).text(),
@@ -56528,7 +56571,7 @@ var pre_check_batch = createSwarmTool({
56528
56571
  directory: tool.schema.string().describe('Directory to run checks in (e.g., "." or "./src")'),
56529
56572
  sast_threshold: tool.schema.enum(["low", "medium", "high", "critical"]).optional().describe("Minimum severity for SAST findings to cause failure (default: medium)")
56530
56573
  },
56531
- async execute(args2, _directory) {
56574
+ async execute(args2, directory) {
56532
56575
  if (!args2 || typeof args2 !== "object") {
56533
56576
  const errorResult = {
56534
56577
  gates_passed: false,
@@ -56544,6 +56587,33 @@ var pre_check_batch = createSwarmTool({
56544
56587
  };
56545
56588
  return JSON.stringify(errorResult, null, 2);
56546
56589
  }
56590
+ if (!directory || typeof directory !== "string" || directory.trim() === "") {
56591
+ const errorResult = {
56592
+ gates_passed: false,
56593
+ lint: {
56594
+ ran: false,
56595
+ error: "project directory is required but was not provided",
56596
+ duration_ms: 0
56597
+ },
56598
+ secretscan: {
56599
+ ran: false,
56600
+ error: "project directory is required but was not provided",
56601
+ duration_ms: 0
56602
+ },
56603
+ sast_scan: {
56604
+ ran: false,
56605
+ error: "project directory is required but was not provided",
56606
+ duration_ms: 0
56607
+ },
56608
+ quality_budget: {
56609
+ ran: false,
56610
+ error: "project directory is required but was not provided",
56611
+ duration_ms: 0
56612
+ },
56613
+ total_duration_ms: 0
56614
+ };
56615
+ return JSON.stringify(errorResult, null, 2);
56616
+ }
56547
56617
  const typedArgs = args2;
56548
56618
  if (!typedArgs.directory) {
56549
56619
  const errorResult = {
@@ -0,0 +1,25 @@
1
+ /** Project Identity Management for opencode-swarm.
2
+ * Handles creation and retrieval of project identity files.
3
+ */
4
+ export interface ProjectIdentity {
5
+ projectHash: string;
6
+ projectName: string;
7
+ repoUrl?: string;
8
+ absolutePath: string;
9
+ createdAt: string;
10
+ swarmVersion: string;
11
+ }
12
+ /**
13
+ * Get identity file path for a project hash.
14
+ * Path: {platform-config-dir}/projects/{projectHash}/identity.json
15
+ */
16
+ export declare function resolveIdentityPath(projectHash: string): string;
17
+ /**
18
+ * Read existing identity.json or return null if it doesn't exist.
19
+ */
20
+ export declare function readProjectIdentity(projectHash: string): Promise<ProjectIdentity | null>;
21
+ /**
22
+ * Create or update identity.json for a project.
23
+ * Uses atomic write pattern (write to temp file, then rename).
24
+ */
25
+ export declare function writeProjectIdentity(directory: string, projectHash: string, projectName: string): Promise<ProjectIdentity>;
@@ -0,0 +1,2 @@
1
+ /** Knowledge system exports for opencode-swarm. */
2
+ export * from './identity.js';
@@ -0,0 +1,27 @@
1
+ export type AgentType = 'architect' | 'coder' | 'reviewer' | 'test_engineer' | 'explorer' | 'sme' | 'critic' | 'docs' | 'designer';
2
+ export type OutputType = 'review' | 'test' | 'research' | 'analysis' | 'summary';
3
+ export interface AgentOutputMetadata {
4
+ agent: AgentType;
5
+ type: OutputType;
6
+ taskId: string;
7
+ phase: number;
8
+ timestamp: string;
9
+ durationMs?: number;
10
+ success?: boolean;
11
+ }
12
+ /**
13
+ * Write agent output to persistent storage
14
+ * Output: .swarm/outputs/phase-N/task-N.M/{agent}-{type}-{timestamp}.md
15
+ */
16
+ export declare function writeAgentOutput(directory: string, metadata: AgentOutputMetadata, content: string): Promise<string>;
17
+ /**
18
+ * Read agent output from persistent storage
19
+ */
20
+ export declare function readAgentOutput(directory: string, phase: number, taskId: string): Promise<{
21
+ metadata: AgentOutputMetadata;
22
+ content: string;
23
+ }[]>;
24
+ /**
25
+ * List all agent outputs for a phase
26
+ */
27
+ export declare function listAgentOutputs(directory: string, phase?: number): Promise<AgentOutputMetadata[]>;
@@ -0,0 +1 @@
1
+ export { type AgentOutputMetadata, type AgentType, listAgentOutputs, type OutputType, readAgentOutput, writeAgentOutput, } from './agent-writer';
@@ -0,0 +1,34 @@
1
+ export interface TaskNode {
2
+ id: string;
3
+ phase: number;
4
+ description: string;
5
+ depends: string[];
6
+ dependents: string[];
7
+ status: 'pending' | 'in_progress' | 'complete' | 'blocked';
8
+ }
9
+ export interface DependencyGraph {
10
+ tasks: Map<string, TaskNode>;
11
+ phases: Map<number, string[]>;
12
+ roots: string[];
13
+ leaves: string[];
14
+ }
15
+ /**
16
+ * Parse plan.json and build dependency graph
17
+ */
18
+ export declare function parseDependencyGraph(planPath: string): DependencyGraph;
19
+ /**
20
+ * Get tasks that can run in parallel (no unresolved dependencies)
21
+ */
22
+ export declare function getRunnableTasks(graph: DependencyGraph): string[];
23
+ /**
24
+ * Check if a task is blocked (has incomplete dependencies)
25
+ */
26
+ export declare function isTaskBlocked(graph: DependencyGraph, taskId: string): boolean;
27
+ /**
28
+ * Get execution order (topological sort)
29
+ */
30
+ export declare function getExecutionOrder(graph: DependencyGraph): string[];
31
+ /**
32
+ * Find all paths from root to a task
33
+ */
34
+ export declare function getDependencyChain(graph: DependencyGraph, taskId: string): string[];
@@ -0,0 +1,33 @@
1
+ export interface FileLock {
2
+ filePath: string;
3
+ agent: string;
4
+ taskId: string;
5
+ timestamp: string;
6
+ expiresAt: number;
7
+ }
8
+ /**
9
+ * Try to acquire a lock on a file
10
+ */
11
+ export declare function tryAcquireLock(directory: string, filePath: string, agent: string, taskId: string): {
12
+ acquired: true;
13
+ lock: FileLock;
14
+ } | {
15
+ acquired: false;
16
+ existing?: FileLock;
17
+ };
18
+ /**
19
+ * Release a lock on a file
20
+ */
21
+ export declare function releaseLock(directory: string, filePath: string, taskId: string): boolean;
22
+ /**
23
+ * Check if a file is locked
24
+ */
25
+ export declare function isLocked(directory: string, filePath: string): FileLock | null;
26
+ /**
27
+ * Clean up expired locks
28
+ */
29
+ export declare function cleanupExpiredLocks(directory: string): number;
30
+ /**
31
+ * List all active locks
32
+ */
33
+ export declare function listActiveLocks(directory: string): FileLock[];
@@ -0,0 +1,4 @@
1
+ export { type DependencyGraph, getDependencyChain, getExecutionOrder, getRunnableTasks, isTaskBlocked, parseDependencyGraph, type TaskNode, } from './dependency-graph.js';
2
+ export { cleanupExpiredLocks, type FileLock, isLocked, listActiveLocks, releaseLock, tryAcquireLock, } from './file-locks.js';
3
+ export { extractMetaSummaries, getLatestTaskSummary, indexMetaSummaries, type MetaSummaryEntry, querySummaries, } from './meta-indexer.js';
4
+ export { type ComplexityMetrics, computeComplexity, type ReviewDepth, type ReviewRouting, routeReview, routeReviewForChanges, shouldParallelizeReview, } from './review-router.js';
@@ -0,0 +1,32 @@
1
+ export interface MetaSummaryEntry {
2
+ timestamp: string;
3
+ phase?: number;
4
+ taskId?: string;
5
+ agent?: string;
6
+ summary: string;
7
+ source?: string;
8
+ }
9
+ /**
10
+ * Extract meta.summary from event JSONL files
11
+ */
12
+ export declare function extractMetaSummaries(eventsPath: string): MetaSummaryEntry[];
13
+ /**
14
+ * Index meta summaries to external knowledge store
15
+ */
16
+ export declare function indexMetaSummaries(directory: string, externalKnowledgeDir?: string): Promise<{
17
+ indexed: number;
18
+ path: string;
19
+ }>;
20
+ /**
21
+ * Query indexed summaries
22
+ */
23
+ export declare function querySummaries(directory: string, options?: {
24
+ phase?: number;
25
+ taskId?: string;
26
+ agent?: string;
27
+ since?: string;
28
+ }): MetaSummaryEntry[];
29
+ /**
30
+ * Get latest summary for a task
31
+ */
32
+ export declare function getLatestTaskSummary(directory: string, taskId: string): MetaSummaryEntry | undefined;
@@ -0,0 +1,29 @@
1
+ export type ReviewDepth = 'single' | 'double';
2
+ export interface ReviewRouting {
3
+ reviewerCount: number;
4
+ testEngineerCount: number;
5
+ depth: ReviewDepth;
6
+ reason: string;
7
+ }
8
+ export interface ComplexityMetrics {
9
+ fileCount: number;
10
+ functionCount: number;
11
+ astChangeCount: number;
12
+ maxFileComplexity: number;
13
+ }
14
+ /**
15
+ * Compute complexity metrics for a set of files
16
+ */
17
+ export declare function computeComplexity(directory: string, changedFiles: string[]): Promise<ComplexityMetrics>;
18
+ /**
19
+ * Determine review routing based on complexity
20
+ */
21
+ export declare function routeReview(metrics: ComplexityMetrics): ReviewRouting;
22
+ /**
23
+ * Route review with full analysis
24
+ */
25
+ export declare function routeReviewForChanges(directory: string, changedFiles: string[]): Promise<ReviewRouting>;
26
+ /**
27
+ * Check if review should be parallelized
28
+ */
29
+ export declare function shouldParallelizeReview(routing: ReviewRouting): boolean;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Skill definition with versioning and per-agent overlays
3
+ */
4
+ export interface AgentOverlay {
5
+ agent: string;
6
+ prompt?: string;
7
+ model?: string;
8
+ }
9
+ export interface SkillDefinition {
10
+ id: string;
11
+ name: string;
12
+ description: string;
13
+ SKILL_VERSION: number;
14
+ basePrompt?: string;
15
+ agents?: AgentOverlay[];
16
+ }
17
+ export declare const skills: SkillDefinition[];
18
+ export declare const AGENT_OVERLAYS: Record<string, AgentOverlay[]>;
19
+ /**
20
+ * Get skill by ID
21
+ */
22
+ export declare function getSkill(id: string): SkillDefinition | undefined;
23
+ /**
24
+ * Get agent overlay for a skill
25
+ */
26
+ export declare function getAgentOverlay(skillId: string, agent: string): AgentOverlay | undefined;
27
+ /**
28
+ * Resolve effective prompt for an agent on a skill
29
+ */
30
+ export declare function resolveAgentPrompt(skillId: string, agent: string, defaultPrompt: string): string;
@@ -29,7 +29,7 @@ export declare function containsControlChars(str: string): boolean;
29
29
  export declare function validateArgs(args: unknown): args is {
30
30
  mode: 'fix' | 'check';
31
31
  };
32
- export declare function getLinterCommand(linter: SupportedLinter, mode: 'fix' | 'check'): string[];
32
+ export declare function getLinterCommand(linter: SupportedLinter, mode: 'fix' | 'check', projectDir: string): string[];
33
33
  /**
34
34
  * Build the shell command for an additional (non-JS/TS) linter.
35
35
  * cppcheck has no --fix mode; csharp and some others behave differently.
@@ -41,7 +41,7 @@ export declare function getAdditionalLinterCommand(linter: AdditionalLinter, mod
41
41
  */
42
42
  export declare function detectAdditionalLinter(cwd: string): 'ruff' | 'clippy' | 'golangci-lint' | 'checkstyle' | 'ktlint' | 'dotnet-format' | 'cppcheck' | 'swiftlint' | 'dart-analyze' | 'rubocop' | null;
43
43
  export declare function detectAvailableLinter(): Promise<SupportedLinter | null>;
44
- export declare function runLint(linter: SupportedLinter, mode: 'fix' | 'check'): Promise<LintResult>;
44
+ export declare function runLint(linter: SupportedLinter, mode: 'fix' | 'check', directory: string): Promise<LintResult>;
45
45
  /**
46
46
  * Run an additional (non-JS/TS) linter.
47
47
  * Follows the same structure as runLint() but uses getAdditionalLinterCommand().
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Delegation Envelope Types
3
+ * Interface for passing delegated tasks between agents
4
+ */
5
+ export interface DelegationEnvelope {
6
+ taskId: string;
7
+ targetAgent: string;
8
+ action: string;
9
+ commandType: 'task' | 'slash_command';
10
+ files: string[];
11
+ acceptanceCriteria: string[];
12
+ technicalContext: string;
13
+ errorStrategy?: 'FAIL_FAST' | 'BEST_EFFORT';
14
+ platformNotes?: string;
15
+ }
16
+ /**
17
+ * Validation result types
18
+ */
19
+ export type EnvelopeValidationResult = {
20
+ valid: true;
21
+ } | {
22
+ valid: false;
23
+ reason: string;
24
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.19.8",
3
+ "version": "6.20.1",
4
4
  "description": "Architect-centric agentic swarm plugin for OpenCode - hub-and-spoke orchestration with SME consultation, code generation, and QA review",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",