@doingdev/opencode-claude-manager-plugin 0.1.20 → 0.1.22

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 (58) hide show
  1. package/README.md +40 -129
  2. package/dist/index.d.ts +5 -4
  3. package/dist/index.js +5 -4
  4. package/dist/plugin/orchestrator.plugin.d.ts +2 -0
  5. package/dist/plugin/orchestrator.plugin.js +114 -0
  6. package/dist/prompts/registry.d.ts +8 -2
  7. package/dist/prompts/registry.js +30 -159
  8. package/dist/providers/claude-code-wrapper.d.ts +13 -0
  9. package/dist/providers/claude-code-wrapper.js +13 -0
  10. package/dist/safety/bash-safety.d.ts +21 -0
  11. package/dist/safety/bash-safety.js +62 -0
  12. package/package.json +3 -5
  13. package/dist/claude/claude-agent-sdk-adapter.d.ts +0 -27
  14. package/dist/claude/claude-agent-sdk-adapter.js +0 -520
  15. package/dist/claude/claude-session.service.d.ts +0 -15
  16. package/dist/claude/claude-session.service.js +0 -23
  17. package/dist/claude/delegated-can-use-tool.d.ts +0 -7
  18. package/dist/claude/delegated-can-use-tool.js +0 -178
  19. package/dist/claude/session-live-tailer.d.ts +0 -51
  20. package/dist/claude/session-live-tailer.js +0 -269
  21. package/dist/claude/tool-approval-manager.d.ts +0 -27
  22. package/dist/claude/tool-approval-manager.js +0 -238
  23. package/dist/manager/context-tracker.d.ts +0 -33
  24. package/dist/manager/context-tracker.js +0 -108
  25. package/dist/manager/git-operations.d.ts +0 -12
  26. package/dist/manager/git-operations.js +0 -76
  27. package/dist/manager/manager-orchestrator.d.ts +0 -17
  28. package/dist/manager/manager-orchestrator.js +0 -178
  29. package/dist/manager/parallel-session-job-manager.d.ts +0 -49
  30. package/dist/manager/parallel-session-job-manager.js +0 -177
  31. package/dist/manager/persistent-manager.d.ts +0 -74
  32. package/dist/manager/persistent-manager.js +0 -167
  33. package/dist/manager/session-controller.d.ts +0 -45
  34. package/dist/manager/session-controller.js +0 -147
  35. package/dist/manager/task-planner.d.ts +0 -5
  36. package/dist/manager/task-planner.js +0 -15
  37. package/dist/metadata/claude-metadata.service.d.ts +0 -12
  38. package/dist/metadata/claude-metadata.service.js +0 -38
  39. package/dist/metadata/repo-claude-config-reader.d.ts +0 -7
  40. package/dist/metadata/repo-claude-config-reader.js +0 -154
  41. package/dist/plugin/claude-code-permission-bridge.d.ts +0 -15
  42. package/dist/plugin/claude-code-permission-bridge.js +0 -184
  43. package/dist/plugin/claude-manager.plugin.d.ts +0 -2
  44. package/dist/plugin/claude-manager.plugin.js +0 -627
  45. package/dist/plugin/service-factory.d.ts +0 -12
  46. package/dist/plugin/service-factory.js +0 -41
  47. package/dist/state/file-run-state-store.d.ts +0 -14
  48. package/dist/state/file-run-state-store.js +0 -87
  49. package/dist/state/transcript-store.d.ts +0 -15
  50. package/dist/state/transcript-store.js +0 -44
  51. package/dist/types/contracts.d.ts +0 -215
  52. package/dist/types/contracts.js +0 -1
  53. package/dist/util/fs-helpers.d.ts +0 -2
  54. package/dist/util/fs-helpers.js +0 -12
  55. package/dist/util/transcript-append.d.ts +0 -7
  56. package/dist/util/transcript-append.js +0 -29
  57. package/dist/worktree/worktree-coordinator.d.ts +0 -21
  58. package/dist/worktree/worktree-coordinator.js +0 -64
@@ -1,49 +0,0 @@
1
- import type { ClaudeAgentSdkAdapter } from '../claude/claude-agent-sdk-adapter.js';
2
- import type { ParallelSessionJobRecord, SessionMode } from '../types/contracts.js';
3
- /**
4
- * Runs additional Claude Code SDK sessions concurrently with the main persistent session.
5
- * Same worktree from multiple jobs can conflict on git — callers should use plan mode or branches.
6
- */
7
- export declare class ParallelSessionJobManager {
8
- private readonly sdkAdapter;
9
- private readonly sessionPrompt;
10
- private readonly modePrefixes;
11
- private readonly jobs;
12
- constructor(sdkAdapter: ClaudeAgentSdkAdapter, sessionPrompt: string, modePrefixes: {
13
- plan: string;
14
- free: string;
15
- });
16
- static get maxConcurrent(): number;
17
- startJob(params: {
18
- cwd: string;
19
- message: string;
20
- model?: string;
21
- mode?: SessionMode;
22
- resumeSessionId?: string;
23
- }): {
24
- ok: true;
25
- jobId: string;
26
- } | {
27
- ok: false;
28
- error: string;
29
- };
30
- private runJob;
31
- abortJob(jobId: string): {
32
- ok: true;
33
- } | {
34
- ok: false;
35
- error: string;
36
- };
37
- getJob(jobId: string): ParallelSessionJobRecord | undefined;
38
- listJobs(): ParallelSessionJobRecord[];
39
- private runningCount;
40
- waitForJobs(params: {
41
- jobIds: string[];
42
- mode: 'any' | 'all';
43
- timeoutMs?: number;
44
- }): Promise<{
45
- finishedJobIds: string[];
46
- timedOut: boolean;
47
- pendingJobIds: string[];
48
- }>;
49
- }
@@ -1,177 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- const MAX_CONCURRENT = 5;
3
- function createCompletionLatch() {
4
- let resolve;
5
- const promise = new Promise((r) => {
6
- resolve = r;
7
- });
8
- return { promise, resolve };
9
- }
10
- /**
11
- * Runs additional Claude Code SDK sessions concurrently with the main persistent session.
12
- * Same worktree from multiple jobs can conflict on git — callers should use plan mode or branches.
13
- */
14
- export class ParallelSessionJobManager {
15
- sdkAdapter;
16
- sessionPrompt;
17
- modePrefixes;
18
- jobs = new Map();
19
- constructor(sdkAdapter, sessionPrompt, modePrefixes) {
20
- this.sdkAdapter = sdkAdapter;
21
- this.sessionPrompt = sessionPrompt;
22
- this.modePrefixes = modePrefixes;
23
- }
24
- static get maxConcurrent() {
25
- return MAX_CONCURRENT;
26
- }
27
- startJob(params) {
28
- if (this.runningCount() >= MAX_CONCURRENT) {
29
- return {
30
- ok: false,
31
- error: `At most ${MAX_CONCURRENT} parallel Claude Code jobs may run at once. Wait or abort a job first.`,
32
- };
33
- }
34
- const jobId = randomUUID();
35
- const now = new Date().toISOString();
36
- const mode = params.mode ?? 'free';
37
- const prefix = this.modePrefixes[mode];
38
- const prompt = prefix ? `${prefix}\n\n${params.message}` : params.message;
39
- const input = {
40
- cwd: params.cwd,
41
- prompt,
42
- persistSession: true,
43
- permissionMode: mode === 'plan' ? 'plan' : 'acceptEdits',
44
- includePartialMessages: true,
45
- model: params.model,
46
- resumeSessionId: params.resumeSessionId,
47
- settingSources: ['user', 'project', 'local'],
48
- agentProgressSummaries: true,
49
- };
50
- if (!params.resumeSessionId) {
51
- input.systemPrompt = this.sessionPrompt;
52
- input.model ??= 'claude-opus-4-6';
53
- input.effort ??= 'high';
54
- }
55
- const abortController = new AbortController();
56
- input.abortSignal = abortController.signal;
57
- const preview = params.message.length > 120
58
- ? `${params.message.slice(0, 120)}...`
59
- : params.message;
60
- const { promise: completion, resolve: resolveCompletion } = createCompletionLatch();
61
- const record = {
62
- id: jobId,
63
- cwd: params.cwd,
64
- status: 'running',
65
- createdAt: now,
66
- updatedAt: now,
67
- promptPreview: preview,
68
- resumeSessionId: params.resumeSessionId,
69
- };
70
- this.jobs.set(jobId, {
71
- record,
72
- abortController,
73
- completion,
74
- resolveCompletion,
75
- });
76
- void this.runJob(jobId, input, resolveCompletion);
77
- return { ok: true, jobId };
78
- }
79
- async runJob(jobId, input, resolveCompletion) {
80
- const entry = this.jobs.get(jobId);
81
- if (!entry) {
82
- resolveCompletion();
83
- return;
84
- }
85
- try {
86
- const result = await this.sdkAdapter.runSession(input);
87
- const rec = entry.record;
88
- rec.updatedAt = new Date().toISOString();
89
- rec.status = 'completed';
90
- rec.sessionId = result.sessionId;
91
- rec.finalText = result.finalText;
92
- rec.turns = result.turns;
93
- rec.totalCostUsd = result.totalCostUsd;
94
- }
95
- catch (error) {
96
- const rec = entry.record;
97
- rec.updatedAt = new Date().toISOString();
98
- if (rec.status !== 'aborted') {
99
- rec.status = 'failed';
100
- rec.error = error instanceof Error ? error.message : String(error);
101
- }
102
- }
103
- finally {
104
- resolveCompletion();
105
- }
106
- }
107
- abortJob(jobId) {
108
- const entry = this.jobs.get(jobId);
109
- if (!entry) {
110
- return { ok: false, error: 'Unknown job id' };
111
- }
112
- if (entry.record.status !== 'running') {
113
- return { ok: false, error: 'Job is not running' };
114
- }
115
- entry.record.status = 'aborted';
116
- entry.record.updatedAt = new Date().toISOString();
117
- entry.abortController.abort();
118
- return { ok: true };
119
- }
120
- getJob(jobId) {
121
- return this.jobs.get(jobId)?.record;
122
- }
123
- listJobs() {
124
- return [...this.jobs.values()]
125
- .map((j) => j.record)
126
- .sort((a, b) => a.createdAt.localeCompare(b.createdAt));
127
- }
128
- runningCount() {
129
- let n = 0;
130
- for (const { record } of this.jobs.values()) {
131
- if (record.status === 'running') {
132
- n += 1;
133
- }
134
- }
135
- return n;
136
- }
137
- async waitForJobs(params) {
138
- const unique = [...new Set(params.jobIds)].filter((id) => this.jobs.has(id));
139
- if (unique.length === 0) {
140
- return {
141
- finishedJobIds: [],
142
- timedOut: false,
143
- pendingJobIds: [],
144
- };
145
- }
146
- const waitWork = async () => {
147
- if (params.mode === 'any') {
148
- await Promise.race(unique.map((id) => this.jobs.get(id).completion));
149
- }
150
- else {
151
- await Promise.all(unique.map((id) => this.jobs.get(id).completion));
152
- }
153
- };
154
- let timedOut = false;
155
- if (params.timeoutMs !== undefined && params.timeoutMs > 0) {
156
- await Promise.race([
157
- waitWork(),
158
- new Promise((resolve) => {
159
- setTimeout(() => {
160
- timedOut = true;
161
- resolve();
162
- }, params.timeoutMs);
163
- }),
164
- ]);
165
- }
166
- else {
167
- await waitWork();
168
- }
169
- const finishedJobIds = unique.filter((id) => this.jobs.get(id)?.record.status !== 'running');
170
- const pendingJobIds = unique.filter((id) => this.jobs.get(id)?.record.status === 'running');
171
- return {
172
- finishedJobIds,
173
- timedOut,
174
- pendingJobIds,
175
- };
176
- }
177
- }
@@ -1,74 +0,0 @@
1
- import type { ClaudeSessionEvent, ClaudeSessionRunResult, PersistentRunRecord, PersistentRunResult, SessionContextSnapshot, GitDiffResult, GitOperationResult } from '../types/contracts.js';
2
- import type { ClaudeSessionEventHandler } from '../claude/claude-agent-sdk-adapter.js';
3
- import type { FileRunStateStore } from '../state/file-run-state-store.js';
4
- import type { TranscriptStore } from '../state/transcript-store.js';
5
- import type { SessionController } from './session-controller.js';
6
- import type { GitOperations } from './git-operations.js';
7
- import type { ContextTracker } from './context-tracker.js';
8
- type PersistentManagerProgressHandler = (run: PersistentRunRecord) => void | Promise<void>;
9
- export declare class PersistentManager {
10
- private readonly sessionController;
11
- private readonly gitOps;
12
- private readonly stateStore;
13
- private readonly contextTracker;
14
- private readonly transcriptStore;
15
- constructor(sessionController: SessionController, gitOps: GitOperations, stateStore: FileRunStateStore, contextTracker: ContextTracker, transcriptStore: TranscriptStore);
16
- /**
17
- * Send a message to the persistent Claude Code session.
18
- * Creates a new session if none exists.
19
- */
20
- sendMessage(cwd: string, message: string, options?: {
21
- model?: string;
22
- effort?: 'low' | 'medium' | 'high' | 'max';
23
- mode?: 'plan' | 'free';
24
- abortSignal?: AbortSignal;
25
- }, onEvent?: ClaudeSessionEventHandler): Promise<{
26
- sessionId: string | undefined;
27
- finalText: string;
28
- turns?: number;
29
- totalCostUsd?: number;
30
- context: SessionContextSnapshot;
31
- }>;
32
- /**
33
- * Get the current git diff.
34
- */
35
- gitDiff(): Promise<GitDiffResult>;
36
- /**
37
- * Commit all current changes.
38
- */
39
- gitCommit(message: string): Promise<GitOperationResult>;
40
- /**
41
- * Hard reset to discard all uncommitted changes.
42
- */
43
- gitReset(): Promise<GitOperationResult>;
44
- /**
45
- * Get current session status and context health.
46
- */
47
- getStatus(): SessionContextSnapshot;
48
- /**
49
- * Clear the active session. Next send creates a fresh one.
50
- */
51
- clearSession(cwd: string): Promise<string | null>;
52
- /**
53
- * Compact the current session to free context.
54
- */
55
- compactSession(cwd: string, onEvent?: ClaudeSessionEventHandler): Promise<ClaudeSessionRunResult>;
56
- /**
57
- * Read persisted transcript events for a session.
58
- */
59
- getTranscriptEvents(cwd: string, sessionId: string): Promise<ClaudeSessionEvent[]>;
60
- /**
61
- * Execute a full task with run tracking.
62
- * Creates a run record, sends the message, and persists the result.
63
- */
64
- executeTask(cwd: string, task: string, options?: {
65
- model?: string;
66
- }, onProgress?: PersistentManagerProgressHandler): Promise<PersistentRunResult>;
67
- /**
68
- * Try to restore session state from disk on startup.
69
- */
70
- tryRestore(cwd: string): Promise<boolean>;
71
- listRuns(cwd: string): Promise<PersistentRunRecord[]>;
72
- getRun(cwd: string, runId: string): Promise<PersistentRunRecord | null>;
73
- }
74
- export {};
@@ -1,167 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- export class PersistentManager {
3
- sessionController;
4
- gitOps;
5
- stateStore;
6
- contextTracker;
7
- transcriptStore;
8
- constructor(sessionController, gitOps, stateStore, contextTracker, transcriptStore) {
9
- this.sessionController = sessionController;
10
- this.gitOps = gitOps;
11
- this.stateStore = stateStore;
12
- this.contextTracker = contextTracker;
13
- this.transcriptStore = transcriptStore;
14
- }
15
- /**
16
- * Send a message to the persistent Claude Code session.
17
- * Creates a new session if none exists.
18
- */
19
- async sendMessage(cwd, message, options, onEvent) {
20
- const result = await this.sessionController.sendMessage(cwd, message, options, onEvent);
21
- if (result.sessionId && result.events.length > 0) {
22
- await this.transcriptStore.appendEvents(cwd, result.sessionId, result.events);
23
- }
24
- return {
25
- sessionId: result.sessionId,
26
- finalText: result.finalText,
27
- turns: result.turns,
28
- totalCostUsd: result.totalCostUsd,
29
- context: this.sessionController.getContextSnapshot(),
30
- };
31
- }
32
- /**
33
- * Get the current git diff.
34
- */
35
- async gitDiff() {
36
- return this.gitOps.diff();
37
- }
38
- /**
39
- * Commit all current changes.
40
- */
41
- async gitCommit(message) {
42
- return this.gitOps.commit(message);
43
- }
44
- /**
45
- * Hard reset to discard all uncommitted changes.
46
- */
47
- async gitReset() {
48
- return this.gitOps.resetHard();
49
- }
50
- /**
51
- * Get current session status and context health.
52
- */
53
- getStatus() {
54
- return this.sessionController.getContextSnapshot();
55
- }
56
- /**
57
- * Clear the active session. Next send creates a fresh one.
58
- */
59
- async clearSession(cwd) {
60
- return this.sessionController.clearSession(cwd);
61
- }
62
- /**
63
- * Compact the current session to free context.
64
- */
65
- async compactSession(cwd, onEvent) {
66
- const result = await this.sessionController.compactSession(cwd, onEvent);
67
- if (result.sessionId && result.events.length > 0) {
68
- await this.transcriptStore.appendEvents(cwd, result.sessionId, result.events);
69
- }
70
- return result;
71
- }
72
- /**
73
- * Read persisted transcript events for a session.
74
- */
75
- getTranscriptEvents(cwd, sessionId) {
76
- return this.transcriptStore.readEvents(cwd, sessionId);
77
- }
78
- /**
79
- * Execute a full task with run tracking.
80
- * Creates a run record, sends the message, and persists the result.
81
- */
82
- async executeTask(cwd, task, options, onProgress) {
83
- const runId = randomUUID();
84
- const createdAt = new Date().toISOString();
85
- const runRecord = {
86
- id: runId,
87
- cwd,
88
- task,
89
- status: 'running',
90
- createdAt,
91
- updatedAt: createdAt,
92
- sessionId: this.sessionController.sessionId,
93
- sessionHistory: [],
94
- messages: [
95
- {
96
- timestamp: createdAt,
97
- direction: 'sent',
98
- text: task,
99
- },
100
- ],
101
- actions: [],
102
- commits: [],
103
- context: this.sessionController.getContextSnapshot(),
104
- };
105
- await this.stateStore.saveRun(runRecord);
106
- await onProgress?.(runRecord);
107
- try {
108
- const result = await this.sessionController.sendMessage(cwd, task, options, async (event) => {
109
- // Update run record with progress events
110
- const currentRun = await this.stateStore.getRun(cwd, runId);
111
- if (currentRun) {
112
- const updated = {
113
- ...currentRun,
114
- updatedAt: new Date().toISOString(),
115
- sessionId: event.sessionId ?? currentRun.sessionId,
116
- context: this.sessionController.getContextSnapshot(),
117
- };
118
- await this.stateStore.saveRun(updated);
119
- await onProgress?.(updated);
120
- }
121
- });
122
- const completedRun = await this.stateStore.updateRun(cwd, runId, (run) => ({
123
- ...run,
124
- status: 'completed',
125
- updatedAt: new Date().toISOString(),
126
- sessionId: result.sessionId ?? run.sessionId,
127
- messages: [
128
- ...run.messages,
129
- {
130
- timestamp: new Date().toISOString(),
131
- direction: 'received',
132
- text: result.finalText,
133
- turns: result.turns,
134
- totalCostUsd: result.totalCostUsd,
135
- inputTokens: result.inputTokens,
136
- outputTokens: result.outputTokens,
137
- },
138
- ],
139
- context: this.sessionController.getContextSnapshot(),
140
- finalSummary: result.finalText,
141
- }));
142
- return { run: completedRun };
143
- }
144
- catch (error) {
145
- const failedRun = await this.stateStore.updateRun(cwd, runId, (run) => ({
146
- ...run,
147
- status: 'failed',
148
- updatedAt: new Date().toISOString(),
149
- context: this.sessionController.getContextSnapshot(),
150
- finalSummary: error instanceof Error ? error.message : String(error),
151
- }));
152
- return { run: failedRun };
153
- }
154
- }
155
- /**
156
- * Try to restore session state from disk on startup.
157
- */
158
- async tryRestore(cwd) {
159
- return this.sessionController.tryRestore(cwd);
160
- }
161
- listRuns(cwd) {
162
- return this.stateStore.listRuns(cwd);
163
- }
164
- getRun(cwd, runId) {
165
- return this.stateStore.getRun(cwd, runId);
166
- }
167
- }
@@ -1,45 +0,0 @@
1
- import type { ClaudeAgentSdkAdapter, ClaudeSessionEventHandler } from '../claude/claude-agent-sdk-adapter.js';
2
- import type { ClaudeSessionRunResult, SessionContextSnapshot, SessionMode } from '../types/contracts.js';
3
- import type { ContextTracker } from './context-tracker.js';
4
- export declare class SessionController {
5
- private readonly sdkAdapter;
6
- private readonly contextTracker;
7
- private readonly sessionPrompt;
8
- private readonly modePrefixes;
9
- private activeSessionId;
10
- constructor(sdkAdapter: ClaudeAgentSdkAdapter, contextTracker: ContextTracker, sessionPrompt: string, modePrefixes?: {
11
- plan: string;
12
- free: string;
13
- });
14
- get isActive(): boolean;
15
- get sessionId(): string | null;
16
- /**
17
- * Send a message to the persistent session. Creates one if none exists.
18
- * Returns the session result including usage data.
19
- */
20
- sendMessage(cwd: string, message: string, options?: {
21
- model?: string;
22
- effort?: 'low' | 'medium' | 'high' | 'max';
23
- mode?: SessionMode;
24
- settingSources?: Array<'user' | 'project' | 'local'>;
25
- abortSignal?: AbortSignal;
26
- }, onEvent?: ClaudeSessionEventHandler): Promise<ClaudeSessionRunResult>;
27
- /**
28
- * Send /compact to the current session to compress context.
29
- */
30
- compactSession(cwd: string, onEvent?: ClaudeSessionEventHandler): Promise<ClaudeSessionRunResult>;
31
- /**
32
- * Clear the current session. The next sendMessage will create a fresh one.
33
- */
34
- clearSession(cwd: string): Promise<string | null>;
35
- /**
36
- * Get current context tracking snapshot.
37
- */
38
- getContextSnapshot(): SessionContextSnapshot;
39
- /**
40
- * Try to restore active session from persisted state on startup.
41
- */
42
- tryRestore(cwd: string): Promise<boolean>;
43
- private persistActiveSession;
44
- private removeActiveSession;
45
- }
@@ -1,147 +0,0 @@
1
- import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
- import { dirname, join } from 'node:path';
3
- const ACTIVE_SESSION_FILE = '.claude-manager/active-session.json';
4
- export class SessionController {
5
- sdkAdapter;
6
- contextTracker;
7
- sessionPrompt;
8
- modePrefixes;
9
- activeSessionId = null;
10
- constructor(sdkAdapter, contextTracker, sessionPrompt, modePrefixes = {
11
- plan: '',
12
- free: '',
13
- }) {
14
- this.sdkAdapter = sdkAdapter;
15
- this.contextTracker = contextTracker;
16
- this.sessionPrompt = sessionPrompt;
17
- this.modePrefixes = modePrefixes;
18
- }
19
- get isActive() {
20
- return this.activeSessionId !== null;
21
- }
22
- get sessionId() {
23
- return this.activeSessionId;
24
- }
25
- /**
26
- * Send a message to the persistent session. Creates one if none exists.
27
- * Returns the session result including usage data.
28
- */
29
- async sendMessage(cwd, message, options, onEvent) {
30
- const mode = options?.mode ?? 'free';
31
- const prefix = this.modePrefixes[mode];
32
- const prompt = prefix ? `${prefix}\n\n${message}` : message;
33
- const input = {
34
- cwd,
35
- prompt,
36
- persistSession: true,
37
- permissionMode: mode === 'plan' ? 'plan' : 'acceptEdits',
38
- includePartialMessages: true,
39
- model: options?.model,
40
- effort: options?.effort,
41
- settingSources: options?.settingSources ?? ['user', 'project', 'local'],
42
- abortSignal: options?.abortSignal,
43
- };
44
- if (this.activeSessionId) {
45
- // Resume existing session
46
- input.resumeSessionId = this.activeSessionId;
47
- }
48
- else {
49
- // New session — apply the expert operator system prompt and defaults
50
- input.systemPrompt = this.sessionPrompt;
51
- input.model ??= 'claude-opus-4-6';
52
- input.effort ??= 'high';
53
- }
54
- const result = await this.sdkAdapter.runSession(input, onEvent);
55
- // Track the session ID
56
- if (result.sessionId) {
57
- this.activeSessionId = result.sessionId;
58
- }
59
- // Update context tracking
60
- this.contextTracker.recordResult({
61
- sessionId: result.sessionId,
62
- turns: result.turns,
63
- totalCostUsd: result.totalCostUsd,
64
- inputTokens: result.inputTokens,
65
- outputTokens: result.outputTokens,
66
- contextWindowSize: result.contextWindowSize,
67
- });
68
- // Persist active session state
69
- await this.persistActiveSession(cwd);
70
- return result;
71
- }
72
- /**
73
- * Send /compact to the current session to compress context.
74
- */
75
- async compactSession(cwd, onEvent) {
76
- if (!this.activeSessionId) {
77
- throw new Error('No active session to compact');
78
- }
79
- const result = await this.sendMessage(cwd, '/compact', undefined, onEvent);
80
- this.contextTracker.recordCompaction();
81
- return result;
82
- }
83
- /**
84
- * Clear the current session. The next sendMessage will create a fresh one.
85
- */
86
- async clearSession(cwd) {
87
- const clearedId = this.activeSessionId;
88
- this.activeSessionId = null;
89
- this.contextTracker.reset();
90
- await this.removeActiveSession(cwd);
91
- return clearedId;
92
- }
93
- /**
94
- * Get current context tracking snapshot.
95
- */
96
- getContextSnapshot() {
97
- return this.contextTracker.snapshot();
98
- }
99
- /**
100
- * Try to restore active session from persisted state on startup.
101
- */
102
- async tryRestore(cwd) {
103
- const filePath = join(cwd, ACTIVE_SESSION_FILE);
104
- try {
105
- const raw = await readFile(filePath, 'utf-8');
106
- const state = JSON.parse(raw);
107
- if (state.sessionId && state.cwd === cwd) {
108
- this.activeSessionId = state.sessionId;
109
- this.contextTracker.restore(state);
110
- return true;
111
- }
112
- }
113
- catch {
114
- // File doesn't exist or is corrupt — start fresh
115
- }
116
- return false;
117
- }
118
- async persistActiveSession(cwd) {
119
- if (!this.activeSessionId) {
120
- return;
121
- }
122
- const snap = this.contextTracker.snapshot();
123
- const state = {
124
- sessionId: this.activeSessionId,
125
- cwd,
126
- startedAt: new Date().toISOString(),
127
- totalTurns: snap.totalTurns,
128
- totalCostUsd: snap.totalCostUsd,
129
- estimatedContextPercent: snap.estimatedContextPercent,
130
- contextWindowSize: snap.contextWindowSize,
131
- latestInputTokens: snap.latestInputTokens,
132
- };
133
- const filePath = join(cwd, ACTIVE_SESSION_FILE);
134
- await mkdir(dirname(filePath), { recursive: true });
135
- await writeFile(filePath, JSON.stringify(state, null, 2));
136
- }
137
- async removeActiveSession(cwd) {
138
- const filePath = join(cwd, ACTIVE_SESSION_FILE);
139
- try {
140
- const { unlink } = await import('node:fs/promises');
141
- await unlink(filePath);
142
- }
143
- catch {
144
- // File doesn't exist — that's fine
145
- }
146
- }
147
- }
@@ -1,5 +0,0 @@
1
- import type { ManagedSubtaskPlan } from '../types/contracts.js';
2
- export declare class TaskPlanner {
3
- plan(tasks: string[], maxSubagents: number): ManagedSubtaskPlan[];
4
- private createPlan;
5
- }
@@ -1,15 +0,0 @@
1
- import { randomUUID } from 'node:crypto';
2
- export class TaskPlanner {
3
- plan(tasks, maxSubagents) {
4
- return tasks
5
- .slice(0, maxSubagents)
6
- .map((task, index) => this.createPlan(tasks.length === 1 ? 'Primary task' : `Subtask ${index + 1}`, task));
7
- }
8
- createPlan(title, prompt) {
9
- return {
10
- id: randomUUID(),
11
- title,
12
- prompt,
13
- };
14
- }
15
- }