@syntesseraai/opencode-feature-factory 0.6.20 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/command/mini-loop/documentation/run.md +3 -1
- package/command/mini-loop/implementation/run.md +3 -1
- package/command/mini-loop/start.md +3 -1
- package/command/pipeline/building/run.md +3 -1
- package/command/pipeline/documentation/run.md +3 -1
- package/command/pipeline/planning/run.md +3 -1
- package/command/pipeline/reviewing/run.md +3 -1
- package/command/pipeline/start.md +3 -1
- package/dist/command-config.d.ts +38 -0
- package/dist/command-config.js +128 -0
- package/dist/index.js +18 -2
- package/dist/tools/index.d.ts +16 -0
- package/dist/tools/index.js +21 -0
- package/dist/tools/mini-loop.d.ts +24 -0
- package/dist/tools/mini-loop.js +133 -0
- package/dist/tools/parsers.d.ts +28 -0
- package/dist/tools/parsers.js +142 -0
- package/dist/tools/pipeline.d.ts +32 -0
- package/dist/tools/pipeline.js +227 -0
- package/dist/tools/prompts.d.ts +24 -0
- package/dist/tools/prompts.js +182 -0
- package/dist/workflow/fan-out.d.ts +84 -0
- package/dist/workflow/fan-out.js +83 -0
- package/dist/workflow/gate-evaluator.d.ts +50 -0
- package/dist/workflow/gate-evaluator.js +118 -0
- package/dist/workflow/orchestrator.d.ts +9 -0
- package/dist/workflow/orchestrator.js +9 -0
- package/dist/workflow/types.d.ts +148 -0
- package/dist/workflow/types.js +62 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Run documentation mini-loop until gate passes
|
|
3
|
-
subtask:
|
|
3
|
+
subtask: false
|
|
4
4
|
agent: general
|
|
5
5
|
model: openai/gpt-5.4
|
|
6
6
|
loop:
|
|
@@ -12,3 +12,5 @@ return:
|
|
|
12
12
|
- /mini-loop/documentation/gate $RESULT[mini-doc-review]
|
|
13
13
|
- If `MINI_LOOP_DOCUMENTATION_GATE=REWORK`, continue loop with prior documentation review feedback included in the next documentation pass.
|
|
14
14
|
---
|
|
15
|
+
|
|
16
|
+
Reply with only: "Documentation phase started"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Run implementation mini-loop until gate passes
|
|
3
|
-
subtask:
|
|
3
|
+
subtask: false
|
|
4
4
|
agent: general
|
|
5
5
|
model: openai/gpt-5.4
|
|
6
6
|
loop:
|
|
@@ -12,3 +12,5 @@ return:
|
|
|
12
12
|
- /mini-loop/implementation/gate $RESULT[mini-impl-review]
|
|
13
13
|
- If `MINI_LOOP_IMPLEMENTATION_GATE=REWORK`, continue loop with prior review feedback included in the next build input.
|
|
14
14
|
---
|
|
15
|
+
|
|
16
|
+
Reply with only: "Implementation phase started"
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Mini-loop two-stage workflow entrypoint
|
|
3
|
-
subtask:
|
|
3
|
+
subtask: false
|
|
4
4
|
agent: general
|
|
5
5
|
model: openai/gpt-5.4
|
|
6
6
|
return:
|
|
7
7
|
- /mini-loop/implementation/run {as:implementation-phase} $ARGUMENTS
|
|
8
8
|
- /mini-loop/documentation/run $RESULT[implementation-phase]
|
|
9
9
|
---
|
|
10
|
+
|
|
11
|
+
Reply with only: "Mini-loop started"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Run build phase from approved plan
|
|
3
|
-
subtask:
|
|
3
|
+
subtask: false
|
|
4
4
|
agent: general
|
|
5
5
|
model: openai/gpt-5.4
|
|
6
6
|
return:
|
|
@@ -9,3 +9,5 @@ return:
|
|
|
9
9
|
- /pipeline/building/implement-batch {as:build-implementation} $RESULT[build-batches]
|
|
10
10
|
- /pipeline/reviewing/run {as:review-phase} $RESULT[build-implementation]
|
|
11
11
|
---
|
|
12
|
+
|
|
13
|
+
Reply with only: "Building phase started"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Run documentation loop after review approval
|
|
3
|
-
subtask:
|
|
3
|
+
subtask: false
|
|
4
4
|
agent: general
|
|
5
5
|
model: openai/gpt-5.4
|
|
6
6
|
loop:
|
|
@@ -12,3 +12,5 @@ return:
|
|
|
12
12
|
- /pipeline/documentation/gate $RESULT[doc-review]
|
|
13
13
|
- If `DOCUMENTATION_GATE=REWORK`, continue loop with review feedback for the next document pass.
|
|
14
14
|
---
|
|
15
|
+
|
|
16
|
+
Reply with only: "Documentation phase started"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Execute one planning iteration
|
|
3
|
-
subtask:
|
|
3
|
+
subtask: false
|
|
4
4
|
agent: general
|
|
5
5
|
model: openai/gpt-5.4
|
|
6
6
|
parallel:
|
|
@@ -11,3 +11,5 @@ return:
|
|
|
11
11
|
- /pipeline/planning/synthesize {as:plan-consensus} $RESULT[plan-opus] $RESULT[plan-gemini] $RESULT[plan-codex]
|
|
12
12
|
- /pipeline/planning/gate $RESULT[plan-consensus]
|
|
13
13
|
---
|
|
14
|
+
|
|
15
|
+
Reply with only: "Planning phase started"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Run review loop for completed tasks
|
|
3
|
-
subtask:
|
|
3
|
+
subtask: false
|
|
4
4
|
agent: general
|
|
5
5
|
model: openai/gpt-5.4
|
|
6
6
|
loop:
|
|
@@ -17,3 +17,5 @@ return:
|
|
|
17
17
|
- /pipeline/reviewing/gate $RESULT[review-synthesis]
|
|
18
18
|
- If `REVIEW_GATE=REWORK`, invoke `/pipeline/building/implement-batch` to apply fixes before the next loop iteration.
|
|
19
19
|
---
|
|
20
|
+
|
|
21
|
+
Reply with only: "Reviewing phase started"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Pipeline workflow entrypoint
|
|
3
|
-
subtask:
|
|
3
|
+
subtask: false
|
|
4
4
|
agent: general
|
|
5
5
|
model: openai/gpt-5.4
|
|
6
6
|
return:
|
|
@@ -10,3 +10,5 @@ return:
|
|
|
10
10
|
- /pipeline/documentation/run $RESULT[build-phase]
|
|
11
11
|
- /pipeline/complete
|
|
12
12
|
---
|
|
13
|
+
|
|
14
|
+
Reply with only: "Workflow started"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
type BunShell = any;
|
|
2
|
+
/**
|
|
3
|
+
* Command configuration type matching the OpenCode `command` config schema.
|
|
4
|
+
*/
|
|
5
|
+
export interface CommandConfig {
|
|
6
|
+
template: string;
|
|
7
|
+
description?: string;
|
|
8
|
+
agent?: string;
|
|
9
|
+
model?: string;
|
|
10
|
+
subtask?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface CommandConfigs {
|
|
13
|
+
[commandName: string]: CommandConfig;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Default commands to register in the global OpenCode config.
|
|
17
|
+
*
|
|
18
|
+
* "Feature-Factory" is a Socratic entrypoint that guides the user through
|
|
19
|
+
* clarifying requirements, choosing between pipeline and mini-loop, confirming
|
|
20
|
+
* model selections, and then invoking the appropriate workflow tool.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DEFAULT_COMMANDS: Record<string, CommandConfig>;
|
|
23
|
+
/**
|
|
24
|
+
* Merge command configs, preserving existing settings and adding new ones.
|
|
25
|
+
* Existing command configs take precedence (we never overwrite them).
|
|
26
|
+
*/
|
|
27
|
+
export declare function mergeCommandConfigs(existing: CommandConfigs | undefined, defaults: Record<string, CommandConfig>): CommandConfigs;
|
|
28
|
+
/**
|
|
29
|
+
* Update the command configuration in global opencode.json.
|
|
30
|
+
*
|
|
31
|
+
* This function:
|
|
32
|
+
* 1. Reads existing config from ~/.config/opencode/opencode.json
|
|
33
|
+
* 2. Preserves existing command settings
|
|
34
|
+
* 3. Adds default Feature Factory commands that don't exist yet
|
|
35
|
+
* 4. Writes updated config back to ~/.config/opencode/opencode.json
|
|
36
|
+
*/
|
|
37
|
+
export declare function updateCommandConfig($: BunShell): Promise<void>;
|
|
38
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { isRecord, updateGlobalOpenCodeConfigBlock } from './opencode-global-config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default commands to register in the global OpenCode config.
|
|
4
|
+
*
|
|
5
|
+
* "Feature-Factory" is a Socratic entrypoint that guides the user through
|
|
6
|
+
* clarifying requirements, choosing between pipeline and mini-loop, confirming
|
|
7
|
+
* model selections, and then invoking the appropriate workflow tool.
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULT_COMMANDS = {
|
|
10
|
+
'feature-factory': {
|
|
11
|
+
description: 'Feature Factory — guided workflow for planning and building features',
|
|
12
|
+
agent: 'general',
|
|
13
|
+
subtask: false,
|
|
14
|
+
template: `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.
|
|
15
|
+
|
|
16
|
+
Work through this process step by step. Do NOT skip steps or launch a tool until all steps are complete.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Step 1: Understand the request
|
|
21
|
+
|
|
22
|
+
The user said: $ARGUMENTS
|
|
23
|
+
|
|
24
|
+
Work through their request in a Socratic manner:
|
|
25
|
+
- Ask clarifying questions about scope, constraints, and acceptance criteria.
|
|
26
|
+
- Summarise your understanding back to them and ask them to confirm or correct it.
|
|
27
|
+
- Continue until you have a clear, unambiguous set of requirements.
|
|
28
|
+
|
|
29
|
+
If $ARGUMENTS is empty, ask the user what they would like to build.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Step 2: Choose workflow
|
|
34
|
+
|
|
35
|
+
Once requirements are agreed, present the two workflow options:
|
|
36
|
+
|
|
37
|
+
**Pipeline** (full multi-model workflow)
|
|
38
|
+
- Multi-model fan-out planning (3 models propose plans, then consensus synthesis)
|
|
39
|
+
- Build phase with task breakdown and batch validation
|
|
40
|
+
- Multi-model fan-out code review
|
|
41
|
+
- Documentation with review loop
|
|
42
|
+
- Best for: complex features, architectural changes, high-risk work
|
|
43
|
+
|
|
44
|
+
**Mini-loop** (lightweight workflow)
|
|
45
|
+
- Direct build → review loop (single model per step)
|
|
46
|
+
- Documentation with review loop
|
|
47
|
+
- Best for: small features, bug fixes, incremental improvements, well-understood changes
|
|
48
|
+
|
|
49
|
+
Ask the user which workflow they prefer. If they are unsure, recommend one based on the complexity of the requirements.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Step 3: Confirm models
|
|
54
|
+
|
|
55
|
+
Present the default models that will be used for the chosen workflow:
|
|
56
|
+
|
|
57
|
+
**Pipeline defaults:**
|
|
58
|
+
- Planning fan-out: opus (anthropic/claude-opus-4-6), gemini (opencode/gemini-3.1-pro), codex (openai/gpt-5.3-codex)
|
|
59
|
+
- Review fan-out: same as planning
|
|
60
|
+
- Orchestrator (synthesis/triage): openai/gpt-5.4
|
|
61
|
+
- Build: openai/gpt-5.3-codex
|
|
62
|
+
- Validate: opencode/gemini-3.1-pro
|
|
63
|
+
- Documentation: openai/gpt-5.3-codex
|
|
64
|
+
- Doc review: opencode/gemini-3.1-pro
|
|
65
|
+
|
|
66
|
+
**Mini-loop defaults:**
|
|
67
|
+
- Build: openai/gpt-5.3-codex
|
|
68
|
+
- Review: openai/gpt-5.4
|
|
69
|
+
- Documentation: openai/gpt-5.3-codex
|
|
70
|
+
- Doc review: opencode/gemini-3.1-pro
|
|
71
|
+
|
|
72
|
+
Ask: "Would you like to use these default models, or would you like to override any of them?"
|
|
73
|
+
|
|
74
|
+
If they want to override, collect the provider/model strings for each role they want to change.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Step 4: Launch
|
|
79
|
+
|
|
80
|
+
Once all three steps are confirmed, call the appropriate tool:
|
|
81
|
+
|
|
82
|
+
- If they chose **Pipeline**: call the \`ff_pipeline\` tool with the agreed requirements and any model overrides.
|
|
83
|
+
- If they chose **Mini-loop**: call the \`ff_mini_loop\` tool with the agreed requirements and any model overrides.
|
|
84
|
+
|
|
85
|
+
Pass only the model parameters that were explicitly overridden; omit any that should use defaults.`,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Merge command configs, preserving existing settings and adding new ones.
|
|
90
|
+
* Existing command configs take precedence (we never overwrite them).
|
|
91
|
+
*/
|
|
92
|
+
export function mergeCommandConfigs(existing, defaults) {
|
|
93
|
+
const existingCommands = existing ?? {};
|
|
94
|
+
const result = { ...existingCommands };
|
|
95
|
+
for (const [commandName, commandConfig] of Object.entries(defaults)) {
|
|
96
|
+
if (!result[commandName]) {
|
|
97
|
+
result[commandName] = commandConfig;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Update the command configuration in global opencode.json.
|
|
104
|
+
*
|
|
105
|
+
* This function:
|
|
106
|
+
* 1. Reads existing config from ~/.config/opencode/opencode.json
|
|
107
|
+
* 2. Preserves existing command settings
|
|
108
|
+
* 3. Adds default Feature Factory commands that don't exist yet
|
|
109
|
+
* 4. Writes updated config back to ~/.config/opencode/opencode.json
|
|
110
|
+
*/
|
|
111
|
+
export async function updateCommandConfig($) {
|
|
112
|
+
void $;
|
|
113
|
+
await updateGlobalOpenCodeConfigBlock({
|
|
114
|
+
blockName: 'command',
|
|
115
|
+
warningLabel: 'command config',
|
|
116
|
+
update: (existingBlock) => {
|
|
117
|
+
const existingCommandConfigs = isRecord(existingBlock)
|
|
118
|
+
? existingBlock
|
|
119
|
+
: undefined;
|
|
120
|
+
const updatedCommandConfigs = mergeCommandConfigs(existingCommandConfigs, DEFAULT_COMMANDS);
|
|
121
|
+
const hasChanges = Object.keys(DEFAULT_COMMANDS).some((commandName) => !existingCommandConfigs?.[commandName]);
|
|
122
|
+
return {
|
|
123
|
+
nextBlock: updatedCommandConfigs,
|
|
124
|
+
changed: hasChanges,
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@ 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 { updateCommandConfig } from './command-config.js';
|
|
6
|
+
import { createWorkflowTools } from './tools/index.js';
|
|
5
7
|
import { $ } from 'bun';
|
|
6
8
|
/**
|
|
7
9
|
* Feature Factory Plugin
|
|
@@ -40,10 +42,24 @@ export const FeatureFactoryPlugin = async (input) => {
|
|
|
40
42
|
catch {
|
|
41
43
|
console.error('Failed to update plugin config in OpenCode plugin');
|
|
42
44
|
}
|
|
45
|
+
// Update command configuration in global OpenCode config
|
|
46
|
+
// This registers the Feature-Factory Socratic entrypoint command
|
|
47
|
+
try {
|
|
48
|
+
await updateCommandConfig($);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
console.error('Failed to update command config in OpenCode plugin');
|
|
52
|
+
}
|
|
43
53
|
// Load hooks from the quality gate plugin
|
|
44
54
|
const qualityGateHooks = await StopQualityGateHooksPlugin(input).catch(() => ({}));
|
|
45
|
-
// Tool registry
|
|
46
|
-
|
|
55
|
+
// Tool registry: workflow tools (ff_pipeline, ff_mini_loop) powered by
|
|
56
|
+
// the SDK client for programmatic session orchestration.
|
|
57
|
+
// The old ff-* artifact tools were removed; these replace the subtask2
|
|
58
|
+
// command-based workflow with TypeScript-driven orchestration.
|
|
59
|
+
const workflowTools = createWorkflowTools(input.client);
|
|
60
|
+
// Merge workflow tools with any existing tools from quality gate hooks
|
|
61
|
+
const existingTools = qualityGateHooks.tool ?? {};
|
|
62
|
+
const tools = { ...existingTools, ...workflowTools };
|
|
47
63
|
// Return combined hooks and tools
|
|
48
64
|
return {
|
|
49
65
|
...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
|
+
};
|