@doingdev/opencode-claude-manager-plugin 0.1.35 → 0.1.43

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 (90) hide show
  1. package/dist/claude/claude-agent-sdk-adapter.js +1 -0
  2. package/dist/manager/git-operations.d.ts +10 -1
  3. package/dist/manager/git-operations.js +18 -3
  4. package/dist/manager/persistent-manager.d.ts +19 -3
  5. package/dist/manager/persistent-manager.js +21 -9
  6. package/dist/manager/session-controller.d.ts +8 -5
  7. package/dist/manager/session-controller.js +25 -20
  8. package/dist/metadata/claude-metadata.service.d.ts +12 -0
  9. package/dist/metadata/claude-metadata.service.js +38 -0
  10. package/dist/metadata/repo-claude-config-reader.d.ts +7 -0
  11. package/dist/metadata/repo-claude-config-reader.js +154 -0
  12. package/dist/plugin/agent-hierarchy.d.ts +9 -9
  13. package/dist/plugin/agent-hierarchy.js +25 -25
  14. package/dist/plugin/claude-manager.plugin.js +83 -46
  15. package/dist/plugin/orchestrator.plugin.d.ts +2 -0
  16. package/dist/plugin/orchestrator.plugin.js +116 -0
  17. package/dist/plugin/service-factory.js +3 -8
  18. package/dist/prompts/registry.js +100 -103
  19. package/dist/providers/claude-code-wrapper.d.ts +13 -0
  20. package/dist/providers/claude-code-wrapper.js +13 -0
  21. package/dist/safety/bash-safety.d.ts +21 -0
  22. package/dist/safety/bash-safety.js +62 -0
  23. package/dist/src/claude/claude-agent-sdk-adapter.d.ts +27 -0
  24. package/dist/src/claude/claude-agent-sdk-adapter.js +517 -0
  25. package/dist/src/claude/claude-session.service.d.ts +10 -0
  26. package/dist/src/claude/claude-session.service.js +18 -0
  27. package/dist/src/claude/session-live-tailer.d.ts +51 -0
  28. package/dist/src/claude/session-live-tailer.js +269 -0
  29. package/dist/src/claude/tool-approval-manager.d.ts +27 -0
  30. package/dist/src/claude/tool-approval-manager.js +232 -0
  31. package/dist/src/index.d.ts +6 -0
  32. package/dist/src/index.js +4 -0
  33. package/dist/src/manager/context-tracker.d.ts +33 -0
  34. package/dist/src/manager/context-tracker.js +106 -0
  35. package/dist/src/manager/git-operations.d.ts +12 -0
  36. package/dist/src/manager/git-operations.js +76 -0
  37. package/dist/src/manager/persistent-manager.d.ts +77 -0
  38. package/dist/src/manager/persistent-manager.js +170 -0
  39. package/dist/src/manager/session-controller.d.ts +44 -0
  40. package/dist/src/manager/session-controller.js +147 -0
  41. package/dist/src/plugin/agent-hierarchy.d.ts +60 -0
  42. package/dist/src/plugin/agent-hierarchy.js +157 -0
  43. package/dist/src/plugin/claude-manager.plugin.d.ts +2 -0
  44. package/dist/src/plugin/claude-manager.plugin.js +563 -0
  45. package/dist/src/plugin/service-factory.d.ts +12 -0
  46. package/dist/src/plugin/service-factory.js +38 -0
  47. package/dist/src/prompts/registry.d.ts +11 -0
  48. package/dist/src/prompts/registry.js +260 -0
  49. package/dist/src/state/file-run-state-store.d.ts +14 -0
  50. package/dist/src/state/file-run-state-store.js +85 -0
  51. package/dist/src/state/transcript-store.d.ts +15 -0
  52. package/dist/src/state/transcript-store.js +44 -0
  53. package/dist/src/types/contracts.d.ts +200 -0
  54. package/dist/src/types/contracts.js +1 -0
  55. package/dist/src/util/fs-helpers.d.ts +2 -0
  56. package/dist/src/util/fs-helpers.js +10 -0
  57. package/dist/src/util/project-context.d.ts +10 -0
  58. package/dist/src/util/project-context.js +105 -0
  59. package/dist/src/util/transcript-append.d.ts +7 -0
  60. package/dist/src/util/transcript-append.js +29 -0
  61. package/dist/test/claude-agent-sdk-adapter.test.d.ts +1 -0
  62. package/dist/test/claude-agent-sdk-adapter.test.js +459 -0
  63. package/dist/test/claude-manager.plugin.test.d.ts +1 -0
  64. package/dist/test/claude-manager.plugin.test.js +331 -0
  65. package/dist/test/context-tracker.test.d.ts +1 -0
  66. package/dist/test/context-tracker.test.js +138 -0
  67. package/dist/test/file-run-state-store.test.d.ts +1 -0
  68. package/dist/test/file-run-state-store.test.js +82 -0
  69. package/dist/test/git-operations.test.d.ts +1 -0
  70. package/dist/test/git-operations.test.js +90 -0
  71. package/dist/test/persistent-manager.test.d.ts +1 -0
  72. package/dist/test/persistent-manager.test.js +208 -0
  73. package/dist/test/project-context.test.d.ts +1 -0
  74. package/dist/test/project-context.test.js +92 -0
  75. package/dist/test/prompt-registry.test.d.ts +1 -0
  76. package/dist/test/prompt-registry.test.js +256 -0
  77. package/dist/test/session-controller.test.d.ts +1 -0
  78. package/dist/test/session-controller.test.js +149 -0
  79. package/dist/test/session-live-tailer.test.d.ts +1 -0
  80. package/dist/test/session-live-tailer.test.js +313 -0
  81. package/dist/test/tool-approval-manager.test.d.ts +1 -0
  82. package/dist/test/tool-approval-manager.test.js +264 -0
  83. package/dist/test/transcript-append.test.d.ts +1 -0
  84. package/dist/test/transcript-append.test.js +37 -0
  85. package/dist/test/transcript-store.test.d.ts +1 -0
  86. package/dist/test/transcript-store.test.js +50 -0
  87. package/dist/types/contracts.d.ts +3 -4
  88. package/dist/vitest.config.d.ts +2 -0
  89. package/dist/vitest.config.js +11 -0
  90. package/package.json +2 -2
@@ -0,0 +1,260 @@
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
+ export const managerPromptRegistry = {
17
+ ctoSystemPrompt: [
18
+ 'You are a staff+ technical owner who uses Claude Code better than anyone.',
19
+ 'You own the outcome — discover the right problem before solving it.',
20
+ '',
21
+ '## Core principle: delegation-first',
22
+ 'Your default action is to delegate. Do not do broad repo exploration yourself',
23
+ 'when an engineer can do it. Direct read/grep/glob is allowed only for:',
24
+ '- Spot-checks to sharpen a delegation.',
25
+ '- Verifying a result after an engineer returns.',
26
+ '- Resolving one high-leverage ambiguity before dispatching.',
27
+ 'If you need more than 2 direct read/grep/glob lookups, stop and delegate',
28
+ 'the investigation to `engineer_plan` instead.',
29
+ '',
30
+ '## Core principle: technical ownership',
31
+ 'You are not a ticket-taker. Before acting, look for:',
32
+ '- Hidden assumptions and missing constraints.',
33
+ '- Ownership issues, abstraction leaks, and better boundaries.',
34
+ '- Root causes — prefer fixing root causes over patching symptoms.',
35
+ '',
36
+ '## Core principle: verification-first',
37
+ 'Every delegation MUST include how to verify success.',
38
+ 'Tests, expected outputs, lint/typecheck commands, or before/after behavior.',
39
+ 'This is the single highest-leverage thing you do.',
40
+ 'Never delegate without telling the engineer how to prove it worked.',
41
+ '',
42
+ '## Right-size your approach',
43
+ 'Not every task needs a plan. Assess complexity, then act:',
44
+ '',
45
+ '**Simple tasks** (typo, rename, add a log line, one-file fix):',
46
+ ' Skip investigation. Delegate directly with specific context.',
47
+ '',
48
+ '**Medium+ tasks** (bug fix, feature, refactor, architecture change):',
49
+ ' Before delegating, determine:',
50
+ ' 1. What the user asked vs. what is actually needed.',
51
+ ' 2. What is underspecified or conflicting.',
52
+ ' 3. What the cleanest architecture is.',
53
+ ' 4. What should be clarified before proceeding.',
54
+ ' Prefer spawning `engineer_plan` for repo exploration rather than reading',
55
+ ' code yourself. Use at most 1-2 spot-check reads to sharpen the delegation.',
56
+ ' Then delegate with file paths, line numbers, patterns, and verification.',
57
+ '',
58
+ '**Complex tasks** (multi-file feature, large refactor):',
59
+ ' 1. Spawn `engineer_plan` to explore the repo, map dependencies, and analyze impact.',
60
+ ' 2. If requirements are unclear, ask the user ONE high-leverage question —',
61
+ ' only when it materially changes architecture, ownership, or destructive behavior.',
62
+ ' Prefer the question tool when discrete options exist.',
63
+ ' 3. Write a plan to the todo list (todowrite). Share it with the user.',
64
+ ' 4. Execute steps sequentially, committing after each.',
65
+ '',
66
+ '## Missed-opportunity check',
67
+ 'Before finalizing any medium+ delegation, check:',
68
+ '- One cleaner alternative you considered.',
69
+ '- One risk the current approach carries.',
70
+ '- One thing the requester likely missed.',
71
+ 'If any of these materially improve the outcome, surface them.',
72
+ '',
73
+ '## How to delegate effectively',
74
+ 'The engineer does not have your context. Every instruction must be self-contained.',
75
+ 'Include:',
76
+ '- Exact files, functions, and line numbers to change.',
77
+ '- Current behavior and desired behavior.',
78
+ '- Code snippets showing the pattern or convention to follow.',
79
+ '- How to verify: "Run `npm test`, expect all green." or',
80
+ ' "The function should return null instead of throwing."',
81
+ '',
82
+ 'Bad: "Fix the auth bug"',
83
+ 'Good: "In src/auth/session.ts, `validateToken` (line 42) throws on expired',
84
+ ' tokens instead of returning null. Change it to return null.',
85
+ ' Update the caller in src/routes/login.ts:87.',
86
+ ' Follow the pattern in src/auth/refresh.ts:23.',
87
+ ' Run `npm test -- --grep auth` to verify. All tests should pass."',
88
+ '',
89
+ '## Review every change',
90
+ 'After each delegation:',
91
+ '1. git_diff — read the FULL diff. Check for unintended changes, missing tests,',
92
+ ' style violations.',
93
+ '2. If correct: spawn `engineer_build` to run tests/lint/typecheck.',
94
+ '3. If tests pass: git_commit to checkpoint.',
95
+ '4. If wrong: spawn `engineer_build` with a specific correction.',
96
+ ' On second failure: git_reset and rewrite the prompt from scratch.',
97
+ ' Never send three corrections for the same problem.',
98
+ '',
99
+ '## Engineers (via the Task tool)',
100
+ '- `engineer_plan` — read-only investigation. Use for: exploring unfamiliar code,',
101
+ ' mapping dependencies, analyzing impact, asking "how does X work?"',
102
+ '- `engineer_build` — implementation. Use for: all code changes, test runs, fixes.',
103
+ '- If steps are independent, spawn multiple engineers in parallel.',
104
+ '',
105
+ '## Context efficiency',
106
+ '- Use `engineer_plan` for broad exploration so your own context stays clean.',
107
+ '- When spawning engineers for unrelated tasks, tell them to use freshSession:true.',
108
+ '- Keep delegations focused — one concern per engineer invocation.',
109
+ '',
110
+ '## What you must NOT do',
111
+ '- Do NOT call any engineer_* tools directly. Use the Task tool.',
112
+ '- Do NOT edit files or run bash commands yourself.',
113
+ '- Do NOT skip review — always git_diff after delegation.',
114
+ '- Do NOT delegate without verification criteria.',
115
+ '',
116
+ '## Tools reference',
117
+ 'todowrite / todoread — track multi-step work',
118
+ 'question — ask the user structured questions with options',
119
+ 'git_diff — review all uncommitted changes',
120
+ 'git_commit — stage all + commit',
121
+ 'git_reset — hard reset + clean (destructive)',
122
+ 'approval_policy — view tool approval rules',
123
+ 'approval_decisions — view recent approval decisions',
124
+ 'approval_update — modify tool approval policy',
125
+ '',
126
+ '## Autonomy blockers',
127
+ 'Surface these to the user immediately:',
128
+ '- Credentials, API keys, or secrets you do not have.',
129
+ '- Architectural decisions with trade-offs the user should weigh.',
130
+ '- Destructive actions on shared state (deploy, publish, force-push).',
131
+ 'State the blocker, what you need, and a concrete suggestion to unblock.',
132
+ ].join('\n'),
133
+ engineerPlanPrompt: [
134
+ 'You are a staff engineer managing a Claude Code session for read-only investigation.',
135
+ 'You are not a forwarding layer — interpret the task in repo context before delegating.',
136
+ '',
137
+ '## Staff-level framing',
138
+ '- Identify the real problem, not just the stated request.',
139
+ '- Look for missing architecture, ownership, or precedence issues before delegating.',
140
+ '- Rewrite weak or underspecified requests into precise prompts for the engineer.',
141
+ '- For medium+ tasks, determine: the actual problem, the cleanest architecture,',
142
+ ' and what needs clarification before work begins.',
143
+ '- Ask ONE clarification first if it materially improves architecture.',
144
+ '',
145
+ '## Repo-context investigation',
146
+ '- Use read/grep/glob sparingly — only for spot-checks to sharpen a delegation.',
147
+ '- If more than 2 lookups are needed, send the investigation to the engineer.',
148
+ '- Do NOT implement changes yourself — investigation only.',
149
+ '',
150
+ '## Behavior',
151
+ '- Send the objective to the engineer using explore.',
152
+ "- Return the engineer's response verbatim. Do not summarize.",
153
+ '- Use freshSession:true on explore when the task is unrelated to prior work.',
154
+ '',
155
+ '## Context management',
156
+ '- Check session_health before sending.',
157
+ '- Under 50%: proceed. Over 70%: compact_context. Over 85%: clear_session.',
158
+ '',
159
+ '## Model selection',
160
+ '- claude-opus-4-6 + high: complex analysis (default).',
161
+ '- claude-sonnet-4-6: lighter analysis.',
162
+ '- effort "medium": simple lookups.',
163
+ '',
164
+ '## Using appended Project Claude Files',
165
+ '- Treat appended Project Claude Files as project guidance for the engineer.',
166
+ '- Extract only the rules relevant to the current task when delegating.',
167
+ '- Prefer guidance from more specific/nested paths over root-level guidance on conflict.',
168
+ '- Direct user instructions override Claude-file guidance.',
169
+ '- Keep delegated instructions tight; do not dump the full file corpus unless needed.',
170
+ '- Cite file paths (e.g. "per packages/core/CLAUDE.md") when the source matters.',
171
+ '',
172
+ '## What you must NOT do',
173
+ '- Do NOT call git_*, approval_*, or any non-engineer tools.',
174
+ '- Do NOT add commentary to the engineer response.',
175
+ ].join('\n'),
176
+ engineerBuildPrompt: [
177
+ 'You are a staff engineer managing a Claude Code session for implementation.',
178
+ 'You are not a forwarding layer — interpret the task in repo context before delegating.',
179
+ '',
180
+ '## Staff-level framing',
181
+ '- Identify the real problem, not just the stated request.',
182
+ '- Look for missing architecture, ownership, or precedence issues before delegating.',
183
+ '- Rewrite weak or underspecified requests into precise prompts for the engineer.',
184
+ '- For medium+ tasks, determine: the actual problem, the cleanest architecture,',
185
+ ' and what needs clarification before work begins.',
186
+ '- Ask ONE clarification first if it materially improves architecture.',
187
+ '',
188
+ '## Repo-context investigation',
189
+ '- Use read/grep/glob sparingly — only for spot-checks to sharpen a delegation.',
190
+ '- If more than 2 lookups are needed, send the investigation to the engineer.',
191
+ '- Do NOT implement changes yourself — investigation only.',
192
+ '',
193
+ '## Behavior',
194
+ '- Send the objective to the engineer using implement.',
195
+ "- Return the engineer's response verbatim. Do not summarize.",
196
+ '- Use freshSession:true on implement when the task is unrelated to prior work.',
197
+ '',
198
+ '## Context management',
199
+ '- Check session_health before sending.',
200
+ '- Under 50%: proceed. Over 70%: compact_context. Over 85%: clear_session.',
201
+ '',
202
+ '## Model selection',
203
+ '- claude-opus-4-6 + high: most coding tasks (default).',
204
+ '- claude-sonnet-4-6: simple renames, formatting, scaffolding.',
205
+ '- effort "max": complex refactors, subtle bugs, cross-cutting changes.',
206
+ '',
207
+ '## Using appended Project Claude Files',
208
+ '- Treat appended Project Claude Files as project guidance for the engineer.',
209
+ '- Extract only the rules relevant to the current task when delegating.',
210
+ '- Prefer guidance from more specific/nested paths over root-level guidance on conflict.',
211
+ '- Direct user instructions override Claude-file guidance.',
212
+ '- Keep delegated instructions tight; do not dump the full file corpus unless needed.',
213
+ '- Cite file paths (e.g. "per packages/core/CLAUDE.md") when the source matters.',
214
+ '',
215
+ '## What you must NOT do',
216
+ '- Do NOT call git_*, approval_*, or any non-engineer tools.',
217
+ '- Do NOT add commentary to the engineer response.',
218
+ ].join('\n'),
219
+ engineerSessionPrompt: [
220
+ 'You are an expert engineer. Execute instructions precisely.',
221
+ '',
222
+ '## Rules',
223
+ '- Execute directly. No preamble, no restating the task.',
224
+ '- Prefer targeted file reads over reading entire files.',
225
+ '- Use subagents for independent parallel work.',
226
+ '- Follow existing repo conventions (naming, style, patterns).',
227
+ '',
228
+ '## Verification',
229
+ '- Always verify your own work before reporting done.',
230
+ '- Run tests, lint, or typecheck when the instruction says to.',
231
+ '- If no verification was specified, still run relevant tests if they exist.',
232
+ '- Report exact output on failure.',
233
+ '',
234
+ '## Git boundary — do NOT run:',
235
+ 'git commit, git push, git reset, git checkout, git stash.',
236
+ 'Git operations are handled externally.',
237
+ '',
238
+ '## Reporting',
239
+ '- End with: what was done, what was verified, what passed/failed.',
240
+ '- Report blockers immediately with specifics: file, line, error.',
241
+ '- If partially complete, state exactly what remains.',
242
+ ].join('\n'),
243
+ modePrefixes: {
244
+ plan: [
245
+ '[PLAN MODE] Read-only. Do NOT create or edit any files.',
246
+ 'Do NOT use ExitPlanMode or write artifacts to disk.',
247
+ 'Use read, grep, glob, and search tools only.',
248
+ 'Analyze the codebase and produce a detailed implementation plan:',
249
+ 'files to change, functions to modify, new files to create, test strategy,',
250
+ 'and risks. End with a numbered step-by-step plan.',
251
+ 'Return the entire plan inline in your response.',
252
+ ].join(' '),
253
+ free: '',
254
+ },
255
+ contextWarnings: {
256
+ moderate: 'Session context is filling up ({percent}% estimated). Consider whether a fresh session would be more efficient.',
257
+ high: 'Session context is heavy ({percent}% estimated, {turns} turns, ${cost}). Start a new session or compact first.',
258
+ critical: 'Session context is near capacity ({percent}% estimated). Clear the session immediately before continuing.',
259
+ },
260
+ };
@@ -0,0 +1,14 @@
1
+ import type { PersistentRunRecord } from '../types/contracts.js';
2
+ export declare class FileRunStateStore {
3
+ private readonly baseDirectoryName;
4
+ private readonly writeQueues;
5
+ constructor(baseDirectoryName?: string);
6
+ saveRun(run: PersistentRunRecord): Promise<void>;
7
+ getRun(cwd: string, runId: string): Promise<PersistentRunRecord | null>;
8
+ listRuns(cwd: string): Promise<PersistentRunRecord[]>;
9
+ updateRun(cwd: string, runId: string, update: (run: PersistentRunRecord) => PersistentRunRecord): Promise<PersistentRunRecord>;
10
+ private getRunKey;
11
+ private getRunsDirectory;
12
+ private getRunPath;
13
+ private enqueueWrite;
14
+ }
@@ -0,0 +1,85 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { isFileNotFoundError, writeJsonAtomically } from '../util/fs-helpers.js';
4
+ export class FileRunStateStore {
5
+ baseDirectoryName;
6
+ writeQueues = new Map();
7
+ constructor(baseDirectoryName = '.claude-manager') {
8
+ this.baseDirectoryName = baseDirectoryName;
9
+ }
10
+ async saveRun(run) {
11
+ await this.enqueueWrite(this.getRunKey(run.cwd, run.id), async () => {
12
+ const runPath = this.getRunPath(run.cwd, run.id);
13
+ await fs.mkdir(path.dirname(runPath), { recursive: true });
14
+ await writeJsonAtomically(runPath, run);
15
+ });
16
+ }
17
+ async getRun(cwd, runId) {
18
+ const runPath = this.getRunPath(cwd, runId);
19
+ try {
20
+ const content = await fs.readFile(runPath, 'utf8');
21
+ return JSON.parse(content);
22
+ }
23
+ catch (error) {
24
+ if (isFileNotFoundError(error)) {
25
+ return null;
26
+ }
27
+ throw error;
28
+ }
29
+ }
30
+ async listRuns(cwd) {
31
+ const runsDirectory = this.getRunsDirectory(cwd);
32
+ try {
33
+ const entries = await fs.readdir(runsDirectory);
34
+ const runs = await Promise.all(entries
35
+ .filter((entry) => entry.endsWith('.json'))
36
+ .map(async (entry) => {
37
+ const content = await fs.readFile(path.join(runsDirectory, entry), 'utf8');
38
+ return JSON.parse(content);
39
+ }));
40
+ return runs.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
41
+ }
42
+ catch (error) {
43
+ if (isFileNotFoundError(error)) {
44
+ return [];
45
+ }
46
+ throw error;
47
+ }
48
+ }
49
+ async updateRun(cwd, runId, update) {
50
+ return this.enqueueWrite(this.getRunKey(cwd, runId), async () => {
51
+ const existingRun = await this.getRun(cwd, runId);
52
+ if (!existingRun) {
53
+ throw new Error(`Run ${runId} does not exist.`);
54
+ }
55
+ const updatedRun = update(existingRun);
56
+ const runPath = this.getRunPath(cwd, runId);
57
+ await fs.mkdir(path.dirname(runPath), { recursive: true });
58
+ await writeJsonAtomically(runPath, updatedRun);
59
+ return updatedRun;
60
+ });
61
+ }
62
+ getRunKey(cwd, runId) {
63
+ return `${cwd}:${runId}`;
64
+ }
65
+ getRunsDirectory(cwd) {
66
+ return path.join(cwd, this.baseDirectoryName, 'runs');
67
+ }
68
+ getRunPath(cwd, runId) {
69
+ return path.join(this.getRunsDirectory(cwd), `${runId}.json`);
70
+ }
71
+ async enqueueWrite(key, operation) {
72
+ const previousOperation = this.writeQueues.get(key) ?? Promise.resolve();
73
+ const resultPromise = previousOperation.catch(() => undefined).then(operation);
74
+ const settledPromise = resultPromise.then(() => undefined, () => undefined);
75
+ this.writeQueues.set(key, settledPromise);
76
+ try {
77
+ return await resultPromise;
78
+ }
79
+ finally {
80
+ if (this.writeQueues.get(key) === settledPromise) {
81
+ this.writeQueues.delete(key);
82
+ }
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,15 @@
1
+ import type { ClaudeSessionEvent } from '../types/contracts.js';
2
+ export declare class TranscriptStore {
3
+ private readonly baseDirectoryName;
4
+ constructor(baseDirectoryName?: string);
5
+ /**
6
+ * Append new events to the transcript file for the given session.
7
+ * Creates the file if it does not exist. Strips trailing partials before persisting.
8
+ */
9
+ appendEvents(cwd: string, sessionId: string, newEvents: ClaudeSessionEvent[]): Promise<void>;
10
+ /**
11
+ * Read all persisted transcript events for a session.
12
+ */
13
+ readEvents(cwd: string, sessionId: string): Promise<ClaudeSessionEvent[]>;
14
+ private getTranscriptPath;
15
+ }
@@ -0,0 +1,44 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { appendTranscriptEvents, stripTrailingPartials } from '../util/transcript-append.js';
4
+ import { isFileNotFoundError, writeJsonAtomically } from '../util/fs-helpers.js';
5
+ export class TranscriptStore {
6
+ baseDirectoryName;
7
+ constructor(baseDirectoryName = '.claude-manager') {
8
+ this.baseDirectoryName = baseDirectoryName;
9
+ }
10
+ /**
11
+ * Append new events to the transcript file for the given session.
12
+ * Creates the file if it does not exist. Strips trailing partials before persisting.
13
+ */
14
+ async appendEvents(cwd, sessionId, newEvents) {
15
+ if (newEvents.length === 0) {
16
+ return;
17
+ }
18
+ const filePath = this.getTranscriptPath(cwd, sessionId);
19
+ const existing = await this.readEvents(cwd, sessionId);
20
+ const merged = appendTranscriptEvents(existing, newEvents);
21
+ const cleaned = stripTrailingPartials(merged);
22
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
23
+ await writeJsonAtomically(filePath, cleaned);
24
+ }
25
+ /**
26
+ * Read all persisted transcript events for a session.
27
+ */
28
+ async readEvents(cwd, sessionId) {
29
+ const filePath = this.getTranscriptPath(cwd, sessionId);
30
+ try {
31
+ const content = await fs.readFile(filePath, 'utf8');
32
+ return JSON.parse(content);
33
+ }
34
+ catch (error) {
35
+ if (isFileNotFoundError(error)) {
36
+ return [];
37
+ }
38
+ throw error;
39
+ }
40
+ }
41
+ getTranscriptPath(cwd, sessionId) {
42
+ return path.join(cwd, this.baseDirectoryName, 'transcripts', `${sessionId}.json`);
43
+ }
44
+ }
@@ -0,0 +1,200 @@
1
+ export interface ManagerPromptRegistry {
2
+ ctoSystemPrompt: string;
3
+ engineerPlanPrompt: string;
4
+ engineerBuildPrompt: string;
5
+ engineerSessionPrompt: string;
6
+ modePrefixes: {
7
+ plan: string;
8
+ free: string;
9
+ };
10
+ contextWarnings: {
11
+ moderate: string;
12
+ high: string;
13
+ critical: string;
14
+ };
15
+ }
16
+ export type SessionMode = 'plan' | 'free';
17
+ export interface ClaudeCommandMetadata {
18
+ name: string;
19
+ description: string;
20
+ argumentHint?: string;
21
+ source: 'sdk' | 'skill' | 'command';
22
+ path?: string;
23
+ }
24
+ export interface ClaudeAgentMetadata {
25
+ name: string;
26
+ description: string;
27
+ model?: string;
28
+ source: 'sdk' | 'filesystem';
29
+ }
30
+ export interface ClaudeSessionEvent {
31
+ type: 'init' | 'assistant' | 'partial' | 'user' | 'tool_call' | 'tool_progress' | 'tool_summary' | 'status' | 'system' | 'result' | 'error';
32
+ sessionId?: string;
33
+ text: string;
34
+ turns?: number;
35
+ totalCostUsd?: number;
36
+ /** Present on live SDK-normalized events; omitted when compact-persisted to save space. */
37
+ rawType?: string;
38
+ }
39
+ export interface RunClaudeSessionInput {
40
+ cwd: string;
41
+ prompt: string;
42
+ systemPrompt?: string;
43
+ model?: string;
44
+ effort?: 'low' | 'medium' | 'high' | 'max';
45
+ mode?: SessionMode;
46
+ permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'dontAsk';
47
+ /** Merged with `Skill` by the SDK adapter unless `Skill` appears in `disallowedTools`. */
48
+ allowedTools?: string[];
49
+ disallowedTools?: string[];
50
+ continueSession?: boolean;
51
+ resumeSessionId?: string;
52
+ forkSession?: boolean;
53
+ persistSession?: boolean;
54
+ includePartialMessages?: boolean;
55
+ settingSources?: Array<'user' | 'project' | 'local'>;
56
+ maxTurns?: number;
57
+ abortSignal?: AbortSignal;
58
+ }
59
+ export interface ClaudeSessionRunResult {
60
+ sessionId?: string;
61
+ events: ClaudeSessionEvent[];
62
+ finalText: string;
63
+ turns?: number;
64
+ totalCostUsd?: number;
65
+ inputTokens?: number;
66
+ outputTokens?: number;
67
+ contextWindowSize?: number;
68
+ }
69
+ export interface ClaudeSessionSummary {
70
+ sessionId: string;
71
+ summary: string;
72
+ cwd?: string;
73
+ gitBranch?: string;
74
+ createdAt?: number;
75
+ lastModified: number;
76
+ }
77
+ export interface ClaudeSessionTranscriptMessage {
78
+ role: 'user' | 'assistant';
79
+ sessionId: string;
80
+ messageId: string;
81
+ text: string;
82
+ }
83
+ export interface ClaudeCapabilitySnapshot {
84
+ commands: ClaudeCommandMetadata[];
85
+ agents: ClaudeAgentMetadata[];
86
+ models: string[];
87
+ }
88
+ export type ContextWarningLevel = 'ok' | 'moderate' | 'high' | 'critical';
89
+ export interface SessionContextSnapshot {
90
+ sessionId: string | null;
91
+ totalTurns: number;
92
+ totalCostUsd: number;
93
+ latestInputTokens: number | null;
94
+ latestOutputTokens: number | null;
95
+ contextWindowSize: number | null;
96
+ estimatedContextPercent: number | null;
97
+ warningLevel: ContextWarningLevel;
98
+ compactionCount: number;
99
+ }
100
+ export interface GitDiffResult {
101
+ hasDiff: boolean;
102
+ diffText: string;
103
+ stats: {
104
+ filesChanged: number;
105
+ insertions: number;
106
+ deletions: number;
107
+ };
108
+ }
109
+ export interface GitOperationResult {
110
+ success: boolean;
111
+ output: string;
112
+ error?: string;
113
+ }
114
+ export interface ActiveSessionState {
115
+ sessionId: string;
116
+ cwd: string;
117
+ startedAt: string;
118
+ totalTurns: number;
119
+ totalCostUsd: number;
120
+ estimatedContextPercent: number | null;
121
+ contextWindowSize: number | null;
122
+ latestInputTokens: number | null;
123
+ }
124
+ export type PersistentRunStatus = 'running' | 'completed' | 'failed';
125
+ export interface PersistentRunMessageRecord {
126
+ timestamp: string;
127
+ direction: 'sent' | 'received';
128
+ text: string;
129
+ turns?: number;
130
+ totalCostUsd?: number;
131
+ inputTokens?: number;
132
+ outputTokens?: number;
133
+ }
134
+ export interface PersistentRunActionRecord {
135
+ timestamp: string;
136
+ type: 'git_diff' | 'git_commit' | 'git_reset' | 'compact' | 'clear';
137
+ result: string;
138
+ }
139
+ export interface PersistentRunRecord {
140
+ id: string;
141
+ cwd: string;
142
+ task: string;
143
+ status: PersistentRunStatus;
144
+ createdAt: string;
145
+ updatedAt: string;
146
+ sessionId: string | null;
147
+ sessionHistory: string[];
148
+ messages: PersistentRunMessageRecord[];
149
+ actions: PersistentRunActionRecord[];
150
+ commits: string[];
151
+ context: SessionContextSnapshot;
152
+ finalSummary?: string;
153
+ }
154
+ export interface PersistentRunResult {
155
+ run: PersistentRunRecord;
156
+ }
157
+ export interface LiveTailEvent {
158
+ type: 'line' | 'error' | 'end';
159
+ sessionId: string;
160
+ data?: unknown;
161
+ rawLine?: string;
162
+ error?: string;
163
+ }
164
+ export interface ToolOutputPreview {
165
+ toolUseId: string;
166
+ content: string;
167
+ isError: boolean;
168
+ }
169
+ export interface DiscoveredClaudeFile {
170
+ /** Relative path from the project root (forward slashes, deterministic order). */
171
+ relativePath: string;
172
+ /** Trimmed UTF-8 text content. */
173
+ content: string;
174
+ }
175
+ export interface ToolApprovalRule {
176
+ id: string;
177
+ description?: string;
178
+ /** Tool name — exact match or glob with * wildcard */
179
+ toolPattern: string;
180
+ /** Optional substring match against JSON-serialized tool input */
181
+ inputPattern?: string;
182
+ action: 'allow' | 'deny';
183
+ denyMessage?: string;
184
+ }
185
+ export interface ToolApprovalPolicy {
186
+ rules: ToolApprovalRule[];
187
+ defaultAction: 'allow' | 'deny';
188
+ defaultDenyMessage?: string;
189
+ enabled: boolean;
190
+ }
191
+ export interface ToolApprovalDecision {
192
+ timestamp: string;
193
+ toolName: string;
194
+ inputPreview: string;
195
+ title?: string;
196
+ matchedRuleId: string;
197
+ action: 'allow' | 'deny';
198
+ denyMessage?: string;
199
+ agentId?: string;
200
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export declare function writeJsonAtomically(filePath: string, data: unknown): Promise<void>;
2
+ export declare function isFileNotFoundError(error: unknown): error is NodeJS.ErrnoException;
@@ -0,0 +1,10 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { promises as fs } from 'node:fs';
3
+ export async function writeJsonAtomically(filePath, data) {
4
+ const tempPath = `${filePath}.${randomUUID()}.tmp`;
5
+ await fs.writeFile(tempPath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
6
+ await fs.rename(tempPath, filePath);
7
+ }
8
+ export function isFileNotFoundError(error) {
9
+ return (error instanceof Error && 'code' in error && error.code === 'ENOENT');
10
+ }
@@ -0,0 +1,10 @@
1
+ import type { DiscoveredClaudeFile } from '../types/contracts.js';
2
+ /**
3
+ * Recursively discover all project-level Claude files:
4
+ * - every `CLAUDE.md` found anywhere in the repo tree
5
+ * - every file under `.claude/` recursively
6
+ *
7
+ * Returns a de-duplicated, deterministically sorted array of
8
+ * { relativePath, content } entries. Empty/blank files are skipped.
9
+ */
10
+ export declare function discoverProjectClaudeFiles(cwd: string): Promise<DiscoveredClaudeFile[]>;