@doingdev/opencode-claude-manager-plugin 0.1.15 → 0.1.16

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.
@@ -151,6 +151,7 @@ export class ClaudeAgentSdkAdapter {
151
151
  settingSources: input.settingSources,
152
152
  maxTurns: input.maxTurns,
153
153
  model: input.model,
154
+ effort: input.effort,
154
155
  permissionMode: input.permissionMode ?? 'acceptEdits',
155
156
  systemPrompt: input.systemPrompt
156
157
  ? { type: 'preset', preset: 'claude_code', append: input.systemPrompt }
@@ -0,0 +1,51 @@
1
+ import type { LiveTailEvent, ToolOutputPreview } from '../types/contracts.js';
2
+ /**
3
+ * Tails Claude Code session JSONL files for live tool output.
4
+ *
5
+ * The SDK streams high-level events (assistant text, tool_call summaries, results)
6
+ * but does not expose the raw tool output that Claude Code writes to the JSONL
7
+ * transcript on disk. This service fills that gap by polling the file for new
8
+ * lines, parsing each one, and forwarding parsed events to a caller-supplied
9
+ * callback.
10
+ */
11
+ export declare class SessionLiveTailer {
12
+ private activeTails;
13
+ /**
14
+ * Locate the JSONL file for a session.
15
+ *
16
+ * Claude Code stores transcripts at:
17
+ * ~/.claude/projects/<sanitized-cwd>/sessions/<session-id>.jsonl
18
+ *
19
+ * The `<sanitized-cwd>` folder name is an internal implementation detail that
20
+ * can change across Claude Code versions, so we search all project directories
21
+ * for the session file rather than attempting to replicate the sanitisation.
22
+ */
23
+ findSessionFile(sessionId: string, cwd?: string): string | null;
24
+ /**
25
+ * Check whether we can locate a JSONL file for the given session.
26
+ */
27
+ sessionFileExists(sessionId: string, cwd?: string): boolean;
28
+ /**
29
+ * Poll a session's JSONL file for new lines and emit parsed events.
30
+ *
31
+ * Returns a stop function. The caller **must** invoke it when tailing is no
32
+ * longer needed (e.g. when the session completes or the tool is interrupted).
33
+ */
34
+ startTailing(sessionId: string, cwd: string | undefined, onEvent: (event: LiveTailEvent) => void, pollIntervalMs?: number): () => void;
35
+ /**
36
+ * Stop tailing a specific session.
37
+ */
38
+ stopTailing(sessionId: string): void;
39
+ /**
40
+ * Stop all active tails (cleanup on shutdown).
41
+ */
42
+ stopAll(): void;
43
+ /**
44
+ * Read the last N lines from a session JSONL file.
45
+ */
46
+ getLastLines(sessionId: string, cwd: string | undefined, lineCount?: number): Promise<string[]>;
47
+ /**
48
+ * Extract a preview of recent tool output from the tail of a session file.
49
+ */
50
+ getToolOutputPreview(sessionId: string, cwd: string | undefined, maxEntries?: number): Promise<ToolOutputPreview[]>;
51
+ }
@@ -0,0 +1,269 @@
1
+ import { createReadStream, existsSync, readdirSync, statSync } from 'node:fs';
2
+ import { createInterface } from 'node:readline';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ /**
6
+ * Tails Claude Code session JSONL files for live tool output.
7
+ *
8
+ * The SDK streams high-level events (assistant text, tool_call summaries, results)
9
+ * but does not expose the raw tool output that Claude Code writes to the JSONL
10
+ * transcript on disk. This service fills that gap by polling the file for new
11
+ * lines, parsing each one, and forwarding parsed events to a caller-supplied
12
+ * callback.
13
+ */
14
+ export class SessionLiveTailer {
15
+ activeTails = new Map();
16
+ // ── Path discovery ──────────────────────────────────────────────────
17
+ /**
18
+ * Locate the JSONL file for a session.
19
+ *
20
+ * Claude Code stores transcripts at:
21
+ * ~/.claude/projects/<sanitized-cwd>/sessions/<session-id>.jsonl
22
+ *
23
+ * The `<sanitized-cwd>` folder name is an internal implementation detail that
24
+ * can change across Claude Code versions, so we search all project directories
25
+ * for the session file rather than attempting to replicate the sanitisation.
26
+ */
27
+ findSessionFile(sessionId, cwd) {
28
+ const projectsDir = path.join(os.homedir(), '.claude', 'projects');
29
+ if (!existsSync(projectsDir)) {
30
+ return null;
31
+ }
32
+ // If cwd is provided, try the sanitised form first (best-effort fast path).
33
+ if (cwd) {
34
+ const sanitised = cwd.replace(/\//g, '-');
35
+ const candidate = path.join(projectsDir, sanitised, 'sessions', `${sessionId}.jsonl`);
36
+ if (existsSync(candidate)) {
37
+ return candidate;
38
+ }
39
+ }
40
+ // Fall back to scanning all project directories.
41
+ try {
42
+ for (const entry of readdirSync(projectsDir, { withFileTypes: true })) {
43
+ if (!entry.isDirectory())
44
+ continue;
45
+ const candidate = path.join(projectsDir, entry.name, 'sessions', `${sessionId}.jsonl`);
46
+ if (existsSync(candidate)) {
47
+ return candidate;
48
+ }
49
+ }
50
+ }
51
+ catch {
52
+ // Permission denied or similar — nothing we can do.
53
+ }
54
+ return null;
55
+ }
56
+ /**
57
+ * Check whether we can locate a JSONL file for the given session.
58
+ */
59
+ sessionFileExists(sessionId, cwd) {
60
+ return this.findSessionFile(sessionId, cwd) !== null;
61
+ }
62
+ // ── Live tailing ────────────────────────────────────────────────────
63
+ /**
64
+ * Poll a session's JSONL file for new lines and emit parsed events.
65
+ *
66
+ * Returns a stop function. The caller **must** invoke it when tailing is no
67
+ * longer needed (e.g. when the session completes or the tool is interrupted).
68
+ */
69
+ startTailing(sessionId, cwd, onEvent, pollIntervalMs = 150) {
70
+ const filePath = this.findSessionFile(sessionId, cwd);
71
+ if (!filePath) {
72
+ onEvent({
73
+ type: 'error',
74
+ sessionId,
75
+ error: `Session JSONL not found for ${sessionId}`,
76
+ });
77
+ return () => { };
78
+ }
79
+ let offset = statSync(filePath).size;
80
+ let buffer = '';
81
+ let reading = false; // guard against overlapping reads
82
+ const interval = setInterval(() => {
83
+ if (reading)
84
+ return;
85
+ try {
86
+ const currentSize = statSync(filePath).size;
87
+ if (currentSize < offset) {
88
+ // File was truncated (rotation / compaction) — reset.
89
+ offset = 0;
90
+ buffer = '';
91
+ }
92
+ if (currentSize <= offset)
93
+ return;
94
+ reading = true;
95
+ const stream = createReadStream(filePath, {
96
+ start: offset,
97
+ end: currentSize - 1,
98
+ encoding: 'utf8',
99
+ });
100
+ let chunk = '';
101
+ stream.on('data', (data) => {
102
+ chunk += data;
103
+ });
104
+ stream.on('end', () => {
105
+ reading = false;
106
+ offset = currentSize;
107
+ buffer += chunk;
108
+ const lines = buffer.split('\n');
109
+ // Keep the last (possibly incomplete) segment in the buffer.
110
+ buffer = lines.pop() ?? '';
111
+ for (const line of lines) {
112
+ const trimmed = line.trim();
113
+ if (!trimmed)
114
+ continue;
115
+ try {
116
+ const parsed = JSON.parse(trimmed);
117
+ onEvent({
118
+ type: 'line',
119
+ sessionId,
120
+ data: parsed,
121
+ rawLine: trimmed,
122
+ });
123
+ }
124
+ catch {
125
+ onEvent({
126
+ type: 'line',
127
+ sessionId,
128
+ data: null,
129
+ rawLine: trimmed,
130
+ });
131
+ }
132
+ }
133
+ });
134
+ stream.on('error', (err) => {
135
+ reading = false;
136
+ onEvent({
137
+ type: 'error',
138
+ sessionId,
139
+ error: err.message,
140
+ });
141
+ });
142
+ }
143
+ catch (err) {
144
+ reading = false;
145
+ onEvent({
146
+ type: 'error',
147
+ sessionId,
148
+ error: err instanceof Error ? err.message : String(err),
149
+ });
150
+ }
151
+ }, pollIntervalMs);
152
+ this.activeTails.set(sessionId, interval);
153
+ return () => this.stopTailing(sessionId);
154
+ }
155
+ /**
156
+ * Stop tailing a specific session.
157
+ */
158
+ stopTailing(sessionId) {
159
+ const interval = this.activeTails.get(sessionId);
160
+ if (interval) {
161
+ clearInterval(interval);
162
+ this.activeTails.delete(sessionId);
163
+ }
164
+ }
165
+ /**
166
+ * Stop all active tails (cleanup on shutdown).
167
+ */
168
+ stopAll() {
169
+ for (const [, interval] of this.activeTails) {
170
+ clearInterval(interval);
171
+ }
172
+ this.activeTails.clear();
173
+ }
174
+ // ── Snapshot helpers ────────────────────────────────────────────────
175
+ /**
176
+ * Read the last N lines from a session JSONL file.
177
+ */
178
+ async getLastLines(sessionId, cwd, lineCount = 20) {
179
+ const filePath = this.findSessionFile(sessionId, cwd);
180
+ if (!filePath)
181
+ return [];
182
+ const lines = [];
183
+ const rl = createInterface({
184
+ input: createReadStream(filePath, { encoding: 'utf8' }),
185
+ });
186
+ for await (const line of rl) {
187
+ lines.push(line);
188
+ if (lines.length > lineCount) {
189
+ lines.shift();
190
+ }
191
+ }
192
+ return lines;
193
+ }
194
+ /**
195
+ * Extract a preview of recent tool output from the tail of a session file.
196
+ */
197
+ async getToolOutputPreview(sessionId, cwd, maxEntries = 5) {
198
+ const lastLines = await this.getLastLines(sessionId, cwd, 100);
199
+ const previews = [];
200
+ for (const line of lastLines) {
201
+ const trimmed = line.trim();
202
+ if (!trimmed)
203
+ continue;
204
+ try {
205
+ const parsed = JSON.parse(trimmed);
206
+ const preview = extractToolOutput(parsed);
207
+ if (preview) {
208
+ previews.push(preview);
209
+ }
210
+ }
211
+ catch {
212
+ // skip unparseable lines
213
+ }
214
+ }
215
+ return previews.slice(-maxEntries);
216
+ }
217
+ }
218
+ // ── Internal helpers ────────────────────────────────────────────────────
219
+ /**
220
+ * Attempt to extract tool output information from a JSONL record.
221
+ *
222
+ * Claude Code JSONL records with tool results can appear as:
223
+ * 1. A top-level `{ type: "user", message: { content: [{ type: "tool_result", ... }] } }`
224
+ * 2. Direct `tool_result` entries (less common).
225
+ */
226
+ function extractToolOutput(record) {
227
+ // Pattern 1: user message wrapping tool_result content blocks
228
+ if (record.type === 'user') {
229
+ const message = record.message;
230
+ if (!message)
231
+ return null;
232
+ const content = message.content;
233
+ if (!Array.isArray(content))
234
+ return null;
235
+ for (const block of content) {
236
+ if (block &&
237
+ typeof block === 'object' &&
238
+ block.type === 'tool_result') {
239
+ const b = block;
240
+ return {
241
+ toolUseId: typeof b.tool_use_id === 'string' ? b.tool_use_id : '',
242
+ content: stringifyContent(b.content),
243
+ isError: b.is_error === true,
244
+ };
245
+ }
246
+ }
247
+ }
248
+ // Pattern 2: direct tool_result record (varies by Claude Code version)
249
+ if (record.type === 'tool_result') {
250
+ return {
251
+ toolUseId: typeof record.tool_use_id === 'string' ? record.tool_use_id : '',
252
+ content: stringifyContent(record.content),
253
+ isError: record.is_error === true,
254
+ };
255
+ }
256
+ return null;
257
+ }
258
+ function stringifyContent(value) {
259
+ if (typeof value === 'string')
260
+ return value;
261
+ if (value === undefined || value === null)
262
+ return '';
263
+ try {
264
+ return JSON.stringify(value);
265
+ }
266
+ catch {
267
+ return String(value);
268
+ }
269
+ }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { Plugin } from '@opencode-ai/plugin';
2
2
  import { ClaudeManagerPlugin } from './plugin/claude-manager.plugin.js';
3
- export type { ClaudeCapabilitySnapshot, ClaudeMetadataSnapshot, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, ManagerPromptRegistry, RunClaudeSessionInput, SessionContextSnapshot, GitDiffResult, GitOperationResult, PersistentRunRecord, PersistentRunResult, ActiveSessionState, ContextWarningLevel, ToolApprovalRule, ToolApprovalPolicy, ToolApprovalDecision, } from './types/contracts.js';
3
+ export type { ClaudeCapabilitySnapshot, ClaudeMetadataSnapshot, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, ManagerPromptRegistry, RunClaudeSessionInput, SessionContextSnapshot, GitDiffResult, GitOperationResult, PersistentRunRecord, PersistentRunResult, ActiveSessionState, ContextWarningLevel, LiveTailEvent, ToolOutputPreview, ToolApprovalRule, ToolApprovalPolicy, ToolApprovalDecision, } from './types/contracts.js';
4
+ export { SessionLiveTailer } from './claude/session-live-tailer.js';
4
5
  export { ClaudeManagerPlugin };
5
6
  export declare const plugin: Plugin;
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  import { ClaudeManagerPlugin } from './plugin/claude-manager.plugin.js';
2
+ export { SessionLiveTailer } from './claude/session-live-tailer.js';
2
3
  export { ClaudeManagerPlugin };
3
4
  export const plugin = ClaudeManagerPlugin;
@@ -15,6 +15,7 @@ export declare class SessionController {
15
15
  */
16
16
  sendMessage(cwd: string, message: string, options?: {
17
17
  model?: string;
18
+ effort?: 'low' | 'medium' | 'high' | 'max';
18
19
  settingSources?: Array<'user' | 'project' | 'local'>;
19
20
  abortSignal?: AbortSignal;
20
21
  }, onEvent?: ClaudeSessionEventHandler): Promise<ClaudeSessionRunResult>;
@@ -29,6 +29,7 @@ export class SessionController {
29
29
  permissionMode: 'acceptEdits',
30
30
  includePartialMessages: true,
31
31
  model: options?.model,
32
+ effort: options?.effort,
32
33
  settingSources: options?.settingSources ?? ['user', 'project', 'local'],
33
34
  abortSignal: options?.abortSignal,
34
35
  };
@@ -37,8 +38,10 @@ export class SessionController {
37
38
  input.resumeSessionId = this.activeSessionId;
38
39
  }
39
40
  else {
40
- // New session — apply the expert operator system prompt
41
+ // New session — apply the expert operator system prompt and defaults
41
42
  input.systemPrompt = this.sessionPrompt;
43
+ input.model ??= 'claude-opus-4-6';
44
+ input.effort ??= 'high';
42
45
  }
43
46
  const result = await this.sdkAdapter.runSession(input, onEvent);
44
47
  // Track the session ID
@@ -214,6 +214,16 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
214
214
  metadata: { sessionId: result.sessionId },
215
215
  });
216
216
  }
217
+ // Fetch recent tool output from the JSONL file for richer feedback.
218
+ let toolOutputs = [];
219
+ if (result.sessionId) {
220
+ try {
221
+ toolOutputs = await services.liveTailer.getToolOutputPreview(result.sessionId, cwd, 3);
222
+ }
223
+ catch {
224
+ // Non-critical — the JSONL file may not exist yet.
225
+ }
226
+ }
217
227
  return JSON.stringify({
218
228
  sessionId: result.sessionId,
219
229
  finalText: result.finalText,
@@ -221,6 +231,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
221
231
  totalCostUsd: result.totalCostUsd,
222
232
  context: result.context,
223
233
  contextWarning,
234
+ toolOutputs: toolOutputs.length > 0 ? toolOutputs : undefined,
224
235
  }, null, 2);
225
236
  },
226
237
  }),
@@ -1,10 +1,12 @@
1
1
  import { ClaudeSessionService } from '../claude/claude-session.service.js';
2
+ import { SessionLiveTailer } from '../claude/session-live-tailer.js';
2
3
  import { ToolApprovalManager } from '../claude/tool-approval-manager.js';
3
4
  import { PersistentManager } from '../manager/persistent-manager.js';
4
5
  interface ClaudeManagerPluginServices {
5
6
  manager: PersistentManager;
6
7
  sessions: ClaudeSessionService;
7
8
  approvalManager: ToolApprovalManager;
9
+ liveTailer: SessionLiveTailer;
8
10
  }
9
11
  export declare function getOrCreatePluginServices(worktree: string): ClaudeManagerPluginServices;
10
12
  export {};
@@ -1,5 +1,6 @@
1
1
  import { ClaudeAgentSdkAdapter } from '../claude/claude-agent-sdk-adapter.js';
2
2
  import { ClaudeSessionService } from '../claude/claude-session.service.js';
3
+ import { SessionLiveTailer } from '../claude/session-live-tailer.js';
3
4
  import { ToolApprovalManager } from '../claude/tool-approval-manager.js';
4
5
  import { ClaudeMetadataService } from '../metadata/claude-metadata.service.js';
5
6
  import { RepoClaudeConfigReader } from '../metadata/repo-claude-config-reader.js';
@@ -28,10 +29,12 @@ export function getOrCreatePluginServices(worktree) {
28
29
  const manager = new PersistentManager(sessionController, gitOps, stateStore, contextTracker, transcriptStore);
29
30
  // Try to restore active session state (fire and forget)
30
31
  manager.tryRestore(worktree).catch(() => { });
32
+ const liveTailer = new SessionLiveTailer();
31
33
  const services = {
32
34
  manager,
33
35
  sessions: sessionService,
34
36
  approvalManager,
37
+ liveTailer,
35
38
  };
36
39
  serviceCache.set(worktree, services);
37
40
  return services;
@@ -1,41 +1,122 @@
1
1
  export const managerPromptRegistry = {
2
2
  managerSystemPrompt: [
3
- 'You orchestrate Claude Code through a persistent session. You are a user proxy —',
4
- 'your job is to make Claude Code do the work, not to do it yourself.',
3
+ 'You are a senior IC operating Claude Code through a persistent session.',
4
+ 'Your job is to make Claude Code do the work not to write code yourself.',
5
+ 'Think like a staff engineer: correctness, maintainability, tests, rollback safety,',
6
+ 'and clear communication to the user.',
5
7
  '',
6
- '## Workflow',
7
- '1. claude_manager_send send clear, specific instructions',
8
- '2. claude_manager_git_diff review what changed',
9
- '3. claude_manager_git_commit checkpoint good work',
10
- '4. claude_manager_git_reset discard bad work',
11
- '5. claude_manager_clear fresh session when needed',
8
+ '## Decision loop',
9
+ 'On every turn, choose exactly one action:',
10
+ ' investigateread files, grep, search the codebase to build context',
11
+ ' delegate — send a focused instruction to Claude Code via claude_manager_send',
12
+ ' review — run claude_manager_git_diff to inspect what changed',
13
+ ' validate — tell Claude Code to run tests, lint, or typecheck',
14
+ ' commit — checkpoint good work with claude_manager_git_commit',
15
+ ' correct — send a targeted fix instruction (never "try again")',
16
+ ' reset — discard bad work with claude_manager_git_reset',
17
+ ' ask — ask the user one narrow, high-value question',
18
+ '',
19
+ 'Default order: investigate → delegate → review → validate → commit.',
20
+ 'Skip steps only when you have strong evidence they are unnecessary.',
21
+ '',
22
+ '## Before you delegate',
23
+ '1. Read the relevant files yourself (you have read, grep, glob).',
24
+ ' For broad investigations, scope them narrowly or use subagents to avoid',
25
+ ' polluting your own context with excessive file contents.',
26
+ '2. Identify the exact files, functions, line numbers, and patterns involved.',
27
+ '3. Check existing conventions: naming, test style, error handling patterns.',
28
+ '4. Craft an instruction that a senior engineer would find unambiguous.',
29
+ ' Bad: "Fix the auth bug"',
30
+ ' Good: "In src/auth/session.ts, the `validateToken` function (line 42)',
31
+ ' throws on expired tokens instead of returning null. Change it to',
32
+ ' return null and update the caller in src/routes/login.ts:87."',
33
+ '',
34
+ '## After delegation — mandatory review',
35
+ 'Never claim success without evidence:',
36
+ '1. claude_manager_git_diff — read the actual diff, not just the summary.',
37
+ '2. Verify the diff matches what you asked for. Check for:',
38
+ ' - Unintended changes or regressions',
39
+ ' - Missing test updates',
40
+ ' - Style violations against repo conventions',
41
+ '3. If changes look correct, tell Claude Code to run tests/lint/typecheck.',
42
+ '4. Only commit after verification passes.',
43
+ '5. If the diff is wrong: send a specific correction or reset.',
44
+ '',
45
+ '## Handling ambiguity',
46
+ 'When requirements are unclear:',
47
+ '1. First, try to resolve it yourself — read code, check tests, grep for usage.',
48
+ '2. If ambiguity remains, ask the user ONE specific question.',
49
+ ' Bad: "What should I do?"',
50
+ ' Good: "The `UserService` has both `deactivate()` and `softDelete()` —',
51
+ ' should the new endpoint use deactivation (reversible) or',
52
+ ' soft-delete (audit-logged)?"',
53
+ '3. Never block on multiple questions at once.',
54
+ '',
55
+ '## Correction and recovery',
56
+ 'If Claude Code produces wrong output:',
57
+ '1. First correction: send a specific, targeted fix instruction.',
58
+ '2. Second correction on the same issue: reset, clear the session,',
59
+ ' and rewrite the prompt incorporating lessons from both failures.',
60
+ 'Never send three corrections for the same problem in one session.',
61
+ '',
62
+ '## Multi-step tasks',
63
+ '- Decompose large tasks into sequential focused instructions.',
64
+ '- Commit after each successful step (checkpoint for rollback).',
65
+ '- Tell Claude Code to use subagents for independent parallel work.',
66
+ '- For complex design decisions, tell Claude Code to "think hard".',
67
+ '- Prefer small diffs — they are easier to review and safer to ship.',
12
68
  '',
13
69
  '## Context management',
14
- 'Check the context snapshot in each send result:',
15
- '- Under 50%: proceed freely',
16
- '- 50-70%: consider if next task should reuse or start fresh',
17
- '- Over 70%: compact or clear before heavy work',
18
- '- Over 85% or 200k tokens: clear immediately',
19
- '',
20
- '## Delegation principles',
21
- '- Write specific task descriptions with file paths, function names, error messages',
22
- '- For large features, send sequential focused instructions',
23
- '- Tell Claude Code to use subagents for parallel/independent parts',
24
- '- After implementation, always review with git diff before committing',
25
- '- If work is wrong, send a correction (specific, not "try again") or reset',
70
+ 'Check the context snapshot returned by each send:',
71
+ '- Under 50%: proceed freely.',
72
+ '- 5070%: finish current step, then evaluate if a fresh session is needed.',
73
+ '- Over 70%: compact or clear before sending heavy instructions.',
74
+ '- Over 85%: clear the session immediately.',
75
+ '',
76
+ '## Tools reference',
77
+ 'claude_manager_send — send instruction (creates or resumes session)',
78
+ 'claude_manager_git_diff review all uncommitted changes',
79
+ 'claude_manager_git_commit stage all + commit',
80
+ 'claude_manager_git_reset — hard reset + clean (destructive)',
81
+ 'claude_manager_clear — drop session, next send starts fresh',
82
+ 'claude_manager_status — context health snapshot',
83
+ 'claude_manager_metadata — inspect repo Claude config',
84
+ 'claude_manager_sessions — list sessions or read transcripts',
85
+ 'claude_manager_runs — list or inspect run records',
86
+ '',
87
+ '## Autonomy blockers — surface these to the user',
88
+ 'Be candid about what you cannot do autonomously:',
89
+ '- Credentials, API keys, or secrets you do not have.',
90
+ '- Architectural decisions with trade-offs the user should weigh.',
91
+ '- Destructive actions on shared state (deploy, publish, force-push).',
92
+ '- Access to external services or environments you cannot reach.',
93
+ 'State the blocker, what you need, and a concrete suggestion to unblock.',
26
94
  ].join('\n'),
27
95
  claudeCodeSessionPrompt: [
28
- 'You are being directed by an expert automated operator. Treat each message',
29
- 'as a precise instruction from a skilled Claude Code user.',
30
- '',
31
- 'Key behaviors:',
32
- '- Execute instructions directly without asking for clarification',
33
- '- Use the Agent tool to spawn subagents for parallel/independent work',
34
- '- Be concise no preamble, no restating the task',
35
- '- Do NOT run git commit, git push, or git reset — the operator handles git',
36
- '- After completing work, end with a brief verification summary',
37
- '- When context is heavy, prefer targeted file reads over reading entire files',
38
- '- Report blockers immediately and specifically',
96
+ 'You are directed by an expert automated operator.',
97
+ 'Treat each message as a precise instruction from a senior engineer.',
98
+ '',
99
+ '## Execution rules',
100
+ '- Execute instructions directly. Do not ask for clarification.',
101
+ '- Be concise no preamble, no restating the task.',
102
+ '- Prefer targeted file reads over reading entire files.',
103
+ '- Use the Agent tool for independent parallel work.',
104
+ '',
105
+ '## Quality expectations',
106
+ '- Follow existing repo conventions (naming, style, patterns).',
107
+ '- When creating or modifying code, consider edge cases and error handling.',
108
+ '- When modifying existing code, preserve surrounding style and structure.',
109
+ '- If asked to implement a feature, include relevant tests unless told otherwise.',
110
+ '- Run tests/lint/typecheck when instructed; report exact output on failure.',
111
+ '',
112
+ '## Git boundary — do NOT run these commands:',
113
+ 'git commit, git push, git reset, git checkout, git stash.',
114
+ 'The operator manages all git operations externally.',
115
+ '',
116
+ '## Reporting',
117
+ '- End with a brief verification summary: what was done, what was verified.',
118
+ '- Report blockers immediately with specifics: file, line, error message.',
119
+ '- If a task is partially complete, state exactly what remains.',
39
120
  ].join('\n'),
40
121
  contextWarnings: {
41
122
  moderate: 'Session context is filling up ({percent}% estimated). Consider whether a fresh session would be more efficient.',
@@ -57,6 +57,7 @@ export interface RunClaudeSessionInput {
57
57
  prompt: string;
58
58
  systemPrompt?: string;
59
59
  model?: string;
60
+ effort?: 'low' | 'medium' | 'high' | 'max';
60
61
  permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'dontAsk';
61
62
  allowedTools?: string[];
62
63
  disallowedTools?: string[];
@@ -167,6 +168,18 @@ export interface PersistentRunRecord {
167
168
  export interface PersistentRunResult {
168
169
  run: PersistentRunRecord;
169
170
  }
171
+ export interface LiveTailEvent {
172
+ type: 'line' | 'error' | 'end';
173
+ sessionId: string;
174
+ data?: unknown;
175
+ rawLine?: string;
176
+ error?: string;
177
+ }
178
+ export interface ToolOutputPreview {
179
+ toolUseId: string;
180
+ content: string;
181
+ isError: boolean;
182
+ }
170
183
  export interface ToolApprovalRule {
171
184
  id: string;
172
185
  description?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doingdev/opencode-claude-manager-plugin",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "OpenCode plugin that orchestrates Claude Code sessions.",
5
5
  "keywords": [
6
6
  "opencode",