opencode-swarm 6.74.1 → 6.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export { createNoopDispatcher, type NoopDispatcher, } from './noop-dispatcher.js';
2
+ export type { DispatchDecision, DispatcherConfig, RunSlot, TaskExecutionHandle, } from './types.js';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * No-op dispatcher — returned when parallelization is disabled (the default).
3
+ *
4
+ * All dispatch methods return a 'reject' decision with reason
5
+ * 'parallelization_disabled'. No file I/O, no side effects, no imports of
6
+ * production runtime modules.
7
+ *
8
+ * PR 2 will implement the enabled dispatcher path behind the same factory
9
+ * interface.
10
+ */
11
+ import type { DispatchDecision, DispatcherConfig, TaskExecutionHandle } from './types.js';
12
+ export interface NoopDispatcher {
13
+ readonly config: DispatcherConfig;
14
+ dispatch(taskId: string): DispatchDecision;
15
+ handles(): TaskExecutionHandle[];
16
+ shutdown(): void;
17
+ }
18
+ export declare function createNoopDispatcher(config: DispatcherConfig): NoopDispatcher;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Tests for the no-op dispatcher (Phase 5 dark foundation).
3
+ *
4
+ * Proves:
5
+ * - disabled config → reject with 'parallelization_disabled'
6
+ * - no file I/O, no side effects on dispatch
7
+ * - handles() always empty
8
+ * - shutdown() is a no-op
9
+ */
10
+ export {};
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Type-only surfaces for the parallel task dispatcher (dark — PR 1 foundation).
3
+ *
4
+ * No runtime behavior here. PR 2 will implement the enabled path.
5
+ */
6
+ export interface DispatcherConfig {
7
+ enabled: boolean;
8
+ maxConcurrentTasks: number;
9
+ evidenceLockTimeoutMs: number;
10
+ }
11
+ export interface RunSlot {
12
+ slotId: string;
13
+ taskId: string;
14
+ runId: string;
15
+ startedAt: number;
16
+ }
17
+ export type DispatchDecision = {
18
+ action: 'dispatch';
19
+ reason: string;
20
+ slot: RunSlot;
21
+ } | {
22
+ action: 'defer';
23
+ reason: string;
24
+ } | {
25
+ action: 'reject';
26
+ reason: string;
27
+ };
28
+ export interface TaskExecutionHandle {
29
+ slotId: string;
30
+ taskId: string;
31
+ runId: string;
32
+ cancel(): void;
33
+ }
@@ -1,3 +1,4 @@
1
+ export { EvidenceLockTimeoutError, withEvidenceLock, } from '../evidence/lock.js';
1
2
  export { type DependencyGraph, getDependencyChain, getExecutionOrder, getRunnableTasks, isTaskBlocked, parseDependencyGraph, type TaskNode, } from './dependency-graph.js';
2
3
  export { cleanupExpiredLocks, type FileLock, isLocked, listActiveLocks, releaseLock, tryAcquireLock, } from './file-locks.js';
3
4
  export { extractMetaSummaries, getLatestTaskSummary, indexMetaSummaries, type MetaSummaryEntry, querySummaries, } from './meta-indexer.js';
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Tests for retryCasWithBackoff — Phase 4 (CAS retry with exponential backoff).
3
+ *
4
+ * Verifies:
5
+ * - Backoff schedule: 5ms start, doubles each attempt, cap 250ms, ±25% jitter
6
+ * - plan_ledger_cas_retry telemetry is emitted on each retry (hash prefixes only)
7
+ * - PlanConcurrentModificationError is thrown when retries are exhausted
8
+ * - verifyValid returning false causes early exit without error
9
+ */
10
+ export {};
@@ -7,8 +7,25 @@ export declare class PlanConcurrentModificationError extends Error {
7
7
  constructor(message: string);
8
8
  }
9
9
  import { type Plan, type RuntimePlan, type TaskStatus } from '../config/plan-schema';
10
+ import { type LedgerEvent, type LedgerEventInput } from './ledger';
10
11
  /** Reset the startup ledger check flag. For testing only. */
11
12
  export declare function resetStartupLedgerCheck(): void;
13
+ /**
14
+ * Append a ledger event with exponential-backoff retry on stale-writer conflicts.
15
+ *
16
+ * Replaces the raw `appendLedgerEventWithRetry` call in savePlan with a helper
17
+ * that uses the project-standard backoff schedule and emits observable telemetry
18
+ * on each retry. Hash values in telemetry are truncated to 8-char prefixes to
19
+ * avoid leaking full content hashes into event streams.
20
+ *
21
+ * Backoff schedule: start=5ms, doubles each attempt, cap=250ms, ±25% jitter.
22
+ */
23
+ export declare function retryCasWithBackoff(directory: string, eventInput: LedgerEventInput, options: {
24
+ expectedHash: string;
25
+ planHashAfter?: string;
26
+ verifyValid?: () => Promise<boolean> | boolean;
27
+ maxRetries?: number;
28
+ }): Promise<LedgerEvent | null>;
12
29
  /**
13
30
  * Load plan.json ONLY without auto-migration from plan.md.
14
31
  * Returns null if plan.json doesn't exist or is invalid.
@@ -0,0 +1,24 @@
1
+ /**
2
+ * AgentRunContext — typed per-run state container.
3
+ *
4
+ * Holds the subset of swarmState needed for future per-run isolation:
5
+ * activeToolCalls, activeAgent, delegationChains, agentSessions,
6
+ * environmentProfiles, and a shared reference to process-global toolAggregates.
7
+ *
8
+ * PR 1 (dark foundation): the class exists and is instantiated for the default
9
+ * single-run path only. No runtime behavior is changed.
10
+ * PR 2 will wire distinct contexts to parallel dispatcher slots.
11
+ *
12
+ * Generic type parameters let state.ts bind concrete internal types without
13
+ * creating a circular import.
14
+ */
15
+ export declare class AgentRunContext<TToolCall = unknown, TToolAgg = unknown, TDelegation = unknown, TSession = unknown, TEnvProfile = unknown> {
16
+ readonly runId: string;
17
+ readonly activeToolCalls: Map<string, TToolCall>;
18
+ readonly activeAgent: Map<string, string>;
19
+ readonly delegationChains: Map<string, TDelegation[]>;
20
+ readonly agentSessions: Map<string, TSession>;
21
+ readonly environmentProfiles: Map<string, TEnvProfile>;
22
+ readonly toolAggregates: Map<string, TToolAgg>;
23
+ constructor(runId: string, toolAggregates: Map<string, TToolAgg>);
24
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Tests for AgentRunContext and getRunContext (Phase 3 — dark foundation).
3
+ *
4
+ * Verifies:
5
+ * 1. swarmState maps are the same objects as defaultRunContext maps (facade equivalence).
6
+ * 2. Distinct AgentRunContext instances do not share per-run maps.
7
+ * 3. toolAggregates is intentionally process-global (shared reference).
8
+ * 4. getRunContext with no arg / unknown runId returns defaultRunContext.
9
+ */
10
+ export {};
package/dist/state.d.ts CHANGED
@@ -9,6 +9,8 @@
9
9
  import type { OpencodeClient } from '@opencode-ai/sdk';
10
10
  import { type QaGates } from './db/qa-gate-profile.js';
11
11
  import { type EnvironmentProfile } from './environment/profile.js';
12
+ import { AgentRunContext } from './state/agent-run-context.js';
13
+ export { AgentRunContext } from './state/agent-run-context.js';
12
14
  /**
13
15
  * Represents a single tool call entry for tracking purposes
14
16
  */
@@ -203,12 +205,24 @@ export interface InvocationWindow {
203
205
  warningReason: string;
204
206
  }
205
207
  /**
206
- * Singleton state object for sharing data across hooks
208
+ * Default run context — the single active run for current single-threaded behavior.
209
+ * PR 2 will create additional contexts for parallel dispatcher slots.
210
+ */
211
+ export declare const defaultRunContext: AgentRunContext<ToolCallEntry, ToolAggregate, DelegationEntry, AgentSessionState, EnvironmentProfile>;
212
+ /**
213
+ * Return the AgentRunContext for the given runId.
214
+ * No argument or unknown runId returns defaultRunContext (single-run semantics preserved).
215
+ */
216
+ export declare function getRunContext(runId?: string): typeof defaultRunContext;
217
+ /**
218
+ * Singleton state object for sharing data across hooks.
219
+ * Per-run maps are backed by defaultRunContext so that swarmState references
220
+ * stay valid and single-run behavior is unchanged.
207
221
  */
208
222
  export declare const swarmState: {
209
223
  /** Active tool calls — keyed by callID for before→after correlation */
210
224
  activeToolCalls: Map<string, ToolCallEntry>;
211
- /** Aggregated tool usage stats — keyed by tool name */
225
+ /** Aggregated tool usage stats — process-global accumulator */
212
226
  toolAggregates: Map<string, ToolAggregate>;
213
227
  /** Active agent per session — keyed by sessionID, updated by chat.message hook */
214
228
  activeAgent: Map<string, string>;
@@ -1,4 +1,4 @@
1
- export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activated' | 'delegation_begin' | 'delegation_end' | 'task_state_changed' | 'gate_passed' | 'gate_failed' | 'phase_changed' | 'budget_updated' | 'model_fallback' | 'hard_limit_hit' | 'revision_limit_hit' | 'loop_detected' | 'scope_violation' | 'qa_skip_violation' | 'heartbeat' | 'turbo_mode_changed' | 'auto_oversight_escalation' | 'environment_detected';
1
+ export type TelemetryEvent = 'session_started' | 'session_ended' | 'agent_activated' | 'delegation_begin' | 'delegation_end' | 'task_state_changed' | 'gate_passed' | 'gate_failed' | 'phase_changed' | 'budget_updated' | 'model_fallback' | 'hard_limit_hit' | 'revision_limit_hit' | 'loop_detected' | 'scope_violation' | 'qa_skip_violation' | 'heartbeat' | 'turbo_mode_changed' | 'auto_oversight_escalation' | 'environment_detected' | 'evidence_lock_acquired' | 'evidence_lock_contended' | 'evidence_lock_stale_recovered' | 'plan_ledger_cas_retry';
2
2
  export type TelemetryListener = (event: TelemetryEvent, data: Record<string, unknown>) => void;
3
3
  /** @internal - For testing only */
4
4
  export declare function resetTelemetryForTesting(): void;
@@ -50,5 +50,37 @@ export interface TestErrorResult {
50
50
  }
51
51
  export type TestResult = TestSuccessResult | TestErrorResult;
52
52
  export declare function detectTestFramework(cwd: string): Promise<TestFramework>;
53
+ /**
54
+ * Returns true when `basename` matches a language-specific test file naming
55
+ * convention that is NOT captured by the compound-extension or dot-separated
56
+ * `.test.`/`.spec.` checks above.
57
+ *
58
+ * Covered patterns (all lower-cased for comparison):
59
+ * Go : <name>_test.go (per `go test` convention)
60
+ * Python: test_<name>.py (pytest discovery default)
61
+ * <name>_test.py (pytest alternative)
62
+ * Ruby : <name>_spec.rb (RSpec convention)
63
+ * Java : Test<Name>.java (JUnit 4/5 prefix)
64
+ * <Name>Test.java (JUnit 4/5 suffix)
65
+ * <Name>Tests.java (JUnit 4/5 plural suffix)
66
+ * <Name>IT.java (Maven Failsafe integration-test suffix)
67
+ * C# : <Name>Test.cs (xUnit/NUnit/MSTest suffix)
68
+ * <Name>Tests.cs (xUnit/NUnit/MSTest plural suffix)
69
+ * Rust : test files are recognized by test-directory placement
70
+ * (for example, tests/<anything>.rs via /tests/ path detection)
71
+ * Kotlin: <Name>Test.kt / <Name>Tests.kt / Test<Name>.kt
72
+ *
73
+ * Exported for unit tests; production code uses it only through
74
+ * getTestFilesFromConvention.
75
+ */
76
+ export declare function isLanguageSpecificTestFile(basename: string): boolean;
77
+ /**
78
+ * Map source files (or already-test files) to the test files that should be
79
+ * run for them. Handles any language whose test files follow a naming convention
80
+ * — TS/JS, Go, Python, Ruby, Java, C#, Kotlin, PowerShell.
81
+ *
82
+ * Exported for unit tests.
83
+ */
84
+ export declare function getTestFilesFromConvention(sourceFiles: string[], workingDir?: string): string[];
53
85
  export declare function runTests(framework: TestFramework, scope: 'all' | 'convention' | 'graph' | 'impact', files: string[], coverage: boolean, timeout_ms: number, cwd: string): Promise<TestResult>;
54
86
  export declare const test_runner: ReturnType<typeof tool>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "6.74.1",
3
+ "version": "6.76.0",
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",