opencode-ultra 0.9.6 → 0.9.7

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.
@@ -13,5 +13,5 @@ export declare function createCommentCheckerHook(internalSessions: Set<string>,
13
13
  args: Record<string, unknown>;
14
14
  sessionID: string;
15
15
  }, output: {
16
- output: string;
16
+ output: unknown;
17
17
  }) => void;
@@ -1,9 +1,9 @@
1
- export declare function truncateMiddle(input: string, maxChars: number): string;
1
+ export declare function truncateMiddle(input: unknown, maxChars: number): string;
2
2
  export declare function createTokenTruncationHook(internalSessions: Set<string>, maxChars?: number): (input: {
3
3
  tool: string | {
4
4
  name: string;
5
5
  };
6
6
  sessionID: string;
7
7
  }, output: {
8
- output: string;
8
+ output: unknown;
9
9
  }) => void;
package/dist/index.js CHANGED
@@ -27942,7 +27942,8 @@ var INJECTION_PATTERNS = [
27942
27942
  { pattern: /(?:\u65B0\u3057\u3044|\u66F4\u65B0\u3055\u308C\u305F)\u6307\u793A\s*[:\uFF1A]/i, label: "new-instructions-ja" }
27943
27943
  ];
27944
27944
  var SUSPICIOUS_UNICODE = /[\u200B-\u200F\u202A-\u202E\u2060-\u2069\uFEFF\u00AD]/g;
27945
- function sanitizeAgentOutput(text) {
27945
+ function sanitizeAgentOutput(input) {
27946
+ let text = typeof input === "string" ? input : JSON.stringify(input) ?? "";
27946
27947
  const warnings = [];
27947
27948
  const invisibleCount = (text.match(SUSPICIOUS_UNICODE) || []).length;
27948
27949
  if (invisibleCount > 0) {
@@ -28277,7 +28278,7 @@ async function runAgent(ctx, task, toolCtx, internalSessions, resilience, provid
28277
28278
  }), { maxAttempts: 3 });
28278
28279
  const messages = messagesResp.data ?? [];
28279
28280
  const lastAssistant = messages.filter((m) => m.info?.role === "assistant").pop();
28280
- const rawResult = lastAssistant?.parts?.filter((p) => p.type === "text" && p.text).map((p) => p.text).join(`
28281
+ const rawResult = lastAssistant?.parts?.filter((p) => p.type === "text" && p.text).map((p) => typeof p.text === "string" ? p.text : JSON.stringify(p.text)).join(`
28281
28282
  `) ?? "(No response from agent)";
28282
28283
  internalSessions.delete(id);
28283
28284
  await ctx.client.session.delete({ path: { id }, query: { directory: ctx.directory } }).catch(() => {});
@@ -30534,7 +30535,8 @@ function createCommentCheckerHook(internalSessions, maxRatio = 0.3, slopThreshol
30534
30535
  const content = fs12.readFileSync(filePath, "utf-8");
30535
30536
  const result = checkComments(content, filePath, maxRatio, slopThreshold);
30536
30537
  if (result.shouldWarn) {
30537
- output.output += `
30538
+ const current = typeof output.output === "string" ? output.output : JSON.stringify(output.output) ?? "";
30539
+ output.output = current + `
30538
30540
 
30539
30541
  [Comment Checker] ${result.message}`;
30540
30542
  log(`Comment Checker warning: ${filePath}`, {
@@ -30549,13 +30551,14 @@ function createCommentCheckerHook(internalSessions, maxRatio = 0.3, slopThreshol
30549
30551
  // src/hooks/token-truncation.ts
30550
30552
  var DEFAULT_MAX_CHARS = 30000;
30551
30553
  function truncateMiddle(input, maxChars) {
30554
+ const text = typeof input === "string" ? input : JSON.stringify(input) ?? "";
30552
30555
  if (!Number.isFinite(maxChars) || maxChars <= 0)
30553
- return input;
30554
- if (input.length <= maxChars)
30555
- return input;
30556
+ return text;
30557
+ if (text.length <= maxChars)
30558
+ return text;
30556
30559
  if (maxChars < 32)
30557
- return input.slice(0, maxChars);
30558
- const len = input.length;
30560
+ return text.slice(0, maxChars);
30561
+ const len = text.length;
30559
30562
  let head = Math.floor(maxChars * 0.4);
30560
30563
  let tail = Math.floor(maxChars * 0.4);
30561
30564
  head = Math.min(Math.max(head, 1), maxChars);
@@ -30577,9 +30580,9 @@ function truncateMiddle(input, maxChars) {
30577
30580
  const marker22 = buildMarker(removed22);
30578
30581
  const budget = h + marker22.length + finalTail2;
30579
30582
  if (budget > maxChars) {
30580
- return input.slice(0, maxChars);
30583
+ return text.slice(0, maxChars);
30581
30584
  }
30582
- return input.slice(0, h) + marker22 + input.slice(len - finalTail2);
30585
+ return text.slice(0, h) + marker22 + text.slice(len - finalTail2);
30583
30586
  };
30584
30587
  const removed = Math.max(0, len - head - tail);
30585
30588
  const marker = buildMarker(removed);
@@ -30596,7 +30599,7 @@ function createTokenTruncationHook(internalSessions, maxChars = DEFAULT_MAX_CHAR
30596
30599
  return (input, output) => {
30597
30600
  if (internalSessions.has(input.sessionID))
30598
30601
  return;
30599
- const before = output.output;
30602
+ const before = typeof output.output === "string" ? output.output : JSON.stringify(output.output) ?? "";
30600
30603
  const after = truncateMiddle(before, budget);
30601
30604
  if (after !== before) {
30602
30605
  output.output = after;
@@ -11,9 +11,9 @@ export interface SanitizeResult {
11
11
  * Sanitize text from agent outputs to prevent prompt injection.
12
12
  * Returns the cleaned text plus any warnings.
13
13
  */
14
- export declare function sanitizeAgentOutput(text: string): SanitizeResult;
14
+ export declare function sanitizeAgentOutput(input: unknown): SanitizeResult;
15
15
  /**
16
16
  * Apply sanitizer to a spawn_agent result string.
17
17
  * Adds a warning banner if injection was detected.
18
18
  */
19
- export declare function sanitizeSpawnResult(result: string): string;
19
+ export declare function sanitizeSpawnResult(result: unknown): string;
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ThreadWeaver — Complexity Router
3
+ * Determines standard/heavy mode and sparse-activates relevant agents.
4
+ */
5
+ import type { AgentRole, ComplexityAnalysis, ThreadWeaverConfig } from "./types";
6
+ /**
7
+ * Compute complexity score (0-11).
8
+ *
9
+ * Token score: 0-3
10
+ * Domain score: 0-3
11
+ * Heavy signal score: 0-3
12
+ * Question score: 0-2
13
+ */
14
+ export declare function computeComplexityScore(query: string): {
15
+ score: number;
16
+ tokens: number;
17
+ domainCount: number;
18
+ matchedDomains: string[];
19
+ heavySignals: number;
20
+ questions: number;
21
+ };
22
+ /**
23
+ * Compute domain relevance score for a specialist agent against the query.
24
+ * Returns 0.0-1.0 indicating how relevant this agent is.
25
+ */
26
+ export declare function computeDomainRelevance(agent: AgentRole, query: string): number;
27
+ /**
28
+ * Sparse-activate specialist agents based on query domain relevance.
29
+ * Returns only specialists above the activation threshold.
30
+ */
31
+ export declare function sparseActivate(query: string, threshold: number): AgentRole[];
32
+ /**
33
+ * Route complexity and select activated agents.
34
+ */
35
+ export declare function routeComplexity(query: string, config: ThreadWeaverConfig): ComplexityAnalysis;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * ThreadWeaver — Public Exports
3
+ */
4
+ export { createThreadWeaverTool } from "./threadweaver-tool";
5
+ export { runThreadWeaver, type ThreadWeaverDeps } from "./protocol";
6
+ export { routeComplexity, computeComplexityScore, computeDomainRelevance, sparseActivate } from "./complexity-router";
7
+ export { computeDynamicWeights, extractConfidence, parseCritiques, computeCrossAgreement } from "./weighting";
8
+ export { CORE_ROLES, SPECIALIST_ROLES, ALL_ROLES, getCoreRoles, getAllRoles, findRole } from "./roles";
9
+ export { type ThreadWeaverConfig, type ThreadWeaverResult, type ComplexityLevel, type ComplexityAnalysis, type AgentRole, type AgentOutput, type AgentWeight, type Critique, type Dissent, type RoundResult, type RoundType, DEFAULT_THREADWEAVER_CONFIG, } from "./types";
@@ -0,0 +1,25 @@
1
+ /**
2
+ * ThreadWeaver — Prompt Templates
3
+ * Structured prompts for each round of the debate protocol.
4
+ */
5
+ import type { AgentRole, AgentOutput, Critique } from "./types";
6
+ /**
7
+ * Build the analysis prompt for Round 1 (parallel initial analysis).
8
+ */
9
+ export declare function buildAnalysisPrompt(role: AgentRole, query: string): string;
10
+ /**
11
+ * Build the cross-critique prompt for Round 2.
12
+ */
13
+ export declare function buildCritiquePrompt(role: AgentRole, query: string, round1Outputs: AgentOutput[]): string;
14
+ /**
15
+ * Build the revision prompt for Round 3.
16
+ */
17
+ export declare function buildRevisionPrompt(role: AgentRole, query: string, ownRound1Output: AgentOutput, critiquesOfMe: Critique[]): string;
18
+ /**
19
+ * Build the synthesis prompt for the Captain (final round).
20
+ */
21
+ export declare function buildSynthesisPrompt(query: string, round3Outputs: AgentOutput[], weights: Array<{
22
+ agentId: string;
23
+ role: string;
24
+ finalWeight: number;
25
+ }>): string;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * ThreadWeaver — Debate Protocol
3
+ * Orchestrates the 3-round debate loop with parallel agent execution.
4
+ */
5
+ import type { PluginInput, ToolContext } from "@opencode-ai/plugin";
6
+ import { ProviderResilience } from "../shared";
7
+ import type { ConcurrencyPool } from "../concurrency";
8
+ import type { ThreadWeaverConfig, ThreadWeaverResult } from "./types";
9
+ export interface ThreadWeaverDeps {
10
+ pool?: ConcurrencyPool;
11
+ resilience?: ProviderResilience;
12
+ internalSessions: Set<string>;
13
+ }
14
+ /**
15
+ * Main entry point: Run the ThreadWeaver debate protocol.
16
+ */
17
+ export declare function runThreadWeaver(ctx: PluginInput, query: string, userConfig: Partial<ThreadWeaverConfig>, deps: ThreadWeaverDeps, toolCtx: ToolContext): Promise<ThreadWeaverResult>;
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ThreadWeaver — Agent Role Definitions
3
+ * Standard (4 core) + Heavy (16 = 4 core + 12 specialists)
4
+ */
5
+ import type { AgentRole } from "./types";
6
+ export declare const CORE_ROLES: AgentRole[];
7
+ export declare const SPECIALIST_ROLES: AgentRole[];
8
+ /** All 16 roles (4 core + 12 specialists) */
9
+ export declare const ALL_ROLES: AgentRole[];
10
+ /** Get core roles only (standard mode) */
11
+ export declare function getCoreRoles(): AgentRole[];
12
+ /** Get all roles (heavy mode) */
13
+ export declare function getAllRoles(): AgentRole[];
14
+ /** Find a role by ID */
15
+ export declare function findRole(id: string): AgentRole | undefined;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * ThreadWeaver — Tool Registration
3
+ * Registers the threadweaver tool with the OpenCode plugin system.
4
+ */
5
+ import type { PluginInput } from "@opencode-ai/plugin";
6
+ import { tool } from "@opencode-ai/plugin";
7
+ import type { ThreadWeaverConfig } from "./types";
8
+ import { type ThreadWeaverDeps } from "./protocol";
9
+ export declare function createThreadWeaverTool(ctx: PluginInput, twConfig: Partial<ThreadWeaverConfig>, deps: ThreadWeaverDeps): ReturnType<typeof tool>;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * ThreadWeaver — Multi-Agent Debate Protocol
3
+ * All TypeScript type definitions.
4
+ */
5
+ export type ComplexityLevel = "standard" | "heavy";
6
+ export interface ThreadWeaverConfig {
7
+ debateRounds: number;
8
+ heavyThreshold: number;
9
+ forceComplexity: ComplexityLevel | null;
10
+ model: string | null;
11
+ activationThreshold: number;
12
+ roundTimeoutMs: number;
13
+ totalTimeoutMs: number;
14
+ saveLedger: boolean;
15
+ }
16
+ export declare const DEFAULT_THREADWEAVER_CONFIG: ThreadWeaverConfig;
17
+ export interface AgentRole {
18
+ id: string;
19
+ role: string;
20
+ grokEquiv: string;
21
+ focus: string;
22
+ /** Domain keywords for sparse activation relevance scoring */
23
+ domains: string[];
24
+ /** For specialist agents, reference to the core role they extend */
25
+ parentRole?: string;
26
+ }
27
+ export type RoundType = "analysis" | "critique" | "revision";
28
+ export interface AgentOutput {
29
+ agentId: string;
30
+ role: string;
31
+ content: string;
32
+ selfConfidence: number;
33
+ durationMs: number;
34
+ error?: string;
35
+ }
36
+ export interface Critique {
37
+ criticId: string;
38
+ targetId: string;
39
+ /** -1 (disagree), 0 (neutral), 1 (agree) */
40
+ agreement: number;
41
+ issues: string[];
42
+ strengths: string[];
43
+ }
44
+ export interface RoundResult {
45
+ roundNumber: number;
46
+ roundType: RoundType;
47
+ outputs: AgentOutput[];
48
+ critiques?: Critique[];
49
+ durationMs: number;
50
+ }
51
+ export interface AgentWeight {
52
+ agentId: string;
53
+ role: string;
54
+ selfConfidence: number;
55
+ crossAgreement: number;
56
+ domainRelevance: number;
57
+ finalWeight: number;
58
+ }
59
+ export interface Dissent {
60
+ topic: string;
61
+ positions: Array<{
62
+ agentId: string;
63
+ position: string;
64
+ }>;
65
+ }
66
+ export interface ThreadWeaverResult {
67
+ query: string;
68
+ complexity: ComplexityLevel;
69
+ activatedAgents: string[];
70
+ rounds: RoundResult[];
71
+ weights: AgentWeight[];
72
+ synthesis: string;
73
+ dissents: Dissent[];
74
+ totalDurationMs: number;
75
+ partial?: boolean;
76
+ }
77
+ export interface ComplexityAnalysis {
78
+ level: ComplexityLevel;
79
+ score: number;
80
+ activatedAgents: AgentRole[];
81
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * ThreadWeaver — Dynamic Weighting
3
+ * Computes final weights from self-confidence, cross-agreement, and domain relevance.
4
+ */
5
+ import type { AgentOutput, AgentWeight, Critique, AgentRole } from "./types";
6
+ /**
7
+ * Extract self-reported confidence from agent output.
8
+ * Looks for "Confidence: X/10" pattern at end of content.
9
+ * Returns 0.0-1.0 (normalized from 0-10 scale).
10
+ * Default: 0.5 if not found.
11
+ */
12
+ export declare function extractConfidence(content: string): number;
13
+ /**
14
+ * Parse critique blocks from an agent's round-2 output.
15
+ *
16
+ * Expected format:
17
+ * ## Re: [agent-id]
18
+ * Agreement: 1 (or 0, -1)
19
+ * Issues: ...
20
+ * Strengths: ...
21
+ */
22
+ export declare function parseCritiques(criticId: string, content: string): Critique[];
23
+ /**
24
+ * Compute cross-agreement score for an agent.
25
+ * Average of all agreement values from other agents, normalized to 0-1.
26
+ * agreement: -1 → 0.0, 0 → 0.5, 1 → 1.0
27
+ */
28
+ export declare function computeCrossAgreement(agentId: string, allCritiques: Critique[]): number;
29
+ /**
30
+ * Compute dynamic weights for all agents after all rounds.
31
+ *
32
+ * Formula:
33
+ * raw_weight = (selfConfidence * 0.25) + (crossAgreement * 0.45) + (domainRelevance * 0.30)
34
+ * final_weight = raw_weight / sum(all_raw_weights)
35
+ */
36
+ export declare function computeDynamicWeights(outputs: AgentOutput[], allCritiques: Critique[], activatedRoles: AgentRole[], query: string): AgentWeight[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-ultra",
3
- "version": "0.9.6",
3
+ "version": "0.9.7",
4
4
  "description": "Lightweight OpenCode 1.2.x plugin — ultrawork mode, multi-agent orchestration, rules injection",
5
5
  "keywords": [
6
6
  "opencode",