opencode-swarm 7.97.0 → 7.98.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.
Files changed (31) hide show
  1. package/README.md +7 -1
  2. package/dist/agents/architect.d.ts +1 -1
  3. package/dist/cli/{config-doctor-h1xrvq83.js → config-doctor-7yrxfa6b.js} +2 -2
  4. package/dist/cli/{guardrail-explain-t6svvtmn.js → guardrail-explain-cm08h4mt.js} +5 -5
  5. package/dist/cli/{guardrail-log-9yyeccv5.js → guardrail-log-53z1cf46.js} +3 -3
  6. package/dist/cli/{index-a9ghr5cx.js → index-0rgde8qc.js} +2 -2
  7. package/dist/cli/{index-tqbb2jx6.js → index-471qxz9g.js} +33 -9
  8. package/dist/cli/{index-b223mczb.js → index-5z2e78tv.js} +1 -1
  9. package/dist/cli/{index-byb9tgay.js → index-attgb1ma.js} +6 -6
  10. package/dist/cli/{index-rdc6nvmw.js → index-gnd1280x.js} +1 -1
  11. package/dist/cli/{index-sgdr2e4n.js → index-zgba613y.js} +63 -64
  12. package/dist/cli/{index-xx3sv77e.js → index-zy22fg5h.js} +1 -1
  13. package/dist/cli/index.js +4 -4
  14. package/dist/cli/{schema-a8fneygm.js → schema-mygkbbe9.js} +5 -1
  15. package/dist/config/constants.d.ts +4 -0
  16. package/dist/config/schema.d.ts +11 -0
  17. package/dist/evidence/normalize-verdict.d.ts +67 -0
  18. package/dist/hooks/knowledge-curator.d.ts +1 -0
  19. package/dist/hooks/knowledge-injector.d.ts +1 -1
  20. package/dist/index.js +758 -355
  21. package/dist/services/external-skill-validator.d.ts +10 -2
  22. package/dist/services/injection-budget.d.ts +98 -0
  23. package/dist/summaries/summarizer.d.ts +36 -0
  24. package/dist/tools/context-status.d.ts +102 -0
  25. package/dist/tools/index.d.ts +1 -0
  26. package/dist/tools/manifest.d.ts +1 -0
  27. package/dist/tools/tool-metadata.d.ts +11 -7
  28. package/dist/tools/write-drift-evidence.d.ts +11 -0
  29. package/dist/tools/write-hallucination-evidence.d.ts +11 -0
  30. package/dist/tools/write-mutation-evidence.d.ts +11 -0
  31. package/package.json +1 -1
@@ -105,7 +105,13 @@ export declare const VALIDATION_RATE_LIMITS: {
105
105
  /** Timeout for individual fetch operations in milliseconds. */
106
106
  readonly fetch_timeout_ms: 30000;
107
107
  };
108
- declare function stripMarkdownCodeForUnsafeScan(text: string): string;
108
+ interface MarkdownSegment {
109
+ value: string;
110
+ isCode: boolean;
111
+ }
112
+ declare function splitMarkdownCodeSegments(text: string): MarkdownSegment[];
113
+ declare function isDangerousRemovalTarget(rawTarget: string): boolean;
114
+ declare function hasDangerousRemovalTarget(text: string): boolean;
109
115
  /**
110
116
  * Scan an external skill candidate for prompt-injection patterns.
111
117
  *
@@ -158,6 +164,8 @@ export declare function evaluateCandidate(candidate: ExternalSkillCandidate, opt
158
164
  export declare const _internals: {
159
165
  getTimestamp: () => string;
160
166
  computeSha256: (content: string) => string;
161
- stripMarkdownCodeForUnsafeScan: typeof stripMarkdownCodeForUnsafeScan;
167
+ splitMarkdownCodeSegments: typeof splitMarkdownCodeSegments;
168
+ hasDangerousRemovalTarget: typeof hasDangerousRemovalTarget;
169
+ isDangerousRemovalTarget: typeof isDangerousRemovalTarget;
162
170
  };
163
171
  export {};
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Unified Injection Budget Service (FR-002).
3
+ *
4
+ * Pure, side-effect-free allocation function for the combined
5
+ * system-enhancer + knowledge-injector injection ceiling.
6
+ *
7
+ * Allocation strategy: proportional share.
8
+ * - When combined demand fits within the budget, each component receives its
9
+ * full requested amount.
10
+ * - When one component alone exceeds the budget, it receives the entire budget
11
+ * and the other receives zero (SC-005: single-component overrun is impossible).
12
+ * - When both together exceed the budget but neither alone does, the budget is
13
+ * split proportionally to each component's demand. The system-enhancer
14
+ * receives the floor of its proportional share; the knowledge-injector
15
+ * receives the remainder so the total always equals the ceiling (SC-006).
16
+ *
17
+ * Proportional share is chosen over first-come-first-served because this
18
+ * service is a pure function with no knowledge of hook ordering; it must
19
+ * produce the same allocation regardless of which component calls first.
20
+ * Priority-based allocation would require an arbitrary component ranking
21
+ * not specified by the acceptance criteria.
22
+ *
23
+ * Char-to-token conversion uses the project's existing 0.33 tok/char ratio
24
+ * (matches `estimateTokens` in src/hooks/utils.ts:200).
25
+ */
26
+ /**
27
+ * Allocation result for a single turn's unified injection budget.
28
+ */
29
+ export interface InjectionBudgetAllocation {
30
+ /** Tokens granted to the system-enhancer (input was already in tokens). */
31
+ systemEnhancerTokens: number;
32
+ /** Tokens granted to the knowledge-injector (converted from chars to tokens). */
33
+ knowledgeInjectorTokens: number;
34
+ /** Sum of both allocations; never exceeds the configured budget. */
35
+ totalTokens: number;
36
+ }
37
+ /**
38
+ * Configuration for the unified injection budget.
39
+ */
40
+ export interface InjectionBudgetConfig {
41
+ /** Unified ceiling (tokens) for combined system-enhancer + knowledge-injector injection per turn. */
42
+ totalBudgetTokens: number;
43
+ }
44
+ /**
45
+ * Allocate the unified injection budget between system-enhancer and
46
+ * knowledge-injector for a single turn.
47
+ *
48
+ * The allocation respects the configured ceiling and guarantees:
49
+ * - totalTokens ≤ config.totalBudgetTokens
50
+ * - If one component alone exceeds the budget, the other receives zero.
51
+ * - If combined demand fits, each receives its full demand.
52
+ * - If combined demand exceeds the budget but neither alone does, the split
53
+ * is proportional to each component's demand.
54
+ *
55
+ * @param systemEnhancerDemandTokens - Tokens requested by the system-enhancer.
56
+ * @param knowledgeInjectorDemandChars - Characters requested by the knowledge-injector.
57
+ * @param config - Budget configuration containing the total ceiling.
58
+ * @returns Allocation breakdown with per-component token grants.
59
+ */
60
+ export declare function allocateInjectionBudget(systemEnhancerDemandTokens: number, knowledgeInjectorDemandChars: number, config: InjectionBudgetConfig): InjectionBudgetAllocation;
61
+ /**
62
+ * Reset the budget for a session to the full unified ceiling.
63
+ * Called by the first component to run for a given turn.
64
+ */
65
+ export declare function resetUnifiedBudget(sessionID: string, totalBudget: number): void;
66
+ /**
67
+ * Return the remaining unified budget for a session.
68
+ */
69
+ export declare function getUnifiedBudgetRemaining(sessionID: string): number;
70
+ /**
71
+ * Request a slice of the unified budget. Returns the granted token count.
72
+ * If the requester's need exceeds the remaining budget, it gets the remainder
73
+ * and the other source is implicitly blocked (remaining drops to 0).
74
+ */
75
+ export declare function requestUnifiedBudget(sessionID: string, requestedTokens: number): number;
76
+ /**
77
+ * Return the total unified budget configured for a session (or 0 if unset).
78
+ */
79
+ export declare function getUnifiedBudgetTotal(sessionID: string): number;
80
+ /**
81
+ * Remove a session's budget entry. Used for cleanup in tests.
82
+ */
83
+ export declare function clearUnifiedBudget(sessionID: string): void;
84
+ /**
85
+ * Ensure a budget entry exists for the session. Creates one with the full
86
+ * budget if none exists; leaves an existing entry untouched.
87
+ */
88
+ export declare function ensureSessionBudget(sessionID: string, totalBudget: number): void;
89
+ /**
90
+ * Store the system-enhancer's actual per-turn token demand so that
91
+ * knowledge-injector can read it and compute its proportional share.
92
+ */
93
+ export declare function setSystemEnhancerDemand(sessionID: string, demand: number): void;
94
+ /**
95
+ * Return the system-enhancer's actual per-turn token demand for a session.
96
+ * Returns 0 if no budget entry exists or demand was not set.
97
+ */
98
+ export declare function getSystemEnhancerDemand(sessionID: string): number;
@@ -26,6 +26,31 @@ export declare function detectContentType(output: string, toolName: string): Con
26
26
  * @returns true if the output should be summarized
27
27
  */
28
28
  export declare function shouldSummarize(output: string, thresholdBytes: number): boolean;
29
+ /**
30
+ * Infer a compact type signature for a JSON value.
31
+ */
32
+ declare function jsonTypeSignature(value: unknown): string;
33
+ /**
34
+ * Build a structure-aware preview for a JSON object.
35
+ * Shows ALL top-level keys with their type signatures (AC-008 / SC-012).
36
+ */
37
+ declare function summarizeJsonObject(parsed: Record<string, unknown>): string;
38
+ /**
39
+ * Build a structure-aware preview for a JSON array.
40
+ */
41
+ declare function summarizeJsonArray(parsed: unknown[]): string;
42
+ /**
43
+ * Extract declaration names from code text.
44
+ */
45
+ declare function extractCodeSignatures(code: string): string[];
46
+ /**
47
+ * Build a preview for code output that includes declaration signatures.
48
+ */
49
+ declare function summarizeCode(output: string): string;
50
+ /**
51
+ * Build a preview for plain text output (leading non-blank lines).
52
+ */
53
+ declare function summarizeText(output: string, maxLines: number): string;
29
54
  /**
30
55
  * Creates a structured summary string from tool output.
31
56
  * @param output - The full tool output string
@@ -35,4 +60,15 @@ export declare function shouldSummarize(output: string, thresholdBytes: number):
35
60
  * @returns Formatted summary string
36
61
  */
37
62
  export declare function createSummary(output: string, toolName: string, summaryId: string, maxSummaryChars: number): string;
63
+ /**
64
+ * Internal helpers exposed for testability.
65
+ */
66
+ export declare const _internals: {
67
+ jsonTypeSignature: typeof jsonTypeSignature;
68
+ summarizeJsonObject: typeof summarizeJsonObject;
69
+ summarizeJsonArray: typeof summarizeJsonArray;
70
+ extractCodeSignatures: typeof extractCodeSignatures;
71
+ summarizeCode: typeof summarizeCode;
72
+ summarizeText: typeof summarizeText;
73
+ };
38
74
  export {};
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Context Status Tool
3
+ *
4
+ * Read-only tool that reports current context-window headroom for the active
5
+ * session. Derives messages from the runtime session context (via
6
+ * `swarmState.opencodeClient.session.messages`) and resolves thresholds from
7
+ * the plugin config, mirroring the active `createContextBudgetHandler` hook's
8
+ * behavior exactly — including strict `>` boundary semantics (exact threshold
9
+ * values do NOT trigger a warning).
10
+ *
11
+ * Pure read-only: no state mutation, no warning injection, no side effects.
12
+ * Works whether `context_budget.enabled` is true or false.
13
+ */
14
+ import { loadPluginConfig } from '../config';
15
+ import { createSwarmTool } from './create-tool';
16
+ /**
17
+ * Shape of a message's info block.
18
+ * Mirrors the `MessageInfo` interface used by the context-budget hook.
19
+ */
20
+ interface MessageInfo {
21
+ role: string;
22
+ agent?: string;
23
+ sessionID?: string;
24
+ modelID?: string;
25
+ providerID?: string;
26
+ [key: string]: unknown;
27
+ }
28
+ /**
29
+ * Shape of a single message part (text chunk).
30
+ * Mirrors the `MessagePart` interface used by the context-budget hook.
31
+ */
32
+ interface MessagePart {
33
+ type: string;
34
+ text?: string;
35
+ [key: string]: unknown;
36
+ }
37
+ /**
38
+ * Shape of a single message in the session array.
39
+ * Mirrors `MessageWithParts` from the context-budget hook.
40
+ */
41
+ export interface ContextMessage {
42
+ info: MessageInfo;
43
+ parts: MessagePart[];
44
+ [key: string]: unknown;
45
+ }
46
+ /**
47
+ * Result returned by the context_status tool.
48
+ */
49
+ export interface ContextStatusResult {
50
+ /** Estimated tokens used across all text parts in the session */
51
+ tokensUsed: number;
52
+ /** Resolved model context limit in tokens */
53
+ modelLimit: number;
54
+ /** Ratio of tokens-used to model-limit (0.0 – 1.0+) */
55
+ usagePercent: number;
56
+ /** Threshold state: 'none' | 'warn' | 'critical' */
57
+ thresholdCrossed: 'none' | 'warn' | 'critical';
58
+ /** Model identifier detected from the most recent assistant message */
59
+ modelId: string | null;
60
+ /** Provider identifier detected from the most recent assistant message */
61
+ provider: string | null;
62
+ }
63
+ /**
64
+ * Test-only dependency-injection seam. Production code calls
65
+ * `_internals.loadPluginConfig(...)` and `_internals.fetchSessionMessages(...)`
66
+ * so tests can replace these functions without `mock.module` leakage across
67
+ * Bun's shared test-runner process. Mutating this local object is file-scoped
68
+ * and trivially restorable via `afterEach`.
69
+ */
70
+ export declare const _internals: {
71
+ loadPluginConfig: typeof loadPluginConfig;
72
+ fetchSessionMessages: (sessionID: string, directory: string, limit?: number) => Promise<ContextMessage[] | null>;
73
+ };
74
+ /**
75
+ * Compute context headroom from a session message array.
76
+ * Pure function — no side effects, no logging, no state mutation.
77
+ *
78
+ * @param messages - Session messages (same shape as experimental.chat.messages.transform output)
79
+ * @param warnThreshold - Usage ratio that triggers 'warn' state (default 0.7)
80
+ * @param criticalThreshold - Usage ratio that triggers 'critical' state (default 0.9)
81
+ * @param modelLimitsConfig - Model-specific limit overrides from config
82
+ * @returns Context status with token usage, limit, and threshold state
83
+ */
84
+ declare function computeContextHeadroom(messages: ContextMessage[], warnThreshold?: number, criticalThreshold?: number, modelLimitsConfig?: Record<string, number>): ContextStatusResult;
85
+ /**
86
+ * context_status tool — read-only context window headroom report.
87
+ *
88
+ * Architects invoke this on demand to check how much context budget remains
89
+ * without triggering the reactive warning injection that the
90
+ * `createContextBudgetHandler` hook performs.
91
+ *
92
+ * The tool derives messages from the active session context (via
93
+ * `ctx.sessionID` and the OpenCode client session API) and resolves
94
+ * warn/critical thresholds from the plugin config, matching the live
95
+ * context-budget hook's behavior.
96
+ *
97
+ * No arguments required — the tool queries current state automatically.
98
+ *
99
+ * Returns JSON string with tokensUsed, modelLimit, usagePercent, thresholdCrossed, modelId, provider.
100
+ */
101
+ export { computeContextHeadroom };
102
+ export declare const context_status: ReturnType<typeof createSwarmTool>;
@@ -10,6 +10,7 @@ export { checkpoint } from './checkpoint';
10
10
  export { co_change_analyzer } from './co-change-analyzer';
11
11
  export { completion_verify } from './completion-verify';
12
12
  export { complexity_hotspots } from './complexity-hotspots';
13
+ export { context_status } from './context-status';
13
14
  export { submit_council_verdicts } from './convene-council';
14
15
  export { convene_general_council } from './convene-general-council';
15
16
  export { curator_analyze } from './curator-analyze';
@@ -76,6 +76,7 @@ export declare const TOOL_MANIFEST: {
76
76
  knowledge_recall: () => ToolDefinition;
77
77
  knowledge_remove: () => ToolDefinition;
78
78
  co_change_analyzer: () => ToolDefinition;
79
+ context_status: () => ToolDefinition;
79
80
  search: () => ToolDefinition;
80
81
  ast_grep: () => ToolDefinition;
81
82
  actionlint_scan: () => ToolDefinition;
@@ -235,6 +235,10 @@ export declare const TOOL_METADATA: {
235
235
  description: string;
236
236
  agents: "architect"[];
237
237
  };
238
+ context_status: {
239
+ description: string;
240
+ agents: "architect"[];
241
+ };
238
242
  search: {
239
243
  description: string;
240
244
  agents: ("reviewer" | "test_engineer" | "coder" | "docs" | "designer" | "explorer" | "sme" | "critic_hallucination_verifier" | "critic_oversight" | "architect" | "researcher" | "docs_design" | "skill_improver" | "spec_writer")[];
@@ -301,19 +305,19 @@ export declare const TOOL_METADATA: {
301
305
  };
302
306
  skill_generate: {
303
307
  description: string;
304
- agents: ("architect" | "skill_improver")[];
308
+ agents: "skill_improver"[];
305
309
  };
306
310
  skill_list: {
307
311
  description: string;
308
- agents: ("architect" | "skill_improver")[];
312
+ agents: "skill_improver"[];
309
313
  };
310
314
  skill_apply: {
311
315
  description: string;
312
- agents: "architect"[];
316
+ agents: never[];
313
317
  };
314
318
  skill_inspect: {
315
319
  description: string;
316
- agents: ("architect" | "skill_improver")[];
320
+ agents: "skill_improver"[];
317
321
  };
318
322
  run_stale_reconciliation: {
319
323
  description: string;
@@ -321,15 +325,15 @@ export declare const TOOL_METADATA: {
321
325
  };
322
326
  skill_regenerate: {
323
327
  description: string;
324
- agents: "architect"[];
328
+ agents: never[];
325
329
  };
326
330
  skill_retire: {
327
331
  description: string;
328
- agents: "architect"[];
332
+ agents: never[];
329
333
  };
330
334
  skill_improve: {
331
335
  description: string;
332
- agents: ("architect" | "skill_improver")[];
336
+ agents: "skill_improver"[];
333
337
  };
334
338
  spec_write: {
335
339
  description: string;
@@ -4,6 +4,7 @@
4
4
  * a gate-contract formatted evidence file.
5
5
  */
6
6
  import type { ToolDefinition } from '@opencode-ai/plugin/tool';
7
+ import { isAcceptedVerdict2, normalizeVerdict2 } from '../evidence/normalize-verdict';
7
8
  /**
8
9
  * Arguments for the write_drift_evidence tool
9
10
  */
@@ -29,6 +30,16 @@ export interface WriteDriftEvidenceArgs {
29
30
  * @returns JSON string with success status and details
30
31
  */
31
32
  export declare function executeWriteDriftEvidence(args: WriteDriftEvidenceArgs, directory: string): Promise<string>;
33
+ /**
34
+ * Dependency-injection seam for testing. Tests can temporarily replace these
35
+ * to verify that this writer delegates to the shared normalize-verdict module.
36
+ * Restore each entry in afterEach via the saved original reference.
37
+ */
38
+ export declare const _internals: {
39
+ normalizeVerdict2: typeof normalizeVerdict2;
40
+ VERDICT_SET_2: readonly string[];
41
+ isAcceptedVerdict2: typeof isAcceptedVerdict2;
42
+ };
32
43
  /**
33
44
  * Tool definition for write_drift_evidence
34
45
  */
@@ -7,6 +7,7 @@
7
7
  * write a plan snapshot — those side-effects belong to drift verification only.
8
8
  */
9
9
  import type { ToolDefinition } from '@opencode-ai/plugin/tool';
10
+ import { isAcceptedVerdict2, normalizeVerdict2 } from '../evidence/normalize-verdict';
10
11
  /**
11
12
  * Arguments for the write_hallucination_evidence tool
12
13
  */
@@ -24,6 +25,16 @@ export interface WriteHallucinationEvidenceArgs {
24
25
  * Execute the write_hallucination_evidence tool.
25
26
  */
26
27
  export declare function executeWriteHallucinationEvidence(args: WriteHallucinationEvidenceArgs, directory: string): Promise<string>;
28
+ /**
29
+ * Dependency-injection seam for testing. Tests can temporarily replace these
30
+ * to verify that this writer delegates to the shared normalize-verdict module.
31
+ * Restore each entry in afterEach via the saved original reference.
32
+ */
33
+ export declare const _internals: {
34
+ normalizeVerdict2: typeof normalizeVerdict2;
35
+ VERDICT_SET_2: readonly string[];
36
+ isAcceptedVerdict2: typeof isAcceptedVerdict2;
37
+ };
27
38
  /**
28
39
  * Tool definition for write_hallucination_evidence
29
40
  */
@@ -7,6 +7,7 @@
7
7
  * write a plan snapshot — those side-effects belong to drift verification only.
8
8
  */
9
9
  import type { ToolDefinition } from '@opencode-ai/plugin/tool';
10
+ import { isAcceptedVerdict4, normalizeVerdict4 } from '../evidence/normalize-verdict';
10
11
  /**
11
12
  * Arguments for the write_mutation_evidence tool
12
13
  */
@@ -28,6 +29,16 @@ export interface WriteMutationEvidenceArgs {
28
29
  * Execute the write_mutation_evidence tool.
29
30
  */
30
31
  export declare function executeWriteMutationEvidence(args: WriteMutationEvidenceArgs, directory: string): Promise<string>;
32
+ /**
33
+ * Dependency-injection seam for testing. Tests can temporarily replace these
34
+ * to verify that this writer delegates to the shared normalize-verdict module.
35
+ * Restore each entry in afterEach via the saved original reference.
36
+ */
37
+ export declare const _internals: {
38
+ normalizeVerdict4: typeof normalizeVerdict4;
39
+ VERDICT_SET_4: readonly string[];
40
+ isAcceptedVerdict4: typeof isAcceptedVerdict4;
41
+ };
31
42
  /**
32
43
  * Tool definition for write_mutation_evidence
33
44
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-swarm",
3
- "version": "7.97.0",
3
+ "version": "7.98.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",