@doingdev/opencode-claude-manager-plugin 0.1.28 → 0.1.30

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.
@@ -11,22 +11,26 @@ export declare const AGENT_CTO = "cto";
11
11
  export declare const AGENT_ENGINEER_PLAN = "engineer_plan";
12
12
  export declare const AGENT_ENGINEER_BUILD = "engineer_build";
13
13
  /** All restricted tool IDs (union of all domain groups) */
14
- export declare const ALL_RESTRICTED_TOOL_IDS: readonly ["engineer_send", "engineer_compact", "engineer_clear", "engineer_status", "engineer_metadata", "engineer_sessions", "engineer_runs", "git_diff", "git_commit", "git_reset", "approval_policy", "approval_decisions", "approval_update"];
14
+ export declare const ALL_RESTRICTED_TOOL_IDS: readonly ["engineer_send", "engineer_send_plan", "engineer_send_build", "engineer_compact", "engineer_clear", "engineer_status", "engineer_metadata", "engineer_sessions", "engineer_runs", "git_diff", "git_commit", "git_reset", "approval_policy", "approval_decisions", "approval_update"];
15
15
  type ToolPermission = 'allow' | 'ask' | 'deny';
16
16
  type AgentPermission = {
17
17
  '*'?: ToolPermission;
18
18
  read?: ToolPermission;
19
19
  grep?: ToolPermission;
20
20
  glob?: ToolPermission;
21
+ list?: ToolPermission;
21
22
  codesearch?: ToolPermission;
22
23
  webfetch?: ToolPermission;
23
24
  websearch?: ToolPermission;
25
+ lsp?: ToolPermission;
24
26
  /** OpenCode built-in: manage session todo list */
25
27
  todowrite?: ToolPermission;
26
28
  /** OpenCode built-in: read session todo list */
27
29
  todoread?: ToolPermission;
28
30
  /** OpenCode built-in: ask the user structured questions with options */
29
31
  question?: ToolPermission;
32
+ /** OpenCode built-in: launch subagents (matches subagent type, last-match-wins) */
33
+ task?: ToolPermission | Record<string, ToolPermission>;
30
34
  bash?: ToolPermission | Record<string, ToolPermission>;
31
35
  [tool: string]: ToolPermission | Record<string, ToolPermission> | undefined;
32
36
  };
@@ -15,9 +15,8 @@ export const AGENT_ENGINEER_BUILD = 'engineer_build';
15
15
  // ---------------------------------------------------------------------------
16
16
  // Tool IDs — grouped by domain
17
17
  // ---------------------------------------------------------------------------
18
- /** All engineer tools session interaction + diagnostics. Owned by wrappers. */
19
- const ENGINEER_TOOL_IDS = [
20
- 'engineer_send',
18
+ /** Shared engineer session tools (compact, clear, status, diagnostics) */
19
+ const ENGINEER_SHARED_TOOL_IDS = [
21
20
  'engineer_compact',
22
21
  'engineer_clear',
23
22
  'engineer_status',
@@ -25,6 +24,23 @@ const ENGINEER_TOOL_IDS = [
25
24
  'engineer_sessions',
26
25
  'engineer_runs',
27
26
  ];
27
+ /** All engineer tools — generic send + mode-locked sends + shared session tools */
28
+ const ENGINEER_TOOL_IDS = [
29
+ 'engineer_send',
30
+ 'engineer_send_plan',
31
+ 'engineer_send_build',
32
+ ...ENGINEER_SHARED_TOOL_IDS,
33
+ ];
34
+ /** Tools for the engineer_plan wrapper (plan-mode send + shared) */
35
+ const ENGINEER_PLAN_TOOL_IDS = [
36
+ 'engineer_send_plan',
37
+ ...ENGINEER_SHARED_TOOL_IDS,
38
+ ];
39
+ /** Tools for the engineer_build wrapper (build-mode send + shared) */
40
+ const ENGINEER_BUILD_TOOL_IDS = [
41
+ 'engineer_send_build',
42
+ ...ENGINEER_SHARED_TOOL_IDS,
43
+ ];
28
44
  /** Git tools — owned by CTO */
29
45
  const GIT_TOOL_IDS = ['git_diff', 'git_commit', 'git_reset'];
30
46
  /** Approval tools — owned by CTO */
@@ -48,9 +64,11 @@ const READONLY_TOOLS = {
48
64
  read: 'allow',
49
65
  grep: 'allow',
50
66
  glob: 'allow',
67
+ list: 'allow',
51
68
  codesearch: 'allow',
52
69
  webfetch: 'allow',
53
70
  websearch: 'allow',
71
+ lsp: 'allow',
54
72
  todowrite: 'allow',
55
73
  todoread: 'allow',
56
74
  question: 'allow',
@@ -58,7 +76,7 @@ const READONLY_TOOLS = {
58
76
  // ---------------------------------------------------------------------------
59
77
  // Permission builders
60
78
  // ---------------------------------------------------------------------------
61
- /** CTO: pure orchestrator — read-only + git + approval + diagnostics. No session tools. */
79
+ /** CTO: pure orchestrator — read-only + git + approval + task (spawn engineers). No session tools. */
62
80
  function buildCtoPermissions() {
63
81
  const denied = {};
64
82
  for (const toolId of ALL_RESTRICTED_TOOL_IDS) {
@@ -73,16 +91,37 @@ function buildCtoPermissions() {
73
91
  ...READONLY_TOOLS,
74
92
  ...denied,
75
93
  ...allowed,
94
+ task: {
95
+ '*': 'deny',
96
+ [AGENT_ENGINEER_PLAN]: 'allow',
97
+ [AGENT_ENGINEER_BUILD]: 'allow',
98
+ },
99
+ };
100
+ }
101
+ /** Engineer plan wrapper: engineer_send_plan + shared session tools. */
102
+ function buildEngineerPlanPermissions() {
103
+ const denied = {};
104
+ for (const toolId of ALL_RESTRICTED_TOOL_IDS) {
105
+ denied[toolId] = 'deny';
106
+ }
107
+ const allowed = {};
108
+ for (const toolId of ENGINEER_PLAN_TOOL_IDS) {
109
+ allowed[toolId] = 'allow';
110
+ }
111
+ return {
112
+ '*': 'deny',
113
+ ...denied,
114
+ ...allowed,
76
115
  };
77
116
  }
78
- /** Engineer wrapper: all engineer tools. No read-only, git, or approval tools. */
79
- function buildEngineerWrapperPermissions() {
117
+ /** Engineer build wrapper: engineer_send_build + shared session tools. */
118
+ function buildEngineerBuildPermissions() {
80
119
  const denied = {};
81
120
  for (const toolId of ALL_RESTRICTED_TOOL_IDS) {
82
121
  denied[toolId] = 'deny';
83
122
  }
84
123
  const allowed = {};
85
- for (const toolId of ENGINEER_TOOL_IDS) {
124
+ for (const toolId of ENGINEER_BUILD_TOOL_IDS) {
86
125
  allowed[toolId] = 'allow';
87
126
  }
88
127
  return {
@@ -108,7 +147,7 @@ export function buildEngineerPlanAgentConfig(prompts) {
108
147
  description: 'Engineer that manages a Claude Code session in plan mode for read-only investigation and analysis.',
109
148
  mode: 'subagent',
110
149
  color: '#D97757',
111
- permission: buildEngineerWrapperPermissions(),
150
+ permission: buildEngineerPlanPermissions(),
112
151
  prompt: prompts.engineerPlanPrompt,
113
152
  };
114
153
  }
@@ -117,7 +156,7 @@ export function buildEngineerBuildAgentConfig(prompts) {
117
156
  description: 'Engineer that manages a Claude Code session in free mode for implementation and execution.',
118
157
  mode: 'subagent',
119
158
  color: '#D97757',
120
- permission: buildEngineerWrapperPermissions(),
159
+ permission: buildEngineerBuildPermissions(),
121
160
  prompt: prompts.engineerBuildPrompt,
122
161
  };
123
162
  }
@@ -4,6 +4,194 @@ import { AGENT_CTO, AGENT_ENGINEER_BUILD, AGENT_ENGINEER_PLAN, buildCtoAgentConf
4
4
  import { getOrCreatePluginServices } from './service-factory.js';
5
5
  export const ClaudeManagerPlugin = async ({ worktree }) => {
6
6
  const services = getOrCreatePluginServices(worktree);
7
+ async function executeEngineerSend(args, context) {
8
+ const cwd = args.cwd ?? context.worktree;
9
+ if (args.freshSession) {
10
+ await services.manager.clearSession(cwd);
11
+ }
12
+ const hasActiveSession = services.manager.getStatus().sessionId !== null;
13
+ const promptPreview = args.message.length > 100
14
+ ? args.message.slice(0, 100) + '...'
15
+ : args.message;
16
+ context.metadata({
17
+ title: hasActiveSession
18
+ ? 'Claude Code: Resuming session...'
19
+ : 'Claude Code: Initializing...',
20
+ metadata: {
21
+ sessionId: services.manager.getStatus().sessionId,
22
+ prompt: promptPreview,
23
+ },
24
+ });
25
+ let turnsSoFar = 0;
26
+ let costSoFar = 0;
27
+ const result = await services.manager.sendMessage(cwd, args.message, {
28
+ model: args.model,
29
+ effort: args.effort,
30
+ mode: args.mode,
31
+ abortSignal: context.abort,
32
+ }, (event) => {
33
+ if (event.turns !== undefined) {
34
+ turnsSoFar = event.turns;
35
+ }
36
+ if (event.totalCostUsd !== undefined) {
37
+ costSoFar = event.totalCostUsd;
38
+ }
39
+ const costLabel = `$${costSoFar.toFixed(4)}`;
40
+ if (event.type === 'tool_call') {
41
+ let toolName = 'tool';
42
+ let inputPreview = '';
43
+ try {
44
+ const parsed = JSON.parse(event.text);
45
+ toolName = parsed.name ?? 'tool';
46
+ if (parsed.input) {
47
+ const inputStr = typeof parsed.input === 'string'
48
+ ? parsed.input
49
+ : JSON.stringify(parsed.input);
50
+ inputPreview =
51
+ inputStr.length > 150
52
+ ? inputStr.slice(0, 150) + '...'
53
+ : inputStr;
54
+ }
55
+ }
56
+ catch {
57
+ // ignore parse errors
58
+ }
59
+ context.metadata({
60
+ title: `Claude Code: Running ${toolName}... (${turnsSoFar} turns, ${costLabel})`,
61
+ metadata: {
62
+ sessionId: event.sessionId,
63
+ type: event.type,
64
+ tool: toolName,
65
+ input: inputPreview,
66
+ },
67
+ });
68
+ }
69
+ else if (event.type === 'assistant') {
70
+ const thinkingPreview = event.text.length > 150
71
+ ? event.text.slice(0, 150) + '...'
72
+ : event.text;
73
+ context.metadata({
74
+ title: `Claude Code: Thinking... (${turnsSoFar} turns, ${costLabel})`,
75
+ metadata: {
76
+ sessionId: event.sessionId,
77
+ type: event.type,
78
+ thinking: thinkingPreview,
79
+ },
80
+ });
81
+ }
82
+ else if (event.type === 'init') {
83
+ context.metadata({
84
+ title: `Claude Code: Session started`,
85
+ metadata: {
86
+ sessionId: event.sessionId,
87
+ prompt: promptPreview,
88
+ },
89
+ });
90
+ }
91
+ else if (event.type === 'user') {
92
+ const preview = event.text.length > 200
93
+ ? event.text.slice(0, 200) + '...'
94
+ : event.text;
95
+ context.metadata({
96
+ title: `Claude Code: Tool result (${turnsSoFar} turns, ${costLabel})`,
97
+ metadata: {
98
+ sessionId: event.sessionId,
99
+ type: event.type,
100
+ output: preview,
101
+ },
102
+ });
103
+ }
104
+ else if (event.type === 'tool_progress') {
105
+ let toolName = 'tool';
106
+ let elapsed = 0;
107
+ try {
108
+ const parsed = JSON.parse(event.text);
109
+ toolName = parsed.name ?? 'tool';
110
+ elapsed = parsed.elapsed ?? 0;
111
+ }
112
+ catch {
113
+ // ignore
114
+ }
115
+ context.metadata({
116
+ title: `Claude Code: ${toolName} running ${elapsed > 0 ? `(${elapsed.toFixed(0)}s)` : ''}... (${turnsSoFar} turns, ${costLabel})`,
117
+ metadata: {
118
+ sessionId: event.sessionId,
119
+ type: event.type,
120
+ tool: toolName,
121
+ elapsed,
122
+ },
123
+ });
124
+ }
125
+ else if (event.type === 'tool_summary') {
126
+ const summary = event.text.length > 200
127
+ ? event.text.slice(0, 200) + '...'
128
+ : event.text;
129
+ context.metadata({
130
+ title: `Claude Code: Tool done (${turnsSoFar} turns, ${costLabel})`,
131
+ metadata: {
132
+ sessionId: event.sessionId,
133
+ type: event.type,
134
+ summary,
135
+ },
136
+ });
137
+ }
138
+ else if (event.type === 'partial') {
139
+ const delta = event.text.length > 200
140
+ ? event.text.slice(0, 200) + '...'
141
+ : event.text;
142
+ context.metadata({
143
+ title: `Claude Code: Writing... (${turnsSoFar} turns, ${costLabel})`,
144
+ metadata: {
145
+ sessionId: event.sessionId,
146
+ type: event.type,
147
+ delta,
148
+ },
149
+ });
150
+ }
151
+ else if (event.type === 'error') {
152
+ context.metadata({
153
+ title: `Claude Code: Error`,
154
+ metadata: {
155
+ sessionId: event.sessionId,
156
+ error: event.text.slice(0, 200),
157
+ },
158
+ });
159
+ }
160
+ });
161
+ const costLabel = `$${(result.totalCostUsd ?? 0).toFixed(4)}`;
162
+ const turns = result.turns ?? 0;
163
+ const contextWarning = formatContextWarning(result.context);
164
+ if (contextWarning) {
165
+ context.metadata({
166
+ title: `Claude Code: Context at ${result.context.estimatedContextPercent}% (${turns} turns)`,
167
+ metadata: { sessionId: result.sessionId, contextWarning },
168
+ });
169
+ }
170
+ else {
171
+ context.metadata({
172
+ title: `Claude Code: Complete (${turns} turns, ${costLabel})`,
173
+ metadata: { sessionId: result.sessionId },
174
+ });
175
+ }
176
+ let toolOutputs = [];
177
+ if (result.sessionId) {
178
+ try {
179
+ toolOutputs = await services.liveTailer.getToolOutputPreview(result.sessionId, cwd, 3);
180
+ }
181
+ catch {
182
+ // Non-critical — the JSONL file may not exist yet.
183
+ }
184
+ }
185
+ return JSON.stringify({
186
+ sessionId: result.sessionId,
187
+ finalText: result.finalText,
188
+ turns: result.turns,
189
+ totalCostUsd: result.totalCostUsd,
190
+ context: result.context,
191
+ contextWarning,
192
+ toolOutputs: toolOutputs.length > 0 ? toolOutputs : undefined,
193
+ }, null, 2);
194
+ }
7
195
  return {
8
196
  config: async (config) => {
9
197
  config.agent ??= {};
@@ -15,12 +203,49 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
15
203
  },
16
204
  tool: {
17
205
  engineer_send: tool({
18
- description: 'Send a message to the persistent Claude Code session. ' +
206
+ description: 'Send a message to the persistent Claude Code session with explicit mode control. ' +
207
+ 'Most agents should use engineer_send_plan or engineer_send_build instead.',
208
+ args: {
209
+ message: tool.schema.string().min(1),
210
+ model: tool.schema
211
+ .enum(['claude-opus-4-6', 'claude-sonnet-4-6', 'claude-sonnet-4-5'])
212
+ .optional(),
213
+ effort: tool.schema
214
+ .enum(['low', 'medium', 'high', 'max'])
215
+ .default('high'),
216
+ mode: tool.schema.enum(['plan', 'free']).default('free'),
217
+ freshSession: tool.schema.boolean().default(false),
218
+ cwd: tool.schema.string().optional(),
219
+ },
220
+ async execute(args, context) {
221
+ return executeEngineerSend(args, context);
222
+ },
223
+ }),
224
+ engineer_send_plan: tool({
225
+ description: 'Send a read-only investigation message to the Claude Code session in plan mode. ' +
226
+ 'The engineer will analyze code without making edits. ' +
227
+ 'Auto-creates a session on first call. Resumes the existing session on subsequent calls. ' +
228
+ 'Returns the assistant response and current context health snapshot.',
229
+ args: {
230
+ message: tool.schema.string().min(1),
231
+ model: tool.schema
232
+ .enum(['claude-opus-4-6', 'claude-sonnet-4-6', 'claude-sonnet-4-5'])
233
+ .optional(),
234
+ effort: tool.schema
235
+ .enum(['low', 'medium', 'high', 'max'])
236
+ .default('high'),
237
+ freshSession: tool.schema.boolean().default(false),
238
+ cwd: tool.schema.string().optional(),
239
+ },
240
+ async execute(args, context) {
241
+ return executeEngineerSend({ ...args, mode: 'plan' }, context);
242
+ },
243
+ }),
244
+ engineer_send_build: tool({
245
+ description: 'Send an implementation message to the Claude Code session in free mode. ' +
246
+ 'The engineer can read, edit, and create files. ' +
19
247
  'Auto-creates a session on first call. Resumes the existing session on subsequent calls. ' +
20
248
  'Returns the assistant response and current context health snapshot. ' +
21
- 'Use mode "plan" for read-only investigation and planning (no edits), ' +
22
- 'or "free" (default) for normal execution with edit permissions. ' +
23
- 'Set freshSession to clear the active session before sending (use for unrelated tasks). ' +
24
249
  'Prefer claude-opus-4-6 (default) for most coding work; use a Sonnet model for faster/lighter tasks. ' +
25
250
  'Prefer effort "high" (default) for most work; use "medium" for lighter tasks and "max" for especially hard problems.',
26
251
  args: {
@@ -31,198 +256,11 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
31
256
  effort: tool.schema
32
257
  .enum(['low', 'medium', 'high', 'max'])
33
258
  .default('high'),
34
- mode: tool.schema.enum(['plan', 'free']).default('free'),
35
259
  freshSession: tool.schema.boolean().default(false),
36
260
  cwd: tool.schema.string().optional(),
37
261
  },
38
262
  async execute(args, context) {
39
- const cwd = args.cwd ?? context.worktree;
40
- if (args.freshSession) {
41
- await services.manager.clearSession(cwd);
42
- }
43
- const hasActiveSession = services.manager.getStatus().sessionId !== null;
44
- const promptPreview = args.message.length > 100
45
- ? args.message.slice(0, 100) + '...'
46
- : args.message;
47
- context.metadata({
48
- title: hasActiveSession
49
- ? 'Claude Code: Resuming session...'
50
- : 'Claude Code: Initializing...',
51
- metadata: {
52
- sessionId: services.manager.getStatus().sessionId,
53
- prompt: promptPreview,
54
- },
55
- });
56
- let turnsSoFar = 0;
57
- let costSoFar = 0;
58
- const result = await services.manager.sendMessage(cwd, args.message, {
59
- model: args.model,
60
- effort: args.effort,
61
- mode: args.mode,
62
- abortSignal: context.abort,
63
- }, (event) => {
64
- if (event.turns !== undefined) {
65
- turnsSoFar = event.turns;
66
- }
67
- if (event.totalCostUsd !== undefined) {
68
- costSoFar = event.totalCostUsd;
69
- }
70
- const costLabel = `$${costSoFar.toFixed(4)}`;
71
- if (event.type === 'tool_call') {
72
- let toolName = 'tool';
73
- let inputPreview = '';
74
- try {
75
- const parsed = JSON.parse(event.text);
76
- toolName = parsed.name ?? 'tool';
77
- if (parsed.input) {
78
- const inputStr = typeof parsed.input === 'string'
79
- ? parsed.input
80
- : JSON.stringify(parsed.input);
81
- inputPreview =
82
- inputStr.length > 150
83
- ? inputStr.slice(0, 150) + '...'
84
- : inputStr;
85
- }
86
- }
87
- catch {
88
- // ignore parse errors
89
- }
90
- context.metadata({
91
- title: `Claude Code: Running ${toolName}... (${turnsSoFar} turns, ${costLabel})`,
92
- metadata: {
93
- sessionId: event.sessionId,
94
- type: event.type,
95
- tool: toolName,
96
- input: inputPreview,
97
- },
98
- });
99
- }
100
- else if (event.type === 'assistant') {
101
- const thinkingPreview = event.text.length > 150
102
- ? event.text.slice(0, 150) + '...'
103
- : event.text;
104
- context.metadata({
105
- title: `Claude Code: Thinking... (${turnsSoFar} turns, ${costLabel})`,
106
- metadata: {
107
- sessionId: event.sessionId,
108
- type: event.type,
109
- thinking: thinkingPreview,
110
- },
111
- });
112
- }
113
- else if (event.type === 'init') {
114
- context.metadata({
115
- title: `Claude Code: Session started`,
116
- metadata: {
117
- sessionId: event.sessionId,
118
- prompt: promptPreview,
119
- },
120
- });
121
- }
122
- else if (event.type === 'user') {
123
- const preview = event.text.length > 200
124
- ? event.text.slice(0, 200) + '...'
125
- : event.text;
126
- context.metadata({
127
- title: `Claude Code: Tool result (${turnsSoFar} turns, ${costLabel})`,
128
- metadata: {
129
- sessionId: event.sessionId,
130
- type: event.type,
131
- output: preview,
132
- },
133
- });
134
- }
135
- else if (event.type === 'tool_progress') {
136
- let toolName = 'tool';
137
- let elapsed = 0;
138
- try {
139
- const parsed = JSON.parse(event.text);
140
- toolName = parsed.name ?? 'tool';
141
- elapsed = parsed.elapsed ?? 0;
142
- }
143
- catch {
144
- // ignore
145
- }
146
- context.metadata({
147
- title: `Claude Code: ${toolName} running ${elapsed > 0 ? `(${elapsed.toFixed(0)}s)` : ''}... (${turnsSoFar} turns, ${costLabel})`,
148
- metadata: {
149
- sessionId: event.sessionId,
150
- type: event.type,
151
- tool: toolName,
152
- elapsed,
153
- },
154
- });
155
- }
156
- else if (event.type === 'tool_summary') {
157
- const summary = event.text.length > 200
158
- ? event.text.slice(0, 200) + '...'
159
- : event.text;
160
- context.metadata({
161
- title: `Claude Code: Tool done (${turnsSoFar} turns, ${costLabel})`,
162
- metadata: {
163
- sessionId: event.sessionId,
164
- type: event.type,
165
- summary,
166
- },
167
- });
168
- }
169
- else if (event.type === 'partial') {
170
- const delta = event.text.length > 200
171
- ? event.text.slice(0, 200) + '...'
172
- : event.text;
173
- context.metadata({
174
- title: `Claude Code: Writing... (${turnsSoFar} turns, ${costLabel})`,
175
- metadata: {
176
- sessionId: event.sessionId,
177
- type: event.type,
178
- delta,
179
- },
180
- });
181
- }
182
- else if (event.type === 'error') {
183
- context.metadata({
184
- title: `Claude Code: Error`,
185
- metadata: {
186
- sessionId: event.sessionId,
187
- error: event.text.slice(0, 200),
188
- },
189
- });
190
- }
191
- });
192
- const costLabel = `$${(result.totalCostUsd ?? 0).toFixed(4)}`;
193
- const turns = result.turns ?? 0;
194
- const contextWarning = formatContextWarning(result.context);
195
- if (contextWarning) {
196
- context.metadata({
197
- title: `Claude Code: Context at ${result.context.estimatedContextPercent}% (${turns} turns)`,
198
- metadata: { sessionId: result.sessionId, contextWarning },
199
- });
200
- }
201
- else {
202
- context.metadata({
203
- title: `Claude Code: Complete (${turns} turns, ${costLabel})`,
204
- metadata: { sessionId: result.sessionId },
205
- });
206
- }
207
- // Fetch recent tool output from the JSONL file for richer feedback.
208
- let toolOutputs = [];
209
- if (result.sessionId) {
210
- try {
211
- toolOutputs = await services.liveTailer.getToolOutputPreview(result.sessionId, cwd, 3);
212
- }
213
- catch {
214
- // Non-critical — the JSONL file may not exist yet.
215
- }
216
- }
217
- return JSON.stringify({
218
- sessionId: result.sessionId,
219
- finalText: result.finalText,
220
- turns: result.turns,
221
- totalCostUsd: result.totalCostUsd,
222
- context: result.context,
223
- contextWarning,
224
- toolOutputs: toolOutputs.length > 0 ? toolOutputs : undefined,
225
- }, null, 2);
263
+ return executeEngineerSend({ ...args, mode: 'free' }, context);
226
264
  },
227
265
  }),
228
266
  engineer_compact: tool({
@@ -1,90 +1,77 @@
1
1
  export const managerPromptRegistry = {
2
2
  ctoSystemPrompt: [
3
- 'You are the CTO a top 0.001% technical leader.',
4
- 'You orchestrate engineers to build the right thing with high quality.',
5
- 'You investigate, clarify requirements, plan, delegate to engineers,',
6
- 'review their work, and commit when satisfied.',
7
- '',
8
- '## Your role',
9
- '- Gather requirements thoroughly before acting. Clarify ambiguity early.',
10
- '- Think like a staff+ engineer: correctness, maintainability, tests, rollback safety.',
11
- '- Plan thoughtfully, delegate with precision, review rigorously.',
12
- '- You have two types of engineers: `engineer_plan` (investigation) and `engineer_build` (implementation).',
13
- '',
14
- '## Decision loop',
15
- 'On every turn, choose exactly one action:',
16
- ' investigate read files, grep, search the codebase to build context',
17
- ' plan — spawn `engineer_plan` to analyze code, map dependencies, or draft a plan',
18
- ' delegate — spawn `engineer_build` with a focused implementation task',
19
- ' review — run git_diff to inspect what the engineer changed',
20
- ' validate — spawn `engineer_build` to run tests, lint, or typecheck',
21
- ' commit — checkpoint good work with git_commit',
22
- ' correct — spawn `engineer_build` with a targeted fix (never "try again")',
23
- ' reset — discard bad work with git_reset',
24
- ' ask — use the question tool for structured choices, or one narrow text question',
25
- '',
26
- 'Default order: investigate plan delegate review validate commit.',
27
- 'Skip steps only when you have strong evidence they are unnecessary.',
28
- '',
29
- '## Before you delegate',
30
- '1. Read the relevant files yourself (you have read, grep, glob, webfetch, websearch).',
31
- ' For broad investigations, spawn `engineer_plan`.',
32
- '2. Identify the exact files, functions, line numbers, and patterns involved.',
33
- '3. Check existing conventions: naming, test style, error handling patterns.',
34
- '4. Craft an instruction that a senior engineer would find unambiguous.',
35
- ' Bad: "Fix the auth bug"',
36
- ' Good: "In src/auth/session.ts, the `validateToken` function (line 42)',
37
- ' throws on expired tokens instead of returning null. Change it to',
38
- ' return null and update the caller in src/routes/login.ts:87."',
39
- '',
40
- '## After delegation mandatory review',
41
- 'Never claim success without evidence:',
42
- '1. git_diff — read the actual diff, not just the summary.',
43
- '2. Verify the diff matches what you asked for. Check for:',
44
- ' - Unintended changes or regressions',
45
- ' - Missing test updates',
46
- ' - Style violations against repo conventions',
47
- '3. If changes look correct, spawn `engineer_build` to run tests/lint/typecheck.',
48
- '4. Only commit after verification passes.',
49
- '5. If the diff is wrong: spawn a targeted correction or reset.',
50
- '',
51
- '## Spawning engineers',
52
- '- `engineer_plan` read-only investigation and analysis.',
53
- ' Use for: exploring unfamiliar code, analyzing dependencies, generating plans.',
54
- '- `engineer_build` — implementation and execution.',
55
- ' Use for: all code changes, test runs, validation, and fixes.',
56
- '- Provide each engineer with a clear, scoped objective and relevant context.',
57
- '- Engineers manage their own sessions. They handle context, compaction, model selection.',
58
- ' You do NOT need to manage these details.',
59
- '- If slices are independent, spawn them in parallel.',
3
+ 'You are a cracked AI-native engineer who uses Claude Code better than anyone.',
4
+ 'You build the right thing, with the right quality, on the first try.',
5
+ '',
6
+ '## Core principle: verification-first',
7
+ 'Every delegation MUST include how to verify success.',
8
+ 'Tests, expected outputs, lint/typecheck commands, or before/after behavior.',
9
+ 'This is the single highest-leverage thing you do.',
10
+ 'Never delegate without telling the engineer how to prove it worked.',
11
+ '',
12
+ '## Right-size your approach',
13
+ 'Not every task needs a plan. Assess complexity, then act:',
14
+ '',
15
+ '**Simple tasks** (typo, rename, add a log line, one-file fix):',
16
+ ' Skip investigation. Delegate directly with specific context.',
17
+ '',
18
+ '**Medium tasks** (bug fix, small feature, refactor one module):',
19
+ ' Read the relevant code yourself. Understand the current state.',
20
+ ' Then delegate with file paths, line numbers, patterns, and verification.',
21
+ '',
22
+ '**Complex tasks** (multi-file feature, architecture change, large refactor):',
23
+ ' 1. Investigate: read code, grep for patterns, spawn `engineer_plan` to explore.',
24
+ ' 2. If requirements are unclear, ask the user ONE specific question.',
25
+ ' Prefer the question tool when discrete options exist.',
26
+ ' 3. Write a plan to the todo list (todowrite). Share it with the user.',
27
+ ' 4. Execute steps sequentially, committing after each.',
28
+ '',
29
+ '## How to delegate effectively',
30
+ 'The engineer does not have your context. Every instruction must be self-contained.',
31
+ 'Include:',
32
+ '- Exact files, functions, and line numbers to change.',
33
+ '- Current behavior and desired behavior.',
34
+ '- Code snippets showing the pattern or convention to follow.',
35
+ '- How to verify: "Run `npm test`, expect all green." or',
36
+ ' "The function should return null instead of throwing."',
37
+ '',
38
+ 'Bad: "Fix the auth bug"',
39
+ 'Good: "In src/auth/session.ts, `validateToken` (line 42) throws on expired',
40
+ ' tokens instead of returning null. Change it to return null.',
41
+ ' Update the caller in src/routes/login.ts:87.',
42
+ ' Follow the pattern in src/auth/refresh.ts:23.',
43
+ ' Run `npm test -- --grep auth` to verify. All tests should pass."',
44
+ '',
45
+ '## Review every change',
46
+ 'After each delegation:',
47
+ '1. git_diff read the FULL diff. Check for unintended changes, missing tests,',
48
+ ' style violations.',
49
+ '2. If correct: spawn `engineer_build` to run tests/lint/typecheck.',
50
+ '3. If tests pass: git_commit to checkpoint.',
51
+ '4. If wrong: spawn `engineer_build` with a specific correction.',
52
+ ' On second failure: git_reset and rewrite the prompt from scratch.',
53
+ ' Never send three corrections for the same problem.',
54
+ '',
55
+ '## Engineers (via the Task tool)',
56
+ '- `engineer_plan` read-only investigation. Use for: exploring unfamiliar code,',
57
+ ' mapping dependencies, analyzing impact, asking "how does X work?"',
58
+ '- `engineer_build` implementation. Use for: all code changes, test runs, fixes.',
59
+ '- If steps are independent, spawn multiple engineers in parallel.',
60
+ '',
61
+ '## Context efficiency',
62
+ '- Use `engineer_plan` for broad exploration so your own context stays clean.',
63
+ '- When spawning engineers for unrelated tasks, tell them to use freshSession:true.',
64
+ '- Keep delegations focused — one concern per engineer invocation.',
60
65
  '',
61
66
  '## What you must NOT do',
62
- '- Do NOT call any engineer_* tools directly. Spawn engineer subagents instead.',
67
+ '- Do NOT call any engineer_* tools directly. Use the Task tool.',
63
68
  '- Do NOT edit files or run bash commands yourself.',
64
- '',
65
- '## Handling ambiguity',
66
- 'When requirements are unclear:',
67
- '1. First, try to resolve it yourself — read code, check tests, grep for usage.',
68
- '2. If ambiguity remains, ask the user ONE specific question.',
69
- ' Prefer the question tool when discrete options exist.',
70
- '3. Never block on multiple questions at once.',
71
- '',
72
- '## Correction and recovery',
73
- 'If the engineer produces wrong output:',
74
- '1. First correction: spawn `engineer_build` with a specific, targeted fix instruction.',
75
- '2. Second correction on the same issue: reset and spawn a fresh engineer',
76
- ' with a rewritten prompt incorporating lessons from both failures.',
77
- 'Never send three corrections for the same problem.',
78
- '',
79
- '## Multi-step tasks',
80
- '- Use todowrite / todoread to track steps; keep items concrete and few.',
81
- '- Decompose large tasks into sequential focused instructions.',
82
- '- Commit after each successful step (checkpoint for rollback).',
83
- '- Prefer small diffs — they are easier to review and safer to ship.',
69
+ '- Do NOT skip review — always git_diff after delegation.',
70
+ '- Do NOT delegate without verification criteria.',
84
71
  '',
85
72
  '## Tools reference',
86
- 'todowrite / todoread — OpenCode session todo list (track multi-step work)',
87
- 'question — OpenCode user prompt with options (clarify trade-offs)',
73
+ 'todowrite / todoread — track multi-step work',
74
+ 'question — ask the user structured questions with options',
88
75
  'git_diff — review all uncommitted changes',
89
76
  'git_commit — stage all + commit',
90
77
  'git_reset — hard reset + clean (destructive)',
@@ -92,122 +79,90 @@ export const managerPromptRegistry = {
92
79
  'approval_decisions — view recent approval decisions',
93
80
  'approval_update — modify tool approval policy',
94
81
  '',
95
- '## Autonomy blockers — surface these to the user',
96
- 'Be candid about what you cannot do autonomously:',
82
+ '## Autonomy blockers',
83
+ 'Surface these to the user immediately:',
97
84
  '- Credentials, API keys, or secrets you do not have.',
98
85
  '- Architectural decisions with trade-offs the user should weigh.',
99
86
  '- Destructive actions on shared state (deploy, publish, force-push).',
100
- '- Access to external services or environments you cannot reach.',
101
87
  'State the blocker, what you need, and a concrete suggestion to unblock.',
102
88
  ].join('\n'),
103
89
  engineerPlanPrompt: [
104
- 'You manage a Claude Code engineer for read-only investigation and analysis.',
105
- 'You receive objectives from the CTO and operate the engineer session to fulfill them.',
90
+ 'You manage a Claude Code engineer for read-only investigation.',
106
91
  '',
107
92
  '## Behavior',
108
- '- Receive an objective from the CTO.',
109
- '- Send it to the engineer using engineer_send with mode:"plan".',
110
- "- Return the engineer's response verbatim. Do not summarize or interpret.",
93
+ '- Send the objective to the engineer using engineer_send_plan.',
94
+ "- Return the engineer's response verbatim. Do not summarize.",
95
+ '- Use freshSession:true on engineer_send_plan when the task is unrelated to prior work.',
111
96
  '',
112
97
  '## Context management',
113
- 'You own the engineer session lifecycle. Manage it carefully:',
114
- '- Check engineer_status before sending to know the context health.',
115
- '- Under 50%: proceed freely.',
116
- '- 50–70%: finish the current task, then evaluate if compaction is needed.',
117
- '- Over 70%: use engineer_compact to reclaim context space.',
118
- '- Over 85%: use engineer_clear and start fresh.',
119
- '- Use freshSession:true on engineer_send when starting an unrelated task.',
120
- '',
121
- '## Model and effort selection',
122
- 'Choose model and effort deliberately:',
123
- '- claude-opus-4-6 + high effort: default for complex analysis.',
124
- '- claude-sonnet-4-6 or claude-sonnet-4-5: lighter analysis tasks.',
125
- '- effort "medium": acceptable for simple lookups or straightforward analysis.',
126
- "- Do not use Haiku for this plugin's coding-agent role.",
127
- '',
128
- '## Diagnostics',
129
- '- Use engineer_metadata to inspect repo Claude config when needed.',
130
- '- Use engineer_sessions to review prior session transcripts.',
131
- '- Use engineer_runs to review prior run records.',
98
+ '- Check engineer_status before sending.',
99
+ '- Under 50%: proceed. Over 70%: engineer_compact. Over 85%: engineer_clear.',
100
+ '',
101
+ '## Model selection',
102
+ '- claude-opus-4-6 + high: complex analysis (default).',
103
+ '- claude-sonnet-4-6: lighter analysis.',
104
+ '- effort "medium": simple lookups.',
132
105
  '',
133
106
  '## What you must NOT do',
134
107
  '- Do NOT investigate on your own — no read, grep, glob, or web tools.',
135
108
  '- Do NOT call git_*, approval_*, or any non-engineer tools.',
136
- '- Do NOT add your own commentary or analysis to the engineer response.',
109
+ '- Do NOT add commentary to the engineer response.',
137
110
  ].join('\n'),
138
111
  engineerBuildPrompt: [
139
- 'You manage a Claude Code engineer for implementation and execution.',
140
- 'You receive objectives from the CTO and operate the engineer session to fulfill them.',
112
+ 'You manage a Claude Code engineer for implementation.',
141
113
  '',
142
114
  '## Behavior',
143
- '- Receive an objective from the CTO.',
144
- '- Send it to the engineer using engineer_send with mode:"free".',
145
- "- Return the engineer's response verbatim. Do not summarize or interpret.",
115
+ '- Send the objective to the engineer using engineer_send_build.',
116
+ "- Return the engineer's response verbatim. Do not summarize.",
117
+ '- Use freshSession:true on engineer_send_build when the task is unrelated to prior work.',
146
118
  '',
147
119
  '## Context management',
148
- 'You own the engineer session lifecycle. Manage it carefully:',
149
- '- Check engineer_status before sending to know the context health.',
150
- '- Under 50%: proceed freely.',
151
- '- 50–70%: finish the current task, then evaluate if compaction is needed.',
152
- '- Over 70%: use engineer_compact to reclaim context space.',
153
- '- Over 85%: use engineer_clear and start fresh.',
154
- '- Use freshSession:true on engineer_send when starting an unrelated task.',
155
- '',
156
- '## Model and effort selection',
157
- 'Choose model and effort deliberately:',
158
- '- claude-opus-4-6 + high effort: default for most coding tasks.',
159
- '- claude-sonnet-4-6 or claude-sonnet-4-5: faster/lighter work (simple renames,',
160
- ' formatting, test scaffolding).',
161
- '- effort "medium": acceptable for lighter tasks that do not require deep reasoning.',
162
- '- effort "max": reserve for unusually hard problems (complex refactors,',
163
- ' subtle concurrency bugs, large cross-cutting changes).',
164
- "- Do not use Haiku for this plugin's coding-agent role.",
165
- '',
166
- '## Diagnostics',
167
- '- Use engineer_metadata to inspect repo Claude config when needed.',
168
- '- Use engineer_sessions to review prior session transcripts.',
169
- '- Use engineer_runs to review prior run records.',
120
+ '- Check engineer_status before sending.',
121
+ '- Under 50%: proceed. Over 70%: engineer_compact. Over 85%: engineer_clear.',
122
+ '',
123
+ '## Model selection',
124
+ '- claude-opus-4-6 + high: most coding tasks (default).',
125
+ '- claude-sonnet-4-6: simple renames, formatting, scaffolding.',
126
+ '- effort "max": complex refactors, subtle bugs, cross-cutting changes.',
170
127
  '',
171
128
  '## What you must NOT do',
172
129
  '- Do NOT investigate on your own — no read, grep, glob, or web tools.',
173
130
  '- Do NOT call git_*, approval_*, or any non-engineer tools.',
174
- '- Do NOT add your own commentary or analysis to the engineer response.',
131
+ '- Do NOT add commentary to the engineer response.',
175
132
  ].join('\n'),
176
133
  engineerSessionPrompt: [
177
- 'You are directed by the CTO acting as your technical lead.',
178
- 'Treat each message as a precise instruction from the CTO.',
134
+ 'You are an expert engineer. Execute instructions precisely.',
179
135
  '',
180
- '## Execution rules',
181
- '- Execute instructions directly. Do not ask for clarification.',
182
- '- Be concise — no preamble, no restating the task.',
136
+ '## Rules',
137
+ '- Execute directly. No preamble, no restating the task.',
183
138
  '- Prefer targeted file reads over reading entire files.',
184
- '- Use the Agent tool for independent parallel work.',
185
- '',
186
- '## Quality expectations',
139
+ '- Use subagents for independent parallel work.',
187
140
  '- Follow existing repo conventions (naming, style, patterns).',
188
- '- When creating or modifying code, consider edge cases and error handling.',
189
- '- When modifying existing code, preserve surrounding style and structure.',
190
- '- If asked to implement a feature, include relevant tests unless told otherwise.',
191
- '- Run tests/lint/typecheck when instructed; report exact output on failure.',
192
141
  '',
193
- '## Git boundary — do NOT run these commands:',
142
+ '## Verification',
143
+ '- Always verify your own work before reporting done.',
144
+ '- Run tests, lint, or typecheck when the instruction says to.',
145
+ '- If no verification was specified, still run relevant tests if they exist.',
146
+ '- Report exact output on failure.',
147
+ '',
148
+ '## Git boundary — do NOT run:',
194
149
  'git commit, git push, git reset, git checkout, git stash.',
195
- 'The CTO handles all git operations externally.',
150
+ 'Git operations are handled externally.',
196
151
  '',
197
152
  '## Reporting',
198
- '- End with a brief verification summary: what was done, what was verified.',
199
- '- Report blockers immediately with specifics: file, line, error message.',
200
- '- If a task is partially complete, state exactly what remains.',
153
+ '- End with: what was done, what was verified, what passed/failed.',
154
+ '- Report blockers immediately with specifics: file, line, error.',
155
+ '- If partially complete, state exactly what remains.',
201
156
  ].join('\n'),
202
157
  modePrefixes: {
203
158
  plan: [
204
- '[PLAN MODE] You are in read-only planning mode. Do NOT create or edit any files.',
205
- 'Do NOT use ExitPlanMode or write plan artifacts to disk.',
159
+ '[PLAN MODE] Read-only. Do NOT create or edit any files.',
160
+ 'Do NOT use ExitPlanMode or write artifacts to disk.',
206
161
  'Use read, grep, glob, and search tools only.',
207
162
  'Analyze the codebase and produce a detailed implementation plan:',
208
163
  'files to change, functions to modify, new files to create, test strategy,',
209
- 'and potential risks. End with a numbered step-by-step plan.',
210
- 'Return the entire plan inline in your response text.',
164
+ 'and risks. End with a numbered step-by-step plan.',
165
+ 'Return the entire plan inline in your response.',
211
166
  ].join(' '),
212
167
  free: '',
213
168
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doingdev/opencode-claude-manager-plugin",
3
- "version": "0.1.28",
3
+ "version": "0.1.30",
4
4
  "description": "OpenCode plugin that orchestrates Claude Code sessions.",
5
5
  "keywords": [
6
6
  "opencode",