@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.
- package/dist/claude/claude-agent-sdk-adapter.d.ts +2 -3
- package/dist/claude/claude-agent-sdk-adapter.js +0 -44
- package/dist/claude/claude-session.service.d.ts +1 -2
- package/dist/claude/claude-session.service.js +0 -3
- package/dist/claude/tool-approval-manager.d.ts +9 -6
- package/dist/claude/tool-approval-manager.js +43 -6
- package/dist/index.d.ts +1 -2
- package/dist/index.js +0 -1
- package/dist/manager/context-tracker.d.ts +0 -1
- package/dist/manager/context-tracker.js +0 -3
- package/dist/manager/git-operations.d.ts +1 -4
- package/dist/manager/git-operations.js +7 -12
- package/dist/manager/persistent-manager.d.ts +3 -53
- package/dist/manager/persistent-manager.js +3 -135
- package/dist/manager/team-orchestrator.d.ts +8 -1
- package/dist/manager/team-orchestrator.js +70 -11
- package/dist/plugin/agent-hierarchy.d.ts +1 -1
- package/dist/plugin/agent-hierarchy.js +3 -1
- package/dist/plugin/claude-manager.plugin.js +169 -21
- package/dist/plugin/service-factory.d.ts +0 -2
- package/dist/plugin/service-factory.js +4 -12
- package/dist/prompts/registry.js +42 -37
- package/dist/src/claude/claude-agent-sdk-adapter.d.ts +2 -3
- package/dist/src/claude/claude-agent-sdk-adapter.js +0 -44
- package/dist/src/claude/claude-session.service.d.ts +1 -2
- package/dist/src/claude/claude-session.service.js +0 -3
- package/dist/src/claude/tool-approval-manager.d.ts +9 -6
- package/dist/src/claude/tool-approval-manager.js +43 -6
- package/dist/src/index.d.ts +1 -2
- package/dist/src/index.js +0 -1
- package/dist/src/manager/context-tracker.d.ts +0 -1
- package/dist/src/manager/context-tracker.js +0 -3
- package/dist/src/manager/git-operations.d.ts +1 -4
- package/dist/src/manager/git-operations.js +7 -12
- package/dist/src/manager/persistent-manager.d.ts +3 -53
- package/dist/src/manager/persistent-manager.js +3 -135
- package/dist/src/manager/team-orchestrator.d.ts +8 -1
- package/dist/src/manager/team-orchestrator.js +70 -11
- package/dist/src/plugin/agent-hierarchy.d.ts +1 -1
- package/dist/src/plugin/agent-hierarchy.js +3 -1
- package/dist/src/plugin/claude-manager.plugin.js +169 -21
- package/dist/src/plugin/service-factory.d.ts +0 -2
- package/dist/src/plugin/service-factory.js +4 -12
- package/dist/src/prompts/registry.js +42 -37
- package/dist/src/state/team-state-store.js +4 -1
- package/dist/src/team/roster.js +1 -0
- package/dist/src/types/contracts.d.ts +9 -49
- package/dist/state/team-state-store.js +4 -1
- package/dist/team/roster.js +1 -0
- package/dist/test/claude-agent-sdk-adapter.test.js +0 -11
- package/dist/test/claude-manager.plugin.test.js +6 -1
- package/dist/test/context-tracker.test.js +0 -8
- package/dist/test/git-operations.test.js +0 -21
- package/dist/test/persistent-manager.test.js +4 -164
- package/dist/test/prompt-registry.test.js +4 -9
- package/dist/test/report-claude-event.test.js +2 -2
- package/dist/test/tool-approval-manager.test.js +17 -17
- package/dist/types/contracts.d.ts +9 -49
- package/package.json +1 -1
|
@@ -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 {
|
|
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
|
}
|
|
@@ -3,7 +3,10 @@ export declare class ToolApprovalManager {
|
|
|
3
3
|
private policy;
|
|
4
4
|
private decisions;
|
|
5
5
|
private readonly maxDecisions;
|
|
6
|
-
|
|
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
|
-
|
|
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/src/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,
|
|
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/src/index.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
27
|
-
return this.git(['diff', 'HEAD', '--stat']);
|
|
28
|
-
}
|
|
29
|
-
async commit(message) {
|
|
26
|
+
async commit(message, paths) {
|
|
30
27
|
try {
|
|
31
|
-
|
|
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,
|
|
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(
|
|
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(
|
|
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;
|