@doingdev/opencode-claude-manager-plugin 0.1.46 → 0.1.49
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/README.md +29 -31
- package/dist/index.d.ts +1 -1
- package/dist/manager/team-orchestrator.d.ts +50 -0
- package/dist/manager/team-orchestrator.js +360 -0
- package/dist/plugin/agent-hierarchy.d.ts +12 -34
- package/dist/plugin/agent-hierarchy.js +36 -129
- package/dist/plugin/claude-manager.plugin.js +233 -421
- package/dist/plugin/service-factory.d.ts +20 -3
- package/dist/plugin/service-factory.js +46 -1
- package/dist/prompts/registry.d.ts +1 -10
- package/dist/prompts/registry.js +42 -261
- package/dist/src/claude/claude-agent-sdk-adapter.js +2 -1
- package/dist/src/claude/session-live-tailer.js +2 -2
- package/dist/src/index.d.ts +1 -1
- package/dist/src/manager/git-operations.d.ts +10 -1
- package/dist/src/manager/git-operations.js +18 -3
- package/dist/src/manager/persistent-manager.d.ts +18 -6
- package/dist/src/manager/persistent-manager.js +19 -13
- package/dist/src/manager/session-controller.d.ts +7 -10
- package/dist/src/manager/session-controller.js +12 -62
- package/dist/src/manager/team-orchestrator.d.ts +50 -0
- package/dist/src/manager/team-orchestrator.js +360 -0
- package/dist/src/plugin/agent-hierarchy.d.ts +12 -26
- package/dist/src/plugin/agent-hierarchy.js +36 -99
- package/dist/src/plugin/claude-manager.plugin.js +257 -391
- package/dist/src/plugin/service-factory.d.ts +20 -3
- package/dist/src/plugin/service-factory.js +47 -9
- package/dist/src/prompts/registry.d.ts +1 -10
- package/dist/src/prompts/registry.js +41 -246
- package/dist/src/state/team-state-store.d.ts +17 -0
- package/dist/src/state/team-state-store.js +107 -0
- package/dist/src/team/roster.d.ts +5 -0
- package/dist/src/team/roster.js +38 -0
- package/dist/src/types/contracts.d.ts +55 -13
- package/dist/src/types/contracts.js +1 -1
- package/dist/state/team-state-store.d.ts +17 -0
- package/dist/state/team-state-store.js +107 -0
- package/dist/team/roster.d.ts +5 -0
- package/dist/team/roster.js +38 -0
- package/dist/test/claude-manager.plugin.test.js +55 -280
- package/dist/test/cto-active-team.test.d.ts +1 -0
- package/dist/test/cto-active-team.test.js +52 -0
- package/dist/test/git-operations.test.js +65 -1
- package/dist/test/persistent-manager.test.js +3 -3
- package/dist/test/prompt-registry.test.js +32 -252
- package/dist/test/report-claude-event.test.d.ts +1 -0
- package/dist/test/report-claude-event.test.js +246 -0
- package/dist/test/session-controller.test.js +27 -27
- package/dist/test/team-orchestrator.test.d.ts +1 -0
- package/dist/test/team-orchestrator.test.js +146 -0
- package/dist/test/team-state-store.test.d.ts +1 -0
- package/dist/test/team-state-store.test.js +72 -0
- package/dist/types/contracts.d.ts +54 -3
- package/dist/types/contracts.js +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import { ClaudeSessionService } from '../claude/claude-session.service.js';
|
|
2
2
|
import { SessionLiveTailer } from '../claude/session-live-tailer.js';
|
|
3
3
|
import { ToolApprovalManager } from '../claude/tool-approval-manager.js';
|
|
4
|
+
import { TeamStateStore } from '../state/team-state-store.js';
|
|
4
5
|
import { PersistentManager } from '../manager/persistent-manager.js';
|
|
5
|
-
|
|
6
|
+
import { TeamOrchestrator } from '../manager/team-orchestrator.js';
|
|
7
|
+
import type { DiscoveredClaudeFile, EngineerName } from '../types/contracts.js';
|
|
8
|
+
export interface ClaudeManagerPluginServices {
|
|
6
9
|
manager: PersistentManager;
|
|
7
10
|
sessions: ClaudeSessionService;
|
|
8
11
|
approvalManager: ToolApprovalManager;
|
|
9
12
|
liveTailer: SessionLiveTailer;
|
|
13
|
+
teamStore: TeamStateStore;
|
|
14
|
+
orchestrator: TeamOrchestrator;
|
|
10
15
|
}
|
|
11
|
-
export declare function getOrCreatePluginServices(worktree: string): ClaudeManagerPluginServices;
|
|
12
|
-
export
|
|
16
|
+
export declare function getOrCreatePluginServices(worktree: string, projectClaudeFiles?: DiscoveredClaudeFile[]): ClaudeManagerPluginServices;
|
|
17
|
+
export declare function clearPluginServices(): void;
|
|
18
|
+
export declare function setActiveTeamSession(worktree: string, teamId: string): void;
|
|
19
|
+
export declare function getActiveTeamSession(worktree: string): string | null;
|
|
20
|
+
export declare function getPersistedActiveTeam(worktree: string): Promise<string | null>;
|
|
21
|
+
export declare function setPersistedActiveTeam(worktree: string, teamId: string): Promise<void>;
|
|
22
|
+
export declare function setWrapperSessionMapping(worktree: string, wrapperSessionId: string, mapping: {
|
|
23
|
+
teamId: string;
|
|
24
|
+
engineer: EngineerName;
|
|
25
|
+
}): void;
|
|
26
|
+
export declare function getWrapperSessionMapping(worktree: string, wrapperSessionId: string): {
|
|
27
|
+
teamId: string;
|
|
28
|
+
engineer: EngineerName;
|
|
29
|
+
} | null;
|
|
@@ -3,13 +3,22 @@ import { ClaudeSessionService } from '../claude/claude-session.service.js';
|
|
|
3
3
|
import { SessionLiveTailer } from '../claude/session-live-tailer.js';
|
|
4
4
|
import { ToolApprovalManager } from '../claude/tool-approval-manager.js';
|
|
5
5
|
import { FileRunStateStore } from '../state/file-run-state-store.js';
|
|
6
|
+
import { TeamStateStore } from '../state/team-state-store.js';
|
|
6
7
|
import { TranscriptStore } from '../state/transcript-store.js';
|
|
7
8
|
import { ContextTracker } from '../manager/context-tracker.js';
|
|
8
9
|
import { GitOperations } from '../manager/git-operations.js';
|
|
9
10
|
import { SessionController } from '../manager/session-controller.js';
|
|
10
11
|
import { PersistentManager } from '../manager/persistent-manager.js';
|
|
11
12
|
import { managerPromptRegistry } from '../prompts/registry.js';
|
|
12
|
-
|
|
13
|
+
import { TeamOrchestrator } from '../manager/team-orchestrator.js';
|
|
14
|
+
const serviceRegistry = new Map();
|
|
15
|
+
const activeTeamRegistry = new Map();
|
|
16
|
+
const wrapperSessionRegistry = new Map();
|
|
17
|
+
export function getOrCreatePluginServices(worktree, projectClaudeFiles = []) {
|
|
18
|
+
const existing = serviceRegistry.get(worktree);
|
|
19
|
+
if (existing) {
|
|
20
|
+
return existing;
|
|
21
|
+
}
|
|
13
22
|
const approvalManager = new ToolApprovalManager();
|
|
14
23
|
const sdkAdapter = new ClaudeAgentSdkAdapter(undefined, approvalManager);
|
|
15
24
|
const sessionService = new ClaudeSessionService(sdkAdapter);
|
|
@@ -18,14 +27,50 @@ export function getOrCreatePluginServices(worktree) {
|
|
|
18
27
|
'default', worktree, managerPromptRegistry.modePrefixes);
|
|
19
28
|
const gitOps = new GitOperations(worktree);
|
|
20
29
|
const stateStore = new FileRunStateStore();
|
|
30
|
+
const teamStore = new TeamStateStore();
|
|
21
31
|
const transcriptStore = new TranscriptStore();
|
|
22
32
|
const manager = new PersistentManager(sessionController, gitOps, stateStore, contextTracker, transcriptStore);
|
|
23
33
|
const liveTailer = new SessionLiveTailer();
|
|
34
|
+
const orchestrator = new TeamOrchestrator(sessionService, teamStore, transcriptStore, managerPromptRegistry.engineerSessionPrompt, projectClaudeFiles);
|
|
24
35
|
const services = {
|
|
25
36
|
manager,
|
|
26
37
|
sessions: sessionService,
|
|
27
38
|
approvalManager,
|
|
28
39
|
liveTailer,
|
|
40
|
+
teamStore,
|
|
41
|
+
orchestrator,
|
|
29
42
|
};
|
|
43
|
+
serviceRegistry.set(worktree, services);
|
|
30
44
|
return services;
|
|
31
45
|
}
|
|
46
|
+
export function clearPluginServices() {
|
|
47
|
+
serviceRegistry.clear();
|
|
48
|
+
activeTeamRegistry.clear();
|
|
49
|
+
wrapperSessionRegistry.clear();
|
|
50
|
+
}
|
|
51
|
+
export function setActiveTeamSession(worktree, teamId) {
|
|
52
|
+
activeTeamRegistry.set(worktree, teamId);
|
|
53
|
+
}
|
|
54
|
+
export function getActiveTeamSession(worktree) {
|
|
55
|
+
return activeTeamRegistry.get(worktree) ?? null;
|
|
56
|
+
}
|
|
57
|
+
export async function getPersistedActiveTeam(worktree) {
|
|
58
|
+
const services = serviceRegistry.get(worktree);
|
|
59
|
+
if (!services) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return services.teamStore.getActiveTeam(worktree);
|
|
63
|
+
}
|
|
64
|
+
export async function setPersistedActiveTeam(worktree, teamId) {
|
|
65
|
+
const services = serviceRegistry.get(worktree);
|
|
66
|
+
if (!services) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
await services.teamStore.setActiveTeam(worktree, teamId);
|
|
70
|
+
}
|
|
71
|
+
export function setWrapperSessionMapping(worktree, wrapperSessionId, mapping) {
|
|
72
|
+
wrapperSessionRegistry.set(`${worktree}:${wrapperSessionId}`, mapping);
|
|
73
|
+
}
|
|
74
|
+
export function getWrapperSessionMapping(worktree, wrapperSessionId) {
|
|
75
|
+
return wrapperSessionRegistry.get(`${worktree}:${wrapperSessionId}`) ?? null;
|
|
76
|
+
}
|
|
@@ -1,11 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
/**
|
|
3
|
-
* Compose a wrapper agent prompt from the base prompt plus discovered
|
|
4
|
-
* project Claude files. Returns the base prompt unchanged when no
|
|
5
|
-
* files are provided.
|
|
6
|
-
*
|
|
7
|
-
* Each file is rendered under a clear path-labeled section so the
|
|
8
|
-
* wrapper agent knows exactly where each instruction came from.
|
|
9
|
-
*/
|
|
10
|
-
export declare function composeWrapperPrompt(basePrompt: string, claudeFiles: DiscoveredClaudeFile[]): string;
|
|
1
|
+
import type { ManagerPromptRegistry } from '../types/contracts.js';
|
|
11
2
|
export declare const managerPromptRegistry: ManagerPromptRegistry;
|
package/dist/prompts/registry.js
CHANGED
|
@@ -1,274 +1,55 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Compose a wrapper agent prompt from the base prompt plus discovered
|
|
3
|
-
* project Claude files. Returns the base prompt unchanged when no
|
|
4
|
-
* files are provided.
|
|
5
|
-
*
|
|
6
|
-
* Each file is rendered under a clear path-labeled section so the
|
|
7
|
-
* wrapper agent knows exactly where each instruction came from.
|
|
8
|
-
*/
|
|
9
|
-
export function composeWrapperPrompt(basePrompt, claudeFiles) {
|
|
10
|
-
if (claudeFiles.length === 0) {
|
|
11
|
-
return basePrompt;
|
|
12
|
-
}
|
|
13
|
-
const sections = claudeFiles.map((f) => `### ${f.relativePath}\n${f.content}`).join('\n\n');
|
|
14
|
-
return `${basePrompt}\n\n## Project Claude Files\nThe following project-level instructions were discovered from the repository.\n\n${sections}`;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Build an engineer wrapper prompt from shared sections plus mode-specific overrides.
|
|
18
|
-
*/
|
|
19
|
-
function buildEngineerWrapperPrompt(opts) {
|
|
20
|
-
return [
|
|
21
|
-
`You are a staff engineer managing a Claude Code session for ${opts.purpose}.`,
|
|
22
|
-
'You are not a forwarding layer — interpret the task in repo context before delegating.',
|
|
23
|
-
'',
|
|
24
|
-
'## Staff-level framing',
|
|
25
|
-
'- Identify the real problem, not just the stated request.',
|
|
26
|
-
'- Look for missing architecture, ownership, or precedence issues before delegating.',
|
|
27
|
-
'- Rewrite weak or underspecified requests into precise prompts for the engineer.',
|
|
28
|
-
'- For medium+ tasks, determine: the actual problem, the cleanest architecture,',
|
|
29
|
-
' and what needs clarification before work begins.',
|
|
30
|
-
'- Ask ONE clarification first if it materially improves architecture.',
|
|
31
|
-
'',
|
|
32
|
-
'## Repo-context investigation',
|
|
33
|
-
'- Use read/grep/glob sparingly — only for spot-checks to sharpen a delegation.',
|
|
34
|
-
'- Do NOT implement changes yourself — investigation only.',
|
|
35
|
-
'',
|
|
36
|
-
'## Behavior',
|
|
37
|
-
`- Send the objective to the engineer using ${opts.toolName}.`,
|
|
38
|
-
"- Return the engineer's response verbatim. Do not summarize.",
|
|
39
|
-
`- Use freshSession:true on ${opts.toolName} when the task is unrelated to prior work.`,
|
|
40
|
-
'',
|
|
41
|
-
'## Constructing the engineer session prompt',
|
|
42
|
-
`When you call \`${opts.toolName}\`, you MUST include a \`sessionSystemPrompt\` argument.`,
|
|
43
|
-
'This becomes the system prompt for the underlying Claude Code session.',
|
|
44
|
-
'Build it as a self-contained description that equips the engineer to execute precisely.',
|
|
45
|
-
'',
|
|
46
|
-
'Structure it as:',
|
|
47
|
-
`1. **Role**: "${opts.roleDescription}"`,
|
|
48
|
-
'2. **Project rules**: Extract only the rules from the Project Claude Files below that',
|
|
49
|
-
' are relevant to this specific task. Synthesize — do not dump everything.',
|
|
50
|
-
' Cite file paths when the source matters (e.g. "per packages/core/CLAUDE.md").',
|
|
51
|
-
'3. **Verification**: How to verify the work (tests, lint, typecheck, expected behavior).',
|
|
52
|
-
'',
|
|
53
|
-
'Keep it concise: 3-6 sentences for role + relevant rules + verification.',
|
|
54
|
-
'The task itself goes in `message`, not in `sessionSystemPrompt`.',
|
|
55
|
-
'',
|
|
56
|
-
'## Context management',
|
|
57
|
-
'- Check session_health before sending.',
|
|
58
|
-
'- Under 50%: proceed. Over 70%: compact_context. Over 85%: clear_session.',
|
|
59
|
-
'',
|
|
60
|
-
'## Model selection',
|
|
61
|
-
...opts.modelDefaults,
|
|
62
|
-
'',
|
|
63
|
-
'## Using appended Project Claude Files',
|
|
64
|
-
'- Treat appended Project Claude Files as project guidance for the engineer.',
|
|
65
|
-
'- Extract only the rules relevant to the current task when constructing sessionSystemPrompt.',
|
|
66
|
-
'- Prefer guidance from more specific/nested paths over root-level guidance on conflict.',
|
|
67
|
-
'- Direct user instructions override Claude-file guidance.',
|
|
68
|
-
'- Keep delegated instructions tight; do not dump the full file corpus unless needed.',
|
|
69
|
-
'- Cite file paths (e.g. "per packages/core/CLAUDE.md") when the source matters.',
|
|
70
|
-
'',
|
|
71
|
-
'## What you must NOT do',
|
|
72
|
-
'- Do NOT call git_*, approval_*, or any non-engineer tools.',
|
|
73
|
-
'- Do NOT add commentary to the engineer response.',
|
|
74
|
-
].join('\n');
|
|
75
|
-
}
|
|
76
1
|
export const managerPromptRegistry = {
|
|
77
2
|
ctoSystemPrompt: [
|
|
78
|
-
'You are
|
|
79
|
-
'
|
|
80
|
-
'',
|
|
81
|
-
'
|
|
82
|
-
'
|
|
83
|
-
'
|
|
84
|
-
'-
|
|
85
|
-
'-
|
|
86
|
-
'-
|
|
87
|
-
'
|
|
88
|
-
'
|
|
89
|
-
'',
|
|
90
|
-
'
|
|
91
|
-
'
|
|
92
|
-
'-
|
|
93
|
-
'-
|
|
94
|
-
'
|
|
95
|
-
'',
|
|
96
|
-
'
|
|
97
|
-
'
|
|
98
|
-
'
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
'',
|
|
102
|
-
'
|
|
103
|
-
'
|
|
104
|
-
'',
|
|
105
|
-
'
|
|
106
|
-
'
|
|
107
|
-
'',
|
|
108
|
-
'**Medium+ tasks** (bug fix, feature, refactor, architecture change):',
|
|
109
|
-
' Before delegating, determine:',
|
|
110
|
-
' 1. What the user asked vs. what is actually needed.',
|
|
111
|
-
' 2. What is underspecified or conflicting.',
|
|
112
|
-
' 3. What the cleanest architecture is.',
|
|
113
|
-
' 4. What should be clarified before proceeding.',
|
|
114
|
-
' Prefer spawning `engineer_explore` for repo exploration rather than reading',
|
|
115
|
-
' code yourself. Use at most 1-2 spot-check reads to sharpen the delegation.',
|
|
116
|
-
' Then delegate with file paths, line numbers, patterns, and verification.',
|
|
117
|
-
'',
|
|
118
|
-
'**Complex tasks** (multi-file feature, large refactor):',
|
|
119
|
-
' 1. Spawn `engineer_explore` to explore the repo, map dependencies, and analyze impact.',
|
|
120
|
-
' 2. If requirements are unclear, ask the user ONE high-leverage question —',
|
|
121
|
-
' only when it materially changes architecture, ownership, or destructive behavior.',
|
|
122
|
-
' Prefer the question tool when discrete options exist.',
|
|
123
|
-
' 3. Write a plan to the todo list (todowrite). Share it with the user.',
|
|
124
|
-
' 4. Execute steps sequentially, committing after each.',
|
|
125
|
-
'',
|
|
126
|
-
'## Missed-opportunity check',
|
|
127
|
-
'Before finalizing any medium+ delegation, check:',
|
|
128
|
-
'- One cleaner alternative you considered.',
|
|
129
|
-
'- One risk the current approach carries.',
|
|
130
|
-
'- One thing the requester likely missed.',
|
|
131
|
-
'If any of these materially improve the outcome, surface them.',
|
|
132
|
-
'',
|
|
133
|
-
'## How to delegate effectively',
|
|
134
|
-
'The engineer does not have your context. Every instruction must be self-contained.',
|
|
135
|
-
'Include:',
|
|
136
|
-
'- Exact files, functions, and line numbers to change.',
|
|
137
|
-
'- Current behavior and desired behavior.',
|
|
138
|
-
'- Code snippets showing the pattern or convention to follow.',
|
|
139
|
-
'- How to verify: "Run `npm test`, expect all green." or',
|
|
140
|
-
' "The function should return null instead of throwing."',
|
|
141
|
-
'',
|
|
142
|
-
'Bad: "Fix the auth bug"',
|
|
143
|
-
'Good: "In src/auth/session.ts, `validateToken` (line 42) throws on expired',
|
|
144
|
-
' tokens instead of returning null. Change it to return null.',
|
|
145
|
-
' Update the caller in src/routes/login.ts:87.',
|
|
146
|
-
' Follow the pattern in src/auth/refresh.ts:23.',
|
|
147
|
-
' Run `npm test -- --grep auth` to verify. All tests should pass."',
|
|
148
|
-
'',
|
|
149
|
-
'## Review every change',
|
|
150
|
-
'After each delegation:',
|
|
151
|
-
'1. git_diff — read the FULL diff. Check for unintended changes, missing tests,',
|
|
152
|
-
' style violations.',
|
|
153
|
-
'2. git_status — check what files changed (quick overview)',
|
|
154
|
-
'3. git_log -n 5 — see recent commits (understand context)',
|
|
155
|
-
'4. If correct: spawn `engineer_implement` to run tests/lint/typecheck.',
|
|
156
|
-
'5. If tests pass: git_commit to checkpoint.',
|
|
157
|
-
'6. If wrong: spawn `engineer_implement` with a specific correction.',
|
|
158
|
-
' On second failure: git_reset and rewrite the prompt from scratch.',
|
|
159
|
-
' Never send three corrections for the same problem.',
|
|
160
|
-
'',
|
|
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.',
|
|
171
|
-
'',
|
|
172
|
-
'## Context efficiency',
|
|
173
|
-
'- Use `engineer_explore` for broad exploration so your own context stays clean.',
|
|
174
|
-
'- When spawning engineers for unrelated tasks, tell them to use freshSession:true.',
|
|
175
|
-
'- Keep delegations focused — one concern per engineer invocation.',
|
|
176
|
-
'',
|
|
177
|
-
'## What you must NOT do',
|
|
178
|
-
'- Do NOT call any engineer_* tools directly. Use the Task tool.',
|
|
179
|
-
'- Do NOT edit files or run bash commands yourself.',
|
|
180
|
-
'- Do NOT skip review — always git_diff after delegation.',
|
|
181
|
-
'- Do NOT delegate without verification criteria.',
|
|
182
|
-
'',
|
|
183
|
-
'## Tools reference',
|
|
184
|
-
'todowrite / todoread — track multi-step work',
|
|
185
|
-
'question — ask the user structured questions with options',
|
|
186
|
-
'git_diff — review changes (filter with paths, staged, ref args)',
|
|
187
|
-
'git_status — quick overview of changed files',
|
|
188
|
-
'git_log — recent commits (default: last 5)',
|
|
189
|
-
'git_commit — stage all + commit',
|
|
190
|
-
'git_reset — hard reset + clean (destructive)',
|
|
191
|
-
'approval_policy — view tool approval rules',
|
|
192
|
-
'approval_decisions — view recent approval decisions',
|
|
193
|
-
'approval_update — modify tool approval policy',
|
|
194
|
-
'',
|
|
195
|
-
'## Autonomy blockers',
|
|
196
|
-
'Surface these to the user immediately:',
|
|
197
|
-
'- Credentials, API keys, or secrets you do not have.',
|
|
198
|
-
'- Architectural decisions with trade-offs the user should weigh.',
|
|
199
|
-
'- Destructive actions on shared state (deploy, publish, force-push).',
|
|
200
|
-
'State the blocker, what you need, and a concrete suggestion to unblock.',
|
|
3
|
+
'You are the CTO. Own the outcome, not just the request.',
|
|
4
|
+
'',
|
|
5
|
+
'Default behavior:',
|
|
6
|
+
'- Find requirement gaps before implementation.',
|
|
7
|
+
'- Ask at most one high-leverage question when the answer changes architecture, scope, or destructive behavior.',
|
|
8
|
+
'- Use the Task tool to delegate to named engineer subagents.',
|
|
9
|
+
'- For medium or large work, spawn two engineers in parallel, compare both plans, and synthesize the strongest path.',
|
|
10
|
+
'- Reuse the same named engineer when follow-up work belongs to their prior context.',
|
|
11
|
+
'- Review diffs with `git_diff`, inspect changed files with `git_status`, and use `git_log` for recent context.',
|
|
12
|
+
'- Use the built-in `question` tool whenever you need a user decision and provide a recommendation.',
|
|
13
|
+
'',
|
|
14
|
+
'Team model:',
|
|
15
|
+
'- Tom, John, Maya, Sara, and Alex are persistent engineers.',
|
|
16
|
+
'- Each engineer keeps one Claude Code session for the active CTO team.',
|
|
17
|
+
'- The plugin maps engineer work back to the active CTO session automatically.',
|
|
18
|
+
'- Only one implementing engineer should modify the worktree at a time.',
|
|
19
|
+
'',
|
|
20
|
+
'Do not:',
|
|
21
|
+
'- Do not edit files or run bash directly.',
|
|
22
|
+
'- Do not expose session babysitting to the user.',
|
|
23
|
+
'- Do not delegate without clear success criteria.',
|
|
24
|
+
].join('\n'),
|
|
25
|
+
engineerAgentPrompt: [
|
|
26
|
+
'You are a named engineer working for the CTO.',
|
|
27
|
+
'Use the `claude` tool for all real work.',
|
|
28
|
+
'The tool remembers prior turns for this engineer inside the active CTO team.',
|
|
29
|
+
'Your prior wrapper context is also reloaded automatically so you can frame Claude requests better over time.',
|
|
30
|
+
'Choose the mode that matches the assignment: explore, implement, or verify.',
|
|
31
|
+
'Return the tool result directly unless a short clarification is truly required.',
|
|
201
32
|
].join('\n'),
|
|
202
|
-
engineerExplorePrompt: buildEngineerWrapperPrompt({
|
|
203
|
-
purpose: 'read-only investigation',
|
|
204
|
-
toolName: 'explore',
|
|
205
|
-
roleDescription: 'You are an expert engineer performing read-only investigation. ' +
|
|
206
|
-
'Execute directly. No preamble. Follow existing repo conventions.',
|
|
207
|
-
modelDefaults: [
|
|
208
|
-
'- claude-opus-4-6 + high: complex analysis (default).',
|
|
209
|
-
'- claude-sonnet-4-6: lighter analysis.',
|
|
210
|
-
'- effort "medium": simple lookups.',
|
|
211
|
-
],
|
|
212
|
-
}),
|
|
213
|
-
engineerImplementPrompt: buildEngineerWrapperPrompt({
|
|
214
|
-
purpose: 'implementation',
|
|
215
|
-
toolName: 'implement',
|
|
216
|
-
roleDescription: 'You are an expert engineer implementing changes. ' +
|
|
217
|
-
'Execute directly. No preamble. Follow existing repo conventions. ' +
|
|
218
|
-
'Do not run git commit, git push, git reset, git checkout, or git stash — git operations are handled externally.',
|
|
219
|
-
modelDefaults: [
|
|
220
|
-
'- claude-opus-4-6 + high: most coding tasks (default).',
|
|
221
|
-
'- claude-sonnet-4-6: simple renames, formatting, scaffolding.',
|
|
222
|
-
'- effort "max": complex refactors, subtle bugs, cross-cutting changes.',
|
|
223
|
-
],
|
|
224
|
-
}),
|
|
225
|
-
engineerVerifyPrompt: buildEngineerWrapperPrompt({
|
|
226
|
-
purpose: 'verification',
|
|
227
|
-
toolName: 'verify',
|
|
228
|
-
roleDescription: 'You are an expert engineer verifying changes. ' +
|
|
229
|
-
'Execute directly. No preamble. Follow existing repo conventions. ' +
|
|
230
|
-
'Do not run git commit, git push, git reset, git checkout, or git stash — git operations are handled externally.',
|
|
231
|
-
modelDefaults: [
|
|
232
|
-
'- claude-opus-4-6 + high: most verification tasks (default).',
|
|
233
|
-
'- claude-sonnet-4-6: simple test runs, lint checks.',
|
|
234
|
-
'- effort "medium": straightforward verification.',
|
|
235
|
-
],
|
|
236
|
-
}),
|
|
237
33
|
engineerSessionPrompt: [
|
|
238
|
-
'You are an expert engineer
|
|
239
|
-
'',
|
|
240
|
-
'
|
|
241
|
-
'
|
|
242
|
-
'
|
|
243
|
-
'
|
|
244
|
-
'',
|
|
245
|
-
'## Verification',
|
|
246
|
-
'- Always verify your own work before reporting done.',
|
|
247
|
-
'- If no verification was specified, still run relevant tests if they exist.',
|
|
248
|
-
'',
|
|
249
|
-
'## Git boundary — do NOT run:',
|
|
250
|
-
'git commit, git push, git reset, git checkout, git stash.',
|
|
251
|
-
'Git operations are handled externally.',
|
|
252
|
-
'',
|
|
253
|
-
'## Reporting',
|
|
254
|
-
'- End with: what was done, what was verified, what passed/failed.',
|
|
255
|
-
'- Report blockers immediately with specifics.',
|
|
34
|
+
'You are an expert software engineer working inside Claude Code.',
|
|
35
|
+
'Execute directly. No preamble.',
|
|
36
|
+
'Follow repository conventions and relevant project instructions.',
|
|
37
|
+
'Use the minimum necessary investigation before acting.',
|
|
38
|
+
'Verify your own work before reporting done.',
|
|
39
|
+
'Report blockers clearly and include exact command output on failure.',
|
|
40
|
+
'Do not run git commit, git push, git reset, git checkout, or git stash.',
|
|
256
41
|
].join('\n'),
|
|
257
42
|
modePrefixes: {
|
|
258
43
|
plan: [
|
|
259
|
-
'[PLAN MODE] Read-only.
|
|
260
|
-
'Do
|
|
261
|
-
'
|
|
262
|
-
'Analyze the codebase and produce a detailed implementation plan:',
|
|
263
|
-
'files to change, functions to modify, new files to create, test strategy,',
|
|
264
|
-
'and risks. End with a numbered step-by-step plan.',
|
|
265
|
-
'Return the entire plan inline in your response.',
|
|
44
|
+
'[PLAN MODE] Read-only.',
|
|
45
|
+
'Do not create or edit files.',
|
|
46
|
+
'Analyze the codebase and return the plan inline.',
|
|
266
47
|
].join(' '),
|
|
267
48
|
free: '',
|
|
268
49
|
},
|
|
269
50
|
contextWarnings: {
|
|
270
|
-
moderate: '
|
|
271
|
-
high: '
|
|
272
|
-
critical: '
|
|
51
|
+
moderate: 'Engineer context is getting full ({percent}% estimated). Reuse is still fine, but keep the next prompt focused.',
|
|
52
|
+
high: 'Engineer context is heavy ({percent}% estimated, {turns} turns, ${cost}). Prefer a narrowly scoped follow-up or internal compaction.',
|
|
53
|
+
critical: 'Engineer context is near capacity ({percent}% estimated). Avoid piling unrelated work into this engineer session.',
|
|
273
54
|
},
|
|
274
55
|
};
|
|
@@ -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(
|
|
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
|
|
267
|
+
return '[non-serializable]';
|
|
268
268
|
}
|
|
269
269
|
}
|
package/dist/src/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,
|
|
3
|
+
export type { ClaudeCapabilitySnapshot, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, ManagerPromptRegistry, RunClaudeSessionInput, SessionContextSnapshot, GitDiffResult, GitOperationResult, PersistentRunRecord, PersistentRunResult, ContextWarningLevel, SessionMode, EngineerName, EngineerWorkMode, WrapperHistoryEntry, TeamEngineerRecord, TeamRecord, EngineerTaskResult, PlanDraft, SynthesizedPlanResult, 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;
|
|
@@ -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(
|
|
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(
|
|
12
|
-
this.git([
|
|
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();
|
|
@@ -21,6 +21,7 @@ export declare class PersistentManager {
|
|
|
21
21
|
model?: string;
|
|
22
22
|
effort?: 'low' | 'medium' | 'high' | 'max';
|
|
23
23
|
mode?: 'plan' | 'free';
|
|
24
|
+
sessionSystemPrompt?: string;
|
|
24
25
|
abortSignal?: AbortSignal;
|
|
25
26
|
}, onEvent?: ClaudeSessionEventHandler): Promise<{
|
|
26
27
|
sessionId: string | undefined;
|
|
@@ -35,11 +36,26 @@ export declare class PersistentManager {
|
|
|
35
36
|
/**
|
|
36
37
|
* Get the current git diff.
|
|
37
38
|
*/
|
|
38
|
-
gitDiff(
|
|
39
|
+
gitDiff(options?: {
|
|
40
|
+
paths?: string[];
|
|
41
|
+
staged?: boolean;
|
|
42
|
+
ref?: string;
|
|
43
|
+
}): Promise<GitDiffResult>;
|
|
39
44
|
/**
|
|
40
45
|
* Commit all current changes.
|
|
41
46
|
*/
|
|
42
47
|
gitCommit(message: string): Promise<GitOperationResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Get git status summary.
|
|
50
|
+
*/
|
|
51
|
+
gitStatus(): Promise<{
|
|
52
|
+
output: string;
|
|
53
|
+
isClean: boolean;
|
|
54
|
+
}>;
|
|
55
|
+
/**
|
|
56
|
+
* Get recent commit log.
|
|
57
|
+
*/
|
|
58
|
+
gitLog(count?: number): Promise<string>;
|
|
43
59
|
/**
|
|
44
60
|
* Hard reset to discard all uncommitted changes.
|
|
45
61
|
*/
|
|
@@ -51,7 +67,7 @@ export declare class PersistentManager {
|
|
|
51
67
|
/**
|
|
52
68
|
* Clear the active session. Next send creates a fresh one.
|
|
53
69
|
*/
|
|
54
|
-
clearSession(
|
|
70
|
+
clearSession(): Promise<string | null>;
|
|
55
71
|
/**
|
|
56
72
|
* Compact the current session to free context.
|
|
57
73
|
*/
|
|
@@ -67,10 +83,6 @@ export declare class PersistentManager {
|
|
|
67
83
|
executeTask(cwd: string, task: string, options?: {
|
|
68
84
|
model?: string;
|
|
69
85
|
}, onProgress?: PersistentManagerProgressHandler): Promise<PersistentRunResult>;
|
|
70
|
-
/**
|
|
71
|
-
* Try to restore session state from disk on startup.
|
|
72
|
-
*/
|
|
73
|
-
tryRestore(cwd: string): Promise<boolean>;
|
|
74
86
|
listRuns(cwd: string): Promise<PersistentRunRecord[]>;
|
|
75
87
|
getRun(cwd: string, runId: string): Promise<PersistentRunRecord | null>;
|
|
76
88
|
}
|