@codemcp/workflows 6.3.1 → 6.5.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/package.json +2 -2
- package/packages/cli/dist/{chunk-D2Q6Y3QQ.js → chunk-4AZGS2GG.js} +321 -388
- package/packages/cli/dist/{cli-QV7U6L54.js → cli-ZCCFBQTP.js} +12 -17
- package/packages/cli/dist/{dist-W7PPKVFG.js → dist-I6VSREAJ.js} +11 -5
- package/packages/cli/dist/{dist-W7VMGB3G.js → dist-MW7THWM3.js} +875 -1136
- package/packages/cli/dist/index.js +2 -2
- package/packages/cli/package.json +1 -1
- package/packages/cli/resources/workflows/bugfix.yaml +14 -0
- package/packages/cli/resources/workflows/epcc.yaml +12 -0
- package/packages/cli/resources/workflows/greenfield.yaml +16 -0
- package/packages/cli/resources/workflows/minor.yaml +8 -0
- package/packages/cli/resources/workflows/skilled-bugfix.yaml +6 -6
- package/packages/cli/resources/workflows/skilled-epcc.yaml +8 -8
- package/packages/cli/resources/workflows/skilled-greenfield.yaml +8 -7
- package/packages/cli/resources/workflows/tdd.yaml +10 -0
- package/packages/cli/resources/workflows/waterfall.yaml +16 -0
- package/packages/core/dist/beads-integration.d.ts +3 -5
- package/packages/core/dist/beads-integration.js +29 -35
- package/packages/core/dist/beads-integration.js.map +1 -1
- package/packages/core/dist/beads-state-manager.d.ts +3 -1
- package/packages/core/dist/beads-state-manager.js +17 -15
- package/packages/core/dist/beads-state-manager.js.map +1 -1
- package/packages/core/dist/file-detection-manager.js +15 -22
- package/packages/core/dist/file-detection-manager.js.map +1 -1
- package/packages/core/dist/index.d.ts +1 -0
- package/packages/core/dist/index.js +1 -0
- package/packages/core/dist/index.js.map +1 -1
- package/packages/core/dist/instruction-generator.d.ts +3 -7
- package/packages/core/dist/instruction-generator.js +17 -25
- package/packages/core/dist/instruction-generator.js.map +1 -1
- package/packages/core/dist/interfaces/instruction-generator.interface.d.ts +13 -4
- package/packages/core/dist/interfaces/plan-manager.interface.d.ts +9 -0
- package/packages/core/dist/logger.d.ts +49 -20
- package/packages/core/dist/logger.js +65 -141
- package/packages/core/dist/logger.js.map +1 -1
- package/packages/core/dist/plan-manager.d.ts +6 -4
- package/packages/core/dist/plan-manager.js +19 -15
- package/packages/core/dist/plan-manager.js.map +1 -1
- package/packages/core/dist/project-docs-manager.d.ts +3 -1
- package/packages/core/dist/project-docs-manager.js +11 -9
- package/packages/core/dist/project-docs-manager.js.map +1 -1
- package/packages/core/dist/state-machine-loader.d.ts +16 -0
- package/packages/core/dist/state-machine-loader.js +29 -0
- package/packages/core/dist/state-machine-loader.js.map +1 -1
- package/packages/core/dist/state-machine-types.d.ts +8 -0
- package/packages/core/dist/string-utils.d.ts +8 -0
- package/packages/core/dist/string-utils.js +14 -0
- package/packages/core/dist/string-utils.js.map +1 -0
- package/packages/core/dist/task-backend.d.ts +6 -3
- package/packages/core/dist/task-backend.js +10 -8
- package/packages/core/dist/task-backend.js.map +1 -1
- package/packages/core/dist/transition-engine.d.ts +3 -6
- package/packages/core/dist/transition-engine.js +31 -76
- package/packages/core/dist/transition-engine.js.map +1 -1
- package/packages/core/dist/workflow-manager.d.ts +2 -0
- package/packages/core/dist/workflow-manager.js +14 -2
- package/packages/core/dist/workflow-manager.js.map +1 -1
- package/packages/core/package.json +1 -1
- package/packages/core/resources/workflows/bugfix.yaml +14 -0
- package/packages/core/resources/workflows/epcc.yaml +12 -0
- package/packages/core/resources/workflows/greenfield.yaml +16 -0
- package/packages/core/resources/workflows/minor.yaml +8 -0
- package/packages/core/resources/workflows/skilled-bugfix.yaml +6 -6
- package/packages/core/resources/workflows/skilled-epcc.yaml +8 -8
- package/packages/core/resources/workflows/skilled-greenfield.yaml +8 -7
- package/packages/core/resources/workflows/tdd.yaml +10 -0
- package/packages/core/resources/workflows/waterfall.yaml +16 -0
- package/packages/docs/.vitepress/dist/404.html +1 -1
- package/packages/docs/.vitepress/dist/assets/{user_advanced-engineering.md.MkETYNtq.js → user_advanced-engineering.md.PD-xOFno.js} +2 -2
- package/packages/docs/.vitepress/dist/assets/{user_agent-setup.md.l0oJQxTR.js → user_agent-setup.md.BhcuRdG8.js} +1 -1
- package/packages/docs/.vitepress/dist/dev/ARCHITECTURE.html +1 -1
- package/packages/docs/.vitepress/dist/dev/DEVELOPMENT.html +1 -1
- package/packages/docs/.vitepress/dist/dev/LOGGING.html +1 -1
- package/packages/docs/.vitepress/dist/dev/PUBLISHING.html +1 -1
- package/packages/docs/.vitepress/dist/hashmap.json +1 -1
- package/packages/docs/.vitepress/dist/index.html +1 -1
- package/packages/docs/.vitepress/dist/user/advanced-engineering.html +4 -4
- package/packages/docs/.vitepress/dist/user/agent-setup.html +3 -3
- package/packages/docs/.vitepress/dist/user/beads-integration.html +1 -1
- package/packages/docs/.vitepress/dist/user/crowd-mcp-integration.html +1 -1
- package/packages/docs/.vitepress/dist/user/custom-workflows.html +1 -1
- package/packages/docs/.vitepress/dist/user/git-commit-feature.html +1 -1
- package/packages/docs/.vitepress/dist/user/how-it-works.html +1 -1
- package/packages/docs/.vitepress/dist/user/long-term-memory.html +1 -1
- package/packages/docs/.vitepress/dist/user/packaged-workflows.html +1 -1
- package/packages/docs/.vitepress/dist/user/tutorial.html +1 -1
- package/packages/docs/.vitepress/dist/user/workflow-selection.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/adr.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/big-bang-conversion.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/boundary-testing.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/bugfix.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/bugfix.yaml +14 -0
- package/packages/docs/.vitepress/dist/workflows/business-analysis.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/c4-analysis.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/epcc.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/epcc.yaml +12 -0
- package/packages/docs/.vitepress/dist/workflows/game-beginner.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/greenfield.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/greenfield.yaml +16 -0
- package/packages/docs/.vitepress/dist/workflows/minor.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/minor.yaml +8 -0
- package/packages/docs/.vitepress/dist/workflows/posts.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/sdd-bugfix-crowd.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/sdd-bugfix.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/sdd-feature-crowd.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/sdd-feature.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/sdd-greenfield-crowd.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/sdd-greenfield.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/skilled-bugfix.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/skilled-bugfix.yaml +6 -6
- package/packages/docs/.vitepress/dist/workflows/skilled-epcc.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/skilled-epcc.yaml +8 -8
- package/packages/docs/.vitepress/dist/workflows/skilled-greenfield.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/skilled-greenfield.yaml +8 -7
- package/packages/docs/.vitepress/dist/workflows/slides.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/tdd.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/tdd.yaml +10 -0
- package/packages/docs/.vitepress/dist/workflows/waterfall.html +1 -1
- package/packages/docs/.vitepress/dist/workflows/waterfall.yaml +16 -0
- package/packages/docs/.vitepress/dist/workflows.html +1 -1
- package/packages/docs/package.json +1 -1
- package/packages/mcp-server/dist/index.d.ts +1027 -0
- package/packages/mcp-server/dist/index.js +879 -1140
- package/packages/mcp-server/package.json +1 -1
- package/packages/mcp-server/resources/workflows/bugfix.yaml +14 -0
- package/packages/mcp-server/resources/workflows/epcc.yaml +12 -0
- package/packages/mcp-server/resources/workflows/greenfield.yaml +16 -0
- package/packages/mcp-server/resources/workflows/minor.yaml +8 -0
- package/packages/mcp-server/resources/workflows/skilled-bugfix.yaml +6 -6
- package/packages/mcp-server/resources/workflows/skilled-epcc.yaml +8 -8
- package/packages/mcp-server/resources/workflows/skilled-greenfield.yaml +8 -7
- package/packages/mcp-server/resources/workflows/tdd.yaml +10 -0
- package/packages/mcp-server/resources/workflows/waterfall.yaml +16 -0
- package/packages/opencode-plugin/dist/index.d.ts +9 -0
- package/packages/opencode-plugin/dist/index.js +11 -0
- package/packages/opencode-plugin/dist/index.js.map +1 -0
- package/packages/opencode-plugin/dist/opencode-logger.d.ts +21 -0
- package/packages/opencode-plugin/dist/opencode-logger.js +104 -0
- package/packages/opencode-plugin/dist/opencode-logger.js.map +1 -0
- package/packages/opencode-plugin/dist/plugin.d.ts +23 -0
- package/packages/opencode-plugin/dist/plugin.js +395 -0
- package/packages/opencode-plugin/dist/plugin.js.map +1 -0
- package/packages/opencode-plugin/dist/server-context.d.ts +40 -0
- package/packages/opencode-plugin/dist/server-context.js +96 -0
- package/packages/opencode-plugin/dist/server-context.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/conduct-review.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/conduct-review.js +37 -0
- package/packages/opencode-plugin/dist/tool-handlers/conduct-review.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/proceed-to-phase.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/proceed-to-phase.js +74 -0
- package/packages/opencode-plugin/dist/tool-handlers/proceed-to-phase.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/reset-development.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/reset-development.js +63 -0
- package/packages/opencode-plugin/dist/tool-handlers/reset-development.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/setup-project-docs.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/setup-project-docs.js +74 -0
- package/packages/opencode-plugin/dist/tool-handlers/setup-project-docs.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/start-development.d.ts +3 -0
- package/packages/opencode-plugin/dist/tool-handlers/start-development.js +69 -0
- package/packages/opencode-plugin/dist/tool-handlers/start-development.js.map +1 -0
- package/packages/opencode-plugin/dist/tool-handlers/tool-helper.d.ts +10 -0
- package/packages/opencode-plugin/dist/tool-handlers/tool-helper.js +7 -0
- package/packages/opencode-plugin/dist/tool-handlers/tool-helper.js.map +1 -0
- package/packages/opencode-plugin/dist/types.d.ts +193 -0
- package/packages/opencode-plugin/dist/types.js +8 -0
- package/packages/opencode-plugin/dist/types.js.map +1 -0
- package/packages/opencode-plugin/dist/utils.d.ts +14 -0
- package/packages/opencode-plugin/dist/utils.js +26 -0
- package/packages/opencode-plugin/dist/utils.js.map +1 -0
- package/packages/opencode-plugin/package.json +52 -0
- package/packages/opencode-tui-plugin/package.json +46 -0
- package/packages/visualizer/package.json +1 -1
- package/resources/workflows/bugfix.yaml +14 -0
- package/resources/workflows/epcc.yaml +12 -0
- package/resources/workflows/greenfield.yaml +16 -0
- package/resources/workflows/minor.yaml +8 -0
- package/resources/workflows/skilled-bugfix.yaml +6 -6
- package/resources/workflows/skilled-epcc.yaml +8 -8
- package/resources/workflows/skilled-greenfield.yaml +8 -7
- package/resources/workflows/tdd.yaml +10 -0
- package/resources/workflows/waterfall.yaml +16 -0
- /package/packages/docs/.vitepress/dist/assets/{user_advanced-engineering.md.MkETYNtq.lean.js → user_advanced-engineering.md.PD-xOFno.lean.js} +0 -0
- /package/packages/docs/.vitepress/dist/assets/{user_agent-setup.md.l0oJQxTR.lean.js → user_agent-setup.md.BhcuRdG8.lean.js} +0 -0
- /package/resources/skills/application-design/{application-design.md → SKILL.md} +0 -0
- /package/resources/skills/architecture/{SKILL.md.md → SKILL.md} +0 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenCode Workflows Plugin
|
|
3
|
+
*
|
|
4
|
+
* Integrates workflows-core state management with OpenCode hooks to provide
|
|
5
|
+
* phase-aware development guidance and file edit restrictions.
|
|
6
|
+
*
|
|
7
|
+
* Hooks implemented:
|
|
8
|
+
* 1. chat.message - Add synthetic part with phase instructions after each user message
|
|
9
|
+
* 2. tool.execute.before - Block editing of certain files based on phase
|
|
10
|
+
* 3. experimental.session.compacting - Inject workflow state into compaction context
|
|
11
|
+
*
|
|
12
|
+
* Logs are sent via OpenCode SDK's client.app.log() API
|
|
13
|
+
*/
|
|
14
|
+
import { createProceedToPhaseTool } from './tool-handlers/proceed-to-phase.js';
|
|
15
|
+
import { createConductReviewTool } from './tool-handlers/conduct-review.js';
|
|
16
|
+
import { createResetDevelopmentTool } from './tool-handlers/reset-development.js';
|
|
17
|
+
import { createStartDevelopmentTool } from './tool-handlers/start-development.js';
|
|
18
|
+
import { createSetupProjectDocsTool } from './tool-handlers/setup-project-docs.js';
|
|
19
|
+
import { createOpenCodeLogger, createOpenCodeLoggerFactory, } from './opencode-logger.js';
|
|
20
|
+
import { PlanManager, InstructionGenerator } from '@codemcp/workflows-core';
|
|
21
|
+
import { WhatsNextHandler, } from '@codemcp/workflows-server';
|
|
22
|
+
import { createServerContext, initializeServerContext, } from './server-context.js';
|
|
23
|
+
import { stripWhatsNextReferences } from './utils.js';
|
|
24
|
+
/**
|
|
25
|
+
* Match a file path against a glob pattern.
|
|
26
|
+
* Supports patterns like:
|
|
27
|
+
* - `**\/*` → matches everything
|
|
28
|
+
* - `**\/*.md` → matches any .md file in any directory
|
|
29
|
+
* - `**\/*.test.ts` → matches test files
|
|
30
|
+
*/
|
|
31
|
+
function matchGlobPattern(filePath, pattern) {
|
|
32
|
+
// Normalise to forward slashes
|
|
33
|
+
const normalised = filePath.replace(/\\/g, '/');
|
|
34
|
+
const baseName = normalised.split('/').pop() ?? '';
|
|
35
|
+
// `**/*` means "allow everything"
|
|
36
|
+
if (pattern === '**/*' || pattern === '*') {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
// Convert glob pattern to a regex:
|
|
40
|
+
// - Escape regex metacharacters except * and .
|
|
41
|
+
// - `**/` at the start → match any path prefix (or empty)
|
|
42
|
+
// - `**` elsewhere → match any sequence of characters incl. /
|
|
43
|
+
// - `*` → match any sequence of characters excl. /
|
|
44
|
+
// - `.` → literal dot
|
|
45
|
+
const regexSource = pattern
|
|
46
|
+
.replace(/\\/g, '/')
|
|
47
|
+
// Escape regex special chars (except * which we handle separately)
|
|
48
|
+
.replace(/[+?^${}()|[\]]/g, '\\$&')
|
|
49
|
+
// Literal dot
|
|
50
|
+
.replace(/\./g, '\\.')
|
|
51
|
+
// `**/` at the start → optional path prefix
|
|
52
|
+
.replace(/^\*\*\//, '(?:.+\\/)?')
|
|
53
|
+
// remaining `**` → any chars including /
|
|
54
|
+
.replace(/\*\*/g, '.*')
|
|
55
|
+
// remaining `*` → any chars except /
|
|
56
|
+
.replace(/\*/g, '[^/]*');
|
|
57
|
+
const regex = new RegExp(`^${regexSource}$`);
|
|
58
|
+
// Try matching against full normalised path and against basename
|
|
59
|
+
return regex.test(normalised) || regex.test(baseName);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if a file edit is allowed based on glob patterns
|
|
63
|
+
*/
|
|
64
|
+
function isFileAllowed(filePath, patterns) {
|
|
65
|
+
// If allowed patterns includes '**/*' or '*', all files are allowed
|
|
66
|
+
if (patterns.includes('**/*') || patterns.includes('*')) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
// Check if the file path matches any allowed glob pattern
|
|
70
|
+
return patterns.some(pattern => matchGlobPattern(filePath, pattern));
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Main plugin export
|
|
74
|
+
*/
|
|
75
|
+
export const WorkflowsPlugin = async (input) => {
|
|
76
|
+
// Initialize logger using OpenCode SDK
|
|
77
|
+
const logger = createOpenCodeLogger(input.client);
|
|
78
|
+
const loggerFactory = createOpenCodeLoggerFactory(input.client);
|
|
79
|
+
logger.info('Plugin initializing', {
|
|
80
|
+
directory: input.directory,
|
|
81
|
+
worktree: input.worktree,
|
|
82
|
+
});
|
|
83
|
+
// Initialize workflows enabled state from environment variable
|
|
84
|
+
const envWorkflows = process.env.WORKFLOWS?.toLowerCase();
|
|
85
|
+
let workflowsEnabled = envWorkflows === 'off' ? false : true; // default: enabled
|
|
86
|
+
logger.info('Workflows state initialized', { workflowsEnabled });
|
|
87
|
+
// Initialize instruction generator
|
|
88
|
+
const planManager = new PlanManager();
|
|
89
|
+
const instructionGenerator = new InstructionGenerator();
|
|
90
|
+
// Cached ServerContext - created once, reused for all requests
|
|
91
|
+
// This avoids creating new WorkflowManager/PluginRegistry instances per request
|
|
92
|
+
let cachedServerContext = null;
|
|
93
|
+
let serverContextInitialized = false;
|
|
94
|
+
// Buffered instructions from tools (proceed_to_phase, start_development).
|
|
95
|
+
// Consumed and cleared by the next chat.message hook call.
|
|
96
|
+
let bufferedInstructions = null;
|
|
97
|
+
/**
|
|
98
|
+
* Set buffered instructions from a tool result.
|
|
99
|
+
* The next chat.message hook will use these instead of calling WhatsNextHandler.
|
|
100
|
+
*/
|
|
101
|
+
function setBufferedInstructions(result) {
|
|
102
|
+
bufferedInstructions = {
|
|
103
|
+
phase: result.phase,
|
|
104
|
+
instructions: result.instructions,
|
|
105
|
+
planFilePath: result.plan_file_path,
|
|
106
|
+
allowedFilePatterns: result.allowed_file_patterns,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
// Helper to get an initialized ServerContext for handler delegation
|
|
110
|
+
// Creates once, reuses for all subsequent calls
|
|
111
|
+
async function getServerContext() {
|
|
112
|
+
if (!cachedServerContext) {
|
|
113
|
+
cachedServerContext = createServerContext({
|
|
114
|
+
projectDir: input.directory,
|
|
115
|
+
planManager,
|
|
116
|
+
instructionGenerator,
|
|
117
|
+
loggerFactory,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (!serverContextInitialized) {
|
|
121
|
+
await initializeServerContext(cachedServerContext);
|
|
122
|
+
serverContextInitialized = true;
|
|
123
|
+
}
|
|
124
|
+
return cachedServerContext;
|
|
125
|
+
}
|
|
126
|
+
// Log registered plugins at startup (once)
|
|
127
|
+
getServerContext()
|
|
128
|
+
.then(context => {
|
|
129
|
+
const pluginNames = context.pluginRegistry?.getPluginNames() ?? [];
|
|
130
|
+
if (pluginNames.length > 0) {
|
|
131
|
+
logger.info('Registered plugins', { plugins: pluginNames });
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
logger.debug('No plugins registered');
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
.catch(() => {
|
|
138
|
+
// Ignore errors during startup plugin check
|
|
139
|
+
});
|
|
140
|
+
/**
|
|
141
|
+
* Read current workflow state from ConversationManager via shared ServerContext.
|
|
142
|
+
* Returns null if no active conversation exists.
|
|
143
|
+
*/
|
|
144
|
+
async function getWorkflowState() {
|
|
145
|
+
try {
|
|
146
|
+
const serverContext = await getServerContext();
|
|
147
|
+
const context = await serverContext.conversationManager.getConversationContext();
|
|
148
|
+
const stateMachine = serverContext.workflowManager.loadWorkflowForProject(context.projectPath, context.workflowName);
|
|
149
|
+
const phaseState = stateMachine.states[context.currentPhase];
|
|
150
|
+
return {
|
|
151
|
+
phase: context.currentPhase,
|
|
152
|
+
phaseDescription: phaseState?.description ?? null,
|
|
153
|
+
allowedFilePatterns: phaseState?.allowed_file_patterns ?? ['**/*'],
|
|
154
|
+
workflowName: context.workflowName,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
catch (_error) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
/**
|
|
163
|
+
* Hook 1: chat.message
|
|
164
|
+
* Fires after user message is created but before LLM processes it.
|
|
165
|
+
* We add a synthetic part with phase instructions.
|
|
166
|
+
*/
|
|
167
|
+
'chat.message': async (hookInput, output) => {
|
|
168
|
+
// Skip if workflows are disabled
|
|
169
|
+
if (!workflowsEnabled) {
|
|
170
|
+
logger.debug('chat.message: Workflows disabled, skipping hook');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
let result = null;
|
|
174
|
+
// If a tool (proceed_to_phase / start_development) buffered instructions,
|
|
175
|
+
// use those — they are authoritative and avoid potential staleness from
|
|
176
|
+
// re-querying WhatsNextHandler.
|
|
177
|
+
if (bufferedInstructions) {
|
|
178
|
+
logger.debug('chat.message: Using buffered instructions from tool call', { phase: bufferedInstructions.phase });
|
|
179
|
+
result = {
|
|
180
|
+
phase: bufferedInstructions.phase,
|
|
181
|
+
instructions: bufferedInstructions.instructions,
|
|
182
|
+
plan_file_path: bufferedInstructions.planFilePath,
|
|
183
|
+
allowed_file_patterns: bufferedInstructions.allowedFilePatterns,
|
|
184
|
+
};
|
|
185
|
+
// Consume the buffer — next call will fall through to WhatsNextHandler
|
|
186
|
+
bufferedInstructions = null;
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
// No buffered instructions — query WhatsNextHandler (reads from disk)
|
|
190
|
+
try {
|
|
191
|
+
const serverContext = await getServerContext();
|
|
192
|
+
const handler = new WhatsNextHandler();
|
|
193
|
+
const handlerResult = await handler.handle({}, serverContext);
|
|
194
|
+
if (!handlerResult.success || !handlerResult.data) {
|
|
195
|
+
logger.info('chat.message: No active workflow, injecting start prompt');
|
|
196
|
+
output.parts.push({
|
|
197
|
+
id: `prt_workflows_${Date.now()}`,
|
|
198
|
+
sessionID: hookInput.sessionID,
|
|
199
|
+
messageID: hookInput.messageID || output.message.id,
|
|
200
|
+
type: 'text',
|
|
201
|
+
text: `No Active Workflow Use the \`start_development\` tool to begin.`,
|
|
202
|
+
});
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
result = handlerResult.data;
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
209
|
+
if (errorMessage.includes('CONVERSATION_NOT_FOUND')) {
|
|
210
|
+
logger.info('chat.message: No active workflow, injecting start prompt');
|
|
211
|
+
output.parts.push({
|
|
212
|
+
id: `prt_workflows_${Date.now()}`,
|
|
213
|
+
sessionID: hookInput.sessionID,
|
|
214
|
+
messageID: hookInput.messageID || output.message.id,
|
|
215
|
+
type: 'text',
|
|
216
|
+
text: `No Active Workflow Use the \`start_development\` tool to begin.`,
|
|
217
|
+
});
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
logger.error('chat.message: Error delegating to WhatsNextHandler', {
|
|
221
|
+
error: errorMessage,
|
|
222
|
+
});
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
logger.info('chat.message hook fired', {
|
|
227
|
+
sessionID: hookInput.sessionID,
|
|
228
|
+
phase: result.phase,
|
|
229
|
+
});
|
|
230
|
+
// Strip whats_next() references — plugin auto-injects instructions
|
|
231
|
+
const instructionText = stripWhatsNextReferences(result.instructions);
|
|
232
|
+
if (!instructionText.trim()) {
|
|
233
|
+
logger.info('chat.message: No instructions to inject');
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
output.parts.push({
|
|
237
|
+
id: `prt_workflows_${Date.now()}`,
|
|
238
|
+
sessionID: hookInput.sessionID,
|
|
239
|
+
messageID: hookInput.messageID || output.message.id,
|
|
240
|
+
type: 'text',
|
|
241
|
+
text: instructionText,
|
|
242
|
+
});
|
|
243
|
+
logger.info('chat.message: injected phase instructions', {
|
|
244
|
+
phase: result.phase,
|
|
245
|
+
length: instructionText.length,
|
|
246
|
+
preview: instructionText.slice(0, 300),
|
|
247
|
+
});
|
|
248
|
+
},
|
|
249
|
+
/**
|
|
250
|
+
* Hook 2: tool.execute.before
|
|
251
|
+
* Fires before each tool execution. We block disallowed file edits based on phase.
|
|
252
|
+
*/
|
|
253
|
+
'tool.execute.before': async (hookInput, output) => {
|
|
254
|
+
// Skip if workflows are disabled
|
|
255
|
+
if (!workflowsEnabled) {
|
|
256
|
+
logger.debug('tool.execute.before: Workflows disabled, skipping hook');
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
const editTools = ['edit', 'write', 'patch', 'apply_patch', 'multiedit'];
|
|
260
|
+
if (!editTools.includes(hookInput.tool)) {
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
// Read current workflow state from ConversationManager
|
|
264
|
+
const state = await getWorkflowState();
|
|
265
|
+
if (!state) {
|
|
266
|
+
// No active workflow — allow all edits
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
logger.debug('tool.execute.before', {
|
|
270
|
+
tool: hookInput.tool,
|
|
271
|
+
phase: state.phase,
|
|
272
|
+
});
|
|
273
|
+
// Extract file path from tool args
|
|
274
|
+
const args = output.args;
|
|
275
|
+
const filePath = String(args?.filePath || args?.path || '');
|
|
276
|
+
if (!filePath) {
|
|
277
|
+
logger.warn('Edit tool called without filePath', {
|
|
278
|
+
tool: hookInput.tool,
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (!isFileAllowed(filePath, state.allowedFilePatterns)) {
|
|
283
|
+
const allowedList = state.allowedFilePatterns
|
|
284
|
+
.map(p => ` • ${p}`)
|
|
285
|
+
.join('\n');
|
|
286
|
+
const error = `BLOCKED: Cannot edit "${filePath}" in ${state.phase} phase.
|
|
287
|
+
|
|
288
|
+
Current phase "${state.phase}" only allows editing:
|
|
289
|
+
${allowedList}
|
|
290
|
+
|
|
291
|
+
ACTION REQUIRED: Use transition_phase tool to move to a phase that allows editing this file type, OR focus on files matching the allowed patterns above.`;
|
|
292
|
+
logger.error('BLOCKING edit', {
|
|
293
|
+
filePath,
|
|
294
|
+
phase: state.phase,
|
|
295
|
+
allowedPatterns: state.allowedFilePatterns,
|
|
296
|
+
});
|
|
297
|
+
throw new Error(error);
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
/**
|
|
301
|
+
* Hook 3: experimental.session.compacting
|
|
302
|
+
* Fires when session is being compacted. We provide minimal guidance on what
|
|
303
|
+
* to preserve and instruct the summary to end with phase continuation.
|
|
304
|
+
*/
|
|
305
|
+
'experimental.session.compacting': async (hookInput, output) => {
|
|
306
|
+
// Skip if workflows are disabled
|
|
307
|
+
if (!workflowsEnabled) {
|
|
308
|
+
logger.debug('experimental.session.compacting: Workflows disabled, skipping hook');
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
logger.debug('experimental.session.compacting hook fired', {
|
|
312
|
+
sessionID: hookInput.sessionID,
|
|
313
|
+
});
|
|
314
|
+
const state = await getWorkflowState();
|
|
315
|
+
if (!state) {
|
|
316
|
+
logger.debug('No active workflow - skipping compaction guidance');
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
output.context.push('Preserve: user intents, key decisions, significant changes and the reasoning why they were made. Remove tool calls, intermediate thoughts, and minor details.');
|
|
320
|
+
output.context.push(`End summary with: "Continue ${state.phase} phase. ${state.phaseDescription || ''}"`);
|
|
321
|
+
logger.info('Injected compaction guidance', { phase: state.phase });
|
|
322
|
+
},
|
|
323
|
+
/**
|
|
324
|
+
* Hook 4: command.execute.before
|
|
325
|
+
* Intercept /workflow and /wf commands to toggle workflows enabled state
|
|
326
|
+
*/
|
|
327
|
+
'command.execute.before': async (hookInput, output) => {
|
|
328
|
+
const cmd = hookInput.command.toLowerCase();
|
|
329
|
+
const args = (hookInput.arguments || '').toLowerCase().trim();
|
|
330
|
+
if (cmd === 'workflow' || cmd === 'wf') {
|
|
331
|
+
if (args === 'on') {
|
|
332
|
+
workflowsEnabled = true;
|
|
333
|
+
output.parts.push({
|
|
334
|
+
id: `prt_workflows_toggle_${Date.now()}`,
|
|
335
|
+
type: 'text',
|
|
336
|
+
text: 'Workflows enabled for this session.',
|
|
337
|
+
});
|
|
338
|
+
logger.info('Workflows toggled via command', { workflowsEnabled });
|
|
339
|
+
}
|
|
340
|
+
else if (args === 'off') {
|
|
341
|
+
workflowsEnabled = false;
|
|
342
|
+
output.parts.push({
|
|
343
|
+
id: `prt_workflows_toggle_${Date.now()}`,
|
|
344
|
+
type: 'text',
|
|
345
|
+
text: 'Workflows disabled for this session. Plugin will not inject instructions or enforce file restrictions.',
|
|
346
|
+
});
|
|
347
|
+
logger.info('Workflows toggled via command', { workflowsEnabled });
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
output.parts.push({
|
|
351
|
+
id: `prt_workflows_toggle_${Date.now()}`,
|
|
352
|
+
type: 'text',
|
|
353
|
+
text: `Usage: /workflow on|off or /wf on|off\nCurrent state: ${workflowsEnabled ? 'enabled' : 'disabled'}`,
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
/**
|
|
359
|
+
* Custom tools - matching MCP server tool names for consistency
|
|
360
|
+
*/
|
|
361
|
+
tool: {
|
|
362
|
+
/**
|
|
363
|
+
* Tool: start_development
|
|
364
|
+
* Starts a new development workflow in the current project
|
|
365
|
+
*/
|
|
366
|
+
start_development: createStartDevelopmentTool(input.directory, getServerContext, setBufferedInstructions),
|
|
367
|
+
/**
|
|
368
|
+
* Tool: proceed_to_phase
|
|
369
|
+
* Transitions to a new workflow phase
|
|
370
|
+
*/
|
|
371
|
+
proceed_to_phase: createProceedToPhaseTool(getServerContext, setBufferedInstructions),
|
|
372
|
+
/**
|
|
373
|
+
* Tool: conduct_review
|
|
374
|
+
* Conducts a review before phase transition
|
|
375
|
+
*/
|
|
376
|
+
conduct_review: createConductReviewTool(getServerContext),
|
|
377
|
+
/**
|
|
378
|
+
* Tool: reset_development
|
|
379
|
+
* Resets the current workflow and starts fresh
|
|
380
|
+
*/
|
|
381
|
+
reset_development: createResetDevelopmentTool(input.directory, getServerContext),
|
|
382
|
+
/**
|
|
383
|
+
* Tool: setup_project_docs
|
|
384
|
+
* Creates project documentation artifacts
|
|
385
|
+
*/
|
|
386
|
+
setup_project_docs: await createSetupProjectDocsTool(input.directory, getServerContext),
|
|
387
|
+
},
|
|
388
|
+
};
|
|
389
|
+
};
|
|
390
|
+
// Default export for opencode plugin loader
|
|
391
|
+
export default {
|
|
392
|
+
id: 'workflows',
|
|
393
|
+
server: WorkflowsPlugin,
|
|
394
|
+
};
|
|
395
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServerContext Builder for OpenCode Plugin
|
|
3
|
+
*
|
|
4
|
+
* Creates a ServerContext compatible with MCP server handlers,
|
|
5
|
+
* allowing the plugin to delegate to handler implementations.
|
|
6
|
+
*/
|
|
7
|
+
import type { ServerContext, HandlerResult } from '@codemcp/workflows-server';
|
|
8
|
+
export type { ServerContext } from '@codemcp/workflows-server';
|
|
9
|
+
import { type IPlanManager, type IInstructionGenerator, type LoggerFactory } from '@codemcp/workflows-core';
|
|
10
|
+
export interface ServerContextOptions {
|
|
11
|
+
projectDir: string;
|
|
12
|
+
planManager: IPlanManager;
|
|
13
|
+
instructionGenerator: IInstructionGenerator;
|
|
14
|
+
/** Optional logger factory - if provided, handlers will use this instead of global createLogger */
|
|
15
|
+
loggerFactory?: LoggerFactory;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Creates a ServerContext that can be passed to MCP server handlers.
|
|
19
|
+
*
|
|
20
|
+
* The handlers expect certain components to be initialized and wired together.
|
|
21
|
+
* This function creates fresh instances for each request to ensure clean state.
|
|
22
|
+
*/
|
|
23
|
+
export declare function createServerContext(options: ServerContextOptions): ServerContext;
|
|
24
|
+
/**
|
|
25
|
+
* Initialize async components of a ServerContext.
|
|
26
|
+
* Call this before using the context with handlers.
|
|
27
|
+
*
|
|
28
|
+
* Note: Workflow loading is done in createServerContext(), not here.
|
|
29
|
+
*/
|
|
30
|
+
export declare function initializeServerContext(context: ServerContext): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Convert MCP handler errors to user-friendly instructions.
|
|
33
|
+
* Returns null if the result is successful and has data.
|
|
34
|
+
*/
|
|
35
|
+
export declare function handleMcpError<T>(result: HandlerResult<T>): string | null;
|
|
36
|
+
/**
|
|
37
|
+
* Unwrap MCP handler result data after error check.
|
|
38
|
+
* Call this only after handleMcpError returns null.
|
|
39
|
+
*/
|
|
40
|
+
export declare function unwrapResult<T>(result: HandlerResult<T>): T;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ServerContext Builder for OpenCode Plugin
|
|
3
|
+
*
|
|
4
|
+
* Creates a ServerContext compatible with MCP server handlers,
|
|
5
|
+
* allowing the plugin to delegate to handler implementations.
|
|
6
|
+
*/
|
|
7
|
+
import { PluginRegistry, BeadsPlugin } from '@codemcp/workflows-server';
|
|
8
|
+
import { ConversationManager, TransitionEngine, WorkflowManager, FileStorage, InteractionLogger, } from '@codemcp/workflows-core';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
/**
|
|
11
|
+
* Creates a ServerContext that can be passed to MCP server handlers.
|
|
12
|
+
*
|
|
13
|
+
* The handlers expect certain components to be initialized and wired together.
|
|
14
|
+
* This function creates fresh instances for each request to ensure clean state.
|
|
15
|
+
*/
|
|
16
|
+
export function createServerContext(options) {
|
|
17
|
+
const { projectDir, planManager, instructionGenerator, loggerFactory } = options;
|
|
18
|
+
// Create workflow manager and load project workflows
|
|
19
|
+
const workflowManager = new WorkflowManager();
|
|
20
|
+
workflowManager.loadProjectWorkflows(projectDir);
|
|
21
|
+
// Create file storage — shared across ConversationManager and InteractionLogger
|
|
22
|
+
// so both operate on the same underlying persistence instance
|
|
23
|
+
const fileStorage = new FileStorage(path.join(projectDir, '.vibe', 'storage'));
|
|
24
|
+
const conversationManager = new ConversationManager(fileStorage, workflowManager, projectDir);
|
|
25
|
+
// InteractionLogger uses the same fileStorage so hasInteractions() works correctly.
|
|
26
|
+
// Without this, isFirstCallFromInitialState() always returns true on session resume,
|
|
27
|
+
// causing WhatsNextHandler to reset the phase to explore on every plugin load.
|
|
28
|
+
const interactionLogger = new InteractionLogger(fileStorage);
|
|
29
|
+
// Create transition engine
|
|
30
|
+
const transitionEngine = new TransitionEngine(projectDir);
|
|
31
|
+
transitionEngine.setConversationManager(conversationManager);
|
|
32
|
+
// Initialize plugin registry and register BeadsPlugin
|
|
33
|
+
// (PluginRegistry.registerPlugin checks isEnabled() internally)
|
|
34
|
+
// Pass loggerFactory so BeadsPlugin logs go through OpenCode SDK
|
|
35
|
+
const pluginRegistry = new PluginRegistry();
|
|
36
|
+
pluginRegistry.registerPlugin(new BeadsPlugin({ projectPath: projectDir, loggerFactory }));
|
|
37
|
+
return {
|
|
38
|
+
conversationManager,
|
|
39
|
+
transitionEngine,
|
|
40
|
+
planManager,
|
|
41
|
+
instructionGenerator,
|
|
42
|
+
workflowManager,
|
|
43
|
+
interactionLogger,
|
|
44
|
+
projectPath: projectDir,
|
|
45
|
+
pluginRegistry,
|
|
46
|
+
loggerFactory,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Initialize async components of a ServerContext.
|
|
51
|
+
* Call this before using the context with handlers.
|
|
52
|
+
*
|
|
53
|
+
* Note: Workflow loading is done in createServerContext(), not here.
|
|
54
|
+
*/
|
|
55
|
+
export async function initializeServerContext(context) {
|
|
56
|
+
// Initialize the file storage that the context's ConversationManager uses.
|
|
57
|
+
// initialize() creates the conversations directory if it doesn't exist.
|
|
58
|
+
// We access it via the conversationManager's database — but since it's not
|
|
59
|
+
// exposed, we create a fresh instance pointing to the same path and initialize it.
|
|
60
|
+
const fileStorage = new FileStorage(path.join(context.projectPath, '.vibe', 'storage'));
|
|
61
|
+
await fileStorage.initialize();
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Convert MCP handler errors to user-friendly instructions.
|
|
65
|
+
* Returns null if the result is successful and has data.
|
|
66
|
+
*/
|
|
67
|
+
export function handleMcpError(result) {
|
|
68
|
+
if (result.success && result.data) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const error = result.error || 'Unknown error';
|
|
72
|
+
// Extract actionable message from known error patterns
|
|
73
|
+
if (error.includes('CONVERSATION_NOT_FOUND')) {
|
|
74
|
+
return 'No active workflow. Use `start_workflow` to begin.';
|
|
75
|
+
}
|
|
76
|
+
if (error.includes('Invalid workflow:')) {
|
|
77
|
+
// Error already contains available workflows list
|
|
78
|
+
return error.replace(/^.*?Invalid workflow:/, 'Invalid workflow:');
|
|
79
|
+
}
|
|
80
|
+
if (error.includes('Available workflows:')) {
|
|
81
|
+
return error;
|
|
82
|
+
}
|
|
83
|
+
// Generic error - return as instruction
|
|
84
|
+
return `Error: ${error}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Unwrap MCP handler result data after error check.
|
|
88
|
+
* Call this only after handleMcpError returns null.
|
|
89
|
+
*/
|
|
90
|
+
export function unwrapResult(result) {
|
|
91
|
+
if (!result.data) {
|
|
92
|
+
throw new Error('No data in result');
|
|
93
|
+
}
|
|
94
|
+
return result.data;
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=server-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-context.js","sourceRoot":"","sources":["../src/server-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { ConductReviewHandler, } from '@codemcp/workflows-server';
|
|
3
|
+
import { tool } from './tool-helper.js';
|
|
4
|
+
import { handleMcpError, unwrapResult } from '../server-context.js';
|
|
5
|
+
import { createLogger } from '@codemcp/workflows-core';
|
|
6
|
+
export function createConductReviewTool(getServerContext) {
|
|
7
|
+
return tool({
|
|
8
|
+
description: 'Conduct a review before phase transition. Args: target_phase',
|
|
9
|
+
args: {
|
|
10
|
+
target_phase: z.string().describe('Target phase after review'),
|
|
11
|
+
},
|
|
12
|
+
execute: async (args) => {
|
|
13
|
+
const { target_phase } = args;
|
|
14
|
+
const serverContext = await getServerContext();
|
|
15
|
+
const logger = serverContext.loggerFactory
|
|
16
|
+
? serverContext.loggerFactory('conduct_review')
|
|
17
|
+
: createLogger('conduct_review');
|
|
18
|
+
logger.debug('conduct_review called', { targetPhase: target_phase });
|
|
19
|
+
try {
|
|
20
|
+
// Delegate to ConductReviewHandler
|
|
21
|
+
const handler = new ConductReviewHandler();
|
|
22
|
+
const result = await handler.handle({ target_phase }, serverContext);
|
|
23
|
+
// Handle errors gracefully
|
|
24
|
+
const errorMsg = handleMcpError(result);
|
|
25
|
+
if (errorMsg) {
|
|
26
|
+
return errorMsg;
|
|
27
|
+
}
|
|
28
|
+
return unwrapResult(result).instructions;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
32
|
+
return `Error: ${errorMessage}`;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=conduct-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conduct-review.js","sourceRoot":"","sources":["../../src/tool-handlers/conduct-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,oBAAoB,GAErB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,MAAM,UAAU,uBAAuB,CACrC,gBAA8C;IAE9C,OAAO,IAAI,CAAC;QACV,WAAW,EAAE,8DAA8D;QAC3E,IAAI,EAAE;YACJ,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;SAC/D;QACD,OAAO,EAAE,KAAK,EAAC,IAAI,EAAC,EAAE;YACpB,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;YAC9B,MAAM,aAAa,GAAG,MAAM,gBAAgB,EAAE,CAAC;YAC/C,MAAM,MAAM,GAAG,aAAa,CAAC,aAAa;gBACxC,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC,gBAAgB,CAAC;gBAC/C,CAAC,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC;YAEnC,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC,CAAC;YAErE,IAAI,CAAC;gBACH,mCAAmC;gBACnC,MAAM,OAAO,GAAG,IAAI,oBAAoB,EAAE,CAAC;gBAC3C,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,EAAE,YAAY,EAAE,EAAE,aAAa,CAAC,CAAC;gBAErE,2BAA2B;gBAC3B,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;gBACxC,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,QAAQ,CAAC;gBAClB,CAAC;gBAED,OAAO,YAAY,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC;YAC3C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,YAAY,GAChB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACzD,OAAO,UAAU,YAAY,EAAE,CAAC;YAClC,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { type ServerContext, type WhatsNextResult } from '@codemcp/workflows-server';
|
|
2
|
+
import type { ToolDefinition } from '../types.js';
|
|
3
|
+
export declare function createProceedToPhaseTool(getServerContext: () => Promise<ServerContext>, setBufferedInstructions: (result: WhatsNextResult) => void): ToolDefinition;
|