@doingdev/opencode-claude-manager-plugin 0.1.34 → 0.1.42

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.
Files changed (79) hide show
  1. package/README.md +14 -15
  2. package/dist/claude/claude-agent-sdk-adapter.js +2 -1
  3. package/dist/claude/session-live-tailer.js +2 -2
  4. package/dist/manager/git-operations.d.ts +10 -1
  5. package/dist/manager/git-operations.js +18 -3
  6. package/dist/manager/persistent-manager.d.ts +16 -1
  7. package/dist/manager/persistent-manager.js +14 -2
  8. package/dist/plugin/agent-hierarchy.d.ts +1 -1
  9. package/dist/plugin/agent-hierarchy.js +12 -17
  10. package/dist/plugin/claude-manager.plugin.js +158 -79
  11. package/dist/prompts/registry.js +16 -12
  12. package/dist/src/claude/claude-agent-sdk-adapter.d.ts +27 -0
  13. package/dist/src/claude/claude-agent-sdk-adapter.js +517 -0
  14. package/dist/src/claude/claude-session.service.d.ts +10 -0
  15. package/dist/src/claude/claude-session.service.js +18 -0
  16. package/dist/src/claude/session-live-tailer.d.ts +51 -0
  17. package/dist/src/claude/session-live-tailer.js +269 -0
  18. package/dist/src/claude/tool-approval-manager.d.ts +27 -0
  19. package/dist/src/claude/tool-approval-manager.js +232 -0
  20. package/dist/src/index.d.ts +6 -0
  21. package/dist/src/index.js +4 -0
  22. package/dist/src/manager/context-tracker.d.ts +33 -0
  23. package/dist/src/manager/context-tracker.js +106 -0
  24. package/dist/src/manager/git-operations.d.ts +12 -0
  25. package/dist/src/manager/git-operations.js +76 -0
  26. package/dist/src/manager/persistent-manager.d.ts +77 -0
  27. package/dist/src/manager/persistent-manager.js +170 -0
  28. package/dist/src/manager/session-controller.d.ts +44 -0
  29. package/dist/src/manager/session-controller.js +147 -0
  30. package/dist/src/plugin/agent-hierarchy.d.ts +60 -0
  31. package/dist/src/plugin/agent-hierarchy.js +157 -0
  32. package/dist/src/plugin/claude-manager.plugin.d.ts +2 -0
  33. package/dist/src/plugin/claude-manager.plugin.js +563 -0
  34. package/dist/src/plugin/service-factory.d.ts +12 -0
  35. package/dist/src/plugin/service-factory.js +38 -0
  36. package/dist/src/prompts/registry.d.ts +11 -0
  37. package/dist/src/prompts/registry.js +260 -0
  38. package/dist/src/state/file-run-state-store.d.ts +14 -0
  39. package/dist/src/state/file-run-state-store.js +85 -0
  40. package/dist/src/state/transcript-store.d.ts +15 -0
  41. package/dist/src/state/transcript-store.js +44 -0
  42. package/dist/src/types/contracts.d.ts +200 -0
  43. package/dist/src/types/contracts.js +1 -0
  44. package/dist/src/util/fs-helpers.d.ts +2 -0
  45. package/dist/src/util/fs-helpers.js +10 -0
  46. package/dist/src/util/project-context.d.ts +10 -0
  47. package/dist/src/util/project-context.js +105 -0
  48. package/dist/src/util/transcript-append.d.ts +7 -0
  49. package/dist/src/util/transcript-append.js +29 -0
  50. package/dist/test/claude-agent-sdk-adapter.test.d.ts +1 -0
  51. package/dist/test/claude-agent-sdk-adapter.test.js +459 -0
  52. package/dist/test/claude-manager.plugin.test.d.ts +1 -0
  53. package/dist/test/claude-manager.plugin.test.js +331 -0
  54. package/dist/test/context-tracker.test.d.ts +1 -0
  55. package/dist/test/context-tracker.test.js +138 -0
  56. package/dist/test/file-run-state-store.test.d.ts +1 -0
  57. package/dist/test/file-run-state-store.test.js +82 -0
  58. package/dist/test/git-operations.test.d.ts +1 -0
  59. package/dist/test/git-operations.test.js +90 -0
  60. package/dist/test/persistent-manager.test.d.ts +1 -0
  61. package/dist/test/persistent-manager.test.js +208 -0
  62. package/dist/test/project-context.test.d.ts +1 -0
  63. package/dist/test/project-context.test.js +92 -0
  64. package/dist/test/prompt-registry.test.d.ts +1 -0
  65. package/dist/test/prompt-registry.test.js +256 -0
  66. package/dist/test/session-controller.test.d.ts +1 -0
  67. package/dist/test/session-controller.test.js +149 -0
  68. package/dist/test/session-live-tailer.test.d.ts +1 -0
  69. package/dist/test/session-live-tailer.test.js +313 -0
  70. package/dist/test/tool-approval-manager.test.d.ts +1 -0
  71. package/dist/test/tool-approval-manager.test.js +264 -0
  72. package/dist/test/transcript-append.test.d.ts +1 -0
  73. package/dist/test/transcript-append.test.js +37 -0
  74. package/dist/test/transcript-store.test.d.ts +1 -0
  75. package/dist/test/transcript-store.test.js +50 -0
  76. package/dist/types/contracts.d.ts +1 -1
  77. package/dist/vitest.config.d.ts +2 -0
  78. package/dist/vitest.config.js +11 -0
  79. package/package.json +2 -2
package/README.md CHANGED
@@ -53,15 +53,15 @@ If you are testing locally, point OpenCode at the local package or plugin file u
53
53
 
54
54
  ### Engineer session
55
55
 
56
- - `engineer_send` — send a message to the persistent Claude Code session. Auto-creates on first call, resumes on subsequent calls.
56
+ - `explore` — investigate and analyze code without making edits. Read-only exploration of the codebase. Preferred first step before implementation.
57
57
  - `message` (required) — the instruction to send.
58
- - `mode` — `"plan"` (read-only investigation) or `"free"` (default, normal execution with edits).
59
58
  - `freshSession` — set to `true` to clear the active session before sending. Use when switching to an unrelated task or when context is contaminated.
60
59
  - `model` — `"claude-opus-4-6"` (default, recommended for most coding work), `"claude-sonnet-4-6"`, or `"claude-sonnet-4-5"` (faster/lighter tasks).
61
60
  - `effort` — `"high"` (default), `"medium"` (lighter tasks), `"low"`, or `"max"` (especially hard problems).
62
- - `engineer_compact` — compress the active session context while preserving session state. Use before clearing when context is high but salvageable.
63
- - `engineer_clear` — drop the active session entirely; next send starts fresh.
64
- - `engineer_status` — get current session health: context %, turns, cost, session ID.
61
+ - `implement` — implement code changes; can read, edit, and create files. Use after exploration to make changes. Same args as `explore`.
62
+ - `compact_context` — compress session history to reclaim context window space. Preserves state while reducing token usage.
63
+ - `clear_session` — clear the active session to start fresh. Use when context is full or starting a new task.
64
+ - `session_health` — check session health metrics: context usage %, turn count, cost, and session ID.
65
65
 
66
66
  ### Git operations
67
67
 
@@ -71,9 +71,8 @@ If you are testing locally, point OpenCode at the local package or plugin file u
71
71
 
72
72
  ### Inspection
73
73
 
74
- - `engineer_metadata` — inspect available Claude commands, skills, hooks, and settings.
75
- - `engineer_sessions` — list Claude sessions or inspect a saved transcript.
76
- - `engineer_runs` — list or inspect persisted manager run records (may be empty if tasks were sent directly via `engineer_send` rather than the run-tracking path).
74
+ - `list_transcripts` — list available session transcripts or inspect a specific transcript by ID.
75
+ - `list_history` — list persistent run records from the manager or inspect a specific run.
77
76
 
78
77
  ### Tool approval
79
78
 
@@ -86,7 +85,7 @@ If you are testing locally, point OpenCode at the local package or plugin file u
86
85
  The plugin registers a CTO → Manager → Engineer hierarchy through the OpenCode plugin `config` hook:
87
86
 
88
87
  - **`cto`** (primary agent) — sets direction and orchestrates work by spawning `manager` subagents. Has read/search/web tools but does NOT operate Claude Code directly.
89
- - **`manager`** (subagent) — operates a Claude Code engineer through a persistent session. Has the full tool surface (`engineer_*`, `git_*`, `approval_*`) plus read/search/web tools for investigation.
88
+ - **`manager`** (subagent) — operates a Claude Code engineer through a persistent session. Has the full tool surface (`explore`, `implement`, `compact_context`, `clear_session`, `session_health`, `list_transcripts`, `list_history`, `git_*`, `approval_*`) plus read/search/web tools for investigation.
90
89
  - **Engineer** — the Claude Code persistent session itself (not an OpenCode agent). Receives instructions from the manager, executes code changes, and reports results.
91
90
 
92
91
  These are added to OpenCode config at runtime by the plugin, so they do not require separate manual `opencode.json` entries.
@@ -95,27 +94,27 @@ These are added to OpenCode config at runtime by the plugin, so they do not requ
95
94
 
96
95
  Typical flow inside OpenCode:
97
96
 
98
- 1. Inspect Claude capabilities with `engineer_metadata`.
99
- 2. Delegate work with `engineer_send`.
97
+ 1. Explore the codebase with `explore`.
98
+ 2. Implement changes with `implement`.
100
99
  3. Review changes with `git_diff`, then commit or reset.
101
- 4. Inspect saved Claude history with `engineer_sessions` or prior orchestration records with `engineer_runs`.
100
+ 4. Inspect saved Claude history with `list_transcripts` or prior orchestration records with `list_history`.
102
101
 
103
102
  Example tasks:
104
103
 
105
104
  ```text
106
- Use engineer_send to implement the new validation logic in src/auth.ts, then review with git_diff.
105
+ Use implement to add the new validation logic in src/auth.ts, then review with git_diff.
107
106
  ```
108
107
 
109
108
  Start a fresh session for an unrelated task:
110
109
 
111
110
  ```text
112
- Use engineer_send with freshSession:true to investigate the failing CI test in test/api.test.ts using mode:"plan".
111
+ Use explore with freshSession:true to investigate the failing CI test in test/api.test.ts.
113
112
  ```
114
113
 
115
114
  Reclaim context mid-session:
116
115
 
117
116
  ```text
118
- Use engineer_compact to free up context, then continue with the next implementation step.
117
+ Use compact_context to free up context, then continue with the next implementation step.
119
118
  ```
120
119
 
121
120
  ## Local Development
@@ -162,6 +162,7 @@ export class ClaudeAgentSdkAdapter {
162
162
  forkSession: input.forkSession,
163
163
  persistSession: input.persistSession,
164
164
  includePartialMessages: input.includePartialMessages,
165
+ enableFileCheckpointing: false,
165
166
  settingSources: input.settingSources,
166
167
  maxTurns: input.maxTurns,
167
168
  model: input.model,
@@ -409,7 +410,7 @@ function truncateJsonish(value, max) {
409
410
  return truncateString(JSON.stringify(value), max);
410
411
  }
411
412
  catch {
412
- return truncateString(String(value), max);
413
+ return truncateString('[non-serializable]', max);
413
414
  }
414
415
  }
415
416
  function truncateString(s, max) {
@@ -99,7 +99,7 @@ export class SessionLiveTailer {
99
99
  });
100
100
  let chunk = '';
101
101
  stream.on('data', (data) => {
102
- chunk += data;
102
+ chunk += typeof data === 'string' ? data : data.toString('utf8');
103
103
  });
104
104
  stream.on('end', () => {
105
105
  reading = false;
@@ -264,6 +264,6 @@ function stringifyContent(value) {
264
264
  return JSON.stringify(value);
265
265
  }
266
266
  catch {
267
- return String(value);
267
+ return '[non-serializable]';
268
268
  }
269
269
  }
@@ -2,10 +2,19 @@ import type { GitDiffResult, GitOperationResult } from '../types/contracts.js';
2
2
  export declare class GitOperations {
3
3
  private readonly cwd;
4
4
  constructor(cwd: string);
5
- diff(): Promise<GitDiffResult>;
5
+ diff(options?: {
6
+ paths?: string[];
7
+ staged?: boolean;
8
+ ref?: string;
9
+ }): Promise<GitDiffResult>;
6
10
  diffStat(): Promise<string>;
7
11
  commit(message: string): Promise<GitOperationResult>;
8
12
  resetHard(): Promise<GitOperationResult>;
13
+ status(): Promise<{
14
+ output: string;
15
+ isClean: boolean;
16
+ }>;
17
+ log(count?: number): Promise<string>;
9
18
  currentBranch(): Promise<string>;
10
19
  recentCommits(count?: number): Promise<string>;
11
20
  private git;
@@ -6,10 +6,15 @@ export class GitOperations {
6
6
  constructor(cwd) {
7
7
  this.cwd = cwd;
8
8
  }
9
- async diff() {
9
+ async diff(options = {}) {
10
+ const ref = options.staged ? '--cached' : (options.ref ?? 'HEAD');
11
+ const args = ['diff', ref];
12
+ if (options.paths && options.paths.length > 0) {
13
+ args.push('--', ...options.paths);
14
+ }
10
15
  const [diffText, statOutput] = await Promise.all([
11
- this.git(['diff', 'HEAD']),
12
- this.git(['diff', 'HEAD', '--stat']),
16
+ this.git(args),
17
+ this.git([...args, '--stat']),
13
18
  ]);
14
19
  const stats = parseStatLine(statOutput);
15
20
  return {
@@ -50,6 +55,16 @@ export class GitOperations {
50
55
  };
51
56
  }
52
57
  }
58
+ async status() {
59
+ const output = await this.git(['status', '-s']);
60
+ return {
61
+ output,
62
+ isClean: output.trim().length === 0,
63
+ };
64
+ }
65
+ async log(count = 5) {
66
+ return this.git(['log', '--oneline', `-${count}`]);
67
+ }
53
68
  async currentBranch() {
54
69
  const branch = await this.git(['rev-parse', '--abbrev-ref', 'HEAD']);
55
70
  return branch.trim();
@@ -35,11 +35,26 @@ export declare class PersistentManager {
35
35
  /**
36
36
  * Get the current git diff.
37
37
  */
38
- gitDiff(): Promise<GitDiffResult>;
38
+ gitDiff(options?: {
39
+ paths?: string[];
40
+ staged?: boolean;
41
+ ref?: string;
42
+ }): Promise<GitDiffResult>;
39
43
  /**
40
44
  * Commit all current changes.
41
45
  */
42
46
  gitCommit(message: string): Promise<GitOperationResult>;
47
+ /**
48
+ * Get git status summary.
49
+ */
50
+ gitStatus(): Promise<{
51
+ output: string;
52
+ isClean: boolean;
53
+ }>;
54
+ /**
55
+ * Get recent commit log.
56
+ */
57
+ gitLog(count?: number): Promise<string>;
43
58
  /**
44
59
  * Hard reset to discard all uncommitted changes.
45
60
  */
@@ -35,8 +35,8 @@ export class PersistentManager {
35
35
  /**
36
36
  * Get the current git diff.
37
37
  */
38
- async gitDiff() {
39
- return this.gitOps.diff();
38
+ async gitDiff(options = {}) {
39
+ return this.gitOps.diff(options);
40
40
  }
41
41
  /**
42
42
  * Commit all current changes.
@@ -44,6 +44,18 @@ export class PersistentManager {
44
44
  async gitCommit(message) {
45
45
  return this.gitOps.commit(message);
46
46
  }
47
+ /**
48
+ * Get git status summary.
49
+ */
50
+ async gitStatus() {
51
+ return this.gitOps.status();
52
+ }
53
+ /**
54
+ * Get recent commit log.
55
+ */
56
+ async gitLog(count = 5) {
57
+ return this.gitOps.log(count);
58
+ }
47
59
  /**
48
60
  * Hard reset to discard all uncommitted changes.
49
61
  */
@@ -11,7 +11,7 @@ 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_send_plan", "engineer_send_build", "engineer_compact", "engineer_clear", "engineer_status", "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 ["explore", "implement", "compact_context", "clear_session", "session_health", "list_transcripts", "list_history", "git_diff", "git_commit", "git_reset", "git_status", "git_log", "approval_policy", "approval_decisions", "approval_update"];
15
15
  type ToolPermission = 'allow' | 'ask' | 'deny';
16
16
  type AgentPermission = {
17
17
  '*'?: ToolPermission;
@@ -17,25 +17,20 @@ export const AGENT_ENGINEER_BUILD = 'engineer_build';
17
17
  // ---------------------------------------------------------------------------
18
18
  /** Shared engineer session tools (compact, clear, status, diagnostics) */
19
19
  const ENGINEER_SHARED_TOOL_IDS = [
20
- 'engineer_compact',
21
- 'engineer_clear',
22
- 'engineer_status',
23
- 'engineer_sessions',
24
- 'engineer_runs',
25
- ];
26
- /** All engineer tools — generic send + mode-locked sends + shared session tools */
27
- const ENGINEER_TOOL_IDS = [
28
- 'engineer_send',
29
- 'engineer_send_plan',
30
- 'engineer_send_build',
31
- ...ENGINEER_SHARED_TOOL_IDS,
20
+ 'compact_context',
21
+ 'clear_session',
22
+ 'session_health',
23
+ 'list_transcripts',
24
+ 'list_history',
32
25
  ];
26
+ /** All engineer tools — mode-locked sends + shared session tools */
27
+ const ENGINEER_TOOL_IDS = ['explore', 'implement', ...ENGINEER_SHARED_TOOL_IDS];
33
28
  /** Tools for the engineer_plan wrapper (plan-mode send + shared) */
34
- const ENGINEER_PLAN_TOOL_IDS = ['engineer_send_plan', ...ENGINEER_SHARED_TOOL_IDS];
29
+ const ENGINEER_PLAN_TOOL_IDS = ['explore', ...ENGINEER_SHARED_TOOL_IDS];
35
30
  /** Tools for the engineer_build wrapper (build-mode send + shared) */
36
- const ENGINEER_BUILD_TOOL_IDS = ['engineer_send_build', ...ENGINEER_SHARED_TOOL_IDS];
31
+ const ENGINEER_BUILD_TOOL_IDS = ['implement', ...ENGINEER_SHARED_TOOL_IDS];
37
32
  /** Git tools — owned by CTO */
38
- const GIT_TOOL_IDS = ['git_diff', 'git_commit', 'git_reset'];
33
+ const GIT_TOOL_IDS = ['git_diff', 'git_commit', 'git_reset', 'git_status', 'git_log'];
39
34
  /** Approval tools — owned by CTO */
40
35
  const APPROVAL_TOOL_IDS = ['approval_policy', 'approval_decisions', 'approval_update'];
41
36
  /** All restricted tool IDs (union of all domain groups) */
@@ -87,7 +82,7 @@ function buildCtoPermissions() {
87
82
  },
88
83
  };
89
84
  }
90
- /** Engineer plan wrapper: read-only investigation + engineer_send_plan + shared session tools. */
85
+ /** Engineer plan wrapper: read-only investigation + explore + shared session tools. */
91
86
  function buildEngineerPlanPermissions() {
92
87
  const denied = {};
93
88
  for (const toolId of ALL_RESTRICTED_TOOL_IDS) {
@@ -104,7 +99,7 @@ function buildEngineerPlanPermissions() {
104
99
  ...allowed,
105
100
  };
106
101
  }
107
- /** Engineer build wrapper: read-only investigation + engineer_send_build + shared session tools. */
102
+ /** Engineer build wrapper: read-only investigation + implement + shared session tools. */
108
103
  function buildEngineerBuildPermissions() {
109
104
  const denied = {};
110
105
  for (const toolId of ALL_RESTRICTED_TOOL_IDS) {