@syntesseraai/opencode-feature-factory 0.6.21 → 0.7.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.
@@ -0,0 +1,95 @@
1
+ ---
2
+ description: Feature Factory — guided workflow for planning and building features. Walks through requirements, workflow selection, model confirmation, then launches the pipeline or mini-loop.
3
+ mode: primary
4
+ color: '#f59e0b'
5
+ tools:
6
+ read: true
7
+ write: false
8
+ edit: false
9
+ bash: false
10
+ skill: true
11
+ task: true
12
+ ff_pipeline: true
13
+ ff_mini_loop: true
14
+ permission:
15
+ skill:
16
+ '*': allow
17
+ task:
18
+ building: allow
19
+ reviewing: allow
20
+ planning: allow
21
+ documenting: allow
22
+ ff-research: allow
23
+ explore: allow
24
+ ---
25
+
26
+ You are the Feature Factory workflow assistant. Your job is to guide the user through a structured process before launching either the full pipeline or the mini-loop.
27
+
28
+ Work through this process step by step. Do NOT skip steps or launch a tool until all steps are complete.
29
+
30
+ ---
31
+
32
+ ## Step 1: Understand the request
33
+
34
+ Work through the user's request in a Socratic manner:
35
+ - Ask clarifying questions about scope, constraints, and acceptance criteria.
36
+ - Summarise your understanding back to them and ask them to confirm or correct it.
37
+ - Continue until you have a clear, unambiguous set of requirements.
38
+
39
+ If the user hasn't provided a request yet, ask them what they would like to build.
40
+
41
+ ---
42
+
43
+ ## Step 2: Choose workflow
44
+
45
+ Once requirements are agreed, present the two workflow options:
46
+
47
+ **Pipeline** (full multi-model workflow)
48
+ - Multi-model fan-out planning (3 models propose plans, then consensus synthesis)
49
+ - Build phase with task breakdown and batch validation
50
+ - Multi-model fan-out code review
51
+ - Documentation with review loop
52
+ - Best for: complex features, architectural changes, high-risk work
53
+
54
+ **Mini-loop** (lightweight workflow)
55
+ - Direct build → review loop (single model per step)
56
+ - Documentation with review loop
57
+ - Best for: small features, bug fixes, incremental improvements, well-understood changes
58
+
59
+ Ask the user which workflow they prefer. If they are unsure, recommend one based on the complexity of the requirements.
60
+
61
+ ---
62
+
63
+ ## Step 3: Confirm models
64
+
65
+ Present the default models that will be used for the chosen workflow:
66
+
67
+ **Pipeline defaults:**
68
+ - Planning fan-out: opus (anthropic/claude-opus-4-6), gemini (opencode/gemini-3.1-pro), codex (openai/gpt-5.3-codex)
69
+ - Review fan-out: same as planning
70
+ - Orchestrator (synthesis/triage): openai/gpt-5.4
71
+ - Build: openai/gpt-5.3-codex
72
+ - Validate: opencode/gemini-3.1-pro
73
+ - Documentation: openai/gpt-5.3-codex
74
+ - Doc review: opencode/gemini-3.1-pro
75
+
76
+ **Mini-loop defaults:**
77
+ - Build: openai/gpt-5.3-codex
78
+ - Review: openai/gpt-5.4
79
+ - Documentation: openai/gpt-5.3-codex
80
+ - Doc review: opencode/gemini-3.1-pro
81
+
82
+ Ask: "Would you like to use these default models, or would you like to override any of them?"
83
+
84
+ If they want to override, collect the provider/model strings for each role they want to change.
85
+
86
+ ---
87
+
88
+ ## Step 4: Launch
89
+
90
+ Once all three steps are confirmed, call the appropriate tool:
91
+
92
+ - If they chose **Pipeline**: call the `ff_pipeline` tool with the agreed requirements and any model overrides.
93
+ - If they chose **Mini-loop**: call the `ff_mini_loop` tool with the agreed requirements and any model overrides.
94
+
95
+ Pass only the model parameters that were explicitly overridden; omit any that should use defaults.
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { StopQualityGateHooksPlugin } from './stop-quality-gate.js';
2
2
  import { updateMCPConfig } from './mcp-config.js';
3
3
  import { updateAgentConfig } from './agent-config.js';
4
4
  import { updatePluginConfig } from './plugin-config.js';
5
+ import { createWorkflowTools } from './tools/index.js';
5
6
  import { $ } from 'bun';
6
7
  /**
7
8
  * Feature Factory Plugin
@@ -42,8 +43,14 @@ export const FeatureFactoryPlugin = async (input) => {
42
43
  }
43
44
  // Load hooks from the quality gate plugin
44
45
  const qualityGateHooks = await StopQualityGateHooksPlugin(input).catch(() => ({}));
45
- // Tool registry intentionally empty after hard removal of ff-* artifact tools.
46
- const tools = {};
46
+ // Tool registry: workflow tools (ff_pipeline, ff_mini_loop) powered by
47
+ // the SDK client for programmatic session orchestration.
48
+ // The old ff-* artifact tools were removed; these replace the subtask2
49
+ // command-based workflow with TypeScript-driven orchestration.
50
+ const workflowTools = createWorkflowTools(input.client);
51
+ // Merge workflow tools with any existing tools from quality gate hooks
52
+ const existingTools = qualityGateHooks.tool ?? {};
53
+ const tools = { ...existingTools, ...workflowTools };
47
54
  // Return combined hooks and tools
48
55
  return {
49
56
  ...qualityGateHooks,
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Tool registry for Feature Factory.
3
+ *
4
+ * Exports a function that creates all FF tools given the SDK client.
5
+ * Only entrypoint tools (pipeline, mini-loop) are exposed to the LLM.
6
+ * Internal workflow steps are orchestrated programmatically, not as
7
+ * individually callable tools.
8
+ */
9
+ import type { ToolDefinition } from '@opencode-ai/plugin/tool';
10
+ import type { Client } from '../workflow/fan-out.js';
11
+ /**
12
+ * Build the tool map to be merged into the plugin's `Hooks.tool` output.
13
+ *
14
+ * @param client - The OpenCode SDK client from PluginInput
15
+ */
16
+ export declare function createWorkflowTools(client: Client): Record<string, ToolDefinition>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Tool registry for Feature Factory.
3
+ *
4
+ * Exports a function that creates all FF tools given the SDK client.
5
+ * Only entrypoint tools (pipeline, mini-loop) are exposed to the LLM.
6
+ * Internal workflow steps are orchestrated programmatically, not as
7
+ * individually callable tools.
8
+ */
9
+ import { createPipelineTool } from './pipeline.js';
10
+ import { createMiniLoopTool } from './mini-loop.js';
11
+ /**
12
+ * Build the tool map to be merged into the plugin's `Hooks.tool` output.
13
+ *
14
+ * @param client - The OpenCode SDK client from PluginInput
15
+ */
16
+ export function createWorkflowTools(client) {
17
+ return {
18
+ ff_pipeline: createPipelineTool(client),
19
+ ff_mini_loop: createMiniLoopTool(client),
20
+ };
21
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * ff_mini_loop — Lightweight build → review → document workflow tool.
3
+ *
4
+ * A simpler two-stage workflow (no multi-model fan-out for planning).
5
+ * Implements a build/review loop, then a documentation loop.
6
+ */
7
+ import { type Client } from '../workflow/orchestrator.js';
8
+ export declare function createMiniLoopTool(client: Client): {
9
+ description: string;
10
+ args: {
11
+ requirements: import("zod").ZodString;
12
+ build_model: import("zod").ZodOptional<import("zod").ZodString>;
13
+ review_model: import("zod").ZodOptional<import("zod").ZodString>;
14
+ doc_model: import("zod").ZodOptional<import("zod").ZodString>;
15
+ doc_review_model: import("zod").ZodOptional<import("zod").ZodString>;
16
+ };
17
+ execute(args: {
18
+ requirements: string;
19
+ build_model?: string | undefined;
20
+ review_model?: string | undefined;
21
+ doc_model?: string | undefined;
22
+ doc_review_model?: string | undefined;
23
+ }, context: import("@opencode-ai/plugin/tool").ToolContext): Promise<string>;
24
+ };
@@ -0,0 +1,133 @@
1
+ /**
2
+ * ff_mini_loop — Lightweight build → review → document workflow tool.
3
+ *
4
+ * A simpler two-stage workflow (no multi-model fan-out for planning).
5
+ * Implements a build/review loop, then a documentation loop.
6
+ */
7
+ import { tool } from '@opencode-ai/plugin/tool';
8
+ import { promptSession, evaluateMiniLoopImplGate, evaluateMiniLoopDocGate, BUILD_MODEL, DOC_MODEL, DOC_REVIEW_MODEL, ORCHESTRATOR_MODEL, parseModelString, } from '../workflow/orchestrator.js';
9
+ import { miniBuildPrompt, miniReviewPrompt, documentPrompt, docReviewPrompt } from './prompts.js';
10
+ import { parseMiniReview, parseDocReview } from './parsers.js';
11
+ // ---------------------------------------------------------------------------
12
+ // Tool factory
13
+ // ---------------------------------------------------------------------------
14
+ export function createMiniLoopTool(client) {
15
+ return tool({
16
+ description: 'Run the Feature Factory mini-loop: build → review (with rework loop) → documentation. ' +
17
+ 'Lighter weight than the full pipeline — no multi-model planning phase. ' +
18
+ 'All model parameters are optional and use sensible defaults.',
19
+ args: {
20
+ requirements: tool.schema
21
+ .string()
22
+ .describe('The feature requirements or task description to implement'),
23
+ build_model: tool.schema
24
+ .string()
25
+ .optional()
26
+ .describe('provider/model for building and implementation. Defaults to openai/gpt-5.3-codex.'),
27
+ review_model: tool.schema
28
+ .string()
29
+ .optional()
30
+ .describe('provider/model for implementation review. Defaults to openai/gpt-5.4.'),
31
+ doc_model: tool.schema
32
+ .string()
33
+ .optional()
34
+ .describe('provider/model for documentation writing. Defaults to the build model.'),
35
+ doc_review_model: tool.schema
36
+ .string()
37
+ .optional()
38
+ .describe('provider/model for documentation review. Defaults to opencode/gemini-3.1-pro.'),
39
+ },
40
+ async execute(args, context) {
41
+ const sessionId = context.sessionID;
42
+ const { requirements } = args;
43
+ // Resolve models — use provided overrides or fall back to defaults
44
+ const buildModel = args.build_model
45
+ ? parseModelString(args.build_model)
46
+ : BUILD_MODEL;
47
+ const reviewModel = args.review_model
48
+ ? parseModelString(args.review_model)
49
+ : ORCHESTRATOR_MODEL;
50
+ const docModel = args.doc_model
51
+ ? parseModelString(args.doc_model)
52
+ : args.build_model
53
+ ? buildModel
54
+ : DOC_MODEL;
55
+ const docReviewModel = args.doc_review_model
56
+ ? parseModelString(args.doc_review_model)
57
+ : DOC_REVIEW_MODEL;
58
+ const report = [];
59
+ const addReport = (phase, msg) => {
60
+ report.push(`## ${phase}\n${msg}`);
61
+ };
62
+ // ===================================================================
63
+ // PHASE 1: IMPLEMENTATION LOOP (build → review → gate, up to 10)
64
+ // ===================================================================
65
+ let implGate = { decision: 'REWORK', feedback: requirements };
66
+ let lastImplRaw = '';
67
+ for (let implIter = 0; implIter < 10 && implGate.decision === 'REWORK'; implIter++) {
68
+ const buildInput = implIter === 0
69
+ ? requirements
70
+ : `${requirements}\n\nPrevious review feedback:\n${implGate.feedback}`;
71
+ // Build
72
+ lastImplRaw = await promptSession(client, sessionId, miniBuildPrompt(buildInput, implIter > 0 ? implGate.feedback : undefined), { model: buildModel, agent: 'building', title: `ff-mini-build-${implIter + 1}` });
73
+ // Review
74
+ const reviewRaw = await promptSession(client, sessionId, miniReviewPrompt(lastImplRaw), {
75
+ model: reviewModel,
76
+ agent: 'reviewing',
77
+ title: `ff-mini-review-${implIter + 1}`,
78
+ });
79
+ const review = parseMiniReview(reviewRaw);
80
+ // Gate (deterministic)
81
+ implGate = evaluateMiniLoopImplGate(review, implIter + 1);
82
+ if (implGate.decision === 'APPROVED') {
83
+ addReport('Implementation', `APPROVED (confidence: ${review.confidence}, iteration: ${implIter + 1})`);
84
+ }
85
+ else if (implGate.decision === 'ESCALATE') {
86
+ addReport('Implementation', `ESCALATE: ${implGate.reason}`);
87
+ return report.join('\n\n');
88
+ }
89
+ // REWORK continues the loop
90
+ }
91
+ if (implGate.decision !== 'APPROVED') {
92
+ addReport('Implementation', `REWORK exhausted (10 iterations). Last feedback:\n${implGate.feedback}`);
93
+ return report.join('\n\n');
94
+ }
95
+ // ===================================================================
96
+ // PHASE 2: DOCUMENTATION LOOP (document → review → gate, up to 5)
97
+ // ===================================================================
98
+ let docInput = lastImplRaw;
99
+ let docGate = { decision: 'REWORK' };
100
+ for (let docIter = 0; docIter < 5 && docGate.decision === 'REWORK'; docIter++) {
101
+ // Write docs
102
+ const docRaw = await promptSession(client, sessionId, documentPrompt(docInput), {
103
+ model: docModel,
104
+ agent: 'documenting',
105
+ title: `ff-mini-doc-write-${docIter + 1}`,
106
+ });
107
+ // Review docs
108
+ const docRevRaw = await promptSession(client, sessionId, docReviewPrompt(docRaw), {
109
+ model: docReviewModel,
110
+ agent: 'reviewing',
111
+ title: `ff-mini-doc-review-${docIter + 1}`,
112
+ });
113
+ const docReview = parseDocReview(docRevRaw);
114
+ // Gate (deterministic)
115
+ docGate = evaluateMiniLoopDocGate(docReview, docIter + 1);
116
+ if (docGate.decision === 'APPROVED') {
117
+ addReport('Documentation', `APPROVED (confidence: ${docReview.confidence}, iteration: ${docIter + 1})`);
118
+ }
119
+ else if (docGate.decision === 'ESCALATE') {
120
+ addReport('Documentation', `ESCALATE: ${docGate.reason}`);
121
+ }
122
+ else {
123
+ docInput = `${docInput}\n\nDocumentation review feedback:\n${docGate.feedback}`;
124
+ }
125
+ }
126
+ // ===================================================================
127
+ // FINAL REPORT
128
+ // ===================================================================
129
+ addReport('Complete', 'Mini-loop finished.');
130
+ return report.join('\n\n');
131
+ },
132
+ });
133
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Response parsers that extract structured data from LLM text output.
3
+ *
4
+ * These are intentionally tolerant — they fall back to raw text when
5
+ * structured sections cannot be found. The gate evaluators work on
6
+ * the parsed numbers/booleans, not on freeform text.
7
+ */
8
+ import type { PlanProposal, ConsensusPlan, ReviewReport, ReviewSynthesis, DocReview, ImplementationReport, DocUpdate } from '../workflow/types.js';
9
+ /** Extract the first integer found after a label in the text. */
10
+ export declare function extractNumber(text: string, label: string, fallback?: number): number;
11
+ /** Extract text between two section headers (markdown-style). */
12
+ export declare function extractSection(text: string, heading: string): string;
13
+ /** Check if a YES/NO field is YES. */
14
+ export declare function isYes(text: string, label: string): boolean;
15
+ export declare function parsePlanProposal(tag: string, raw: string): PlanProposal;
16
+ export declare function parseConsensusPlan(raw: string): ConsensusPlan;
17
+ export declare function parseReviewReport(tag: string, raw: string): ReviewReport;
18
+ export declare function parseReviewSynthesis(raw: string): ReviewSynthesis;
19
+ export declare function parseDocUpdate(raw: string): DocUpdate;
20
+ export declare function parseDocReview(raw: string): DocReview;
21
+ export declare function parseImplementationReport(raw: string): ImplementationReport;
22
+ export declare function parseMiniReview(raw: string): {
23
+ confidence: number;
24
+ changeRequested: boolean;
25
+ unresolvedIssues: number;
26
+ reworkInstructions?: string;
27
+ raw: string;
28
+ };
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Response parsers that extract structured data from LLM text output.
3
+ *
4
+ * These are intentionally tolerant — they fall back to raw text when
5
+ * structured sections cannot be found. The gate evaluators work on
6
+ * the parsed numbers/booleans, not on freeform text.
7
+ */
8
+ // ---------------------------------------------------------------------------
9
+ // Generic helpers
10
+ // ---------------------------------------------------------------------------
11
+ /** Extract the first integer found after a label in the text. */
12
+ export function extractNumber(text, label, fallback = 0) {
13
+ // Try patterns like "CONSENSUS_SCORE: 85", "confidence: 92", "CONFIDENCE=95"
14
+ const patterns = [
15
+ new RegExp(`${label}[=:\\s]+([0-9]+)`, 'i'),
16
+ new RegExp(`${label}[^0-9]*([0-9]+)`, 'i'),
17
+ ];
18
+ for (const re of patterns) {
19
+ const m = text.match(re);
20
+ if (m)
21
+ return parseInt(m[1], 10);
22
+ }
23
+ return fallback;
24
+ }
25
+ /** Extract text between two section headers (markdown-style). */
26
+ export function extractSection(text, heading) {
27
+ // Try numbered list style: "1. HEADING" or "## HEADING" or "**HEADING**"
28
+ const patterns = [
29
+ new RegExp(`(?:^|\\n)(?:\\d+\\.\\s*)?\\*{0,2}${heading}\\*{0,2}[:\\s]*\\n([\\s\\S]*?)(?=\\n(?:\\d+\\.\\s*)?\\*{0,2}[A-Z_]+|$)`, 'i'),
30
+ new RegExp(`(?:^|\\n)#{1,3}\\s*${heading}[:\\s]*\\n([\\s\\S]*?)(?=\\n#{1,3}\\s|$)`, 'i'),
31
+ ];
32
+ for (const re of patterns) {
33
+ const m = text.match(re);
34
+ if (m)
35
+ return m[1].trim();
36
+ }
37
+ return '';
38
+ }
39
+ /** Check if a YES/NO field is YES. */
40
+ export function isYes(text, label) {
41
+ const m = text.match(new RegExp(`${label}[=:\\s]*(YES|NO)`, 'i'));
42
+ return m ? m[1].toUpperCase() === 'YES' : false;
43
+ }
44
+ // ---------------------------------------------------------------------------
45
+ // Planning parsers
46
+ // ---------------------------------------------------------------------------
47
+ export function parsePlanProposal(tag, raw) {
48
+ return {
49
+ tag,
50
+ requirementsSummary: extractSection(raw, 'REQUIREMENTS_SUMMARY') || raw.slice(0, 200),
51
+ architectureValidation: extractSection(raw, 'ARCHITECTURE_VALIDATION'),
52
+ implementationSteps: extractSection(raw, 'IMPLEMENTATION_STEPS'),
53
+ risksAndMitigations: extractSection(raw, 'RISKS_AND_MITIGATIONS'),
54
+ testingStrategy: extractSection(raw, 'TESTING_AND_VALIDATION_STRATEGY'),
55
+ raw,
56
+ };
57
+ }
58
+ export function parseConsensusPlan(raw) {
59
+ return {
60
+ consensusScore: extractNumber(raw, 'CONSENSUS_SCORE'),
61
+ agreedElements: extractSection(raw, 'AGREED_ELEMENTS'),
62
+ divergentElements: extractSection(raw, 'DIVERGENT_ELEMENTS'),
63
+ synthesizedPlan: extractSection(raw, 'SYNTHESIZED_PLAN'),
64
+ openQuestions: extractSection(raw, 'OPEN_QUESTIONS'),
65
+ raw,
66
+ };
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Review parsers
70
+ // ---------------------------------------------------------------------------
71
+ export function parseReviewReport(tag, raw) {
72
+ return {
73
+ tag,
74
+ findings: raw,
75
+ confidence: extractNumber(raw, 'confidence'),
76
+ raw,
77
+ };
78
+ }
79
+ export function parseReviewSynthesis(raw) {
80
+ const confidence = extractNumber(raw, 'confidence');
81
+ const unresolvedIssues = extractNumber(raw, 'unresolved');
82
+ const verdictMatch = raw.match(/verdict[=:\s]*(APPROVED|REWORK_REQUIRED)/i);
83
+ const verdict = (verdictMatch?.[1]?.toUpperCase() === 'APPROVED' ? 'APPROVED' : 'REWORK_REQUIRED');
84
+ const reworkSection = extractSection(raw, 'rework');
85
+ return {
86
+ overallConfidence: confidence,
87
+ consolidatedFindings: raw,
88
+ unresolvedIssues,
89
+ verdict,
90
+ reworkInstructions: reworkSection || undefined,
91
+ raw,
92
+ };
93
+ }
94
+ // ---------------------------------------------------------------------------
95
+ // Doc parsers
96
+ // ---------------------------------------------------------------------------
97
+ export function parseDocUpdate(raw) {
98
+ return {
99
+ filesChanged: [], // The LLM lists these in the raw text; we keep the raw for the gate
100
+ rationale: raw,
101
+ raw,
102
+ };
103
+ }
104
+ export function parseDocReview(raw) {
105
+ const confidence = extractNumber(raw, 'confidence');
106
+ const unresolvedIssues = extractNumber(raw, 'unresolved');
107
+ const verdictMatch = raw.match(/verdict[=:\s]*(APPROVED|REWORK_REQUIRED)/i);
108
+ const verdict = (verdictMatch?.[1]?.toUpperCase() === 'APPROVED' ? 'APPROVED' : 'REWORK_REQUIRED');
109
+ const reworkSection = extractSection(raw, 'rework');
110
+ return {
111
+ verdict,
112
+ unresolvedIssues,
113
+ confidence,
114
+ reworkInstructions: reworkSection || undefined,
115
+ raw,
116
+ };
117
+ }
118
+ // ---------------------------------------------------------------------------
119
+ // Implementation parsers
120
+ // ---------------------------------------------------------------------------
121
+ export function parseImplementationReport(raw) {
122
+ return {
123
+ filesChanged: [],
124
+ testsRun: [],
125
+ testsPassed: !raw.toLowerCase().includes('failed'),
126
+ openIssues: [],
127
+ raw,
128
+ };
129
+ }
130
+ // ---------------------------------------------------------------------------
131
+ // Mini-loop review parser
132
+ // ---------------------------------------------------------------------------
133
+ export function parseMiniReview(raw) {
134
+ return {
135
+ confidence: extractNumber(raw, 'CONFIDENCE'),
136
+ changeRequested: isYes(raw, 'CHANGE_REQUESTED'),
137
+ unresolvedIssues: extractNumber(raw, 'UNRESOLVED_BLOCKING_ISSUES') ||
138
+ extractNumber(raw, 'UNRESOLVED_DOCUMENTATION_ISSUES'),
139
+ reworkInstructions: extractSection(raw, 'rework') || undefined,
140
+ raw,
141
+ };
142
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * ff_pipeline — Full plan → build → review → document workflow tool.
3
+ *
4
+ * This is an entrypoint tool exposed to the LLM. It orchestrates the
5
+ * complete Feature Factory pipeline using deterministic control flow
6
+ * (TypeScript loops and gates) while delegating creative work to
7
+ * model-specific prompts via the SDK client.
8
+ */
9
+ import { type Client } from '../workflow/orchestrator.js';
10
+ export declare function createPipelineTool(client: Client): {
11
+ description: string;
12
+ args: {
13
+ requirements: import("zod").ZodString;
14
+ planning_models: import("zod").ZodOptional<import("zod").ZodString>;
15
+ review_models: import("zod").ZodOptional<import("zod").ZodString>;
16
+ orchestrator_model: import("zod").ZodOptional<import("zod").ZodString>;
17
+ build_model: import("zod").ZodOptional<import("zod").ZodString>;
18
+ validate_model: import("zod").ZodOptional<import("zod").ZodString>;
19
+ doc_model: import("zod").ZodOptional<import("zod").ZodString>;
20
+ doc_review_model: import("zod").ZodOptional<import("zod").ZodString>;
21
+ };
22
+ execute(args: {
23
+ requirements: string;
24
+ planning_models?: string | undefined;
25
+ review_models?: string | undefined;
26
+ orchestrator_model?: string | undefined;
27
+ build_model?: string | undefined;
28
+ validate_model?: string | undefined;
29
+ doc_model?: string | undefined;
30
+ doc_review_model?: string | undefined;
31
+ }, context: import("@opencode-ai/plugin/tool").ToolContext): Promise<string>;
32
+ };