@doingdev/opencode-claude-manager-plugin 0.1.49 → 0.1.50

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 (59) hide show
  1. package/dist/claude/claude-agent-sdk-adapter.d.ts +2 -3
  2. package/dist/claude/claude-agent-sdk-adapter.js +0 -44
  3. package/dist/claude/claude-session.service.d.ts +1 -2
  4. package/dist/claude/claude-session.service.js +0 -3
  5. package/dist/claude/tool-approval-manager.d.ts +9 -6
  6. package/dist/claude/tool-approval-manager.js +43 -6
  7. package/dist/index.d.ts +1 -2
  8. package/dist/index.js +0 -1
  9. package/dist/manager/context-tracker.d.ts +0 -1
  10. package/dist/manager/context-tracker.js +0 -3
  11. package/dist/manager/git-operations.d.ts +1 -4
  12. package/dist/manager/git-operations.js +7 -12
  13. package/dist/manager/persistent-manager.d.ts +3 -53
  14. package/dist/manager/persistent-manager.js +3 -135
  15. package/dist/manager/team-orchestrator.d.ts +8 -1
  16. package/dist/manager/team-orchestrator.js +70 -11
  17. package/dist/plugin/agent-hierarchy.d.ts +1 -1
  18. package/dist/plugin/agent-hierarchy.js +3 -1
  19. package/dist/plugin/claude-manager.plugin.js +169 -21
  20. package/dist/plugin/service-factory.d.ts +0 -2
  21. package/dist/plugin/service-factory.js +4 -12
  22. package/dist/prompts/registry.js +42 -37
  23. package/dist/src/claude/claude-agent-sdk-adapter.d.ts +2 -3
  24. package/dist/src/claude/claude-agent-sdk-adapter.js +0 -44
  25. package/dist/src/claude/claude-session.service.d.ts +1 -2
  26. package/dist/src/claude/claude-session.service.js +0 -3
  27. package/dist/src/claude/tool-approval-manager.d.ts +9 -6
  28. package/dist/src/claude/tool-approval-manager.js +43 -6
  29. package/dist/src/index.d.ts +1 -2
  30. package/dist/src/index.js +0 -1
  31. package/dist/src/manager/context-tracker.d.ts +0 -1
  32. package/dist/src/manager/context-tracker.js +0 -3
  33. package/dist/src/manager/git-operations.d.ts +1 -4
  34. package/dist/src/manager/git-operations.js +7 -12
  35. package/dist/src/manager/persistent-manager.d.ts +3 -53
  36. package/dist/src/manager/persistent-manager.js +3 -135
  37. package/dist/src/manager/team-orchestrator.d.ts +8 -1
  38. package/dist/src/manager/team-orchestrator.js +70 -11
  39. package/dist/src/plugin/agent-hierarchy.d.ts +1 -1
  40. package/dist/src/plugin/agent-hierarchy.js +3 -1
  41. package/dist/src/plugin/claude-manager.plugin.js +169 -21
  42. package/dist/src/plugin/service-factory.d.ts +0 -2
  43. package/dist/src/plugin/service-factory.js +4 -12
  44. package/dist/src/prompts/registry.js +42 -37
  45. package/dist/src/state/team-state-store.js +4 -1
  46. package/dist/src/team/roster.js +1 -0
  47. package/dist/src/types/contracts.d.ts +9 -49
  48. package/dist/state/team-state-store.js +4 -1
  49. package/dist/team/roster.js +1 -0
  50. package/dist/test/claude-agent-sdk-adapter.test.js +0 -11
  51. package/dist/test/claude-manager.plugin.test.js +6 -1
  52. package/dist/test/context-tracker.test.js +0 -8
  53. package/dist/test/git-operations.test.js +0 -21
  54. package/dist/test/persistent-manager.test.js +4 -164
  55. package/dist/test/prompt-registry.test.js +4 -9
  56. package/dist/test/report-claude-event.test.js +2 -2
  57. package/dist/test/tool-approval-manager.test.js +17 -17
  58. package/dist/types/contracts.d.ts +9 -49
  59. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
- import { type Options, type Query, type SDKSessionInfo, type SessionMessage, type SettingSource } from '@anthropic-ai/claude-agent-sdk';
2
- import type { ClaudeCapabilitySnapshot, ClaudeSessionEvent, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, RunClaudeSessionInput } from '../types/contracts.js';
1
+ import { type Options, type Query, type SDKSessionInfo, type SessionMessage } from '@anthropic-ai/claude-agent-sdk';
2
+ import type { ClaudeSessionEvent, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, RunClaudeSessionInput } from '../types/contracts.js';
3
3
  import type { ToolApprovalManager } from './tool-approval-manager.js';
4
4
  export type ClaudeSessionEventHandler = (event: ClaudeSessionEvent) => void | Promise<void>;
5
5
  interface ClaudeAgentSdkFacade {
@@ -21,7 +21,6 @@ export declare class ClaudeAgentSdkAdapter {
21
21
  runSession(input: RunClaudeSessionInput, onEvent?: ClaudeSessionEventHandler): Promise<ClaudeSessionRunResult>;
22
22
  listSavedSessions(cwd?: string): Promise<ClaudeSessionSummary[]>;
23
23
  getTranscript(sessionId: string, cwd?: string): Promise<ClaudeSessionTranscriptMessage[]>;
24
- probeCapabilities(cwd: string, settingSources?: SettingSource[]): Promise<ClaudeCapabilitySnapshot>;
25
24
  private buildOptions;
26
25
  }
27
26
  export {};
@@ -123,34 +123,6 @@ export class ClaudeAgentSdkAdapter {
123
123
  text: extractText(message.message),
124
124
  }));
125
125
  }
126
- async probeCapabilities(cwd, settingSources = ['project']) {
127
- const sessionQuery = this.sdkFacade.query({
128
- prompt: 'Reply with OK.',
129
- options: {
130
- cwd,
131
- maxTurns: 1,
132
- permissionMode: 'plan',
133
- persistSession: false,
134
- tools: [],
135
- settingSources,
136
- },
137
- });
138
- try {
139
- const [commands, agents, models] = await Promise.all([
140
- sessionQuery.supportedCommands(),
141
- sessionQuery.supportedAgents(),
142
- sessionQuery.supportedModels(),
143
- ]);
144
- return {
145
- commands: commands.map(mapSlashCommand),
146
- agents: agents.map(mapAgent),
147
- models: models.map((model) => model.value),
148
- };
149
- }
150
- finally {
151
- sessionQuery.close();
152
- }
153
- }
154
126
  buildOptions(input) {
155
127
  const options = {
156
128
  cwd: input.cwd,
@@ -465,22 +437,6 @@ function extractText(payload) {
465
437
  }
466
438
  return JSON.stringify(payload);
467
439
  }
468
- function mapSlashCommand(command) {
469
- return {
470
- name: command.name,
471
- description: command.description,
472
- argumentHint: command.argumentHint,
473
- source: 'sdk',
474
- };
475
- }
476
- function mapAgent(agent) {
477
- return {
478
- name: agent.name,
479
- description: agent.description,
480
- model: agent.model,
481
- source: 'sdk',
482
- };
483
- }
484
440
  function extractUsageFromResult(message) {
485
441
  if (message.type !== 'result') {
486
442
  return {};
@@ -1,4 +1,4 @@
1
- import type { ClaudeCapabilitySnapshot, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, RunClaudeSessionInput } from '../types/contracts.js';
1
+ import type { ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, RunClaudeSessionInput } from '../types/contracts.js';
2
2
  import type { ClaudeAgentSdkAdapter, ClaudeSessionEventHandler } from './claude-agent-sdk-adapter.js';
3
3
  export declare class ClaudeSessionService {
4
4
  private readonly sdkAdapter;
@@ -6,5 +6,4 @@ export declare class ClaudeSessionService {
6
6
  runTask(input: RunClaudeSessionInput, onEvent?: ClaudeSessionEventHandler): Promise<ClaudeSessionRunResult>;
7
7
  listSessions(cwd?: string): Promise<ClaudeSessionSummary[]>;
8
8
  getTranscript(sessionId: string, cwd?: string): Promise<ClaudeSessionTranscriptMessage[]>;
9
- probeCapabilities(cwd: string): Promise<ClaudeCapabilitySnapshot>;
10
9
  }
@@ -12,7 +12,4 @@ export class ClaudeSessionService {
12
12
  getTranscript(sessionId, cwd) {
13
13
  return this.sdkAdapter.getTranscript(sessionId, cwd);
14
14
  }
15
- probeCapabilities(cwd) {
16
- return this.sdkAdapter.probeCapabilities(cwd);
17
- }
18
15
  }
@@ -3,7 +3,10 @@ export declare class ToolApprovalManager {
3
3
  private policy;
4
4
  private decisions;
5
5
  private readonly maxDecisions;
6
- constructor(policy?: Partial<ToolApprovalPolicy>, maxDecisions?: number);
6
+ private readonly persistPath;
7
+ constructor(policy?: Partial<ToolApprovalPolicy>, maxDecisions?: number, persistPath?: string);
8
+ loadPersistedPolicy(): Promise<void>;
9
+ private persistPolicy;
7
10
  evaluate(toolName: string, input: Record<string, unknown>, options?: {
8
11
  title?: string;
9
12
  agentID?: string;
@@ -17,11 +20,11 @@ export declare class ToolApprovalManager {
17
20
  getDeniedDecisions(limit?: number): ToolApprovalDecision[];
18
21
  clearDecisions(): void;
19
22
  getPolicy(): ToolApprovalPolicy;
20
- setPolicy(policy: ToolApprovalPolicy): void;
21
- addRule(rule: ToolApprovalRule, position?: number): void;
22
- removeRule(ruleId: string): boolean;
23
- setDefaultAction(action: 'allow' | 'deny'): void;
24
- setEnabled(enabled: boolean): void;
23
+ setPolicy(policy: ToolApprovalPolicy): Promise<void>;
24
+ addRule(rule: ToolApprovalRule, position?: number): Promise<void>;
25
+ removeRule(ruleId: string): Promise<boolean>;
26
+ setDefaultAction(action: 'allow' | 'deny'): Promise<void>;
27
+ setEnabled(enabled: boolean): Promise<void>;
25
28
  private findMatchingRule;
26
29
  private recordDecision;
27
30
  }
@@ -1,3 +1,6 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { isFileNotFoundError, writeJsonAtomically } from '../util/fs-helpers.js';
1
4
  const DEFAULT_MAX_DECISIONS = 500;
2
5
  const INPUT_PREVIEW_MAX = 300;
3
6
  function getDefaultRules() {
@@ -120,7 +123,8 @@ export class ToolApprovalManager {
120
123
  policy;
121
124
  decisions = [];
122
125
  maxDecisions;
123
- constructor(policy, maxDecisions) {
126
+ persistPath;
127
+ constructor(policy, maxDecisions, persistPath) {
124
128
  this.policy = {
125
129
  rules: policy?.rules ?? getDefaultRules(),
126
130
  defaultAction: policy?.defaultAction ?? 'allow',
@@ -128,6 +132,34 @@ export class ToolApprovalManager {
128
132
  enabled: policy?.enabled ?? true,
129
133
  };
130
134
  this.maxDecisions = maxDecisions ?? DEFAULT_MAX_DECISIONS;
135
+ this.persistPath = persistPath ?? null;
136
+ }
137
+ async loadPersistedPolicy() {
138
+ if (!this.persistPath) {
139
+ return;
140
+ }
141
+ try {
142
+ const content = await fs.readFile(this.persistPath, 'utf8');
143
+ const loaded = JSON.parse(content);
144
+ this.policy = {
145
+ rules: loaded.rules ?? getDefaultRules(),
146
+ defaultAction: loaded.defaultAction ?? 'allow',
147
+ defaultDenyMessage: loaded.defaultDenyMessage ?? 'Tool call denied by approval policy.',
148
+ enabled: loaded.enabled ?? true,
149
+ };
150
+ }
151
+ catch (error) {
152
+ if (!isFileNotFoundError(error)) {
153
+ throw error;
154
+ }
155
+ }
156
+ }
157
+ async persistPolicy() {
158
+ if (!this.persistPath) {
159
+ return;
160
+ }
161
+ await fs.mkdir(path.dirname(this.persistPath), { recursive: true });
162
+ await writeJsonAtomically(this.persistPath, this.policy);
131
163
  }
132
164
  evaluate(toolName, input, options) {
133
165
  if (!this.policy.enabled) {
@@ -168,30 +200,35 @@ export class ToolApprovalManager {
168
200
  getPolicy() {
169
201
  return { ...this.policy, rules: [...this.policy.rules] };
170
202
  }
171
- setPolicy(policy) {
203
+ async setPolicy(policy) {
172
204
  this.policy = { ...policy, rules: [...policy.rules] };
205
+ await this.persistPolicy();
173
206
  }
174
- addRule(rule, position) {
207
+ async addRule(rule, position) {
175
208
  if (position !== undefined && position >= 0 && position < this.policy.rules.length) {
176
209
  this.policy.rules.splice(position, 0, rule);
177
210
  }
178
211
  else {
179
212
  this.policy.rules.push(rule);
180
213
  }
214
+ await this.persistPolicy();
181
215
  }
182
- removeRule(ruleId) {
216
+ async removeRule(ruleId) {
183
217
  const index = this.policy.rules.findIndex((r) => r.id === ruleId);
184
218
  if (index === -1) {
185
219
  return false;
186
220
  }
187
221
  this.policy.rules.splice(index, 1);
222
+ await this.persistPolicy();
188
223
  return true;
189
224
  }
190
- setDefaultAction(action) {
225
+ async setDefaultAction(action) {
191
226
  this.policy.defaultAction = action;
227
+ await this.persistPolicy();
192
228
  }
193
- setEnabled(enabled) {
229
+ async setEnabled(enabled) {
194
230
  this.policy.enabled = enabled;
231
+ await this.persistPolicy();
195
232
  }
196
233
  findMatchingRule(toolName, inputJson) {
197
234
  for (const rule of this.policy.rules) {
package/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
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, ContextWarningLevel, SessionMode, EngineerName, EngineerWorkMode, WrapperHistoryEntry, TeamEngineerRecord, TeamRecord, EngineerTaskResult, PlanDraft, SynthesizedPlanResult, LiveTailEvent, ToolOutputPreview, ToolApprovalRule, ToolApprovalPolicy, ToolApprovalDecision, } from './types/contracts.js';
4
- export { SessionLiveTailer } from './claude/session-live-tailer.js';
3
+ export type { ClaudeCapabilitySnapshot, ClaudeSessionRunResult, ClaudeSessionSummary, ClaudeSessionTranscriptMessage, ManagerPromptRegistry, RunClaudeSessionInput, SessionContextSnapshot, GitDiffResult, GitOperationResult, ContextWarningLevel, SessionMode, EngineerName, EngineerWorkMode, EngineerFailureKind, EngineerFailureResult, WrapperHistoryEntry, TeamEngineerRecord, TeamRecord, EngineerTaskResult, PlanDraft, SynthesizedPlanResult, ToolApprovalRule, ToolApprovalPolicy, ToolApprovalDecision, } from './types/contracts.js';
5
4
  export { ClaudeManagerPlugin };
6
5
  export declare const plugin: Plugin;
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
1
  import { ClaudeManagerPlugin } from './plugin/claude-manager.plugin.js';
2
- export { SessionLiveTailer } from './claude/session-live-tailer.js';
3
2
  export { ClaudeManagerPlugin };
4
3
  export const plugin = ClaudeManagerPlugin;
@@ -19,7 +19,6 @@ export declare class ContextTracker {
19
19
  snapshot(): SessionContextSnapshot;
20
20
  warningLevel(): ContextWarningLevel;
21
21
  estimateContextPercent(): number | null;
22
- isAboveTokenThreshold(thresholdTokens?: number): boolean;
23
22
  reset(): void;
24
23
  /** Restore from persisted active session state. */
25
24
  restore(state: {
@@ -83,9 +83,6 @@ export class ContextTracker {
83
83
  }
84
84
  return null;
85
85
  }
86
- isAboveTokenThreshold(thresholdTokens = 200_000) {
87
- return this.latestInputTokens !== null && this.latestInputTokens >= thresholdTokens;
88
- }
89
86
  reset() {
90
87
  this.totalTurns = 0;
91
88
  this.totalCostUsd = 0;
@@ -7,15 +7,12 @@ export declare class GitOperations {
7
7
  staged?: boolean;
8
8
  ref?: string;
9
9
  }): Promise<GitDiffResult>;
10
- diffStat(): Promise<string>;
11
- commit(message: string): Promise<GitOperationResult>;
10
+ commit(message: string, paths?: string[]): Promise<GitOperationResult>;
12
11
  resetHard(): Promise<GitOperationResult>;
13
12
  status(): Promise<{
14
13
  output: string;
15
14
  isClean: boolean;
16
15
  }>;
17
16
  log(count?: number): Promise<string>;
18
- currentBranch(): Promise<string>;
19
- recentCommits(count?: number): Promise<string>;
20
17
  private git;
21
18
  }
@@ -23,12 +23,14 @@ export class GitOperations {
23
23
  stats,
24
24
  };
25
25
  }
26
- async diffStat() {
27
- return this.git(['diff', 'HEAD', '--stat']);
28
- }
29
- async commit(message) {
26
+ async commit(message, paths) {
30
27
  try {
31
- await this.git(['add', '-A']);
28
+ if (paths && paths.length > 0) {
29
+ await this.git(['add', '--', ...paths]);
30
+ }
31
+ else {
32
+ await this.git(['add', '-A']);
33
+ }
32
34
  const output = await this.git(['commit', '-m', message]);
33
35
  return { success: true, output };
34
36
  }
@@ -65,13 +67,6 @@ export class GitOperations {
65
67
  async log(count = 5) {
66
68
  return this.git(['log', '--oneline', `-${count}`]);
67
69
  }
68
- async currentBranch() {
69
- const branch = await this.git(['rev-parse', '--abbrev-ref', 'HEAD']);
70
- return branch.trim();
71
- }
72
- async recentCommits(count = 5) {
73
- return this.git(['log', `--oneline`, `-${count}`]);
74
- }
75
70
  async git(args) {
76
71
  const { stdout } = await execFileAsync('git', args, { cwd: this.cwd });
77
72
  return stdout;
@@ -1,38 +1,10 @@
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';
1
+ import type { ClaudeSessionEvent, GitDiffResult, GitOperationResult } from '../types/contracts.js';
4
2
  import type { TranscriptStore } from '../state/transcript-store.js';
5
- import type { SessionController } from './session-controller.js';
6
3
  import type { GitOperations } from './git-operations.js';
7
- import type { ContextTracker } from './context-tracker.js';
8
- type PersistentManagerProgressHandler = (run: PersistentRunRecord) => void | Promise<void>;
9
4
  export declare class PersistentManager {
10
- private readonly sessionController;
11
5
  private readonly gitOps;
12
- private readonly stateStore;
13
- private readonly contextTracker;
14
6
  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
- sessionSystemPrompt?: string;
25
- abortSignal?: AbortSignal;
26
- }, onEvent?: ClaudeSessionEventHandler): Promise<{
27
- sessionId: string | undefined;
28
- finalText: string;
29
- turns?: number;
30
- totalCostUsd?: number;
31
- inputTokens?: number;
32
- outputTokens?: number;
33
- contextWindowSize?: number;
34
- context: SessionContextSnapshot;
35
- }>;
7
+ constructor(gitOps: GitOperations, transcriptStore: TranscriptStore);
36
8
  /**
37
9
  * Get the current git diff.
38
10
  */
@@ -44,7 +16,7 @@ export declare class PersistentManager {
44
16
  /**
45
17
  * Commit all current changes.
46
18
  */
47
- gitCommit(message: string): Promise<GitOperationResult>;
19
+ gitCommit(message: string, paths?: string[]): Promise<GitOperationResult>;
48
20
  /**
49
21
  * Get git status summary.
50
22
  */
@@ -60,30 +32,8 @@ export declare class PersistentManager {
60
32
  * Hard reset to discard all uncommitted changes.
61
33
  */
62
34
  gitReset(): Promise<GitOperationResult>;
63
- /**
64
- * Get current session status and context health.
65
- */
66
- getStatus(): SessionContextSnapshot;
67
- /**
68
- * Clear the active session. Next send creates a fresh one.
69
- */
70
- clearSession(): Promise<string | null>;
71
- /**
72
- * Compact the current session to free context.
73
- */
74
- compactSession(cwd: string, onEvent?: ClaudeSessionEventHandler): Promise<ClaudeSessionRunResult>;
75
35
  /**
76
36
  * Read persisted transcript events for a session.
77
37
  */
78
38
  getTranscriptEvents(cwd: string, sessionId: string): Promise<ClaudeSessionEvent[]>;
79
- /**
80
- * Execute a full task with run tracking.
81
- * Creates a run record, sends the message, and persists the result.
82
- */
83
- executeTask(cwd: string, task: string, options?: {
84
- model?: string;
85
- }, onProgress?: PersistentManagerProgressHandler): Promise<PersistentRunResult>;
86
- listRuns(cwd: string): Promise<PersistentRunRecord[]>;
87
- getRun(cwd: string, runId: string): Promise<PersistentRunRecord | null>;
88
39
  }
89
- export {};
@@ -1,37 +1,10 @@
1
- import { randomUUID } from 'node:crypto';
2
1
  export class PersistentManager {
3
- sessionController;
4
2
  gitOps;
5
- stateStore;
6
- contextTracker;
7
3
  transcriptStore;
8
- constructor(sessionController, gitOps, stateStore, contextTracker, transcriptStore) {
9
- this.sessionController = sessionController;
4
+ constructor(gitOps, transcriptStore) {
10
5
  this.gitOps = gitOps;
11
- this.stateStore = stateStore;
12
- this.contextTracker = contextTracker;
13
6
  this.transcriptStore = transcriptStore;
14
7
  }
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(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
- inputTokens: result.inputTokens,
30
- outputTokens: result.outputTokens,
31
- contextWindowSize: result.contextWindowSize,
32
- context: this.sessionController.getContextSnapshot(),
33
- };
34
- }
35
8
  /**
36
9
  * Get the current git diff.
37
10
  */
@@ -41,8 +14,8 @@ export class PersistentManager {
41
14
  /**
42
15
  * Commit all current changes.
43
16
  */
44
- async gitCommit(message) {
45
- return this.gitOps.commit(message);
17
+ async gitCommit(message, paths) {
18
+ return this.gitOps.commit(message, paths);
46
19
  }
47
20
  /**
48
21
  * Get git status summary.
@@ -62,115 +35,10 @@ export class PersistentManager {
62
35
  async gitReset() {
63
36
  return this.gitOps.resetHard();
64
37
  }
65
- /**
66
- * Get current session status and context health.
67
- */
68
- getStatus() {
69
- return this.sessionController.getContextSnapshot();
70
- }
71
- /**
72
- * Clear the active session. Next send creates a fresh one.
73
- */
74
- async clearSession() {
75
- return this.sessionController.clearSession();
76
- }
77
- /**
78
- * Compact the current session to free context.
79
- */
80
- async compactSession(cwd, onEvent) {
81
- const result = await this.sessionController.compactSession(onEvent);
82
- if (result.sessionId && result.events.length > 0) {
83
- await this.transcriptStore.appendEvents(cwd, result.sessionId, result.events);
84
- }
85
- return result;
86
- }
87
38
  /**
88
39
  * Read persisted transcript events for a session.
89
40
  */
90
41
  getTranscriptEvents(cwd, sessionId) {
91
42
  return this.transcriptStore.readEvents(cwd, sessionId);
92
43
  }
93
- /**
94
- * Execute a full task with run tracking.
95
- * Creates a run record, sends the message, and persists the result.
96
- */
97
- async executeTask(cwd, task, options, onProgress) {
98
- const runId = randomUUID();
99
- const createdAt = new Date().toISOString();
100
- const runRecord = {
101
- id: runId,
102
- cwd,
103
- task,
104
- status: 'running',
105
- createdAt,
106
- updatedAt: createdAt,
107
- sessionId: this.sessionController.sessionId,
108
- sessionHistory: [],
109
- messages: [
110
- {
111
- timestamp: createdAt,
112
- direction: 'sent',
113
- text: task,
114
- },
115
- ],
116
- actions: [],
117
- commits: [],
118
- context: this.sessionController.getContextSnapshot(),
119
- };
120
- await this.stateStore.saveRun(runRecord);
121
- await onProgress?.(runRecord);
122
- try {
123
- const result = await this.sessionController.sendMessage(task, options, async (event) => {
124
- // Update run record with progress events
125
- const currentRun = await this.stateStore.getRun(cwd, runId);
126
- if (currentRun) {
127
- const updated = {
128
- ...currentRun,
129
- updatedAt: new Date().toISOString(),
130
- sessionId: event.sessionId ?? currentRun.sessionId,
131
- context: this.sessionController.getContextSnapshot(),
132
- };
133
- await this.stateStore.saveRun(updated);
134
- await onProgress?.(updated);
135
- }
136
- });
137
- const completedRun = await this.stateStore.updateRun(cwd, runId, (run) => ({
138
- ...run,
139
- status: 'completed',
140
- updatedAt: new Date().toISOString(),
141
- sessionId: result.sessionId ?? run.sessionId,
142
- messages: [
143
- ...run.messages,
144
- {
145
- timestamp: new Date().toISOString(),
146
- direction: 'received',
147
- text: result.finalText,
148
- turns: result.turns,
149
- totalCostUsd: result.totalCostUsd,
150
- inputTokens: result.inputTokens,
151
- outputTokens: result.outputTokens,
152
- },
153
- ],
154
- context: this.sessionController.getContextSnapshot(),
155
- finalSummary: result.finalText,
156
- }));
157
- return { run: completedRun };
158
- }
159
- catch (error) {
160
- const failedRun = await this.stateStore.updateRun(cwd, runId, (run) => ({
161
- ...run,
162
- status: 'failed',
163
- updatedAt: new Date().toISOString(),
164
- context: this.sessionController.getContextSnapshot(),
165
- finalSummary: error instanceof Error ? error.message : String(error),
166
- }));
167
- return { run: failedRun };
168
- }
169
- }
170
- listRuns(cwd) {
171
- return this.stateStore.listRuns(cwd);
172
- }
173
- getRun(cwd, runId) {
174
- return this.stateStore.getRun(cwd, runId);
175
- }
176
44
  }
@@ -2,7 +2,7 @@ import type { ClaudeSessionEventHandler } from '../claude/claude-agent-sdk-adapt
2
2
  import type { ClaudeSessionService } from '../claude/claude-session.service.js';
3
3
  import type { TeamStateStore } from '../state/team-state-store.js';
4
4
  import type { TranscriptStore } from '../state/transcript-store.js';
5
- import type { DiscoveredClaudeFile, EngineerName, EngineerTaskResult, EngineerWorkMode, SynthesizedPlanResult, TeamRecord } from '../types/contracts.js';
5
+ import type { DiscoveredClaudeFile, EngineerFailureResult, EngineerName, EngineerTaskResult, EngineerWorkMode, SynthesizedPlanResult, TeamRecord } from '../types/contracts.js';
6
6
  interface DispatchEngineerInput {
7
7
  teamId: string;
8
8
  cwd: string;
@@ -29,7 +29,14 @@ export declare class TeamOrchestrator {
29
29
  teamId: string;
30
30
  engineer: EngineerName;
31
31
  } | null>;
32
+ resetEngineer(cwd: string, teamId: string, engineer: EngineerName, options?: {
33
+ clearSession?: boolean;
34
+ clearHistory?: boolean;
35
+ }): Promise<void>;
32
36
  dispatchEngineer(input: DispatchEngineerInput): Promise<EngineerTaskResult>;
37
+ static classifyError(error: unknown): EngineerFailureResult & {
38
+ cause: unknown;
39
+ };
33
40
  planWithTeam(input: {
34
41
  teamId: string;
35
42
  cwd: string;