@syntesseraai/opencode-feature-factory 0.10.13 → 0.10.15

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/AGENTS.md CHANGED
@@ -5,11 +5,11 @@ This file is installed to `~/.config/opencode/AGENTS.md` by `@syntesseraai/openc
5
5
  ## What Feature Factory Provides
6
6
 
7
7
  - Native workflow orchestration through the `feature-factory` agent.
8
- - Default orchestrator model: `feature-factory` -> `openai/gpt-5.4`
8
+ - Default orchestrator model: `feature-factory` -> `github-copilot/gpt-5.4-mini`
9
9
  - Stage sub-agents with default model routing:
10
10
  - `planning` -> `openai/gpt-5.4`
11
11
  - `building` -> `openai/gpt-5.3-codex`
12
- - `reviewing` -> `opencode/claude-opus-4-6`
12
+ - `reviewing` -> `opencode/glm-5.1`
13
13
  - `documenting` -> `opencode/gemini-3.1-pro`
14
14
  - Specialized agents: `feature-factory`, `planning`, `building`, `reviewing`, `documenting`, and `ff-research`.
15
15
  - Quick commands: `/ff-review [optional prompt]`, `/ff-document [optional prompt]`, and `/ff-rework [optional prompt]` (all run as subtasks on the relevant stage agent).
@@ -36,7 +36,8 @@ When work changes behavior, workflows, configuration, operational guidance, or r
36
36
 
37
37
  ## Preferred Tooling Pattern
38
38
 
39
- - Use `morph-mcp_codebase_search` first for semantic codebase discovery.
39
+ - Use codebase-memory MCP graph tools first in stage agents (`codebase-memory-mcp_search_graph`, `codebase-memory-mcp_get_architecture`, `codebase-memory-mcp_trace_call_path`, `codebase-memory-mcp_get_code_snippet`) for discovery, architecture context, and call-path impact analysis.
40
+ - Keep `morph-mcp_codebase_search` as fallback when codebase-memory MCP is unavailable or the repository has not been indexed.
40
41
  - Use `read`, `glob`, and `grep` for targeted file inspection.
41
42
  - Writable agents should prefer `morph-mcp` `edit_file`, then fallback to native `edit` when needed.
42
43
  - Keep `edit` restricted on read-only agents (`planning`, `reviewing`, `ff-research`).
package/README.md CHANGED
@@ -56,10 +56,10 @@ The plugin no longer exposes `ff_pipeline`, `ff_mini_loop`, or `ff_list_models`
56
56
 
57
57
  Instead, the `feature-factory` primary agent orchestrates workflows natively by delegating to stage sub-agents:
58
58
 
59
- - `feature-factory` (orchestrator) -> default model `openai/gpt-5.4`
59
+ - `feature-factory` (orchestrator) -> default model `github-copilot/gpt-5.4-mini`
60
60
  - `planning` -> default model `openai/gpt-5.4`
61
61
  - `building` -> default model `openai/gpt-5.3-codex`
62
- - `reviewing` -> default model `opencode/claude-opus-4-6`
62
+ - `reviewing` -> default model `opencode/glm-5.1`
63
63
  - `documenting` -> default model `opencode/gemini-3.1-pro`
64
64
 
65
65
  ### Fixed execution path
@@ -76,6 +76,17 @@ Each transition carries forward prior-stage context (summary, gate/verdict, acti
76
76
 
77
77
  Writable stage agents (`building`, `documenting`) prefer Morph MCP `edit_file` and can fallback to native `edit` (and `write` for new files) when needed. Read-only agents keep `edit` disabled.
78
78
 
79
+ Stage-agent code discovery is graph-first: planning/building/reviewing/documenting prefer codebase-memory MCP tools (`codebase-memory-mcp_search_graph`, `codebase-memory-mcp_get_architecture`, `codebase-memory-mcp_trace_call_path`, `codebase-memory-mcp_get_code_snippet`) before semantic warp_grep/warpgrep-style fallbacks.
80
+
81
+ ### Plugin auto-handoff safety net
82
+
83
+ The plugin now includes an auto-handoff hook that can continue deterministic next steps by reading explicit machine-readable fields from assistant output and dispatching `client.session.prompt(...)`.
84
+
85
+ - The orchestrator (`@feature-factory`) remains the source of truth for workflow progression.
86
+ - Auto-handoff is a continuation safety net, not a replacement for orchestrator logic.
87
+ - Multi-stage continuation should target `feature-factory`; one-stage follow-up can target a stage agent.
88
+ - Dispatch is performed through direct API prompt calls (not slash-command execution).
89
+
79
90
  ## Quick Commands
80
91
 
81
92
  The plugin installs global custom slash commands in `~/.config/opencode/commands/`:
@@ -83,14 +94,17 @@ The plugin installs global custom slash commands in `~/.config/opencode/commands
83
94
  - `/ff-review [optional prompt]`
84
95
  - Agent: `reviewing`
85
96
  - Subtask: `true` (always runs as a subtask)
97
+ - Mode: manual standalone helper (does not continue the full pipeline automatically)
86
98
  - Default prompt when no argument is provided: `Review the changes so far`
87
99
  - `/ff-document [optional prompt]`
88
100
  - Agent: `documenting`
89
101
  - Subtask: `true` (always runs as a subtask)
102
+ - Mode: manual standalone helper (does not continue the full pipeline automatically)
90
103
  - Default prompt when no argument is provided: `Document all the changes so far`
91
104
  - `/ff-rework [optional prompt]`
92
105
  - Agent: `building`
93
106
  - Subtask: `true` (always runs as a subtask)
107
+ - Mode: manual standalone helper (does not continue the full pipeline automatically)
94
108
  - Default prompt when no argument is provided: `apply the rework recommendations`
95
109
 
96
110
  Examples:
@@ -111,6 +125,8 @@ The plugin merges the following MCP servers into global OpenCode config when mis
111
125
  - `context7`
112
126
  - `morph-mcp`
113
127
 
128
+ `codebase-memory-mcp` is currently treated as an optional prerequisite (not auto-provisioned by this plugin) because it commonly requires repository-specific indexing/setup. Stage agents still include morph semantic fallback guidance when codebase-memory MCP is unavailable.
129
+
114
130
  `morph-mcp` is configured as:
115
131
 
116
132
  ```json
@@ -11,6 +11,11 @@ tools:
11
11
  bash: true
12
12
  skill: true
13
13
  task: true
14
+ 'codebase-memory-mcp_search_graph': true
15
+ 'codebase-memory-mcp_get_architecture': true
16
+ 'codebase-memory-mcp_trace_call_path': true
17
+ 'codebase-memory-mcp_get_code_snippet': true
18
+ 'codebase-memory-mcp_search_code': true
14
19
  'morph-mcp_codebase_search': true
15
20
  permission:
16
21
  skill:
@@ -43,29 +48,38 @@ You are the building specialist.
43
48
 
44
49
  ## Editing Workflow (Required)
45
50
 
46
- Prefer Morph MCP `edit_file` for all implementation edits.
51
+ Prefer the OpenCode `edit_file` tool (Fast Apply) for all implementation edits.
52
+
53
+ Fallback policy:
54
+
55
+ - **Codex models:** use `patch` or `apply_patch`.
56
+ - **Non-Codex models:** use `edit`.
57
+ - **New files (all models):** `write` or `patch` are acceptable.
47
58
 
48
59
  1. **Read before editing** to confirm current behavior and scope.
49
60
  2. **Apply changes with `edit_file`** for targeted replacements/insertions whenever available.
50
61
  3. **Re-read after edits** to verify the applied diff and avoid stale assumptions.
51
- 4. If `edit_file` is unavailable or cannot express the required change, fallback to `edit`.
52
- 5. Use `write` when creating brand-new files.
62
+ 4. If `edit_file` is unavailable or cannot express the required change, choose fallback by model family: Codex → `patch`/`apply_patch`; non-Codex → `edit`.
63
+ 5. For brand-new files, use `write` or `patch`.
53
64
 
54
65
  ## Semantic Code Search
55
66
 
56
- Use `morph-mcp_codebase_search` for semantic code search when you need to:
67
+ Use codebase-memory MCP tools first for semantic/structural code search when you need to:
57
68
 
58
- - Find implementations by meaning, not just text matching (e.g., "authentication logic", "database connection handling")
59
- - Locate related code without knowing exact names or keywords
60
- - Understand how features work across the codebase
69
+ - Find implementations by meaning with `codebase-memory-mcp_search_graph`
70
+ - Understand package/service boundaries via `codebase-memory-mcp_get_architecture`
71
+ - Trace caller/callee impact with `codebase-memory-mcp_trace_call_path`
72
+ - Read exact source around graph hits with `codebase-memory-mcp_get_code_snippet`
61
73
 
62
- Prefer this over `grep` when searching by concept rather than exact text.
74
+ Prefer this over warp_grep/warpgrep-style search because graph context reduces false positives and improves dependency-aware edits.
63
75
 
64
76
  Search fallback order:
65
77
 
66
- 1. `morph-mcp_codebase_search` for semantic discovery.
67
- 2. `read` to inspect exact implementation details before editing.
68
- 3. `grep` for exact symbol/literal checks when needed.
78
+ 1. `codebase-memory-mcp_search_graph` + `codebase-memory-mcp_get_architecture` for discovery.
79
+ 2. `codebase-memory-mcp_trace_call_path` / `codebase-memory-mcp_get_code_snippet` for impact and code verification.
80
+ 3. `morph-mcp_codebase_search` if codebase-memory MCP is unavailable or unindexed.
81
+ 4. `read` to inspect exact implementation details before editing.
82
+ 5. `grep` for exact symbol/literal checks when needed.
69
83
 
70
84
  ## GitHub Workflow Guidance
71
85
 
@@ -11,6 +11,11 @@ tools:
11
11
  bash: false
12
12
  skill: true
13
13
  task: true
14
+ 'codebase-memory-mcp_search_graph': true
15
+ 'codebase-memory-mcp_get_architecture': true
16
+ 'codebase-memory-mcp_trace_call_path': true
17
+ 'codebase-memory-mcp_get_code_snippet': true
18
+ 'codebase-memory-mcp_search_code': true
14
19
  'morph-mcp_codebase_search': true
15
20
  permission:
16
21
  skill:
@@ -47,25 +52,38 @@ Always load `ff-documentation-rules` before scoping or editing documentation. Tr
47
52
 
48
53
  ## Editing Workflow (Required)
49
54
 
50
- Prefer Morph MCP `edit_file` for documentation updates.
55
+ Prefer the OpenCode `edit_file` tool (Fast Apply) for documentation updates.
56
+
57
+ Fallback policy:
58
+
59
+ - **Codex models:** use `patch` or `apply_patch`.
60
+ - **Non-Codex models:** use `edit`.
61
+ - **New files (all models):** `write` or `patch` are acceptable.
51
62
 
52
63
  1. **Read the current navigation chain first** — inspect the root `README.md`, `docs/INDEX.md`, relevant nested `docs/**/INDEX.md` files, and affected leaf docs before editing.
53
64
  2. **Verify behavior from code** — use semantic search and targeted reads so the documentation matches what actually ships.
54
65
  3. **Update canonical docs and navigation together** — change the affected leaf docs, every impacted `INDEX.md`, and the root `README.md` when primary documentation entry points or doc structure change.
55
66
  4. **Apply changes with `edit_file`** for precise doc updates whenever available.
56
67
  5. **Re-read after edits** to validate wording, relative links, and cross-doc consistency.
57
- 6. If `edit_file` is unavailable or cannot express the required change, fallback to `edit`.
58
- 7. Use `write` when creating brand-new documentation files.
68
+ 6. If `edit_file` is unavailable or cannot express the required change, choose fallback by model family: Codex → `patch`/`apply_patch`; non-Codex → `edit`.
69
+ 7. For brand-new documentation files, use `write` or `patch`.
59
70
 
60
71
  ## Semantic Code Search
61
72
 
62
- Use `morph-mcp_codebase_search` to understand how code actually works before documenting it. Search by meaning (e.g., "how are users authenticated", "error handling middleware") rather than exact text.
73
+ Use codebase-memory MCP tools first to understand how code actually works before documenting it.
74
+
75
+ - `codebase-memory-mcp_search_graph` to locate relevant functions/classes/routes
76
+ - `codebase-memory-mcp_get_architecture` to capture subsystem context accurately
77
+ - `codebase-memory-mcp_trace_call_path` for workflow and dependency narratives
78
+ - `codebase-memory-mcp_get_code_snippet` to verify exact behavior before writing docs
63
79
 
64
80
  Search fallback order:
65
81
 
66
- 1. `morph-mcp_codebase_search` for semantic discovery.
67
- 2. `read` to verify exact behavior before writing docs.
68
- 3. `grep` for exact symbol/literal checks when needed.
82
+ 1. `codebase-memory-mcp_search_graph` + `codebase-memory-mcp_get_architecture` for graph-first discovery.
83
+ 2. `codebase-memory-mcp_trace_call_path` / `codebase-memory-mcp_get_code_snippet` for behavior confirmation.
84
+ 3. `morph-mcp_codebase_search` if codebase-memory MCP is unavailable or the repo is not indexed.
85
+ 4. `read` to verify exact behavior before writing docs.
86
+ 5. `grep` for exact symbol/literal checks when needed.
69
87
 
70
88
  ## GitHub Workflow Guidance
71
89
 
@@ -191,6 +191,13 @@ For each iteration `n`:
191
191
  7. If either gate is not `APPROVED`, route back to Build with consolidated action items from both review outputs.
192
192
  8. If 10 iterations are exhausted, stop and escalate to the user.
193
193
 
194
+ ### Autonomous continuation rule
195
+
196
+ - After the required user confirmation checkpoint is satisfied, do not pause between required stages.
197
+ - Do not ask the user what to do next while required workflow stages remain unfinished.
198
+ - Do not use optional phrasing like "If you want, I can..." for unfinished required workflow steps.
199
+ - If a stage reports partial progress (for example "waiting for tests"), treat it as non-terminal and issue a focused same-stage follow-up immediately.
200
+
194
201
  ### Direct-execution prohibition
195
202
 
196
203
  - Do not substitute manual/orchestrator-only answers for work that should be performed by stage agents.
@@ -208,3 +215,30 @@ When a workflow ends (success or escalation), return:
208
215
  4. `TEST_RESULTS` (if reported)
209
216
  5. `OPEN_ISSUES`
210
217
  6. `RECOMMENDED_NEXT_STEP`
218
+
219
+ `RECOMMENDED_NEXT_STEP` is reserved for true end-of-workflow recommendations only; do not use it to defer unfinished required stages.
220
+
221
+ ## Auto-handoff contract (plugin-facing)
222
+
223
+ When the next step is deterministic and does not require user input, append this exact block at the end of the response:
224
+
225
+ ```text
226
+ RECOMMENDED_NEXT_STEP=<ACTION> "<human-readable next step>"
227
+
228
+ AUTO_HANDOFF=YES|NO
229
+ AUTO_HANDOFF_TARGET=feature-factory|building|documenting|reviewing
230
+ AUTO_HANDOFF_REASON=CONTINUE_WORKFLOW|REWORK|DOCUMENT|REVIEW
231
+ AUTO_HANDOFF_PROMPT<<FF_PROMPT
232
+ <exact prompt text for next turn>
233
+ FF_PROMPT
234
+ ```
235
+
236
+ Rules:
237
+
238
+ - Use `AUTO_HANDOFF=YES` only when the next step is deterministic and should run automatically.
239
+ - Use `AUTO_HANDOFF_TARGET=feature-factory` when the workflow should continue across multiple stages.
240
+ - Use stage targets (`building`, `documenting`, `reviewing`) only for focused one-stage follow-up.
241
+ - Never use `AUTO_HANDOFF=YES` before the required user confirmation checkpoint.
242
+ - If complete, blocked, escalated, or waiting on the user, output `AUTO_HANDOFF=NO`.
243
+ - `RECOMMENDED_NEXT_STEP` must match the machine-readable handoff block semantically.
244
+ - For normal workflow progression, continue by delegating to stage agents directly (`@building`, `@documenting`, `@reviewing`), not by invoking slash commands such as `/ff-review`, `/ff-document`, or `/ff-rework`.
@@ -9,6 +9,11 @@ tools:
9
9
  bash: false
10
10
  skill: true
11
11
  task: false
12
+ 'codebase-memory-mcp_search_graph': true
13
+ 'codebase-memory-mcp_get_architecture': true
14
+ 'codebase-memory-mcp_trace_call_path': true
15
+ 'codebase-memory-mcp_get_code_snippet': true
16
+ 'codebase-memory-mcp_search_code': true
12
17
  'morph-mcp_codebase_search': true
13
18
  'morph-mcp_github_codebase_search': true
14
19
  permission:
@@ -53,13 +58,19 @@ You have access to powerful external research tools. **Use them proactively:**
53
58
 
54
59
  ### Semantic Code Search
55
60
 
56
- - **`morph-mcp_codebase_search`** — Search the local codebase by meaning. Use to understand the project's existing patterns before recommending changes.
61
+ - **`codebase-memory-mcp_search_graph`** — Graph-first local discovery for functions/classes/routes and their relationships.
62
+ - **`codebase-memory-mcp_get_architecture`** — High-level package/service map for architectural context.
63
+ - **`codebase-memory-mcp_trace_call_path`** — Call-chain tracing for impact analysis and behavior verification.
64
+ - **`codebase-memory-mcp_get_code_snippet`** — Read exact symbol source after graph discovery.
65
+ - **`morph-mcp_codebase_search`** — Semantic local fallback when graph indexing is unavailable.
57
66
 
58
67
  Search fallback order for code understanding:
59
68
 
60
- 1. `morph-mcp_codebase_search` for semantic discovery in local code.
61
- 2. `morph-mcp_github_codebase_search` for upstream/public GitHub internals when needed.
62
- 3. `gh_grep_searchGitHub` for exact code pattern matching across public repos.
69
+ 1. `codebase-memory-mcp_search_graph` + `codebase-memory-mcp_get_architecture` for local graph-first discovery.
70
+ 2. `codebase-memory-mcp_trace_call_path` / `codebase-memory-mcp_get_code_snippet` for local behavior verification.
71
+ 3. `morph-mcp_codebase_search` for local semantic fallback when graph search is unavailable.
72
+ 4. `morph-mcp_github_codebase_search` for upstream/public GitHub internals when needed.
73
+ 5. `gh_grep_searchGitHub` for exact code pattern matching across public repos.
63
74
 
64
75
  ## GitHub Workflow Guidance
65
76
 
@@ -10,6 +10,11 @@ tools:
10
10
  bash: false
11
11
  skill: true
12
12
  task: true
13
+ 'codebase-memory-mcp_search_graph': true
14
+ 'codebase-memory-mcp_get_architecture': true
15
+ 'codebase-memory-mcp_trace_call_path': true
16
+ 'codebase-memory-mcp_get_code_snippet': true
17
+ 'codebase-memory-mcp_search_code': true
13
18
  'morph-mcp_codebase_search': true
14
19
  permission:
15
20
  skill:
@@ -40,19 +45,22 @@ You are a read-only agent — you do not write or edit files.
40
45
 
41
46
  ## Semantic Code Search
42
47
 
43
- Use `morph-mcp_codebase_search` for semantic code search when planning:
48
+ Use codebase-memory MCP tools first when planning:
44
49
 
45
- - Understand existing architecture by meaning (e.g., "authentication logic", "API routing")
46
- - Find related implementations before proposing changes
47
- - Verify assumptions about how code works
50
+ - `codebase-memory-mcp_search_graph` to find candidate functions, classes, and routes
51
+ - `codebase-memory-mcp_get_architecture` for package/service-level orientation
52
+ - `codebase-memory-mcp_trace_call_path` for dependency and impact analysis
53
+ - `codebase-memory-mcp_get_code_snippet` to inspect exact implementation context
48
54
 
49
- Prefer this over `grep` when searching by concept rather than exact text.
55
+ This is preferred over warp_grep/warpgrep-style semantic discovery because graph-aware results surface structural context directly.
50
56
 
51
57
  Search fallback order:
52
58
 
53
- 1. `morph-mcp_codebase_search` for semantic discovery.
54
- 2. `read` to verify relevant source context.
55
- 3. `grep` for exact symbol/literal checks when needed.
59
+ 1. `codebase-memory-mcp_search_graph` + `codebase-memory-mcp_get_architecture` for graph-first discovery.
60
+ 2. `codebase-memory-mcp_trace_call_path` / `codebase-memory-mcp_get_code_snippet` for call-flow and source verification.
61
+ 3. `morph-mcp_codebase_search` if codebase-memory MCP is unavailable or the repository is not indexed yet.
62
+ 4. `read` to verify relevant source context.
63
+ 5. `grep` for exact symbol/literal checks when needed.
56
64
 
57
65
  ## GitHub Workflow Guidance
58
66
 
@@ -2,7 +2,7 @@
2
2
  description: Unified validation agent for code and documentation. Performs acceptance, quality, security, and architecture review with context-driven scope.
3
3
  mode: primary
4
4
  color: '#8b5cf6'
5
- model: opencode/claude-opus-4-6
5
+ model: opencode/glm-5.1
6
6
  tools:
7
7
  read: true
8
8
  write: false
@@ -10,6 +10,11 @@ tools:
10
10
  bash: false
11
11
  skill: true
12
12
  task: true
13
+ 'codebase-memory-mcp_search_graph': true
14
+ 'codebase-memory-mcp_get_architecture': true
15
+ 'codebase-memory-mcp_trace_call_path': true
16
+ 'codebase-memory-mcp_get_code_snippet': true
17
+ 'codebase-memory-mcp_search_code': true
13
18
  'morph-mcp_codebase_search': true
14
19
  permission:
15
20
  skill:
@@ -40,19 +45,22 @@ You are a read-only agent — you do not write or edit files.
40
45
 
41
46
  ## Semantic Code Search
42
47
 
43
- Use `morph-mcp_codebase_search` for semantic code search when reviewing:
48
+ Use codebase-memory MCP tools first when reviewing:
44
49
 
45
- - Search by meaning to find related code (e.g., "input validation", "access control checks")
46
- - Verify that implementations match architectural patterns across the codebase
47
- - Find similar code to check for consistency
50
+ - `codebase-memory-mcp_search_graph` to locate related implementations by structure + name pattern
51
+ - `codebase-memory-mcp_get_architecture` to validate subsystem boundaries and coupling
52
+ - `codebase-memory-mcp_trace_call_path` to verify security/validation coverage across call paths
53
+ - `codebase-memory-mcp_get_code_snippet` to inspect concrete evidence for findings
48
54
 
49
- Prefer this over `grep` when searching by concept rather than exact text.
55
+ Prefer this over warp_grep/warpgrep-style search so findings are anchored to graph-aware dependencies, not isolated text matches.
50
56
 
51
57
  Search fallback order:
52
58
 
53
- 1. `morph-mcp_codebase_search` for semantic discovery.
54
- 2. `read` to verify concrete evidence and line references.
55
- 3. `grep` for exact symbol/literal checks when needed.
59
+ 1. `codebase-memory-mcp_search_graph` + `codebase-memory-mcp_get_architecture` for discovery and context.
60
+ 2. `codebase-memory-mcp_trace_call_path` / `codebase-memory-mcp_get_code_snippet` for evidence collection.
61
+ 3. `morph-mcp_codebase_search` if codebase-memory MCP is unavailable or not indexed.
62
+ 4. `read` to verify concrete evidence and line references.
63
+ 5. `grep` for exact symbol/literal checks when needed.
56
64
 
57
65
  ## GitHub Workflow Guidance
58
66
 
@@ -96,6 +104,28 @@ When acting as gate reviewer, output status line exactly:
96
104
  - `REVIEW_GATE=APPROVED|REWORK|ESCALATE`
97
105
  - `DOCUMENTATION_GATE=APPROVED|REWORK|ESCALATE`
98
106
 
107
+ ## Auto-handoff output contract (for standalone review runs)
108
+
109
+ When a standalone review clearly requires rework and the next action is deterministic, append:
110
+
111
+ ```text
112
+ RECOMMENDED_NEXT_STEP=REWORK "<specific rework summary>"
113
+ AUTO_HANDOFF=YES
114
+ AUTO_HANDOFF_TARGET=building
115
+ AUTO_HANDOFF_REASON=REWORK
116
+ AUTO_HANDOFF_PROMPT<<FF_PROMPT
117
+ apply the rework recommendations
118
+
119
+ - <specific action item>
120
+ FF_PROMPT
121
+ ```
122
+
123
+ Otherwise emit:
124
+
125
+ ```text
126
+ AUTO_HANDOFF=NO
127
+ ```
128
+
99
129
  ## Operating Mode
100
130
 
101
131
  - Use result-based handoff (`$RESULT[...]`) rather than file-based artifacts.
@@ -0,0 +1,22 @@
1
+ import { type Plugin, type PluginInput } from '@opencode-ai/plugin';
2
+ type AutoHandoffTarget = 'feature-factory' | 'building' | 'documenting' | 'reviewing';
3
+ type AutoHandoffReason = 'CONTINUE_WORKFLOW' | 'REWORK' | 'DOCUMENT' | 'REVIEW';
4
+ export type ParsedAutoHandoff = {
5
+ enabled: false;
6
+ } | {
7
+ enabled: true;
8
+ target: AutoHandoffTarget;
9
+ reason: AutoHandoffReason;
10
+ prompt: string;
11
+ };
12
+ type Client = PluginInput['client'];
13
+ type SessionMetadata = {
14
+ parentID?: string;
15
+ };
16
+ export declare function parseAutoHandoff(text: string): ParsedAutoHandoff | null;
17
+ export declare function fingerprint(sessionId: string, messageId: string, handoff: Extract<ParsedAutoHandoff, {
18
+ enabled: true;
19
+ }>): string;
20
+ export declare function getSessionMetadata(client: Client, sessionId: string): Promise<SessionMetadata>;
21
+ export declare const AutoHandoffHooksPlugin: Plugin;
22
+ export {};
@@ -0,0 +1,195 @@
1
+ const SERVICE_NAME = 'feature-factory';
2
+ const MAX_AUTO_HANDOFFS_PER_SESSION = 5;
3
+ const AUTO_HANDOFF_FLAG_RE = /^AUTO_HANDOFF=(YES|NO)$/m;
4
+ const AUTO_HANDOFF_TARGET_RE = /^AUTO_HANDOFF_TARGET=(feature-factory|building|documenting|reviewing)$/m;
5
+ const AUTO_HANDOFF_REASON_RE = /^AUTO_HANDOFF_REASON=(CONTINUE_WORKFLOW|REWORK|DOCUMENT|REVIEW)$/m;
6
+ const AUTO_HANDOFF_PROMPT_RE = /AUTO_HANDOFF_PROMPT<<FF_PROMPT\r?\n([\s\S]*?)\r?\nFF_PROMPT/m;
7
+ async function log(client, level, message, extra) {
8
+ try {
9
+ await client.app.log({
10
+ body: {
11
+ service: SERVICE_NAME,
12
+ level,
13
+ message,
14
+ extra,
15
+ },
16
+ });
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ function extractMessageText(info) {
23
+ if (!info || typeof info !== 'object') {
24
+ return '';
25
+ }
26
+ const parts = info.parts;
27
+ if (!Array.isArray(parts)) {
28
+ return '';
29
+ }
30
+ return parts
31
+ .map((part) => {
32
+ if (!part || typeof part !== 'object') {
33
+ return '';
34
+ }
35
+ const typedPart = part;
36
+ return typedPart.type === 'text' && typeof typedPart.text === 'string' ? typedPart.text : '';
37
+ })
38
+ .join('');
39
+ }
40
+ export function parseAutoHandoff(text) {
41
+ const enabledMatch = text.match(AUTO_HANDOFF_FLAG_RE);
42
+ if (!enabledMatch) {
43
+ return null;
44
+ }
45
+ const enabled = enabledMatch[1];
46
+ if (enabled === 'NO') {
47
+ return { enabled: false };
48
+ }
49
+ const targetMatch = text.match(AUTO_HANDOFF_TARGET_RE);
50
+ const reasonMatch = text.match(AUTO_HANDOFF_REASON_RE);
51
+ const promptMatch = text.match(AUTO_HANDOFF_PROMPT_RE);
52
+ const target = targetMatch?.[1];
53
+ const reason = reasonMatch?.[1];
54
+ const prompt = promptMatch?.[1]?.trim();
55
+ if (!target || !reason || !prompt) {
56
+ return null;
57
+ }
58
+ return {
59
+ enabled: true,
60
+ target: target,
61
+ reason: reason,
62
+ prompt,
63
+ };
64
+ }
65
+ export function fingerprint(sessionId, messageId, handoff) {
66
+ return [sessionId, messageId, handoff.target, handoff.reason, handoff.prompt].join('::');
67
+ }
68
+ export async function getSessionMetadata(client, sessionId) {
69
+ try {
70
+ const response = await client.session.get({ path: { id: sessionId } });
71
+ return {
72
+ parentID: response.data?.parentID,
73
+ };
74
+ }
75
+ catch {
76
+ await log(client, 'warn', 'auto-handoff.session-metadata-fetch-failed', { sessionId });
77
+ return {};
78
+ }
79
+ }
80
+ export const AutoHandoffHooksPlugin = async ({ client }) => {
81
+ const buffers = new Map();
82
+ const sessionState = new Map();
83
+ return {
84
+ event: async ({ event }) => {
85
+ const properties = event
86
+ .properties;
87
+ const sessionId = properties?.sessionID ?? properties?.sessionId;
88
+ if (!sessionId) {
89
+ return;
90
+ }
91
+ if (event.type === 'session.deleted') {
92
+ buffers.delete(sessionId);
93
+ sessionState.delete(sessionId);
94
+ return;
95
+ }
96
+ if (event.type === 'message.updated') {
97
+ const info = event
98
+ .properties?.info;
99
+ if (!info || info.role !== 'assistant' || !info.id) {
100
+ return;
101
+ }
102
+ buffers.set(sessionId, {
103
+ messageId: info.id,
104
+ text: extractMessageText(info),
105
+ });
106
+ return;
107
+ }
108
+ if (event.type === 'message.part.updated') {
109
+ const state = buffers.get(sessionId);
110
+ if (!state) {
111
+ return;
112
+ }
113
+ const props = event.properties;
114
+ const part = props?.part;
115
+ if (part?.type !== 'text') {
116
+ return;
117
+ }
118
+ if (typeof props?.delta === 'string') {
119
+ state.text += props.delta;
120
+ }
121
+ else if (typeof part.text === 'string') {
122
+ state.text = part.text;
123
+ }
124
+ buffers.set(sessionId, state);
125
+ return;
126
+ }
127
+ if (event.type !== 'session.idle') {
128
+ return;
129
+ }
130
+ const buffer = buffers.get(sessionId);
131
+ if (!buffer?.text) {
132
+ return;
133
+ }
134
+ const parsed = parseAutoHandoff(buffer.text);
135
+ if (!parsed || !parsed.enabled) {
136
+ return;
137
+ }
138
+ const meta = await getSessionMetadata(client, sessionId);
139
+ if (meta.parentID) {
140
+ await log(client, 'debug', 'auto-handoff.skipped-sub-agent-session', {
141
+ sessionId,
142
+ parentID: meta.parentID,
143
+ });
144
+ return;
145
+ }
146
+ const state = sessionState.get(sessionId) ?? {
147
+ count: 0,
148
+ fingerprints: new Set(),
149
+ };
150
+ if (state.count >= MAX_AUTO_HANDOFFS_PER_SESSION) {
151
+ await log(client, 'warn', 'auto-handoff.skipped-cap-reached', {
152
+ sessionId,
153
+ max: MAX_AUTO_HANDOFFS_PER_SESSION,
154
+ });
155
+ sessionState.set(sessionId, state);
156
+ return;
157
+ }
158
+ const key = fingerprint(sessionId, buffer.messageId, parsed);
159
+ if (state.fingerprints.has(key)) {
160
+ await log(client, 'debug', 'auto-handoff.skipped-duplicate', { sessionId });
161
+ return;
162
+ }
163
+ state.fingerprints.add(key);
164
+ state.count += 1;
165
+ sessionState.set(sessionId, state);
166
+ await log(client, 'info', 'auto-handoff.dispatching', {
167
+ sessionId,
168
+ target: parsed.target,
169
+ reason: parsed.reason,
170
+ });
171
+ try {
172
+ await client.session.prompt({
173
+ path: { id: sessionId },
174
+ body: {
175
+ agent: parsed.target,
176
+ parts: [
177
+ {
178
+ type: 'text',
179
+ text: parsed.prompt,
180
+ },
181
+ ],
182
+ },
183
+ });
184
+ }
185
+ catch (error) {
186
+ await log(client, 'error', 'auto-handoff.dispatch-failed', {
187
+ sessionId,
188
+ target: parsed.target,
189
+ reason: parsed.reason,
190
+ error: String(error),
191
+ });
192
+ }
193
+ },
194
+ };
195
+ };
package/dist/index.js CHANGED
@@ -1,8 +1,20 @@
1
1
  import { StopQualityGateHooksPlugin } from './stop-quality-gate.js';
2
+ import { AutoHandoffHooksPlugin } from './auto-handoff.js';
2
3
  import { updateMCPConfig } from './mcp-config.js';
3
4
  import { updateAgentConfig } from './agent-config.js';
4
5
  import { updatePluginConfig } from './plugin-config.js';
5
6
  import { $ } from 'bun';
7
+ function composeAsyncHandlers(...handlers) {
8
+ const activeHandlers = handlers.filter((handler) => Boolean(handler));
9
+ if (activeHandlers.length === 0) {
10
+ return undefined;
11
+ }
12
+ return (async (...args) => {
13
+ for (const handler of activeHandlers) {
14
+ await handler(...args);
15
+ }
16
+ });
17
+ }
6
18
  /**
7
19
  * Feature Factory Plugin
8
20
  *
@@ -42,10 +54,13 @@ export const FeatureFactoryPlugin = async (input) => {
42
54
  }
43
55
  // Load hooks from the quality gate plugin
44
56
  const qualityGateHooks = await StopQualityGateHooksPlugin(input).catch(() => ({}));
57
+ const autoHandoffHooks = await AutoHandoffHooksPlugin(input).catch(() => ({}));
45
58
  // Feature Factory orchestration now runs via native sub-agent handoff in
46
59
  // the feature-factory agent prompt (LLM-driven workflow). ff_* workflow MCP
47
60
  // tools are no longer registered from this plugin.
48
61
  return {
49
- ...qualityGateHooks,
62
+ event: composeAsyncHandlers(qualityGateHooks.event, autoHandoffHooks.event),
63
+ 'tool.execute.before': composeAsyncHandlers(qualityGateHooks['tool.execute.before'], autoHandoffHooks['tool.execute.before']),
64
+ 'tool.execute.after': composeAsyncHandlers(qualityGateHooks['tool.execute.after'], autoHandoffHooks['tool.execute.after']),
50
65
  };
51
66
  };
@@ -2,6 +2,10 @@ type BunShell = any;
2
2
  /**
3
3
  * Default MCP server configuration to be added by the plugin
4
4
  * These servers will be merged into the global OpenCode config.
5
+ *
6
+ * Note: codebase-memory-mcp is intentionally not auto-provisioned here.
7
+ * It is treated as an optional prerequisite because it commonly needs
8
+ * repository-specific indexing/setup before graph queries are useful.
5
9
  */
6
10
  export declare const DEFAULT_MCP_SERVERS: {
7
11
  readonly 'jina-ai': {
@@ -2,6 +2,10 @@ import { isRecord, updateGlobalOpenCodeConfigBlock } from './opencode-global-con
2
2
  /**
3
3
  * Default MCP server configuration to be added by the plugin
4
4
  * These servers will be merged into the global OpenCode config.
5
+ *
6
+ * Note: codebase-memory-mcp is intentionally not auto-provisioned here.
7
+ * It is treated as an optional prerequisite because it commonly needs
8
+ * repository-specific indexing/setup before graph queries are useful.
5
9
  */
6
10
  export const DEFAULT_MCP_SERVERS = {
7
11
  'jina-ai': {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@syntesseraai/opencode-feature-factory",
4
- "version": "0.10.13",
4
+ "version": "0.10.15",
5
5
  "type": "module",
6
6
  "description": "OpenCode plugin for Feature Factory agents - provides sub-agents and skills for validation, review, security, and architecture assessment",
7
7
  "license": "MIT",
@@ -34,9 +34,7 @@
34
34
  ],
35
35
  "scripts": {},
36
36
  "dependencies": {
37
- "@modelcontextprotocol/sdk": "^1.0.0",
38
- "@opencode-ai/plugin": "^1.1.48",
39
- "glob": "^10.0.0"
37
+ "@opencode-ai/plugin": "^1.1.48"
40
38
  },
41
39
  "devDependencies": {
42
40
  "@types/bun": "^1.2.6",