@doingdev/opencode-claude-manager-plugin 0.1.0

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.
@@ -0,0 +1,42 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ export class TaskPlanner {
3
+ plan(task, mode, maxSubagents) {
4
+ if (mode === 'single') {
5
+ return [this.createPlan('Primary task', task)];
6
+ }
7
+ const splitCandidates = extractTaskCandidates(task).slice(0, maxSubagents);
8
+ if (mode === 'split' && splitCandidates.length === 0) {
9
+ return [this.createPlan('Primary task', task)];
10
+ }
11
+ if (mode === 'auto' && splitCandidates.length < 2) {
12
+ return [this.createPlan('Primary task', task)];
13
+ }
14
+ if (splitCandidates.length === 0) {
15
+ return [this.createPlan('Primary task', task)];
16
+ }
17
+ return splitCandidates.map((candidate, index) => this.createPlan(`Subtask ${index + 1}`, candidate));
18
+ }
19
+ createPlan(title, prompt) {
20
+ return {
21
+ id: randomUUID(),
22
+ title,
23
+ prompt,
24
+ };
25
+ }
26
+ }
27
+ function extractTaskCandidates(task) {
28
+ const listMatches = task
29
+ .split(/\r?\n/)
30
+ .map((line) => line.trim())
31
+ .filter((line) => /^(-|\*|\d+\.)\s+/.test(line))
32
+ .map((line) => line.replace(/^(-|\*|\d+\.)\s+/, '').trim())
33
+ .filter(Boolean);
34
+ if (listMatches.length > 0) {
35
+ return listMatches;
36
+ }
37
+ const sentenceMatches = task
38
+ .split(/;|\n{2,}/)
39
+ .map((part) => part.trim())
40
+ .filter((part) => part.length > 20);
41
+ return sentenceMatches.length > 1 ? sentenceMatches : [];
42
+ }
@@ -0,0 +1,12 @@
1
+ import type { ClaudeMetadataSnapshot, ClaudeSettingSource } from '../types/contracts.js';
2
+ import type { ClaudeAgentSdkAdapter } from '../claude/claude-agent-sdk-adapter.js';
3
+ import type { RepoClaudeConfigReader } from './repo-claude-config-reader.js';
4
+ export declare class ClaudeMetadataService {
5
+ private readonly configReader;
6
+ private readonly sdkAdapter;
7
+ constructor(configReader: RepoClaudeConfigReader, sdkAdapter: ClaudeAgentSdkAdapter);
8
+ collect(cwd: string, options?: {
9
+ includeSdkProbe?: boolean;
10
+ settingSources?: ClaudeSettingSource[];
11
+ }): Promise<ClaudeMetadataSnapshot>;
12
+ }
@@ -0,0 +1,38 @@
1
+ export class ClaudeMetadataService {
2
+ configReader;
3
+ sdkAdapter;
4
+ constructor(configReader, sdkAdapter) {
5
+ this.configReader = configReader;
6
+ this.sdkAdapter = sdkAdapter;
7
+ }
8
+ async collect(cwd, options = {}) {
9
+ const baseSnapshot = await this.configReader.read(cwd);
10
+ if (!options.includeSdkProbe) {
11
+ return dedupeSnapshot(baseSnapshot);
12
+ }
13
+ const capabilities = await this.sdkAdapter.probeCapabilities(cwd, options.settingSources);
14
+ return dedupeSnapshot({
15
+ ...baseSnapshot,
16
+ commands: [...baseSnapshot.commands, ...capabilities.commands],
17
+ agents: capabilities.agents,
18
+ });
19
+ }
20
+ }
21
+ function dedupeSnapshot(snapshot) {
22
+ return {
23
+ ...snapshot,
24
+ commands: dedupeByName(snapshot.commands),
25
+ skills: dedupeByName(snapshot.skills),
26
+ hooks: dedupeByName(snapshot.hooks),
27
+ agents: dedupeByName(snapshot.agents),
28
+ };
29
+ }
30
+ function dedupeByName(items) {
31
+ const seen = new Map();
32
+ for (const item of items) {
33
+ if (!seen.has(item.name)) {
34
+ seen.set(item.name, item);
35
+ }
36
+ }
37
+ return [...seen.values()].sort((left, right) => left.name.localeCompare(right.name));
38
+ }
@@ -0,0 +1,7 @@
1
+ import type { ClaudeMetadataSnapshot } from '../types/contracts.js';
2
+ export declare class RepoClaudeConfigReader {
3
+ read(cwd: string): Promise<ClaudeMetadataSnapshot>;
4
+ private readSkills;
5
+ private readCommands;
6
+ private readSettings;
7
+ }
@@ -0,0 +1,154 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import JSON5 from 'json5';
4
+ export class RepoClaudeConfigReader {
5
+ async read(cwd) {
6
+ const claudeDirectory = path.join(cwd, '.claude');
7
+ const skillsDirectory = path.join(claudeDirectory, 'skills');
8
+ const commandsDirectory = path.join(claudeDirectory, 'commands');
9
+ const claudeMdCandidates = [
10
+ path.join(cwd, 'CLAUDE.md'),
11
+ path.join(claudeDirectory, 'CLAUDE.md'),
12
+ ];
13
+ const collectedAt = new Date().toISOString();
14
+ const [skills, commands, settingsResult, claudeMdPath] = await Promise.all([
15
+ this.readSkills(skillsDirectory),
16
+ this.readCommands(commandsDirectory),
17
+ this.readSettings(claudeDirectory),
18
+ findFirstExistingPath(claudeMdCandidates),
19
+ ]);
20
+ return {
21
+ collectedAt,
22
+ cwd,
23
+ commands: [...skillsToCommands(skills), ...commands],
24
+ skills,
25
+ hooks: settingsResult.hooks,
26
+ agents: [],
27
+ claudeMdPath: claudeMdPath ?? undefined,
28
+ settingsPaths: settingsResult.settingsPaths,
29
+ };
30
+ }
31
+ async readSkills(directory) {
32
+ if (!(await pathExists(directory))) {
33
+ return [];
34
+ }
35
+ const entries = await fs.readdir(directory, { withFileTypes: true });
36
+ const skills = await Promise.all(entries
37
+ .filter((entry) => entry.isDirectory())
38
+ .map(async (entry) => {
39
+ const skillPath = path.join(directory, entry.name, 'SKILL.md');
40
+ if (!(await pathExists(skillPath))) {
41
+ return null;
42
+ }
43
+ const content = await fs.readFile(skillPath, 'utf8');
44
+ return {
45
+ name: entry.name,
46
+ description: extractMarkdownDescription(content),
47
+ path: skillPath,
48
+ source: 'skill',
49
+ };
50
+ }));
51
+ return skills.filter((skill) => skill !== null);
52
+ }
53
+ async readCommands(directory) {
54
+ if (!(await pathExists(directory))) {
55
+ return [];
56
+ }
57
+ const commandFiles = await collectMarkdownFiles(directory);
58
+ const commands = await Promise.all(commandFiles.map(async (commandPath) => {
59
+ const content = await fs.readFile(commandPath, 'utf8');
60
+ return {
61
+ name: path.basename(commandPath, path.extname(commandPath)),
62
+ description: extractMarkdownDescription(content),
63
+ source: 'command',
64
+ path: commandPath,
65
+ };
66
+ }));
67
+ return commands.sort((left, right) => left.name.localeCompare(right.name));
68
+ }
69
+ async readSettings(claudeDirectory) {
70
+ const candidatePaths = [
71
+ path.join(claudeDirectory, 'settings.json'),
72
+ path.join(claudeDirectory, 'settings.local.json'),
73
+ ];
74
+ const settingsPaths = [];
75
+ const hooks = [];
76
+ for (const candidatePath of candidatePaths) {
77
+ if (!(await pathExists(candidatePath))) {
78
+ continue;
79
+ }
80
+ settingsPaths.push(candidatePath);
81
+ const content = await fs.readFile(candidatePath, 'utf8');
82
+ const parsed = JSON5.parse(content);
83
+ const hookEntries = Object.entries(parsed.hooks ?? {});
84
+ for (const [hookName, hookValue] of hookEntries) {
85
+ const hookMatchers = Array.isArray(hookValue) ? hookValue : [hookValue];
86
+ for (const hookMatcher of hookMatchers) {
87
+ if (!hookMatcher || typeof hookMatcher !== 'object') {
88
+ continue;
89
+ }
90
+ const matcher = typeof hookMatcher.matcher === 'string'
91
+ ? hookMatcher.matcher
92
+ : undefined;
93
+ const commandCount = Array.isArray(hookMatcher.hooks)
94
+ ? (hookMatcher.hooks?.length ?? 0)
95
+ : 0;
96
+ hooks.push({
97
+ name: hookName,
98
+ matcher,
99
+ sourcePath: candidatePath,
100
+ commandCount,
101
+ });
102
+ }
103
+ }
104
+ }
105
+ return {
106
+ settingsPaths,
107
+ hooks,
108
+ };
109
+ }
110
+ }
111
+ function extractMarkdownDescription(markdown) {
112
+ const lines = markdown
113
+ .split(/\r?\n/)
114
+ .map((line) => line.trim())
115
+ .filter(Boolean);
116
+ const descriptionLine = lines.find((line) => !line.startsWith('#') && !line.startsWith('---'));
117
+ return descriptionLine ?? 'No description provided.';
118
+ }
119
+ async function collectMarkdownFiles(directory) {
120
+ const entries = await fs.readdir(directory, { withFileTypes: true });
121
+ const files = await Promise.all(entries.map(async (entry) => {
122
+ const resolvedPath = path.join(directory, entry.name);
123
+ if (entry.isDirectory()) {
124
+ return collectMarkdownFiles(resolvedPath);
125
+ }
126
+ return entry.name.endsWith('.md') ? [resolvedPath] : [];
127
+ }));
128
+ return files.flat();
129
+ }
130
+ async function pathExists(candidatePath) {
131
+ try {
132
+ await fs.access(candidatePath);
133
+ return true;
134
+ }
135
+ catch {
136
+ return false;
137
+ }
138
+ }
139
+ async function findFirstExistingPath(candidatePaths) {
140
+ for (const candidatePath of candidatePaths) {
141
+ if (await pathExists(candidatePath)) {
142
+ return candidatePath;
143
+ }
144
+ }
145
+ return null;
146
+ }
147
+ function skillsToCommands(skills) {
148
+ return skills.map((skill) => ({
149
+ name: skill.name,
150
+ description: skill.description,
151
+ source: 'skill',
152
+ path: skill.path,
153
+ }));
154
+ }
@@ -0,0 +1,2 @@
1
+ import { type Plugin } from '@opencode-ai/plugin';
2
+ export declare const ClaudeManagerPlugin: Plugin;
@@ -0,0 +1,102 @@
1
+ import { tool } from '@opencode-ai/plugin';
2
+ import { getOrCreatePluginServices } from './service-factory.js';
3
+ export const ClaudeManagerPlugin = async ({ worktree }) => {
4
+ const services = getOrCreatePluginServices(worktree);
5
+ return {
6
+ tool: {
7
+ claude_manager_run: tool({
8
+ description: 'Delegate a task to Claude Code with optional subagents and worktrees.',
9
+ args: {
10
+ task: tool.schema.string().min(1),
11
+ mode: tool.schema.enum(['auto', 'single', 'split']).default('auto'),
12
+ maxSubagents: tool.schema.number().int().min(1).max(8).default(3),
13
+ useWorktrees: tool.schema.boolean().default(true),
14
+ includeProjectSettings: tool.schema.boolean().default(true),
15
+ model: tool.schema.string().optional(),
16
+ cwd: tool.schema.string().optional(),
17
+ },
18
+ async execute(args, context) {
19
+ annotateToolRun(context, 'Delegating task to Claude manager', {
20
+ task: args.task,
21
+ mode: args.mode,
22
+ });
23
+ const result = await services.manager.run({
24
+ cwd: args.cwd ?? context.worktree,
25
+ task: args.task,
26
+ mode: args.mode,
27
+ maxSubagents: args.maxSubagents,
28
+ useWorktrees: args.useWorktrees,
29
+ includeProjectSettings: args.includeProjectSettings,
30
+ model: args.model,
31
+ });
32
+ return JSON.stringify(result.run, null, 2);
33
+ },
34
+ }),
35
+ claude_manager_metadata: tool({
36
+ description: 'Inspect Claude slash commands, skills, hooks, and repo settings.',
37
+ args: {
38
+ cwd: tool.schema.string().optional(),
39
+ includeSdkProbe: tool.schema.boolean().default(false),
40
+ },
41
+ async execute(args, context) {
42
+ annotateToolRun(context, 'Collecting Claude metadata', {
43
+ includeSdkProbe: args.includeSdkProbe,
44
+ });
45
+ const metadata = await services.sessions.inspectRepository(args.cwd ?? context.worktree, {
46
+ includeSdkProbe: args.includeSdkProbe,
47
+ });
48
+ return JSON.stringify(metadata, null, 2);
49
+ },
50
+ }),
51
+ claude_manager_sessions: tool({
52
+ description: 'List Claude sessions or inspect a saved transcript.',
53
+ args: {
54
+ cwd: tool.schema.string().optional(),
55
+ sessionId: tool.schema.string().optional(),
56
+ },
57
+ async execute(args, context) {
58
+ annotateToolRun(context, 'Inspecting Claude session history', {});
59
+ if (args.sessionId) {
60
+ const transcript = await services.sessions.getTranscript(args.sessionId, args.cwd ?? context.worktree);
61
+ return JSON.stringify(transcript, null, 2);
62
+ }
63
+ const sessions = await services.sessions.listSessions(args.cwd ?? context.worktree);
64
+ return JSON.stringify(sessions, null, 2);
65
+ },
66
+ }),
67
+ claude_manager_runs: tool({
68
+ description: 'List manager runs previously recorded for this repo.',
69
+ args: {
70
+ cwd: tool.schema.string().optional(),
71
+ runId: tool.schema.string().optional(),
72
+ },
73
+ async execute(args, context) {
74
+ annotateToolRun(context, 'Reading manager run state', {});
75
+ if (args.runId) {
76
+ const run = await services.manager.getRun(args.cwd ?? context.worktree, args.runId);
77
+ return JSON.stringify(run, null, 2);
78
+ }
79
+ const runs = await services.manager.listRuns(args.cwd ?? context.worktree);
80
+ return JSON.stringify(runs, null, 2);
81
+ },
82
+ }),
83
+ claude_manager_cleanup_run: tool({
84
+ description: 'Explicitly remove git worktrees created for a recorded manager run.',
85
+ args: {
86
+ runId: tool.schema.string().min(1),
87
+ cwd: tool.schema.string().optional(),
88
+ },
89
+ async execute(args, context) {
90
+ annotateToolRun(context, 'Cleaning manager worktrees', {
91
+ runId: args.runId,
92
+ });
93
+ const run = await services.manager.cleanupRunWorktrees(args.cwd ?? context.worktree, args.runId);
94
+ return JSON.stringify(run, null, 2);
95
+ },
96
+ }),
97
+ },
98
+ };
99
+ };
100
+ function annotateToolRun(context, title, metadata) {
101
+ context.metadata({ title, metadata });
102
+ }
@@ -0,0 +1,7 @@
1
+ import { ClaudeSessionService } from '../claude/claude-session.service.js';
2
+ import { ManagerOrchestrator } from '../manager/manager-orchestrator.js';
3
+ export interface ClaudeManagerPluginServices {
4
+ manager: ManagerOrchestrator;
5
+ sessions: ClaudeSessionService;
6
+ }
7
+ export declare function getOrCreatePluginServices(worktree: string): ClaudeManagerPluginServices;
@@ -0,0 +1,25 @@
1
+ import { ClaudeAgentSdkAdapter } from '../claude/claude-agent-sdk-adapter.js';
2
+ import { ClaudeSessionService } from '../claude/claude-session.service.js';
3
+ import { ManagerOrchestrator } from '../manager/manager-orchestrator.js';
4
+ import { TaskPlanner } from '../manager/task-planner.js';
5
+ import { ClaudeMetadataService } from '../metadata/claude-metadata.service.js';
6
+ import { RepoClaudeConfigReader } from '../metadata/repo-claude-config-reader.js';
7
+ import { FileRunStateStore } from '../state/file-run-state-store.js';
8
+ import { WorktreeCoordinator } from '../worktree/worktree-coordinator.js';
9
+ const serviceCache = new Map();
10
+ export function getOrCreatePluginServices(worktree) {
11
+ const cachedServices = serviceCache.get(worktree);
12
+ if (cachedServices) {
13
+ return cachedServices;
14
+ }
15
+ const sdkAdapter = new ClaudeAgentSdkAdapter();
16
+ const metadataService = new ClaudeMetadataService(new RepoClaudeConfigReader(), sdkAdapter);
17
+ const sessionService = new ClaudeSessionService(sdkAdapter, metadataService);
18
+ const manager = new ManagerOrchestrator(sessionService, new FileRunStateStore(), new WorktreeCoordinator(), new TaskPlanner());
19
+ const services = {
20
+ manager,
21
+ sessions: sessionService,
22
+ };
23
+ serviceCache.set(worktree, services);
24
+ return services;
25
+ }
@@ -0,0 +1,2 @@
1
+ import type { ManagerPromptRegistry } from '../types/contracts.js';
2
+ export declare const managerPromptRegistry: ManagerPromptRegistry;
@@ -0,0 +1,11 @@
1
+ export const managerPromptRegistry = {
2
+ managerSystemPrompt: [
3
+ 'You are the OpenCode manager for Claude Code sessions.',
4
+ 'Plan first, delegate carefully, and keep user-visible progress concise.',
5
+ 'Prefer deterministic orchestration in code over prompt-only control flow.',
6
+ ].join(' '),
7
+ subagentSystemPrompt: [
8
+ 'You are a Claude execution worker managed by OpenCode.',
9
+ 'Stay within assigned scope, report blockers explicitly, and summarize changes with verification notes.',
10
+ ].join(' '),
11
+ };
@@ -0,0 +1,14 @@
1
+ import type { ManagerRunRecord } from '../types/contracts.js';
2
+ export declare class FileRunStateStore {
3
+ private readonly baseDirectoryName;
4
+ private readonly writeQueues;
5
+ constructor(baseDirectoryName?: string);
6
+ saveRun(run: ManagerRunRecord): Promise<void>;
7
+ getRun(cwd: string, runId: string): Promise<ManagerRunRecord | null>;
8
+ listRuns(cwd: string): Promise<ManagerRunRecord[]>;
9
+ updateRun(cwd: string, runId: string, update: (run: ManagerRunRecord) => ManagerRunRecord): Promise<ManagerRunRecord>;
10
+ private getRunKey;
11
+ private getRunsDirectory;
12
+ private getRunPath;
13
+ private enqueueWrite;
14
+ }
@@ -0,0 +1,97 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { promises as fs } from 'node:fs';
3
+ import path from 'node:path';
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
74
+ .catch(() => undefined)
75
+ .then(operation);
76
+ const settledPromise = resultPromise.then(() => undefined, () => undefined);
77
+ this.writeQueues.set(key, settledPromise);
78
+ try {
79
+ return await resultPromise;
80
+ }
81
+ finally {
82
+ if (this.writeQueues.get(key) === settledPromise) {
83
+ this.writeQueues.delete(key);
84
+ }
85
+ }
86
+ }
87
+ }
88
+ async function writeJsonAtomically(filePath, data) {
89
+ const tempPath = `${filePath}.${randomUUID()}.tmp`;
90
+ await fs.writeFile(tempPath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
91
+ await fs.rename(tempPath, filePath);
92
+ }
93
+ function isFileNotFoundError(error) {
94
+ return (error instanceof Error &&
95
+ 'code' in error &&
96
+ error.code === 'ENOENT');
97
+ }
@@ -0,0 +1,145 @@
1
+ export interface ManagerPromptRegistry {
2
+ managerSystemPrompt: string;
3
+ subagentSystemPrompt: string;
4
+ }
5
+ export type ClaudeSettingSource = 'user' | 'project' | 'local';
6
+ export interface ClaudeCommandMetadata {
7
+ name: string;
8
+ description: string;
9
+ argumentHint?: string;
10
+ source: 'sdk' | 'skill' | 'command';
11
+ path?: string;
12
+ }
13
+ export interface ClaudeSkillMetadata {
14
+ name: string;
15
+ description: string;
16
+ path: string;
17
+ source: 'skill' | 'command';
18
+ }
19
+ export interface ClaudeHookMetadata {
20
+ name: string;
21
+ matcher?: string;
22
+ sourcePath: string;
23
+ commandCount: number;
24
+ }
25
+ export interface ClaudeAgentMetadata {
26
+ name: string;
27
+ description: string;
28
+ model?: string;
29
+ source: 'sdk' | 'filesystem';
30
+ }
31
+ export interface ClaudeMetadataSnapshot {
32
+ collectedAt: string;
33
+ cwd: string;
34
+ commands: ClaudeCommandMetadata[];
35
+ skills: ClaudeSkillMetadata[];
36
+ hooks: ClaudeHookMetadata[];
37
+ agents: ClaudeAgentMetadata[];
38
+ claudeMdPath?: string;
39
+ settingsPaths: string[];
40
+ }
41
+ export interface ClaudeSessionEvent {
42
+ type: 'init' | 'assistant' | 'partial' | 'status' | 'system' | 'result' | 'error';
43
+ sessionId?: string;
44
+ text: string;
45
+ turns?: number;
46
+ totalCostUsd?: number;
47
+ rawType: string;
48
+ }
49
+ export interface RunClaudeSessionInput {
50
+ cwd: string;
51
+ prompt: string;
52
+ systemPrompt?: string;
53
+ model?: string;
54
+ permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'dontAsk';
55
+ allowedTools?: string[];
56
+ disallowedTools?: string[];
57
+ continueSession?: boolean;
58
+ resumeSessionId?: string;
59
+ forkSession?: boolean;
60
+ persistSession?: boolean;
61
+ includePartialMessages?: boolean;
62
+ settingSources?: ClaudeSettingSource[];
63
+ maxTurns?: number;
64
+ }
65
+ export interface ClaudeSessionRunResult {
66
+ sessionId?: string;
67
+ events: ClaudeSessionEvent[];
68
+ finalText: string;
69
+ turns?: number;
70
+ totalCostUsd?: number;
71
+ }
72
+ export interface ClaudeSessionSummary {
73
+ sessionId: string;
74
+ summary: string;
75
+ cwd?: string;
76
+ gitBranch?: string;
77
+ createdAt?: number;
78
+ lastModified: number;
79
+ }
80
+ export interface ClaudeSessionTranscriptMessage {
81
+ role: 'user' | 'assistant';
82
+ sessionId: string;
83
+ messageId: string;
84
+ text: string;
85
+ }
86
+ export interface ClaudeCapabilitySnapshot {
87
+ commands: ClaudeCommandMetadata[];
88
+ agents: ClaudeAgentMetadata[];
89
+ models: string[];
90
+ }
91
+ export type ManagerRunMode = 'auto' | 'single' | 'split';
92
+ export type ManagerRunStatus = 'pending' | 'running' | 'completed' | 'failed';
93
+ export type WorktreeMode = 'shared-root' | 'git-worktree';
94
+ export interface ManagedSubtaskPlan {
95
+ id: string;
96
+ title: string;
97
+ prompt: string;
98
+ }
99
+ export interface WorktreeAssignment {
100
+ mode: WorktreeMode;
101
+ cwd: string;
102
+ rootCwd: string;
103
+ branchName?: string;
104
+ }
105
+ export interface ManagedSessionRecord {
106
+ id: string;
107
+ title: string;
108
+ prompt: string;
109
+ status: ManagerRunStatus;
110
+ cwd: string;
111
+ worktreeMode: WorktreeMode;
112
+ branchName?: string;
113
+ claudeSessionId?: string;
114
+ finalText?: string;
115
+ turns?: number;
116
+ totalCostUsd?: number;
117
+ error?: string;
118
+ events: ClaudeSessionEvent[];
119
+ }
120
+ export interface ManagerRunRecord {
121
+ id: string;
122
+ cwd: string;
123
+ task: string;
124
+ mode: ManagerRunMode;
125
+ useWorktrees: boolean;
126
+ includeProjectSettings: boolean;
127
+ status: ManagerRunStatus;
128
+ createdAt: string;
129
+ updatedAt: string;
130
+ metadata: ClaudeMetadataSnapshot;
131
+ sessions: ManagedSessionRecord[];
132
+ finalSummary?: string;
133
+ }
134
+ export interface ManagerTaskRequest {
135
+ cwd: string;
136
+ task: string;
137
+ mode?: ManagerRunMode;
138
+ maxSubagents?: number;
139
+ useWorktrees?: boolean;
140
+ includeProjectSettings?: boolean;
141
+ model?: string;
142
+ }
143
+ export interface ManagerRunResult {
144
+ run: ManagerRunRecord;
145
+ }
@@ -0,0 +1 @@
1
+ export {};