@doingdev/opencode-claude-manager-plugin 0.1.16 → 0.1.17
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/dist/claude/claude-agent-sdk-adapter.js +30 -0
- package/dist/index.d.ts +1 -1
- package/dist/manager/persistent-manager.d.ts +1 -0
- package/dist/manager/session-controller.d.ts +7 -2
- package/dist/manager/session-controller.js +11 -3
- package/dist/plugin/claude-manager.plugin.js +65 -2
- package/dist/plugin/service-factory.js +1 -1
- package/dist/prompts/registry.js +10 -0
- package/dist/types/contracts.d.ts +7 -1
- package/package.json +1 -1
|
@@ -245,6 +245,36 @@ function normalizeSdkMessages(message, includePartials) {
|
|
|
245
245
|
if (message.type === 'user') {
|
|
246
246
|
return normalizeUserSdkMessage(message, sessionId);
|
|
247
247
|
}
|
|
248
|
+
if (message.type === 'tool_progress') {
|
|
249
|
+
const toolName = 'tool_name' in message && typeof message.tool_name === 'string'
|
|
250
|
+
? message.tool_name
|
|
251
|
+
: 'tool';
|
|
252
|
+
const elapsed = 'elapsed_time_seconds' in message &&
|
|
253
|
+
typeof message.elapsed_time_seconds === 'number'
|
|
254
|
+
? message.elapsed_time_seconds
|
|
255
|
+
: 0;
|
|
256
|
+
return [
|
|
257
|
+
{
|
|
258
|
+
type: 'tool_progress',
|
|
259
|
+
sessionId,
|
|
260
|
+
text: JSON.stringify({ name: toolName, elapsed }),
|
|
261
|
+
rawType: message.type,
|
|
262
|
+
},
|
|
263
|
+
];
|
|
264
|
+
}
|
|
265
|
+
if (message.type === 'tool_use_summary') {
|
|
266
|
+
const summary = 'summary' in message && typeof message.summary === 'string'
|
|
267
|
+
? message.summary
|
|
268
|
+
: '';
|
|
269
|
+
return [
|
|
270
|
+
{
|
|
271
|
+
type: 'tool_summary',
|
|
272
|
+
sessionId,
|
|
273
|
+
text: summary,
|
|
274
|
+
rawType: message.type,
|
|
275
|
+
},
|
|
276
|
+
];
|
|
277
|
+
}
|
|
248
278
|
return [
|
|
249
279
|
{
|
|
250
280
|
type: 'system',
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +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, LiveTailEvent, ToolOutputPreview, ToolApprovalRule, ToolApprovalPolicy, ToolApprovalDecision, } from './types/contracts.js';
|
|
3
|
+
export type { ClaudeCapabilitySnapshot, ClaudeMetadataSnapshot, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, ManagerPromptRegistry, RunClaudeSessionInput, SessionContextSnapshot, GitDiffResult, GitOperationResult, PersistentRunRecord, PersistentRunResult, ActiveSessionState, ContextWarningLevel, SessionMode, LiveTailEvent, ToolOutputPreview, ToolApprovalRule, ToolApprovalPolicy, ToolApprovalDecision, } from './types/contracts.js';
|
|
4
4
|
export { SessionLiveTailer } from './claude/session-live-tailer.js';
|
|
5
5
|
export { ClaudeManagerPlugin };
|
|
6
6
|
export declare const plugin: Plugin;
|
|
@@ -19,6 +19,7 @@ export declare class PersistentManager {
|
|
|
19
19
|
*/
|
|
20
20
|
sendMessage(cwd: string, message: string, options?: {
|
|
21
21
|
model?: string;
|
|
22
|
+
mode?: 'plan' | 'free';
|
|
22
23
|
abortSignal?: AbortSignal;
|
|
23
24
|
}, onEvent?: ClaudeSessionEventHandler): Promise<{
|
|
24
25
|
sessionId: string | undefined;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { ClaudeAgentSdkAdapter, ClaudeSessionEventHandler } from '../claude/claude-agent-sdk-adapter.js';
|
|
2
|
-
import type { ClaudeSessionRunResult, SessionContextSnapshot } from '../types/contracts.js';
|
|
2
|
+
import type { ClaudeSessionRunResult, SessionContextSnapshot, SessionMode } from '../types/contracts.js';
|
|
3
3
|
import type { ContextTracker } from './context-tracker.js';
|
|
4
4
|
export declare class SessionController {
|
|
5
5
|
private readonly sdkAdapter;
|
|
6
6
|
private readonly contextTracker;
|
|
7
7
|
private readonly sessionPrompt;
|
|
8
|
+
private readonly modePrefixes;
|
|
8
9
|
private activeSessionId;
|
|
9
|
-
constructor(sdkAdapter: ClaudeAgentSdkAdapter, contextTracker: ContextTracker, sessionPrompt: string
|
|
10
|
+
constructor(sdkAdapter: ClaudeAgentSdkAdapter, contextTracker: ContextTracker, sessionPrompt: string, modePrefixes?: {
|
|
11
|
+
plan: string;
|
|
12
|
+
free: string;
|
|
13
|
+
});
|
|
10
14
|
get isActive(): boolean;
|
|
11
15
|
get sessionId(): string | null;
|
|
12
16
|
/**
|
|
@@ -16,6 +20,7 @@ export declare class SessionController {
|
|
|
16
20
|
sendMessage(cwd: string, message: string, options?: {
|
|
17
21
|
model?: string;
|
|
18
22
|
effort?: 'low' | 'medium' | 'high' | 'max';
|
|
23
|
+
mode?: SessionMode;
|
|
19
24
|
settingSources?: Array<'user' | 'project' | 'local'>;
|
|
20
25
|
abortSignal?: AbortSignal;
|
|
21
26
|
}, onEvent?: ClaudeSessionEventHandler): Promise<ClaudeSessionRunResult>;
|
|
@@ -5,11 +5,16 @@ export class SessionController {
|
|
|
5
5
|
sdkAdapter;
|
|
6
6
|
contextTracker;
|
|
7
7
|
sessionPrompt;
|
|
8
|
+
modePrefixes;
|
|
8
9
|
activeSessionId = null;
|
|
9
|
-
constructor(sdkAdapter, contextTracker, sessionPrompt
|
|
10
|
+
constructor(sdkAdapter, contextTracker, sessionPrompt, modePrefixes = {
|
|
11
|
+
plan: '',
|
|
12
|
+
free: '',
|
|
13
|
+
}) {
|
|
10
14
|
this.sdkAdapter = sdkAdapter;
|
|
11
15
|
this.contextTracker = contextTracker;
|
|
12
16
|
this.sessionPrompt = sessionPrompt;
|
|
17
|
+
this.modePrefixes = modePrefixes;
|
|
13
18
|
}
|
|
14
19
|
get isActive() {
|
|
15
20
|
return this.activeSessionId !== null;
|
|
@@ -22,11 +27,14 @@ export class SessionController {
|
|
|
22
27
|
* Returns the session result including usage data.
|
|
23
28
|
*/
|
|
24
29
|
async sendMessage(cwd, message, options, onEvent) {
|
|
30
|
+
const mode = options?.mode ?? 'free';
|
|
31
|
+
const prefix = this.modePrefixes[mode];
|
|
32
|
+
const prompt = prefix ? `${prefix}\n\n${message}` : message;
|
|
25
33
|
const input = {
|
|
26
34
|
cwd,
|
|
27
|
-
prompt
|
|
35
|
+
prompt,
|
|
28
36
|
persistSession: true,
|
|
29
|
-
permissionMode: 'acceptEdits',
|
|
37
|
+
permissionMode: mode === 'plan' ? 'plan' : 'acceptEdits',
|
|
30
38
|
includePartialMessages: true,
|
|
31
39
|
model: options?.model,
|
|
32
40
|
effort: options?.effort,
|
|
@@ -107,10 +107,13 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
107
107
|
claude_manager_send: tool({
|
|
108
108
|
description: 'Send a message to the persistent Claude Code session. ' +
|
|
109
109
|
'Auto-creates a session on first call. Resumes the existing session on subsequent calls. ' +
|
|
110
|
-
'Returns the assistant response and current context health snapshot.'
|
|
110
|
+
'Returns the assistant response and current context health snapshot. ' +
|
|
111
|
+
'Use mode "plan" for read-only investigation and planning (no edits), ' +
|
|
112
|
+
'or "free" (default) for normal execution with edit permissions.',
|
|
111
113
|
args: {
|
|
112
114
|
message: tool.schema.string().min(1),
|
|
113
115
|
model: tool.schema.string().optional(),
|
|
116
|
+
mode: tool.schema.enum(['plan', 'free']).default('free'),
|
|
114
117
|
cwd: tool.schema.string().optional(),
|
|
115
118
|
},
|
|
116
119
|
async execute(args, context) {
|
|
@@ -130,7 +133,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
130
133
|
});
|
|
131
134
|
let turnsSoFar = 0;
|
|
132
135
|
let costSoFar = 0;
|
|
133
|
-
const result = await services.manager.sendMessage(cwd, args.message, { model: args.model, abortSignal: context.abort }, (event) => {
|
|
136
|
+
const result = await services.manager.sendMessage(cwd, args.message, { model: args.model, mode: args.mode, abortSignal: context.abort }, (event) => {
|
|
134
137
|
if (event.turns !== undefined) {
|
|
135
138
|
turnsSoFar = event.turns;
|
|
136
139
|
}
|
|
@@ -189,6 +192,66 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
|
|
|
189
192
|
},
|
|
190
193
|
});
|
|
191
194
|
}
|
|
195
|
+
else if (event.type === 'user') {
|
|
196
|
+
const preview = event.text.length > 200
|
|
197
|
+
? event.text.slice(0, 200) + '...'
|
|
198
|
+
: event.text;
|
|
199
|
+
context.metadata({
|
|
200
|
+
title: `Claude Code: Tool result (${turnsSoFar} turns, ${costLabel})`,
|
|
201
|
+
metadata: {
|
|
202
|
+
sessionId: event.sessionId,
|
|
203
|
+
type: event.type,
|
|
204
|
+
output: preview,
|
|
205
|
+
},
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
else if (event.type === 'tool_progress') {
|
|
209
|
+
let toolName = 'tool';
|
|
210
|
+
let elapsed = 0;
|
|
211
|
+
try {
|
|
212
|
+
const parsed = JSON.parse(event.text);
|
|
213
|
+
toolName = parsed.name ?? 'tool';
|
|
214
|
+
elapsed = parsed.elapsed ?? 0;
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
// ignore
|
|
218
|
+
}
|
|
219
|
+
context.metadata({
|
|
220
|
+
title: `Claude Code: ${toolName} running ${elapsed > 0 ? `(${elapsed.toFixed(0)}s)` : ''}... (${turnsSoFar} turns, ${costLabel})`,
|
|
221
|
+
metadata: {
|
|
222
|
+
sessionId: event.sessionId,
|
|
223
|
+
type: event.type,
|
|
224
|
+
tool: toolName,
|
|
225
|
+
elapsed,
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
else if (event.type === 'tool_summary') {
|
|
230
|
+
const summary = event.text.length > 200
|
|
231
|
+
? event.text.slice(0, 200) + '...'
|
|
232
|
+
: event.text;
|
|
233
|
+
context.metadata({
|
|
234
|
+
title: `Claude Code: Tool done (${turnsSoFar} turns, ${costLabel})`,
|
|
235
|
+
metadata: {
|
|
236
|
+
sessionId: event.sessionId,
|
|
237
|
+
type: event.type,
|
|
238
|
+
summary,
|
|
239
|
+
},
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
else if (event.type === 'partial') {
|
|
243
|
+
const delta = event.text.length > 200
|
|
244
|
+
? event.text.slice(0, 200) + '...'
|
|
245
|
+
: event.text;
|
|
246
|
+
context.metadata({
|
|
247
|
+
title: `Claude Code: Writing... (${turnsSoFar} turns, ${costLabel})`,
|
|
248
|
+
metadata: {
|
|
249
|
+
sessionId: event.sessionId,
|
|
250
|
+
type: event.type,
|
|
251
|
+
delta,
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
}
|
|
192
255
|
else if (event.type === 'error') {
|
|
193
256
|
context.metadata({
|
|
194
257
|
title: `Claude Code: Error`,
|
|
@@ -22,7 +22,7 @@ export function getOrCreatePluginServices(worktree) {
|
|
|
22
22
|
const metadataService = new ClaudeMetadataService(new RepoClaudeConfigReader(), sdkAdapter);
|
|
23
23
|
const sessionService = new ClaudeSessionService(sdkAdapter, metadataService);
|
|
24
24
|
const contextTracker = new ContextTracker();
|
|
25
|
-
const sessionController = new SessionController(sdkAdapter, contextTracker, managerPromptRegistry.claudeCodeSessionPrompt);
|
|
25
|
+
const sessionController = new SessionController(sdkAdapter, contextTracker, managerPromptRegistry.claudeCodeSessionPrompt, managerPromptRegistry.modePrefixes);
|
|
26
26
|
const gitOps = new GitOperations(worktree);
|
|
27
27
|
const stateStore = new FileRunStateStore();
|
|
28
28
|
const transcriptStore = new TranscriptStore();
|
package/dist/prompts/registry.js
CHANGED
|
@@ -118,6 +118,16 @@ export const managerPromptRegistry = {
|
|
|
118
118
|
'- Report blockers immediately with specifics: file, line, error message.',
|
|
119
119
|
'- If a task is partially complete, state exactly what remains.',
|
|
120
120
|
].join('\n'),
|
|
121
|
+
modePrefixes: {
|
|
122
|
+
plan: [
|
|
123
|
+
'[PLAN MODE] You are in read-only planning mode. Do NOT create or edit any files.',
|
|
124
|
+
'Use read, grep, glob, and search tools only.',
|
|
125
|
+
'Analyze the codebase and produce a detailed implementation plan:',
|
|
126
|
+
'files to change, functions to modify, new files to create, test strategy,',
|
|
127
|
+
'and potential risks. End with a numbered step-by-step plan.',
|
|
128
|
+
].join(' '),
|
|
129
|
+
free: '',
|
|
130
|
+
},
|
|
121
131
|
contextWarnings: {
|
|
122
132
|
moderate: 'Session context is filling up ({percent}% estimated). Consider whether a fresh session would be more efficient.',
|
|
123
133
|
high: 'Session context is heavy ({percent}% estimated, {turns} turns, ${cost}). Start a new session or compact first.',
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export interface ManagerPromptRegistry {
|
|
2
2
|
managerSystemPrompt: string;
|
|
3
3
|
claudeCodeSessionPrompt: string;
|
|
4
|
+
modePrefixes: {
|
|
5
|
+
plan: string;
|
|
6
|
+
free: string;
|
|
7
|
+
};
|
|
4
8
|
contextWarnings: {
|
|
5
9
|
moderate: string;
|
|
6
10
|
high: string;
|
|
@@ -8,6 +12,7 @@ export interface ManagerPromptRegistry {
|
|
|
8
12
|
};
|
|
9
13
|
}
|
|
10
14
|
export type ClaudeSettingSource = 'user' | 'project' | 'local';
|
|
15
|
+
export type SessionMode = 'plan' | 'free';
|
|
11
16
|
export interface ClaudeCommandMetadata {
|
|
12
17
|
name: string;
|
|
13
18
|
description: string;
|
|
@@ -44,7 +49,7 @@ export interface ClaudeMetadataSnapshot {
|
|
|
44
49
|
settingsPaths: string[];
|
|
45
50
|
}
|
|
46
51
|
export interface ClaudeSessionEvent {
|
|
47
|
-
type: 'init' | 'assistant' | 'partial' | 'user' | 'tool_call' | 'status' | 'system' | 'result' | 'error';
|
|
52
|
+
type: 'init' | 'assistant' | 'partial' | 'user' | 'tool_call' | 'tool_progress' | 'tool_summary' | 'status' | 'system' | 'result' | 'error';
|
|
48
53
|
sessionId?: string;
|
|
49
54
|
text: string;
|
|
50
55
|
turns?: number;
|
|
@@ -58,6 +63,7 @@ export interface RunClaudeSessionInput {
|
|
|
58
63
|
systemPrompt?: string;
|
|
59
64
|
model?: string;
|
|
60
65
|
effort?: 'low' | 'medium' | 'high' | 'max';
|
|
66
|
+
mode?: SessionMode;
|
|
61
67
|
permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'dontAsk';
|
|
62
68
|
allowedTools?: string[];
|
|
63
69
|
disallowedTools?: string[];
|