@opencode_weave/weave
Advanced tools
| import type { AdherenceReport, QualityReport } from "./types"; | ||
| /** | ||
| * Baseline tokens-per-task for efficiency scoring. | ||
| * A plan consuming this many tokens per task gets an efficiency score of 0.5. | ||
| * Plans below baseline score above 0.5; plans above baseline score below 0.5. | ||
| * Exported for future configurability and test reference. | ||
| */ | ||
| export declare const BASELINE_TOKENS_PER_TASK = 50000; | ||
| /** | ||
| * Calculate a composite quality score for a completed plan. | ||
| * | ||
| * Inputs: | ||
| * - adherence: coverage and precision from the adherence report | ||
| * - totalTasks / completedTasks: from getPlanProgress() | ||
| * - totalTokens: sum of input + output + reasoning tokens across all sessions | ||
| * | ||
| * Component weights: | ||
| * - adherenceCoverage (30%): fraction of planned files actually changed | ||
| * - adherencePrecision (25%): fraction of actual changes that were planned | ||
| * - taskCompletion (30%): fraction of tasks marked [x] | ||
| * - efficiency (15%): inverse of normalized tokens-per-task (sigmoid-like) | ||
| * | ||
| * Pure function — no I/O. | ||
| */ | ||
| export declare function calculateQualityScore(params: { | ||
| adherence: AdherenceReport; | ||
| totalTasks: number; | ||
| completedTasks: number; | ||
| totalTokens: number; | ||
| }): QualityReport; |
| import type { AssertionResult, EvalArtifacts, TrajectoryAssertionEvaluator } from "../types"; | ||
| export declare function runTrajectoryAssertionEvaluator(spec: TrajectoryAssertionEvaluator, artifacts: EvalArtifacts): AssertionResult[]; |
| /** | ||
| * GitHub Models API caller for live eval execution. | ||
| * | ||
| * Provides a fetch-based approach for calling GitHub Models API | ||
| * in Phase 2 live eval harness. Uses only built-in fetch() — no new dependencies. | ||
| */ | ||
| export declare const GITHUB_MODELS_API_URL = "https://models.inference.ai.azure.com/chat/completions"; | ||
| export declare const DELAY_BETWEEN_CALLS_MS = 1000; | ||
| export interface GitHubModelsResponse { | ||
| content: string; | ||
| durationMs: number; | ||
| } | ||
| export declare function callGitHubModels(systemPrompt: string, userMessage: string, model: string, token: string): Promise<GitHubModelsResponse>; |
| import type { EvalArtifacts, ExecutionContext, ResolvedTarget, TrajectoryRunExecutor } from "../types"; | ||
| export declare function detectDelegation(response: string): string | null; | ||
| export declare function executeTrajectoryRun(resolvedTarget: ResolvedTarget, executor: TrajectoryRunExecutor, context: ExecutionContext): Promise<EvalArtifacts>; |
| /** | ||
| * compaction-todo-preserver hook | ||
| * | ||
| * Snapshots todos before compaction, restores them if wiped by compaction. | ||
| * Defense-in-depth against OpenCode's context compaction clearing the todo list. | ||
| */ | ||
| import type { PluginContext } from "../plugin/types"; | ||
| export type TodoSnapshot = { | ||
| content: string; | ||
| status: string; | ||
| priority: string; | ||
| }; | ||
| export declare function createCompactionTodoPreserver(client: PluginContext["client"]): { | ||
| capture: (sessionID: string) => Promise<void>; | ||
| handleEvent: (event: { | ||
| type: string; | ||
| properties?: unknown; | ||
| }) => Promise<void>; | ||
| getSnapshot: (sessionID: string) => TodoSnapshot[] | undefined; | ||
| }; |
| /** | ||
| * todo-continuation-enforcer hook | ||
| * | ||
| * Ensures in_progress todos are finalized when a session goes idle. | ||
| * Extracted from the inline finalization logic in plugin-interface.ts. | ||
| * | ||
| * Primary path (zero-cost): If opencode/session/todo is available, directly | ||
| * mutates the todo list to mark in_progress items as completed. | ||
| * | ||
| * Fallback path (1 LLM turn): If unavailable, injects a prompt asking the LLM | ||
| * to finalize the todos. | ||
| */ | ||
| import type { PluginContext } from "../plugin/types"; | ||
| import { type TodoWriter } from "./todo-writer"; | ||
| export declare const FINALIZE_TODOS_MARKER = "<!-- weave:finalize-todos -->"; | ||
| export declare function createTodoContinuationEnforcer(client: PluginContext["client"], options?: { | ||
| /** Inject a mock todo writer for testing (bypasses dynamic import) */ | ||
| todoWriterOverride?: TodoWriter | null; | ||
| }): { | ||
| checkAndFinalize: (sessionID: string) => Promise<void>; | ||
| markFinalized: (sessionID: string) => void; | ||
| isFinalized: (sessionID: string) => boolean; | ||
| clearFinalized: (sessionID: string) => void; | ||
| clearSession: (sessionID: string) => void; | ||
| }; |
| /** | ||
| * todo-description-override hook | ||
| * | ||
| * Overrides the TodoWrite tool description with stronger language emphasizing | ||
| * that it is a destructive full-array replacement and items must NEVER be dropped. | ||
| */ | ||
| export declare const TODOWRITE_DESCRIPTION = "Manages the sidebar todo list. CRITICAL: This tool performs a FULL ARRAY REPLACEMENT \u2014 every call completely DELETES all existing todos and replaces them with whatever you send. NEVER drop existing items. ALWAYS include ALL current todos in EVERY call. If unsure what todos currently exist, call todoread BEFORE calling this tool. Rules: max 35 chars per item, encode WHERE + WHAT (e.g. \"src/foo.ts: add error handler\"). Status values: \"pending\", \"in_progress\", \"completed\", \"cancelled\". Priority values: \"high\", \"medium\", \"low\"."; | ||
| /** | ||
| * Applies the enhanced TodoWrite description override. | ||
| * Mutates `output.description` when `input.toolID === "todowrite"`. | ||
| * Pure function — no side effects, no async, no state. | ||
| */ | ||
| export declare function applyTodoDescriptionOverride(input: { | ||
| toolID: string; | ||
| }, output: { | ||
| description: string; | ||
| parameters?: unknown; | ||
| }): void; |
| /** | ||
| * Shared todo-writer resolution utility. | ||
| * | ||
| * Dynamically imports opencode/session/todo to get Todo.update(). | ||
| * Uses a variable for the module specifier to prevent bundler inlining. | ||
| * Returns null if the module is unavailable (non-fatal). | ||
| */ | ||
| export type TodoItem = { | ||
| content: string; | ||
| status: string; | ||
| priority?: string; | ||
| }; | ||
| export type TodoWriter = (input: { | ||
| sessionID: string; | ||
| todos: TodoItem[]; | ||
| }) => void; | ||
| export declare function resolveTodoWriter(): Promise<TodoWriter | null>; |
| /** | ||
| * Safely resolve a user-supplied directory path, ensuring it stays within the | ||
| * project root (sandbox). Returns the resolved absolute path, or null if the | ||
| * path escapes the sandbox. | ||
| * | ||
| * Security rules: | ||
| * - Absolute paths are rejected (must be relative to projectRoot) | ||
| * - Resolved path must start with projectRoot (prevents `../../` traversal) | ||
| * | ||
| * @param dir - User-supplied directory path (from config) | ||
| * @param projectRoot - Project root to resolve relative paths against and sandbox within | ||
| * @returns Resolved absolute path, or null if the path is rejected | ||
| */ | ||
| export declare function resolveSafePath(dir: string, projectRoot: string): string | null; |
@@ -12,3 +12,3 @@ /** | ||
| } | ||
| export declare function buildTapestryRoleSection(): string; | ||
| export declare function buildTapestryRoleSection(disabled?: Set<string>): string; | ||
| export declare function buildTapestryDisciplineSection(): string; | ||
@@ -18,4 +18,6 @@ export declare function buildTapestrySidebarTodosSection(): string; | ||
| export declare function buildTapestryVerificationSection(): string; | ||
| export declare function buildTapestryVerificationGateSection(): string; | ||
| export declare function buildTapestryPostExecutionReviewSection(disabled: Set<string>): string; | ||
| export declare function buildTapestryExecutionSection(): string; | ||
| export declare function buildTapestryDebuggingSection(): string; | ||
| export declare function buildTapestryStyleSection(): string; | ||
@@ -22,0 +24,0 @@ /** |
@@ -87,3 +87,2 @@ import { z } from "zod"; | ||
| context_window_critical_threshold: z.ZodOptional<z.ZodNumber>; | ||
| task_system: z.ZodDefault<z.ZodBoolean>; | ||
| }, z.core.$strip>; | ||
@@ -166,2 +165,3 @@ export declare const DelegationTriggerSchema: z.ZodObject<{ | ||
| disabled_workflows: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| directories: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| }, z.core.$strip>; | ||
@@ -239,2 +239,3 @@ export declare const WeaveConfigSchema: z.ZodObject<{ | ||
| disabled_skills: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| skill_directories: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| background: z.ZodOptional<z.ZodObject<{ | ||
@@ -265,6 +266,6 @@ defaultConcurrency: z.ZodOptional<z.ZodNumber>; | ||
| context_window_critical_threshold: z.ZodOptional<z.ZodNumber>; | ||
| task_system: z.ZodDefault<z.ZodBoolean>; | ||
| }, z.core.$strip>>; | ||
| workflows: z.ZodOptional<z.ZodObject<{ | ||
| disabled_workflows: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| directories: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| }, z.core.$strip>>; | ||
@@ -271,0 +272,0 @@ }, z.core.$strip>; |
| import type { WorkState } from "../work-state/types"; | ||
| import type { MetricsReport } from "./types"; | ||
| /** | ||
| * Generate a Phase 1 metrics report for a completed plan. | ||
| * Generate a metrics report for a completed plan. | ||
| * | ||
@@ -10,9 +10,9 @@ * Orchestrates: | ||
| * 3. Calculate adherence (coverage, precision) | ||
| * 4. Aggregate token usage across all sessions for this plan | ||
| * 4. Aggregate token usage (with per-session and model detail) across all sessions | ||
| * 5. Compute total duration from session summaries | ||
| * 6. Write the report to metrics-reports.jsonl | ||
| * 6. Calculate quality score (composite of adherence, task completion, efficiency) | ||
| * 7. Write the report to metrics-reports.jsonl | ||
| * | ||
| * In Phase 1, `quality` and `gaps` are undefined. | ||
| * Returns the report if successful, null on error. | ||
| */ | ||
| export declare function generateMetricsReport(directory: string, state: WorkState): MetricsReport | null; |
@@ -1,2 +0,2 @@ | ||
| export type { ToolUsageEntry, DelegationEntry, SessionSummary, TokenUsage, MetricsTokenUsage, AdherenceReport, MetricsReport, DetectedStack, ProjectFingerprint, Suggestion, InFlightToolCall, TrackedSession, } from "./types"; | ||
| export type { ToolUsageEntry, DelegationEntry, SessionSummary, TokenUsage, MetricsTokenUsage, AdherenceReport, MetricsReport, QualityReport, SessionTokenBreakdown, DetectedStack, ProjectFingerprint, InFlightToolCall, TrackedSession, } from "./types"; | ||
| export { ANALYTICS_DIR, SESSION_SUMMARIES_FILE, FINGERPRINT_FILE, METRICS_REPORTS_FILE, MAX_METRICS_ENTRIES, zeroTokenUsage, } from "./types"; | ||
@@ -6,3 +6,2 @@ export { ensureAnalyticsDir, appendSessionSummary, readSessionSummaries, writeFingerprint, readFingerprint, writeMetricsReport, readMetricsReports, } from "./storage"; | ||
| export { SessionTracker, createSessionTracker } from "./session-tracker"; | ||
| export { generateSuggestions, getSuggestionsForProject } from "./suggestions"; | ||
| export { generateTokenReport, getTokenReport } from "./token-report"; | ||
@@ -14,3 +13,5 @@ export { formatMetricsMarkdown } from "./format-metrics"; | ||
| export { calculateAdherence } from "./adherence"; | ||
| export { aggregateTokensForPlan } from "./plan-token-aggregator"; | ||
| export { aggregateTokensForPlan, aggregateTokensDetailed } from "./plan-token-aggregator"; | ||
| export type { DetailedTokenAggregation } from "./plan-token-aggregator"; | ||
| export { calculateQualityScore, BASELINE_TOKENS_PER_TASK } from "./quality-score"; | ||
| import type { SessionTracker } from "./session-tracker"; | ||
@@ -17,0 +18,0 @@ import type { ProjectFingerprint } from "./types"; |
@@ -1,2 +0,2 @@ | ||
| import type { MetricsTokenUsage } from "./types"; | ||
| import type { MetricsTokenUsage, SessionTokenBreakdown } from "./types"; | ||
| /** | ||
@@ -12,1 +12,24 @@ * Aggregate token usage for a plan by summing across matching session summaries. | ||
| export declare function aggregateTokensForPlan(directory: string, sessionIds: string[]): MetricsTokenUsage; | ||
| /** Result of detailed token aggregation across sessions for a plan */ | ||
| export interface DetailedTokenAggregation { | ||
| /** Total token usage across all sessions */ | ||
| total: MetricsTokenUsage; | ||
| /** Total dollar cost across all sessions */ | ||
| totalCost: number; | ||
| /** Per-session breakdowns */ | ||
| sessions: SessionTokenBreakdown[]; | ||
| /** Per-model aggregation (grouped by model ID, "(unknown)" for sessions without model) */ | ||
| modelBreakdown: Array<{ | ||
| model: string; | ||
| tokens: MetricsTokenUsage; | ||
| cost: number; | ||
| sessionCount: number; | ||
| }>; | ||
| } | ||
| /** | ||
| * Aggregate token usage for a plan with per-session and per-model detail. | ||
| * | ||
| * The existing `aggregateTokensForPlan()` is unchanged for backward compatibility. | ||
| * This function adds per-session breakdowns and model attribution. | ||
| */ | ||
| export declare function aggregateTokensDetailed(directory: string, sessionIds: string[]): DetailedTokenAggregation; |
@@ -32,2 +32,7 @@ import type { TrackedSession, SessionSummary } from "./types"; | ||
| /** | ||
| * Set the model ID for a session. Only sets on first call (captures primary model). | ||
| * Safe to call for untracked sessions (no-op, no throw). | ||
| */ | ||
| trackModel(sessionId: string, modelId: string): void; | ||
| /** | ||
| * Accumulate dollar cost from a message into the session total. | ||
@@ -34,0 +39,0 @@ */ |
@@ -62,2 +62,4 @@ /** | ||
| agentName?: string; | ||
| /** Model ID used in this session (e.g., "claude-sonnet-4-20250514") */ | ||
| model?: string; | ||
| /** Total dollar cost accumulated across all messages */ | ||
@@ -96,13 +98,42 @@ totalCost?: number; | ||
| } | ||
| /** A suggestion generated from session analytics */ | ||
| export interface Suggestion { | ||
| /** Unique identifier for deduplication */ | ||
| id: string; | ||
| /** Human-readable suggestion text */ | ||
| text: string; | ||
| /** Category of suggestion */ | ||
| category: "tool-usage" | "delegation" | "workflow" | "token-usage"; | ||
| /** Confidence level */ | ||
| confidence: "high" | "medium" | "low"; | ||
| /** Composite quality score for a completed plan */ | ||
| export interface QualityReport { | ||
| /** Composite quality score (0-1) — weighted average of components */ | ||
| composite: number; | ||
| /** Component scores (each 0-1) */ | ||
| components: { | ||
| /** Fraction of planned files that were actually changed */ | ||
| adherenceCoverage: number; | ||
| /** Fraction of actual changes that were planned */ | ||
| adherencePrecision: number; | ||
| /** Fraction of plan tasks marked as complete ([x]) */ | ||
| taskCompletion: number; | ||
| /** Efficiency score — inverse of normalized tokens-per-task */ | ||
| efficiency: number; | ||
| }; | ||
| /** Raw data used to compute efficiency (for transparency) */ | ||
| efficiencyData: { | ||
| /** Total tokens consumed */ | ||
| totalTokens: number; | ||
| /** Number of tasks in the plan */ | ||
| totalTasks: number; | ||
| /** Tokens per task */ | ||
| tokensPerTask: number; | ||
| }; | ||
| } | ||
| /** Per-session token breakdown within a plan's metrics report */ | ||
| export interface SessionTokenBreakdown { | ||
| /** Session ID */ | ||
| sessionId: string; | ||
| /** Model ID used in this session */ | ||
| model?: string; | ||
| /** Display name of the agent */ | ||
| agentName?: string; | ||
| /** Token usage for this session */ | ||
| tokens: MetricsTokenUsage; | ||
| /** Dollar cost for this session */ | ||
| cost?: number; | ||
| /** Duration in milliseconds */ | ||
| durationMs: number; | ||
| } | ||
| /** File name for metrics reports (JSONL format) */ | ||
@@ -152,6 +183,4 @@ export declare const METRICS_REPORTS_FILE = "metrics-reports.jsonl"; | ||
| adherence: AdherenceReport; | ||
| /** Code quality score (Phase 2 — undefined in Phase 1) */ | ||
| quality?: unknown; | ||
| /** Quality gaps (Phase 2 — undefined in Phase 1) */ | ||
| gaps?: unknown; | ||
| /** Composite quality score for the plan */ | ||
| quality?: QualityReport; | ||
| /** Token usage across all sessions */ | ||
@@ -169,2 +198,8 @@ tokenUsage: MetricsTokenUsage; | ||
| sessionIds: string[]; | ||
| /** Deduplicated list of model IDs used across all sessions */ | ||
| modelsUsed?: string[]; | ||
| /** Total dollar cost across all sessions */ | ||
| totalCost?: number; | ||
| /** Per-session token breakdown */ | ||
| sessionBreakdown?: SessionTokenBreakdown[]; | ||
| } | ||
@@ -194,2 +229,4 @@ /** Tracks in-flight tool calls for duration measurement */ | ||
| agentName?: string; | ||
| /** Model ID used in this session (e.g., "claude-sonnet-4-20250514") */ | ||
| model?: string; | ||
| /** Accumulated dollar cost across all messages */ | ||
@@ -196,0 +233,0 @@ totalCost: number; |
| import type { EvalArtifacts, ExecutionContext, ModelResponseExecutor, ResolvedTarget } from "../types"; | ||
| export declare function executeModelResponse(resolvedTarget: ResolvedTarget, executor: ModelResponseExecutor, _context: ExecutionContext): EvalArtifacts; | ||
| /** | ||
| * Executes a model-response eval case by calling the GitHub Models API. | ||
| * | ||
| * Phase 2 is live-only — requires GITHUB_TOKEN env var. | ||
| */ | ||
| export declare function executeModelResponse(resolvedTarget: ResolvedTarget, executor: ModelResponseExecutor, context: ExecutionContext): Promise<EvalArtifacts>; |
| import type { EvalArtifacts, ExecutionContext, ExecutorSpec, ResolvedTarget } from "../types"; | ||
| export declare function executePromptRender(resolvedTarget: ResolvedTarget, executor: ExecutorSpec, _context: ExecutionContext): EvalArtifacts; | ||
| export declare function executePromptRender(resolvedTarget: ResolvedTarget, executor: ExecutorSpec, _context: ExecutionContext): Promise<EvalArtifacts>; |
@@ -12,14 +12,17 @@ /** | ||
| */ | ||
| export type { EvalPhase, EvalTarget, ExecutorSpec, EvaluatorSpec, EvalSuiteManifest, EvalCase, LoadedEvalCase, LoadedEvalSuiteManifest, EvalArtifacts, AssertionResult, EvalCaseResult, EvalRunResult, EvalRunSummary, RunEvalSuiteOptions, RunnerFilters, } from "./types"; | ||
| export { EvalCaseSchema, EvalSuiteManifestSchema, EvalRunResultSchema } from "./schema"; | ||
| export { EvalConfigError, loadEvalSuiteManifest, loadEvalCasesForSuite, resolveSuitePath } from "./loader"; | ||
| export type { EvalPhase, EvalTarget, ExecutorSpec, EvaluatorSpec, EvalSuiteManifest, EvalCase, LoadedEvalCase, LoadedEvalSuiteManifest, EvalArtifacts, AssertionResult, EvalCaseResult, EvalRunResult, EvalRunSummary, RunEvalSuiteOptions, RunnerFilters, TrajectoryScenario, TrajectoryTurn, TrajectoryTrace, TrajectoryTurnResult, TrajectoryAssertionEvaluator, } from "./types"; | ||
| export { isTrajectoryTrace } from "./types"; | ||
| export { EvalCaseSchema, EvalSuiteManifestSchema, EvalRunResultSchema, TrajectoryScenarioSchema, TrajectoryTurnSchema, TrajectoryAssertionEvaluatorSchema, } from "./schema"; | ||
| export { EvalConfigError, loadEvalSuiteManifest, loadEvalCasesForSuite, resolveSuitePath, loadTrajectoryScenario, } from "./loader"; | ||
| export { resolveBuiltinAgentTarget } from "./targets/builtin-agent-target"; | ||
| export { executePromptRender } from "./executors/prompt-renderer"; | ||
| export { executeModelResponse } from "./executors/model-response"; | ||
| export { executeTrajectoryRun, detectDelegation } from "./executors/trajectory-run"; | ||
| export { runDeterministicEvaluator } from "./evaluators/deterministic"; | ||
| export { runLlmJudgeEvaluator } from "./evaluators/llm-judge"; | ||
| export { runTrajectoryAssertionEvaluator } from "./evaluators/trajectory-assertion"; | ||
| export { deriveDeterministicBaseline, readDeterministicBaseline, compareDeterministicBaseline } from "./baseline"; | ||
| export { ensureEvalStorageDir, getDefaultEvalRunPath, writeEvalRunResult } from "./storage"; | ||
| export { formatEvalSummary } from "./reporter"; | ||
| export { ensureEvalStorageDir, getDefaultEvalRunPath, writeEvalRunResult, getDefaultJsonlPath, appendEvalRunJsonl } from "./storage"; | ||
| export { formatEvalSummary, formatJobSummaryMarkdown } from "./reporter"; | ||
| export type { RunEvalSuiteOutput } from "./runner"; | ||
| export { runEvalSuite } from "./runner"; |
@@ -1,2 +0,2 @@ | ||
| import type { LoadedEvalCase, LoadedEvalSuiteManifest } from "./types"; | ||
| import type { LoadedEvalCase, LoadedEvalSuiteManifest, TrajectoryScenario } from "./types"; | ||
| export declare class EvalConfigError extends Error { | ||
@@ -9,1 +9,2 @@ constructor(message: string); | ||
| export declare function loadEvalCasesForSuite(directory: string, suite: LoadedEvalSuiteManifest): LoadedEvalCase[]; | ||
| export declare function loadTrajectoryScenario(directory: string, scenarioRef: string): TrajectoryScenario; |
| import type { EvalRunResult } from "./types"; | ||
| export declare function formatEvalSummary(result: EvalRunResult): string; | ||
| export declare function formatJobSummaryMarkdown(result: EvalRunResult): string; |
@@ -7,2 +7,2 @@ import type { EvalRunResult, RunEvalSuiteOptions } from "./types"; | ||
| } | ||
| export declare function runEvalSuite(options: RunEvalSuiteOptions): RunEvalSuiteOutput; | ||
| export declare function runEvalSuite(options: RunEvalSuiteOptions): Promise<RunEvalSuiteOutput>; |
| import { z } from "zod"; | ||
| export declare const EvalPhaseSchema: z.ZodEnum<{ | ||
| phase1: "phase1"; | ||
| phase2: "phase2"; | ||
| phase3: "phase3"; | ||
| phase4: "phase4"; | ||
| prompt: "prompt"; | ||
| experimental: "experimental"; | ||
| routing: "routing"; | ||
| trajectory: "trajectory"; | ||
| }>; | ||
@@ -17,2 +17,3 @@ export declare const BuiltinAgentPromptVariantSchema: z.ZodObject<{ | ||
| tapestry: "tapestry"; | ||
| shuttle: "shuttle"; | ||
| thread: "thread"; | ||
@@ -47,2 +48,3 @@ spindle: "spindle"; | ||
| tapestry: "tapestry"; | ||
| shuttle: "shuttle"; | ||
| thread: "thread"; | ||
@@ -149,3 +151,36 @@ spindle: "spindle"; | ||
| assertionRef: z.ZodOptional<z.ZodString>; | ||
| expectedSequence: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| requiredAgents: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| forbiddenAgents: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| minTurns: z.ZodOptional<z.ZodNumber>; | ||
| maxTurns: z.ZodOptional<z.ZodNumber>; | ||
| }, z.core.$strip>; | ||
| export declare const TrajectoryTurnSchema: z.ZodObject<{ | ||
| turn: z.ZodNumber; | ||
| role: z.ZodEnum<{ | ||
| user: "user"; | ||
| assistant: "assistant"; | ||
| }>; | ||
| agent: z.ZodOptional<z.ZodString>; | ||
| content: z.ZodString; | ||
| mockResponse: z.ZodOptional<z.ZodString>; | ||
| expectedDelegation: z.ZodOptional<z.ZodString>; | ||
| }, z.core.$strip>; | ||
| export declare const TrajectoryScenarioSchema: z.ZodObject<{ | ||
| id: z.ZodString; | ||
| title: z.ZodString; | ||
| description: z.ZodOptional<z.ZodString>; | ||
| agents: z.ZodArray<z.ZodString>; | ||
| turns: z.ZodArray<z.ZodObject<{ | ||
| turn: z.ZodNumber; | ||
| role: z.ZodEnum<{ | ||
| user: "user"; | ||
| assistant: "assistant"; | ||
| }>; | ||
| agent: z.ZodOptional<z.ZodString>; | ||
| content: z.ZodString; | ||
| mockResponse: z.ZodOptional<z.ZodString>; | ||
| expectedDelegation: z.ZodOptional<z.ZodString>; | ||
| }, z.core.$strip>>; | ||
| }, z.core.$strip>; | ||
| export declare const EvaluatorSpecSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{ | ||
@@ -198,2 +233,7 @@ weight: z.ZodOptional<z.ZodNumber>; | ||
| assertionRef: z.ZodOptional<z.ZodString>; | ||
| expectedSequence: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| requiredAgents: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| forbiddenAgents: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| minTurns: z.ZodOptional<z.ZodNumber>; | ||
| maxTurns: z.ZodOptional<z.ZodNumber>; | ||
| }, z.core.$strip>], "kind">; | ||
@@ -203,7 +243,8 @@ export declare const EvalCaseSchema: z.ZodObject<{ | ||
| title: z.ZodString; | ||
| description: z.ZodOptional<z.ZodString>; | ||
| phase: z.ZodEnum<{ | ||
| phase1: "phase1"; | ||
| phase2: "phase2"; | ||
| phase3: "phase3"; | ||
| phase4: "phase4"; | ||
| prompt: "prompt"; | ||
| experimental: "experimental"; | ||
| routing: "routing"; | ||
| trajectory: "trajectory"; | ||
| }>; | ||
@@ -216,2 +257,3 @@ target: z.ZodDiscriminatedUnion<[z.ZodObject<{ | ||
| tapestry: "tapestry"; | ||
| shuttle: "shuttle"; | ||
| thread: "thread"; | ||
@@ -295,2 +337,7 @@ spindle: "spindle"; | ||
| assertionRef: z.ZodOptional<z.ZodString>; | ||
| expectedSequence: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| requiredAgents: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| forbiddenAgents: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| minTurns: z.ZodOptional<z.ZodNumber>; | ||
| maxTurns: z.ZodOptional<z.ZodNumber>; | ||
| }, z.core.$strip>], "kind">>; | ||
@@ -304,6 +351,6 @@ tags: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| phase: z.ZodEnum<{ | ||
| phase1: "phase1"; | ||
| phase2: "phase2"; | ||
| phase3: "phase3"; | ||
| phase4: "phase4"; | ||
| prompt: "prompt"; | ||
| experimental: "experimental"; | ||
| routing: "routing"; | ||
| trajectory: "trajectory"; | ||
| }>; | ||
@@ -353,2 +400,3 @@ caseFiles: z.ZodArray<z.ZodString>; | ||
| caseId: z.ZodString; | ||
| description: z.ZodOptional<z.ZodString>; | ||
| status: z.ZodEnum<{ | ||
@@ -418,6 +466,6 @@ error: "error"; | ||
| phase: z.ZodEnum<{ | ||
| phase1: "phase1"; | ||
| phase2: "phase2"; | ||
| phase3: "phase3"; | ||
| phase4: "phase4"; | ||
| prompt: "prompt"; | ||
| experimental: "experimental"; | ||
| routing: "routing"; | ||
| trajectory: "trajectory"; | ||
| }>; | ||
@@ -435,2 +483,3 @@ summary: z.ZodObject<{ | ||
| caseId: z.ZodString; | ||
| description: z.ZodOptional<z.ZodString>; | ||
| status: z.ZodEnum<{ | ||
@@ -437,0 +486,0 @@ error: "error"; |
@@ -8,1 +8,3 @@ import type { EvalRunResult } from "./types"; | ||
| export declare function writeEvalRunResult(directory: string, result: EvalRunResult, outputPath?: string): string; | ||
| export declare function getDefaultJsonlPath(directory: string, suiteId: string): string; | ||
| export declare function appendEvalRunJsonl(directory: string, result: EvalRunResult, jsonlPath?: string): string; |
| import type { WeaveAgentName } from "../../agents/types"; | ||
| export declare const EVAL_PHASES: readonly ["phase1", "phase2", "phase3", "phase4"]; | ||
| export declare const EVAL_PHASES: readonly ["prompt", "routing", "trajectory", "experimental"]; | ||
| export type EvalPhase = (typeof EVAL_PHASES)[number]; | ||
@@ -10,3 +10,3 @@ export declare const EVAL_TARGET_KINDS: readonly ["builtin-agent-prompt", "custom-agent-prompt", "single-turn-agent", "trajectory-agent"]; | ||
| export type EvaluatorKind = (typeof EVALUATOR_KINDS)[number]; | ||
| export type BuiltinEvalAgentName = Exclude<WeaveAgentName, "shuttle">; | ||
| export type BuiltinEvalAgentName = WeaveAgentName; | ||
| export interface BuiltinAgentPromptVariant { | ||
@@ -98,2 +98,7 @@ disabledAgents?: string[]; | ||
| assertionRef?: string; | ||
| expectedSequence?: string[]; | ||
| requiredAgents?: string[]; | ||
| forbiddenAgents?: string[]; | ||
| minTurns?: number; | ||
| maxTurns?: number; | ||
| } | ||
@@ -111,2 +116,3 @@ export type EvaluatorSpec = ContainsAllEvaluator | ContainsAnyEvaluator | ExcludesAllEvaluator | SectionContainsAllEvaluator | OrderedContainsEvaluator | XmlSectionsPresentEvaluator | ToolPolicyEvaluator | MinLengthEvaluator | LlmJudgeEvaluator | BaselineDiffEvaluator | TrajectoryAssertionEvaluator; | ||
| title: string; | ||
| description?: string; | ||
| phase: EvalPhase; | ||
@@ -151,2 +157,3 @@ target: EvalTarget; | ||
| caseId: string; | ||
| description?: string; | ||
| status: "passed" | "failed" | "error"; | ||
@@ -187,2 +194,3 @@ score: number; | ||
| outputPath?: string; | ||
| modelOverride?: string; | ||
| } | ||
@@ -200,2 +208,3 @@ export interface RunnerFilters { | ||
| mode?: ExecutionContext["mode"]; | ||
| modelOverride?: string; | ||
| } | ||
@@ -230,1 +239,33 @@ export interface EvalLoadErrorContext { | ||
| } | ||
| export interface TrajectoryTurn { | ||
| turn: number; | ||
| role: "user" | "assistant"; | ||
| agent?: string; | ||
| content: string; | ||
| mockResponse?: string; | ||
| expectedDelegation?: string; | ||
| } | ||
| export interface TrajectoryScenario { | ||
| id: string; | ||
| title: string; | ||
| description?: string; | ||
| agents: string[]; | ||
| turns: TrajectoryTurn[]; | ||
| } | ||
| export interface TrajectoryTurnResult { | ||
| turn: number; | ||
| agent: string; | ||
| role: "user" | "assistant"; | ||
| response: string; | ||
| expectedDelegation?: string; | ||
| observedDelegation?: string | null; | ||
| durationMs: number; | ||
| } | ||
| export interface TrajectoryTrace { | ||
| scenarioId: string; | ||
| turns: TrajectoryTurnResult[]; | ||
| delegationSequence: string[]; | ||
| totalTurns: number; | ||
| completedTurns: number; | ||
| } | ||
| export declare function isTrajectoryTrace(trace: unknown): trace is TrajectoryTrace; |
@@ -6,3 +6,5 @@ import type { SkillDiscoveryResult } from './types'; | ||
| disabledSkills?: string[]; | ||
| /** Additional directories to scan for skills (from config `skill_directories`) */ | ||
| customDirs?: string[]; | ||
| } | ||
| export declare function loadSkills(options: LoadSkillsOptions): Promise<SkillDiscoveryResult>; |
@@ -14,4 +14,5 @@ import type { WorkflowInstance, WorkflowDefinition, WorkflowStepDefinition } from "./types"; | ||
| * Build the full context-threaded prompt for a step. | ||
| * Combines: (1) workflow context header, (2) resolved step prompt. | ||
| * Combines: (1) workflow context header, (2) delegation instruction if step | ||
| * targets a non-loom agent, (3) resolved step prompt. | ||
| */ | ||
| export declare function composeStepPrompt(stepDef: WorkflowStepDefinition, instance: WorkflowInstance, definition: WorkflowDefinition): string; |
@@ -16,5 +16,8 @@ import type { WorkflowDefinition } from "./types"; | ||
| /** | ||
| * Discover all valid workflow definitions from project and user directories. | ||
| * Project workflows override user workflows with the same name. | ||
| * Discover all valid workflow definitions from project, custom, and user directories. | ||
| * Override precedence (highest wins): project > custom > user. | ||
| * | ||
| * @param directory - Project root directory (used to resolve relative custom paths) | ||
| * @param customDirs - Optional extra directories to scan (from config `workflows.directories`) | ||
| */ | ||
| export declare function discoverWorkflows(directory: string): DiscoveredWorkflow[]; | ||
| export declare function discoverWorkflows(directory: string, customDirs?: string[]): DiscoveredWorkflow[]; |
@@ -33,2 +33,3 @@ /** | ||
| directory: string; | ||
| workflowDirs?: string[]; | ||
| }): WorkflowHookResult; | ||
@@ -45,2 +46,3 @@ /** | ||
| lastUserMessage?: string; | ||
| workflowDirs?: string[]; | ||
| }): { | ||
@@ -47,0 +49,0 @@ continuationPrompt: string | null; |
@@ -8,2 +8,3 @@ import type { WeaveConfig } from "../config/schema"; | ||
| import { buildVerificationReminder } from "./verification-reminder"; | ||
| import { applyTodoDescriptionOverride } from "./todo-description-override"; | ||
| export type CreatedHooks = ReturnType<typeof createHooks>; | ||
@@ -40,3 +41,6 @@ export declare function createHooks(args: { | ||
| verificationReminder: typeof buildVerificationReminder | null; | ||
| todoDescriptionOverride: typeof applyTodoDescriptionOverride | null; | ||
| compactionTodoPreserverEnabled: boolean; | ||
| todoContinuationEnforcerEnabled: boolean; | ||
| analyticsEnabled: boolean; | ||
| }; |
@@ -15,1 +15,7 @@ export { createHooks } from "./create-hooks"; | ||
| export type { SessionTokenEntry } from "./session-token-state"; | ||
| export { applyTodoDescriptionOverride, TODOWRITE_DESCRIPTION } from "./todo-description-override"; | ||
| export { createCompactionTodoPreserver } from "./compaction-todo-preserver"; | ||
| export type { TodoSnapshot } from "./compaction-todo-preserver"; | ||
| export { createTodoContinuationEnforcer, FINALIZE_TODOS_MARKER } from "./todo-continuation-enforcer"; | ||
| export { resolveTodoWriter } from "./todo-writer"; | ||
| export type { TodoItem, TodoWriter } from "./todo-writer"; |
@@ -17,3 +17,2 @@ import type { PluginInterface, ToolsRecord } from "./types"; | ||
| tracker?: SessionTracker; | ||
| taskSystemEnabled?: boolean; | ||
| }): PluginInterface; |
| import type { Plugin, ToolDefinition } from "@opencode-ai/plugin"; | ||
| export type PluginContext = Parameters<Plugin>[0]; | ||
| export type PluginInstance = Awaited<ReturnType<Plugin>>; | ||
| export type PluginInterface = Required<Pick<PluginInstance, "tool" | "config" | "chat.message" | "chat.params" | "chat.headers" | "event" | "tool.execute.before" | "tool.execute.after" | "command.execute.before">>; | ||
| export type PluginInterface = Required<Pick<PluginInstance, "tool" | "config" | "chat.message" | "chat.params" | "chat.headers" | "event" | "tool.execute.before" | "tool.execute.after" | "command.execute.before" | "tool.definition" | "experimental.session.compacting">>; | ||
| export type ToolsRecord = Record<string, ToolDefinition>; |
+10
-8
| { | ||
| "name": "@opencode_weave/weave", | ||
| "version": "0.7.3", | ||
| "version": "0.7.4-preview.1", | ||
| "description": "Weave — lean OpenCode plugin with multi-agent orchestration", | ||
@@ -30,4 +30,6 @@ "author": "Weave", | ||
| "eval": "bun run script/eval.ts", | ||
| "eval:smoke": "bun run script/eval.ts --suite pr-smoke", | ||
| "eval:coverage": "bun run script/verify-eval-coverage.ts" | ||
| "eval:smoke": "bun run script/eval.ts --suite prompt-smoke", | ||
| "eval:phase2": "bun run script/eval.ts --suite agent-routing", | ||
| "eval:coverage": "bun run script/verify-eval-coverage.ts", | ||
| "eval:trend": "bun run script/eval-trend-report.ts" | ||
| }, | ||
@@ -45,4 +47,4 @@ "keywords": [ | ||
| "dependencies": { | ||
| "@opencode-ai/plugin": "^1.1.19", | ||
| "@opencode-ai/sdk": "^1.1.19", | ||
| "@opencode-ai/plugin": "^1.3.3", | ||
| "@opencode-ai/sdk": "^1.3.3", | ||
| "jsonc-parser": "^3.3.1", | ||
@@ -53,6 +55,6 @@ "picocolors": "^1.1.1", | ||
| "devDependencies": { | ||
| "bun": "^1.3.9", | ||
| "bun-types": "^1.3.6", | ||
| "typescript": "^5.7.3" | ||
| "bun": "^1.3.11", | ||
| "bun-types": "^1.3.11", | ||
| "typescript": "^6.0.2" | ||
| } | ||
| } |
+3
-196
@@ -9,34 +9,2 @@ <p align="center"> | ||
| ## Table of Contents | ||
| - [Overview](#overview) | ||
| - [Documentation](#documentation) | ||
| - [Agents](#agents) | ||
| - [Agent Modes](#agent-modes) | ||
| - [Agent Details](#agent-details) | ||
| - [Workflow](#workflow) | ||
| - [When the Full Workflow Is Used](#when-the-full-workflow-is-used) | ||
| - [1. Plan](#1-plan) | ||
| - [2. Review (Optional)](#2-review-optional) | ||
| - [3. Execute](#3-execute) | ||
| - [Resuming Interrupted Work](#resuming-interrupted-work) | ||
| - [Quick Tasks (No Plan Needed)](#quick-tasks-no-plan-needed) | ||
| - [Installation](#installation) | ||
| - [Prerequisites](#prerequisites) | ||
| - [Step 1: Add to opencode.json](#step-1-add-to-opencodejson) | ||
| - [Step 2: Restart OpenCode](#step-2-restart-opencode) | ||
| - [Troubleshooting](#troubleshooting) | ||
| - [Uninstalling](#uninstalling) | ||
| - [Configuration](#configuration) | ||
| - [Example Configuration](#example-configuration) | ||
| - [Configuration Fields](#configuration-fields) | ||
| - [Features](#features) | ||
| - [Hooks](#hooks) | ||
| - [Skills](#skills) | ||
| - [Background Agents](#background-agents) | ||
| - [Tool Permissions](#tool-permissions) | ||
| - [Development](#development) | ||
| - [Acknowledgments](#acknowledgments) | ||
| - [License](#license) | ||
| ## Overview | ||
@@ -54,4 +22,6 @@ | ||
| Visit [tryweave.io](https://tryweave.io) for more information, or head straight to the [documentation](https://tryweave.io/docs/) for detailed guides on setup, configuration, and usage. | ||
| For detailed guides on configuration, workflows, agents, features, and more, visit the **[Weave documentation](https://tryweave.io/docs/)**. | ||
| For agent routing eval trends and dashboards, see the **[Eval Dashboard](https://tryweave.io/evals/)**. | ||
| ## Agents | ||
@@ -70,83 +40,2 @@ | ||
| ### Agent Modes | ||
| - `primary`: Respects the user-selected model in the OpenCode UI. | ||
| - `subagent`: Uses its own model or fallback chain, ignoring UI selection for predictable specialization. | ||
| - `all`: Available in both primary and subagent contexts. | ||
| ### Agent Details | ||
| **Loom** is the central orchestrator and the default entry point for every request. It breaks down complex problems into tasks, decides which agents to delegate to, and tracks progress obsessively via todo lists. Loom never implements code directly — it plans and delegates. For quick fixes it acts immediately; for complex work it kicks off the plan → review → execute workflow. | ||
| **Pattern** is the strategic planner. When a task requires 5+ steps or involves architectural decisions, Loom delegates to Pattern, which researches the codebase (via Thread) and external docs (via Spindle), then produces a structured implementation plan saved to `.weave/plans/{name}.md`. Plans use `- [ ]` checkboxes for every actionable task. Pattern never writes code — only plans. | ||
| **Weft** is the reviewer and auditor. It validates plans before execution and reviews completed work after implementation. Weft is approval-biased and only rejects for true blocking issues (max 3 per review). It checks that file references are correct, tasks have sufficient context, implementations match requirements, and no stubs or TODOs are left behind. Weft is read-only. | ||
| **Warp** is the security and specification compliance auditor. It reviews code changes for security vulnerabilities (injection, auth bypass, token handling, crypto weaknesses) and verifies compliance with standards like OAuth2, OIDC, WebAuthn, and JWT. Warp has a skeptical bias — unlike Weft, it rejects by default when security patterns are detected. It self-triages to fast-exit on non-security changes, and can webfetch RFCs for verification. Warp is read-only. | ||
| **Tapestry** is the execution engine. Activated by the `/start-work` command, it reads a plan from `.weave/plans/` and works through tasks sequentially — writing code, running commands, verifying output, and marking checkboxes as it goes. Tapestry cannot spawn subagents; it focuses on heads-down implementation. If interrupted, it resumes from the first unchecked task. | ||
| **Thread** is the fast codebase explorer. Loom delegates to Thread whenever it needs to understand code structure, find files, or answer questions about the repository. Thread uses grep, glob, and read tools with zero creativity (temperature 0.0) to return precise, factual answers with file paths and line numbers. Thread is read-only. | ||
| **Spindle** is the external researcher. When Loom needs documentation for a library, API reference, or any information outside the codebase, Spindle fetches URLs, reads docs, and synthesizes findings with source citations. Spindle is read-only. | ||
| **Shuttle** is the domain specialist. When work falls into a specific category (e.g., visual engineering, data processing), Loom dispatches Shuttle with full tool access to execute the task. Shuttle's model and configuration can be overridden per-category for domain-optimized performance. | ||
| ## Workflow | ||
| Weave uses a structured **Plan → Review → Execute** workflow for complex tasks. Simple requests are handled directly by Loom without the full cycle. | ||
| ### When the Full Workflow Is Used | ||
| - Tasks requiring 5+ steps or architectural decisions | ||
| - Multi-file refactors or new feature implementations | ||
| - Work that benefits from a reviewable plan before execution | ||
| ### 1. Plan | ||
| Loom delegates to **Pattern**, which researches the codebase and produces a detailed implementation plan: | ||
| ``` | ||
| User Request → Loom (assesses complexity) → Pattern (researches + plans) | ||
| ↓ | ||
| .weave/plans/{name}.md | ||
| ``` | ||
| The plan includes clear objectives, deliverables, and atomic tasks marked with `- [ ]` checkboxes. Pattern never writes code. | ||
| ### 2. Review (Optional) | ||
| For high-stakes or complex plans, Loom delegates to **Weft** to validate the plan before execution: | ||
| ``` | ||
| .weave/plans/{name}.md → Weft (validates) → APPROVE or REJECT | ||
| ``` | ||
| Weft checks that referenced files exist, tasks have sufficient context, and there are no contradictions. If rejected, issues are sent back to Pattern for revision. | ||
| ### 3. Execute | ||
| The user runs `/start-work` to begin execution: | ||
| ``` | ||
| /start-work [plan-name] → creates .weave/state.json → switches to Tapestry | ||
| ``` | ||
| **Tapestry** reads the plan and executes tasks sequentially: | ||
| 1. Find the first unchecked `- [ ]` task | ||
| 2. Implement the task (write code, run commands, create files) | ||
| 3. Verify completion (read files, run tests, check acceptance criteria) | ||
| 4. Mark the checkbox `- [x]` | ||
| 5. Move to the next unchecked task | ||
| 6. When all tasks are complete, report a final summary | ||
| ### Resuming Interrupted Work | ||
| If a session is interrupted, running `/start-work` again resumes from the first unchecked task — no re-planning or restarting. The work state is persisted in `.weave/state.json`, so progress is never lost. | ||
| ### Quick Tasks (No Plan Needed) | ||
| For simple requests — single-file fixes, quick questions, small edits — Loom handles the work directly or delegates to the appropriate agent without creating a formal plan. | ||
| ## Installation | ||
@@ -217,84 +106,2 @@ | ||
| ## Configuration | ||
| Weave searches for configuration files in the following locations, merging them in order (user config → project config → defaults): | ||
| - **Project**: `.opencode/weave-opencode.jsonc` or `.opencode/weave-opencode.json` | ||
| - **User**: `~/.config/opencode/weave-opencode.jsonc` or `~/.config/opencode/weave-opencode.json` | ||
| The configuration uses JSONC format, allowing for comments and trailing commas. | ||
| ### Example Configuration | ||
| ```jsonc | ||
| { | ||
| // Override agent models and parameters | ||
| "agents": { | ||
| "loom": { | ||
| "model": "anthropic/claude-3-5-sonnet", | ||
| "temperature": 0.1 | ||
| }, | ||
| "thread": { | ||
| "model": "openai/gpt-4o-mini" | ||
| } | ||
| }, | ||
| // Category-based dispatch overrides | ||
| "categories": { | ||
| "visual-engineering": { | ||
| "model": "google/gemini-2-pro" | ||
| } | ||
| }, | ||
| // Selective feature toggling | ||
| "disabled_hooks": [], | ||
| "disabled_agents": [], | ||
| "disabled_tools": [], | ||
| "disabled_skills": [], | ||
| // Background agent concurrency limits | ||
| "background": { | ||
| "defaultConcurrency": 5 | ||
| } | ||
| } | ||
| ``` | ||
| ### Configuration Fields | ||
| - `agents` — Override model, temperature, prompt_append, tools, and skills per agent. | ||
| - `categories` — Custom model and tool configurations for category-based dispatch. | ||
| - `disabled_hooks` / `disabled_agents` / `disabled_tools` / `disabled_skills` — Selective feature disabling. | ||
| - `background` — Concurrency limits and timeouts for parallel background agents. | ||
| - `tmux` — Terminal multiplexer layout settings for TUI integration. | ||
| - `skills` — Custom skill discovery paths and recursion settings. | ||
| - `experimental` — Plugin load timeouts and context window threshold adjustments. | ||
| ## Features | ||
| ### Hooks | ||
| Weave includes 5 built-in hooks that monitor and modify agent behavior: | ||
| - `context-window-monitor` — Warns when token usage approaches limits and suggests recovery strategies. | ||
| - `write-existing-file-guard` — Tracks file reads to prevent agents from overwriting files they haven't examined. | ||
| - `rules-injector` — Automatically injects contextual rules when agents enter directories containing AGENTS.md. | ||
| - `first-message-variant` — Applies specific prompt variants on session start for consistent behavior. | ||
| - `keyword-detector` — Detects keywords in messages to trigger behavioral changes or agent switches. | ||
| All hooks are enabled by default and can be disabled via the `disabled_hooks` configuration. | ||
| ### Skills | ||
| Skills are injectable prompt expertise loaded from markdown files (SKILL.md). They modify agent behavior by prepending domain-specific instructions to the agent's system prompt. | ||
| Skills are discovered across three scopes: | ||
| - `builtin` — Provided by the Weave plugin. | ||
| - `user` — Located in the user's global configuration directory. | ||
| - `project` — Located in the current project's `.opencode/skills/` directory. | ||
| ### Background Agents | ||
| Weave supports parallel asynchronous sub-agent management via the BackgroundManager. This allows Loom to spawn multiple agents simultaneously to handle independent tasks, with configurable concurrency limits to manage API rate limits. | ||
| ### Tool Permissions | ||
| Tool access is controlled per-agent to ensure safety and specialized focus. For example, **Thread** and **Spindle** are strictly read-only; they are denied access to write, edit, and task management tools. These permissions can be customized globally or per-agent in the configuration. | ||
| ## Development | ||
@@ -301,0 +108,0 @@ |
| import type { SessionSummary, Suggestion } from "./types"; | ||
| /** | ||
| * Generate suggestions based on session history. | ||
| * Analyzes tool usage patterns, delegation frequency, and workflow patterns. | ||
| */ | ||
| export declare function generateSuggestions(summaries: SessionSummary[]): Suggestion[]; | ||
| /** | ||
| * Generate suggestions from stored session summaries for a project. | ||
| */ | ||
| export declare function getSuggestionsForProject(directory: string): Suggestion[]; |
| export { createTaskCreateTool, createTaskUpdateTool, createTaskListTool } from "./tools"; | ||
| export { TaskStatus, TaskObjectSchema, TaskStatusSchema } from "./types"; | ||
| export type { TaskObject, TaskCreateInput, TaskUpdateInput, TaskListInput } from "./types"; | ||
| export { getTaskDir, generateTaskId, readTask, writeTask, readAllTasks } from "./storage"; | ||
| export { syncTaskToTodo, syncTaskTodoUpdate, syncAllTasksToTodos } from "./todo-sync"; | ||
| export type { TodoWriter, TodoInfo } from "./todo-sync"; |
| import { type TaskObject } from "./types"; | ||
| /** | ||
| * Derive the task storage directory for a given project. | ||
| * Uses the opencode config dir (~/.config/opencode by default) + sanitized project slug. | ||
| */ | ||
| export declare function getTaskDir(directory: string, configDir?: string): string; | ||
| /** Generate a unique task ID */ | ||
| export declare function generateTaskId(): string; | ||
| /** | ||
| * Read and parse a JSON file safely. Returns null for missing, corrupt, or invalid data. | ||
| */ | ||
| export declare function readJsonSafe<T>(filePath: string, schema: { | ||
| parse: (data: unknown) => T; | ||
| }): T | null; | ||
| /** | ||
| * Write JSON atomically: write to a temp file then rename. | ||
| * This prevents partial writes from corrupting the target file. | ||
| */ | ||
| export declare function writeJsonAtomic(filePath: string, data: unknown): void; | ||
| /** | ||
| * Acquire a file-based lock. Uses exclusive file creation (wx flag). | ||
| * Returns a release function on success, null on failure. | ||
| * | ||
| * Stale locks older than `staleThresholdMs` (default 30s) are automatically broken. | ||
| */ | ||
| export declare function acquireLock(lockPath: string, staleThresholdMs?: number): (() => void) | null; | ||
| /** Ensure a directory exists */ | ||
| export declare function ensureDir(dirPath: string): void; | ||
| /** List task files (T-*.json) in the task directory */ | ||
| export declare function listTaskFiles(taskDir: string): string[]; | ||
| /** Get the file path for a task by ID */ | ||
| export declare function getTaskFilePath(taskDir: string, taskId: string): string; | ||
| /** Read a single task from file storage */ | ||
| export declare function readTask(taskDir: string, taskId: string): TaskObject | null; | ||
| /** Write a single task to file storage (atomic) */ | ||
| export declare function writeTask(taskDir: string, task: TaskObject): void; | ||
| /** Read all tasks from a task directory */ | ||
| export declare function readAllTasks(taskDir: string): TaskObject[]; |
| import type { TaskObject } from "./types"; | ||
| /** TodoInfo matches the shape expected by OpenCode's todo sidebar */ | ||
| export interface TodoInfo { | ||
| id?: string; | ||
| content: string; | ||
| status: "pending" | "in_progress" | "completed"; | ||
| priority?: "high" | "medium" | "low"; | ||
| } | ||
| /** TodoWriter interface — abstracts the OpenCode todo write API */ | ||
| export interface TodoWriter { | ||
| read(sessionId: string): Promise<TodoInfo[]>; | ||
| update(sessionId: string, todos: TodoInfo[]): Promise<void>; | ||
| } | ||
| /** | ||
| * Map a TaskObject to a TodoInfo for the sidebar. | ||
| * Returns null for deleted tasks (they should be removed from the sidebar). | ||
| */ | ||
| export declare function syncTaskToTodo(task: TaskObject): TodoInfo | null; | ||
| /** | ||
| * Check if two todo items match by ID first, then by content as fallback. | ||
| */ | ||
| export declare function todosMatch(a: TodoInfo, b: TodoInfo): boolean; | ||
| /** | ||
| * Sync a single task to the todo sidebar. | ||
| * This is the anti-obliteration mechanism: | ||
| * 1. Read current todos | ||
| * 2. Filter out the matching item (by ID or content) | ||
| * 3. Push the updated item (or omit it if deleted) | ||
| * 4. Write back the full list | ||
| * | ||
| * Non-task todos (those not matching any task ID) survive intact. | ||
| */ | ||
| export declare function syncTaskTodoUpdate(writer: TodoWriter | null, sessionId: string, task: TaskObject): Promise<void>; | ||
| /** | ||
| * Sync all tasks to the todo sidebar, preserving non-task todos. | ||
| * Used for bulk reconciliation. | ||
| */ | ||
| export declare function syncAllTasksToTodos(writer: TodoWriter | null, sessionId: string, tasks: TaskObject[]): Promise<void>; |
| export { createTaskCreateTool } from "./task-create"; | ||
| export { createTaskUpdateTool } from "./task-update"; | ||
| export { createTaskListTool } from "./task-list"; |
| import { type ToolDefinition } from "@opencode-ai/plugin"; | ||
| import { type TodoWriter } from "../todo-sync"; | ||
| declare const TASK_ID_PATTERN: RegExp; | ||
| export declare function createTaskCreateTool(options: { | ||
| directory: string; | ||
| configDir?: string; | ||
| todoWriter?: TodoWriter | null; | ||
| }): ToolDefinition; | ||
| export { TASK_ID_PATTERN }; |
| import { type ToolDefinition } from "@opencode-ai/plugin"; | ||
| export declare function createTaskListTool(options: { | ||
| directory: string; | ||
| configDir?: string; | ||
| }): ToolDefinition; |
| import { type ToolDefinition } from "@opencode-ai/plugin"; | ||
| import { type TodoWriter } from "../todo-sync"; | ||
| export declare function createTaskUpdateTool(options: { | ||
| directory: string; | ||
| configDir?: string; | ||
| todoWriter?: TodoWriter | null; | ||
| }): ToolDefinition; |
| import { z } from "zod"; | ||
| /** Task status values */ | ||
| export declare const TaskStatus: { | ||
| readonly PENDING: "pending"; | ||
| readonly IN_PROGRESS: "in_progress"; | ||
| readonly COMPLETED: "completed"; | ||
| readonly DELETED: "deleted"; | ||
| }; | ||
| export type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus]; | ||
| export declare const TaskStatusSchema: z.ZodEnum<{ | ||
| pending: "pending"; | ||
| completed: "completed"; | ||
| in_progress: "in_progress"; | ||
| deleted: "deleted"; | ||
| }>; | ||
| /** | ||
| * Core task object — simplified from OmO's schema. | ||
| * Drops: activeForm, owner, repoURL, parentID (per design decision D4). | ||
| */ | ||
| export declare const TaskObjectSchema: z.ZodObject<{ | ||
| id: z.ZodString; | ||
| subject: z.ZodString; | ||
| description: z.ZodString; | ||
| status: z.ZodEnum<{ | ||
| pending: "pending"; | ||
| completed: "completed"; | ||
| in_progress: "in_progress"; | ||
| deleted: "deleted"; | ||
| }>; | ||
| threadID: z.ZodString; | ||
| blocks: z.ZodDefault<z.ZodArray<z.ZodString>>; | ||
| blockedBy: z.ZodDefault<z.ZodArray<z.ZodString>>; | ||
| metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>; | ||
| }, z.core.$strip>; | ||
| export type TaskObject = z.infer<typeof TaskObjectSchema>; | ||
| /** Input schema for task_create tool */ | ||
| export declare const TaskCreateInputSchema: z.ZodObject<{ | ||
| subject: z.ZodString; | ||
| description: z.ZodOptional<z.ZodString>; | ||
| blocks: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| blockedBy: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>; | ||
| }, z.core.$strip>; | ||
| export type TaskCreateInput = z.infer<typeof TaskCreateInputSchema>; | ||
| /** Input schema for task_update tool */ | ||
| export declare const TaskUpdateInputSchema: z.ZodObject<{ | ||
| id: z.ZodString; | ||
| subject: z.ZodOptional<z.ZodString>; | ||
| description: z.ZodOptional<z.ZodString>; | ||
| status: z.ZodOptional<z.ZodEnum<{ | ||
| pending: "pending"; | ||
| completed: "completed"; | ||
| in_progress: "in_progress"; | ||
| deleted: "deleted"; | ||
| }>>; | ||
| addBlocks: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| addBlockedBy: z.ZodOptional<z.ZodArray<z.ZodString>>; | ||
| metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>; | ||
| }, z.core.$strip>; | ||
| export type TaskUpdateInput = z.infer<typeof TaskUpdateInputSchema>; | ||
| /** Input schema for task_list tool (no args needed for PoC) */ | ||
| export declare const TaskListInputSchema: z.ZodObject<{}, z.core.$strip>; | ||
| export type TaskListInput = z.infer<typeof TaskListInputSchema>; |
Sorry, the diff of this file is too big to display
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
377097
1.58%9401
3.81%26
-7.14%117
-62.26%Updated
Updated