@doingdev/opencode-claude-manager-plugin 0.1.44 → 0.1.46

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/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, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, ManagerPromptRegistry, RunClaudeSessionInput, SessionContextSnapshot, GitDiffResult, GitOperationResult, PersistentRunRecord, PersistentRunResult, AgentSlotType, RunningTask, SlotStatus, ManagerStatus, ContextWarningLevel, SessionMode, LiveTailEvent, ToolOutputPreview, ToolApprovalRule, ToolApprovalPolicy, ToolApprovalDecision, } from './types/contracts.js';
3
+ export type { ClaudeCapabilitySnapshot, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, ManagerPromptRegistry, RunClaudeSessionInput, SessionContextSnapshot, GitDiffResult, GitOperationResult, PersistentRunRecord, PersistentRunResult, 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;
@@ -1,4 +1,4 @@
1
- import type { AgentSlotType, ClaudeSessionEvent, ClaudeSessionRunResult, GitDiffResult, GitOperationResult, ManagerStatus, PersistentRunRecord, PersistentRunResult, RunningTask, SessionContextSnapshot, SlotStatus } from '../types/contracts.js';
1
+ import type { ClaudeSessionEvent, ClaudeSessionRunResult, PersistentRunRecord, PersistentRunResult, SessionContextSnapshot, GitDiffResult, GitOperationResult } from '../types/contracts.js';
2
2
  import type { ClaudeSessionEventHandler } from '../claude/claude-agent-sdk-adapter.js';
3
3
  import type { FileRunStateStore } from '../state/file-run-state-store.js';
4
4
  import type { TranscriptStore } from '../state/transcript-store.js';
@@ -12,10 +12,6 @@ export declare class PersistentManager {
12
12
  private readonly stateStore;
13
13
  private readonly contextTracker;
14
14
  private readonly transcriptStore;
15
- private static readonly slotCounts;
16
- private static readonly slotWaiters;
17
- private static readonly runningTaskList;
18
- private static readonly SLOT_MAXIMA;
19
15
  constructor(sessionController: SessionController, gitOps: GitOperations, stateStore: FileRunStateStore, contextTracker: ContextTracker, transcriptStore: TranscriptStore);
20
16
  /**
21
17
  * Send a message to the persistent Claude Code session.
@@ -65,25 +61,9 @@ export declare class PersistentManager {
65
61
  */
66
62
  gitReset(): Promise<GitOperationResult>;
67
63
  /**
68
- * Get current session status, context health, and slot usage.
64
+ * Get current session status and context health.
69
65
  */
70
- getStatus(): ManagerStatus;
71
- /**
72
- * Acquire a concurrency slot. Blocks if at capacity (implement=1, verify=5, explore=unlimited).
73
- */
74
- acquireSlot(slotType: AgentSlotType, taskDescription?: string): Promise<void>;
75
- /**
76
- * Release a concurrency slot. Wakes the next waiter if any.
77
- */
78
- releaseSlot(slotType: AgentSlotType, taskDescription?: string): void;
79
- /**
80
- * Get current slot usage across all agent types.
81
- */
82
- getSlotStatus(): SlotStatus;
83
- /**
84
- * List all currently running tasks with their slot types.
85
- */
86
- listRunningTasks(): RunningTask[];
66
+ getStatus(): SessionContextSnapshot;
87
67
  /**
88
68
  * Clear the active session. Next send creates a fresh one.
89
69
  */
@@ -5,19 +5,6 @@ export class PersistentManager {
5
5
  stateStore;
6
6
  contextTracker;
7
7
  transcriptStore;
8
- // --- Slot tracking (static — shared across all instances) ---
9
- static slotCounts = new Map([
10
- ['implement', 0],
11
- ['verify', 0],
12
- ['explore', 0],
13
- ]);
14
- static slotWaiters = new Map();
15
- static runningTaskList = [];
16
- static SLOT_MAXIMA = {
17
- implement: 1,
18
- verify: 5,
19
- explore: Infinity,
20
- };
21
8
  constructor(sessionController, gitOps, stateStore, contextTracker, transcriptStore) {
22
9
  this.sessionController = sessionController;
23
10
  this.gitOps = gitOps;
@@ -76,90 +63,10 @@ export class PersistentManager {
76
63
  return this.gitOps.resetHard();
77
64
  }
78
65
  /**
79
- * Get current session status, context health, and slot usage.
66
+ * Get current session status and context health.
80
67
  */
81
68
  getStatus() {
82
- return {
83
- context: this.sessionController.getContextSnapshot(),
84
- slotStatus: this.getSlotStatus(),
85
- runningTasks: this.listRunningTasks(),
86
- };
87
- }
88
- /**
89
- * Acquire a concurrency slot. Blocks if at capacity (implement=1, verify=5, explore=unlimited).
90
- */
91
- async acquireSlot(slotType, taskDescription) {
92
- const max = PersistentManager.SLOT_MAXIMA[slotType];
93
- const current = PersistentManager.slotCounts.get(slotType) ?? 0;
94
- if (current < max) {
95
- PersistentManager.slotCounts.set(slotType, current + 1);
96
- }
97
- else {
98
- // At capacity — wait for a slot to be transferred by releaseSlot
99
- await new Promise((resolve) => {
100
- let waiters = PersistentManager.slotWaiters.get(slotType);
101
- if (!waiters) {
102
- waiters = [];
103
- PersistentManager.slotWaiters.set(slotType, waiters);
104
- }
105
- waiters.push(resolve);
106
- });
107
- // Slot was transferred — count stays the same
108
- }
109
- if (taskDescription) {
110
- PersistentManager.runningTaskList.push({
111
- slotType,
112
- task: taskDescription,
113
- startedAt: new Date().toISOString(),
114
- });
115
- }
116
- }
117
- /**
118
- * Release a concurrency slot. Wakes the next waiter if any.
119
- */
120
- releaseSlot(slotType, taskDescription) {
121
- if (taskDescription) {
122
- const idx = PersistentManager.runningTaskList.findIndex((t) => t.slotType === slotType && t.task === taskDescription);
123
- if (idx !== -1) {
124
- PersistentManager.runningTaskList.splice(idx, 1);
125
- }
126
- }
127
- const waiters = PersistentManager.slotWaiters.get(slotType);
128
- if (waiters && waiters.length > 0) {
129
- // Transfer the slot directly to the next waiter (don't decrement count)
130
- const next = waiters.shift();
131
- next();
132
- }
133
- else {
134
- const current = PersistentManager.slotCounts.get(slotType) ?? 0;
135
- if (current > 0) {
136
- PersistentManager.slotCounts.set(slotType, current - 1);
137
- }
138
- }
139
- }
140
- /**
141
- * Get current slot usage across all agent types.
142
- */
143
- getSlotStatus() {
144
- return {
145
- implement: {
146
- used: PersistentManager.slotCounts.get('implement') ?? 0,
147
- max: PersistentManager.SLOT_MAXIMA.implement,
148
- },
149
- verify: {
150
- used: PersistentManager.slotCounts.get('verify') ?? 0,
151
- max: PersistentManager.SLOT_MAXIMA.verify,
152
- },
153
- explore: {
154
- used: PersistentManager.slotCounts.get('explore') ?? 0,
155
- },
156
- };
157
- }
158
- /**
159
- * List all currently running tasks with their slot types.
160
- */
161
- listRunningTasks() {
162
- return [...PersistentManager.runningTaskList];
69
+ return this.sessionController.getContextSnapshot();
163
70
  }
164
71
  /**
165
72
  * Clear the active session. Next send creates a fresh one.
@@ -10,8 +10,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
10
10
  if (args.freshSession) {
11
11
  await wrapperServices.manager.clearSession();
12
12
  }
13
- const managerStatus = wrapperServices.manager.getStatus();
14
- const hasActiveSession = managerStatus.context.sessionId !== null;
13
+ const hasActiveSession = wrapperServices.manager.getStatus().sessionId !== null;
15
14
  const promptPreview = args.message.length > 100 ? args.message.slice(0, 100) + '...' : args.message;
16
15
  context.metadata({
17
16
  title: hasActiveSession
@@ -19,7 +18,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
19
18
  : '⚡ Claude Code: Initializing...',
20
19
  metadata: {
21
20
  status: 'running',
22
- sessionId: managerStatus.context.sessionId,
21
+ sessionId: wrapperServices.manager.getStatus().sessionId,
23
22
  prompt: promptPreview,
24
23
  },
25
24
  });
@@ -236,14 +235,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
236
235
  sessionSystemPrompt: tool.schema.string().optional(),
237
236
  },
238
237
  async execute(args, context) {
239
- const taskDesc = args.message.length > 100 ? args.message.slice(0, 100) + '...' : args.message;
240
- await services.manager.acquireSlot('explore', taskDesc);
241
- try {
242
- return await executeDelegate({ ...args, mode: 'plan', wrapperType: 'explore' }, context);
243
- }
244
- finally {
245
- services.manager.releaseSlot('explore', taskDesc);
246
- }
238
+ return executeDelegate({ ...args, mode: 'plan', wrapperType: 'explore' }, context);
247
239
  },
248
240
  }),
249
241
  verify: tool({
@@ -259,14 +251,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
259
251
  sessionSystemPrompt: tool.schema.string().optional(),
260
252
  },
261
253
  async execute(args, context) {
262
- const taskDesc = args.message.length > 100 ? args.message.slice(0, 100) + '...' : args.message;
263
- await services.manager.acquireSlot('verify', taskDesc);
264
- try {
265
- return await executeDelegate({ ...args, mode: 'free', wrapperType: 'engineer_verify' }, context);
266
- }
267
- finally {
268
- services.manager.releaseSlot('verify', taskDesc);
269
- }
254
+ return executeDelegate({ ...args, mode: 'free', wrapperType: 'engineer_verify' }, context);
270
255
  },
271
256
  }),
272
257
  implement: tool({
@@ -282,14 +267,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
282
267
  sessionSystemPrompt: tool.schema.string().optional(),
283
268
  },
284
269
  async execute(args, context) {
285
- const taskDesc = args.message.length > 100 ? args.message.slice(0, 100) + '...' : args.message;
286
- await services.manager.acquireSlot('implement', taskDesc);
287
- try {
288
- return await executeDelegate({ ...args, mode: 'free', wrapperType: 'implement' }, context);
289
- }
290
- finally {
291
- services.manager.releaseSlot('implement', taskDesc);
292
- }
270
+ return executeDelegate({ ...args, mode: 'free', wrapperType: 'implement' }, context);
293
271
  },
294
272
  }),
295
273
  compact_context: tool({
@@ -303,11 +281,11 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
303
281
  annotateToolRun(context, 'Compacting session', {});
304
282
  const result = await wrapperServices.manager.compactSession(context.worktree);
305
283
  const snap = wrapperServices.manager.getStatus();
306
- const contextWarning = formatContextWarning(snap.context);
284
+ const contextWarning = formatContextWarning(snap);
307
285
  context.metadata({
308
286
  title: contextWarning
309
- ? `⚠️ Claude Code: Compacted — context at ${snap.context.estimatedContextPercent}%`
310
- : `✅ Claude Code: Compacted (${snap.context.totalTurns} turns, $${(snap.context.totalCostUsd ?? 0).toFixed(4)})`,
287
+ ? `⚠️ Claude Code: Compacted — context at ${snap.estimatedContextPercent}%`
288
+ : `✅ Claude Code: Compacted (${snap.totalTurns} turns, $${(snap.totalCostUsd ?? 0).toFixed(4)})`,
311
289
  metadata: {
312
290
  status: contextWarning ? 'warning' : 'success',
313
291
  sessionId: result.sessionId,
@@ -318,7 +296,7 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
318
296
  finalText: result.finalText,
319
297
  turns: result.turns,
320
298
  totalCostUsd: result.totalCostUsd,
321
- context: snap.context,
299
+ context: snap,
322
300
  contextWarning,
323
301
  }, null, 2);
324
302
  },
@@ -419,10 +397,10 @@ export const ClaudeManagerPlugin = async ({ worktree }) => {
419
397
  const status = wrapperServices.manager.getStatus();
420
398
  return JSON.stringify({
421
399
  ...status,
422
- transcriptFile: status.context.sessionId
423
- ? `.claude-manager/transcripts/${status.context.sessionId}.json`
400
+ transcriptFile: status.sessionId
401
+ ? `.claude-manager/transcripts/${status.sessionId}.json`
424
402
  : null,
425
- contextWarning: formatContextWarning(status.context),
403
+ contextWarning: formatContextWarning(status),
426
404
  }, null, 2);
427
405
  },
428
406
  }),
@@ -158,25 +158,16 @@ export const managerPromptRegistry = {
158
158
  ' On second failure: git_reset and rewrite the prompt from scratch.',
159
159
  ' Never send three corrections for the same problem.',
160
160
  '',
161
- '## Agent parallelism rules (enforced by the system)',
162
- '- `engineer_explore`: UNLIMITED spawn as many as you want for independent investigations',
163
- '- `engineer_verify`: up to 5 run multiple verifications in parallel (tests, lint, etc.)',
164
- '- `engineer_implement`: STRICTLY 1 only one can run at a time',
165
- '',
166
- '## Smarter orchestration patterns',
167
- "- For important decisions, send the SAME feature to 2-3 engineer_explore agents with different angles:",
168
- ' "Explore approach A for feature X" vs "Explore approach B for feature X"',
169
- ' Then compare the plans and pick the best, or combine the best of both.',
170
- "- Use engineer_verify to run verification in parallel with other work it's cheap and independent.",
171
- '- Before committing, run engineer_verify on the changed files to catch issues early.',
172
- '- When blocked on one engineer (waiting for implement), run other explorations in parallel.',
173
- "- Check getStatus().slotStatus before spawning — know what's running and what's available.",
174
- '',
175
- '## Available parallel agents',
176
- 'You have access to:',
177
- '- Multiple engineer_explore agents (unlimited, read-only, different angles)',
178
- '- Multiple engineer_verify agents (up to 5, verification commands)',
179
- '- One engineer_implement at a time (makes changes to worktree)',
161
+ '## Engineers (via the Task tool)',
162
+ '- `engineer_explore`read-only investigation. Use for: exploring unfamiliar code,',
163
+ ' mapping dependencies, analyzing impact, asking "how does X work?"',
164
+ '- `engineer_implement` implementation. Use for: all code changes, test runs, fixes.',
165
+ '- `engineer_verify` — verification. Use for: running tests, lint, typecheck, build.',
166
+ ' Use after implementation to confirm correctness.',
167
+ '- You may run MULTIPLE `engineer_explore` agents in parallel for independent investigations.',
168
+ '- You may run MULTIPLE `engineer_verify` agents in parallel for independent verification tasks.',
169
+ '- Only run ONE `engineer_implement` agent at a time it makes changes to the worktree.',
170
+ '- Coordinate so that only one implement/verify runs at a time to avoid git conflicts.',
180
171
  '',
181
172
  '## Context efficiency',
182
173
  '- Use `engineer_explore` for broad exploration so your own context stays clean.',
@@ -98,30 +98,6 @@ export interface SessionContextSnapshot {
98
98
  warningLevel: ContextWarningLevel;
99
99
  compactionCount: number;
100
100
  }
101
- export type AgentSlotType = 'implement' | 'verify' | 'explore';
102
- export interface RunningTask {
103
- slotType: AgentSlotType;
104
- task: string;
105
- startedAt: string;
106
- }
107
- export interface SlotStatus {
108
- implement: {
109
- used: number;
110
- max: number;
111
- };
112
- verify: {
113
- used: number;
114
- max: number;
115
- };
116
- explore: {
117
- used: number;
118
- };
119
- }
120
- export interface ManagerStatus {
121
- context: SessionContextSnapshot;
122
- slotStatus: SlotStatus;
123
- runningTasks: RunningTask[];
124
- }
125
101
  export interface GitDiffResult {
126
102
  hasDiff: boolean;
127
103
  diffText: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doingdev/opencode-claude-manager-plugin",
3
- "version": "0.1.44",
3
+ "version": "0.1.46",
4
4
  "description": "OpenCode plugin that orchestrates Claude Code sessions.",
5
5
  "keywords": [
6
6
  "opencode",