@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.
- package/README.md +40 -129
- package/dist/index.d.ts +5 -4
- package/dist/index.js +5 -4
- package/dist/plugin/orchestrator.plugin.d.ts +2 -0
- package/dist/plugin/orchestrator.plugin.js +114 -0
- package/dist/prompts/registry.d.ts +8 -2
- package/dist/prompts/registry.js +30 -159
- package/dist/providers/claude-code-wrapper.d.ts +13 -0
- package/dist/providers/claude-code-wrapper.js +13 -0
- package/dist/safety/bash-safety.d.ts +21 -0
- package/dist/safety/bash-safety.js +62 -0
- package/package.json +3 -5
- package/dist/claude/claude-agent-sdk-adapter.d.ts +0 -27
- package/dist/claude/claude-agent-sdk-adapter.js +0 -520
- package/dist/claude/claude-session.service.d.ts +0 -15
- package/dist/claude/claude-session.service.js +0 -23
- package/dist/claude/delegated-can-use-tool.d.ts +0 -7
- package/dist/claude/delegated-can-use-tool.js +0 -178
- package/dist/claude/session-live-tailer.d.ts +0 -51
- package/dist/claude/session-live-tailer.js +0 -269
- package/dist/claude/tool-approval-manager.d.ts +0 -27
- package/dist/claude/tool-approval-manager.js +0 -238
- package/dist/manager/context-tracker.d.ts +0 -33
- package/dist/manager/context-tracker.js +0 -108
- package/dist/manager/git-operations.d.ts +0 -12
- package/dist/manager/git-operations.js +0 -76
- package/dist/manager/manager-orchestrator.d.ts +0 -17
- package/dist/manager/manager-orchestrator.js +0 -178
- package/dist/manager/parallel-session-job-manager.d.ts +0 -49
- package/dist/manager/parallel-session-job-manager.js +0 -177
- package/dist/manager/persistent-manager.d.ts +0 -74
- package/dist/manager/persistent-manager.js +0 -167
- package/dist/manager/session-controller.d.ts +0 -45
- package/dist/manager/session-controller.js +0 -147
- package/dist/manager/task-planner.d.ts +0 -5
- package/dist/manager/task-planner.js +0 -15
- package/dist/metadata/claude-metadata.service.d.ts +0 -12
- package/dist/metadata/claude-metadata.service.js +0 -38
- package/dist/metadata/repo-claude-config-reader.d.ts +0 -7
- package/dist/metadata/repo-claude-config-reader.js +0 -154
- package/dist/plugin/claude-code-permission-bridge.d.ts +0 -15
- package/dist/plugin/claude-code-permission-bridge.js +0 -184
- package/dist/plugin/claude-manager.plugin.d.ts +0 -2
- package/dist/plugin/claude-manager.plugin.js +0 -627
- package/dist/plugin/service-factory.d.ts +0 -12
- package/dist/plugin/service-factory.js +0 -41
- package/dist/state/file-run-state-store.d.ts +0 -14
- package/dist/state/file-run-state-store.js +0 -87
- package/dist/state/transcript-store.d.ts +0 -15
- package/dist/state/transcript-store.js +0 -44
- package/dist/types/contracts.d.ts +0 -215
- package/dist/types/contracts.js +0 -1
- package/dist/util/fs-helpers.d.ts +0 -2
- package/dist/util/fs-helpers.js +0 -12
- package/dist/util/transcript-append.d.ts +0 -7
- package/dist/util/transcript-append.js +0 -29
- package/dist/worktree/worktree-coordinator.d.ts +0 -21
- package/dist/worktree/worktree-coordinator.js +0 -64
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { ClaudeAgentSdkAdapter } from '../claude/claude-agent-sdk-adapter.js';
|
|
2
|
-
import { ClaudeSessionService } from '../claude/claude-session.service.js';
|
|
3
|
-
import { SessionLiveTailer } from '../claude/session-live-tailer.js';
|
|
4
|
-
import { ToolApprovalManager } from '../claude/tool-approval-manager.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 { TranscriptStore } from '../state/transcript-store.js';
|
|
9
|
-
import { ContextTracker } from '../manager/context-tracker.js';
|
|
10
|
-
import { GitOperations } from '../manager/git-operations.js';
|
|
11
|
-
import { SessionController } from '../manager/session-controller.js';
|
|
12
|
-
import { PersistentManager } from '../manager/persistent-manager.js';
|
|
13
|
-
import { managerPromptRegistry } from '../prompts/registry.js';
|
|
14
|
-
const serviceCache = new Map();
|
|
15
|
-
export function getOrCreatePluginServices(worktree) {
|
|
16
|
-
const cachedServices = serviceCache.get(worktree);
|
|
17
|
-
if (cachedServices) {
|
|
18
|
-
return cachedServices;
|
|
19
|
-
}
|
|
20
|
-
const approvalManager = new ToolApprovalManager();
|
|
21
|
-
const sdkAdapter = new ClaudeAgentSdkAdapter(undefined, approvalManager);
|
|
22
|
-
const metadataService = new ClaudeMetadataService(new RepoClaudeConfigReader(), sdkAdapter);
|
|
23
|
-
const sessionService = new ClaudeSessionService(sdkAdapter, metadataService);
|
|
24
|
-
const contextTracker = new ContextTracker();
|
|
25
|
-
const sessionController = new SessionController(sdkAdapter, contextTracker, managerPromptRegistry.claudeCodeSessionPrompt, managerPromptRegistry.modePrefixes);
|
|
26
|
-
const gitOps = new GitOperations(worktree);
|
|
27
|
-
const stateStore = new FileRunStateStore();
|
|
28
|
-
const transcriptStore = new TranscriptStore();
|
|
29
|
-
const manager = new PersistentManager(sessionController, gitOps, stateStore, contextTracker, transcriptStore);
|
|
30
|
-
// Try to restore active session state (fire and forget)
|
|
31
|
-
manager.tryRestore(worktree).catch(() => { });
|
|
32
|
-
const liveTailer = new SessionLiveTailer();
|
|
33
|
-
const services = {
|
|
34
|
-
manager,
|
|
35
|
-
sessions: sessionService,
|
|
36
|
-
approvalManager,
|
|
37
|
-
liveTailer,
|
|
38
|
-
};
|
|
39
|
-
serviceCache.set(worktree, services);
|
|
40
|
-
return services;
|
|
41
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { PersistentRunRecord } from '../types/contracts.js';
|
|
2
|
-
export declare class FileRunStateStore {
|
|
3
|
-
private readonly baseDirectoryName;
|
|
4
|
-
private readonly writeQueues;
|
|
5
|
-
constructor(baseDirectoryName?: string);
|
|
6
|
-
saveRun(run: PersistentRunRecord): Promise<void>;
|
|
7
|
-
getRun(cwd: string, runId: string): Promise<PersistentRunRecord | null>;
|
|
8
|
-
listRuns(cwd: string): Promise<PersistentRunRecord[]>;
|
|
9
|
-
updateRun(cwd: string, runId: string, update: (run: PersistentRunRecord) => PersistentRunRecord): Promise<PersistentRunRecord>;
|
|
10
|
-
private getRunKey;
|
|
11
|
-
private getRunsDirectory;
|
|
12
|
-
private getRunPath;
|
|
13
|
-
private enqueueWrite;
|
|
14
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { isFileNotFoundError, writeJsonAtomically, } from '../util/fs-helpers.js';
|
|
4
|
-
export class FileRunStateStore {
|
|
5
|
-
baseDirectoryName;
|
|
6
|
-
writeQueues = new Map();
|
|
7
|
-
constructor(baseDirectoryName = '.claude-manager') {
|
|
8
|
-
this.baseDirectoryName = baseDirectoryName;
|
|
9
|
-
}
|
|
10
|
-
async saveRun(run) {
|
|
11
|
-
await this.enqueueWrite(this.getRunKey(run.cwd, run.id), async () => {
|
|
12
|
-
const runPath = this.getRunPath(run.cwd, run.id);
|
|
13
|
-
await fs.mkdir(path.dirname(runPath), { recursive: true });
|
|
14
|
-
await writeJsonAtomically(runPath, run);
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
async getRun(cwd, runId) {
|
|
18
|
-
const runPath = this.getRunPath(cwd, runId);
|
|
19
|
-
try {
|
|
20
|
-
const content = await fs.readFile(runPath, 'utf8');
|
|
21
|
-
return JSON.parse(content);
|
|
22
|
-
}
|
|
23
|
-
catch (error) {
|
|
24
|
-
if (isFileNotFoundError(error)) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
throw error;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
async listRuns(cwd) {
|
|
31
|
-
const runsDirectory = this.getRunsDirectory(cwd);
|
|
32
|
-
try {
|
|
33
|
-
const entries = await fs.readdir(runsDirectory);
|
|
34
|
-
const runs = await Promise.all(entries
|
|
35
|
-
.filter((entry) => entry.endsWith('.json'))
|
|
36
|
-
.map(async (entry) => {
|
|
37
|
-
const content = await fs.readFile(path.join(runsDirectory, entry), 'utf8');
|
|
38
|
-
return JSON.parse(content);
|
|
39
|
-
}));
|
|
40
|
-
return runs.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
|
|
41
|
-
}
|
|
42
|
-
catch (error) {
|
|
43
|
-
if (isFileNotFoundError(error)) {
|
|
44
|
-
return [];
|
|
45
|
-
}
|
|
46
|
-
throw error;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
async updateRun(cwd, runId, update) {
|
|
50
|
-
return this.enqueueWrite(this.getRunKey(cwd, runId), async () => {
|
|
51
|
-
const existingRun = await this.getRun(cwd, runId);
|
|
52
|
-
if (!existingRun) {
|
|
53
|
-
throw new Error(`Run ${runId} does not exist.`);
|
|
54
|
-
}
|
|
55
|
-
const updatedRun = update(existingRun);
|
|
56
|
-
const runPath = this.getRunPath(cwd, runId);
|
|
57
|
-
await fs.mkdir(path.dirname(runPath), { recursive: true });
|
|
58
|
-
await writeJsonAtomically(runPath, updatedRun);
|
|
59
|
-
return updatedRun;
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
getRunKey(cwd, runId) {
|
|
63
|
-
return `${cwd}:${runId}`;
|
|
64
|
-
}
|
|
65
|
-
getRunsDirectory(cwd) {
|
|
66
|
-
return path.join(cwd, this.baseDirectoryName, 'runs');
|
|
67
|
-
}
|
|
68
|
-
getRunPath(cwd, runId) {
|
|
69
|
-
return path.join(this.getRunsDirectory(cwd), `${runId}.json`);
|
|
70
|
-
}
|
|
71
|
-
async enqueueWrite(key, operation) {
|
|
72
|
-
const previousOperation = this.writeQueues.get(key) ?? Promise.resolve();
|
|
73
|
-
const resultPromise = previousOperation
|
|
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
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { ClaudeSessionEvent } from '../types/contracts.js';
|
|
2
|
-
export declare class TranscriptStore {
|
|
3
|
-
private readonly baseDirectoryName;
|
|
4
|
-
constructor(baseDirectoryName?: string);
|
|
5
|
-
/**
|
|
6
|
-
* Append new events to the transcript file for the given session.
|
|
7
|
-
* Creates the file if it does not exist. Strips trailing partials before persisting.
|
|
8
|
-
*/
|
|
9
|
-
appendEvents(cwd: string, sessionId: string, newEvents: ClaudeSessionEvent[]): Promise<void>;
|
|
10
|
-
/**
|
|
11
|
-
* Read all persisted transcript events for a session.
|
|
12
|
-
*/
|
|
13
|
-
readEvents(cwd: string, sessionId: string): Promise<ClaudeSessionEvent[]>;
|
|
14
|
-
private getTranscriptPath;
|
|
15
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import { appendTranscriptEvents, stripTrailingPartials, } from '../util/transcript-append.js';
|
|
4
|
-
import { isFileNotFoundError, writeJsonAtomically, } from '../util/fs-helpers.js';
|
|
5
|
-
export class TranscriptStore {
|
|
6
|
-
baseDirectoryName;
|
|
7
|
-
constructor(baseDirectoryName = '.claude-manager') {
|
|
8
|
-
this.baseDirectoryName = baseDirectoryName;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* Append new events to the transcript file for the given session.
|
|
12
|
-
* Creates the file if it does not exist. Strips trailing partials before persisting.
|
|
13
|
-
*/
|
|
14
|
-
async appendEvents(cwd, sessionId, newEvents) {
|
|
15
|
-
if (newEvents.length === 0) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
const filePath = this.getTranscriptPath(cwd, sessionId);
|
|
19
|
-
const existing = await this.readEvents(cwd, sessionId);
|
|
20
|
-
const merged = appendTranscriptEvents(existing, newEvents);
|
|
21
|
-
const cleaned = stripTrailingPartials(merged);
|
|
22
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
23
|
-
await writeJsonAtomically(filePath, cleaned);
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Read all persisted transcript events for a session.
|
|
27
|
-
*/
|
|
28
|
-
async readEvents(cwd, sessionId) {
|
|
29
|
-
const filePath = this.getTranscriptPath(cwd, sessionId);
|
|
30
|
-
try {
|
|
31
|
-
const content = await fs.readFile(filePath, 'utf8');
|
|
32
|
-
return JSON.parse(content);
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
if (isFileNotFoundError(error)) {
|
|
36
|
-
return [];
|
|
37
|
-
}
|
|
38
|
-
throw error;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
getTranscriptPath(cwd, sessionId) {
|
|
42
|
-
return path.join(cwd, this.baseDirectoryName, 'transcripts', `${sessionId}.json`);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
export interface ManagerPromptRegistry {
|
|
2
|
-
managerSystemPrompt: string;
|
|
3
|
-
claudeCodeSessionPrompt: string;
|
|
4
|
-
modePrefixes: {
|
|
5
|
-
plan: string;
|
|
6
|
-
free: string;
|
|
7
|
-
};
|
|
8
|
-
contextWarnings: {
|
|
9
|
-
moderate: string;
|
|
10
|
-
high: string;
|
|
11
|
-
critical: string;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
export type ClaudeSettingSource = 'user' | 'project' | 'local';
|
|
15
|
-
export type SessionMode = 'plan' | 'free';
|
|
16
|
-
export interface ClaudeCommandMetadata {
|
|
17
|
-
name: string;
|
|
18
|
-
description: string;
|
|
19
|
-
argumentHint?: string;
|
|
20
|
-
source: 'sdk' | 'skill' | 'command';
|
|
21
|
-
path?: string;
|
|
22
|
-
}
|
|
23
|
-
export interface ClaudeSkillMetadata {
|
|
24
|
-
name: string;
|
|
25
|
-
description: string;
|
|
26
|
-
path: string;
|
|
27
|
-
source: 'skill' | 'command';
|
|
28
|
-
}
|
|
29
|
-
export interface ClaudeHookMetadata {
|
|
30
|
-
name: string;
|
|
31
|
-
matcher?: string;
|
|
32
|
-
sourcePath: string;
|
|
33
|
-
commandCount: number;
|
|
34
|
-
}
|
|
35
|
-
export interface ClaudeAgentMetadata {
|
|
36
|
-
name: string;
|
|
37
|
-
description: string;
|
|
38
|
-
model?: string;
|
|
39
|
-
source: 'sdk' | 'filesystem';
|
|
40
|
-
}
|
|
41
|
-
export interface ClaudeMetadataSnapshot {
|
|
42
|
-
collectedAt: string;
|
|
43
|
-
cwd: string;
|
|
44
|
-
commands: ClaudeCommandMetadata[];
|
|
45
|
-
skills: ClaudeSkillMetadata[];
|
|
46
|
-
hooks: ClaudeHookMetadata[];
|
|
47
|
-
agents: ClaudeAgentMetadata[];
|
|
48
|
-
claudeMdPath?: string;
|
|
49
|
-
settingsPaths: string[];
|
|
50
|
-
}
|
|
51
|
-
export interface ClaudeSessionEvent {
|
|
52
|
-
type: 'init' | 'assistant' | 'partial' | 'user' | 'tool_call' | 'tool_progress' | 'tool_summary' | 'status' | 'system' | 'result' | 'error';
|
|
53
|
-
sessionId?: string;
|
|
54
|
-
text: string;
|
|
55
|
-
turns?: number;
|
|
56
|
-
totalCostUsd?: number;
|
|
57
|
-
/** Present on live SDK-normalized events; omitted when compact-persisted to save space. */
|
|
58
|
-
rawType?: string;
|
|
59
|
-
}
|
|
60
|
-
export interface RunClaudeSessionInput {
|
|
61
|
-
cwd: string;
|
|
62
|
-
prompt: string;
|
|
63
|
-
systemPrompt?: string;
|
|
64
|
-
model?: string;
|
|
65
|
-
effort?: 'low' | 'medium' | 'high' | 'max';
|
|
66
|
-
mode?: SessionMode;
|
|
67
|
-
permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'dontAsk';
|
|
68
|
-
/** Merged with `Skill` by the SDK adapter unless `Skill` appears in `disallowedTools`. */
|
|
69
|
-
allowedTools?: string[];
|
|
70
|
-
disallowedTools?: string[];
|
|
71
|
-
continueSession?: boolean;
|
|
72
|
-
resumeSessionId?: string;
|
|
73
|
-
forkSession?: boolean;
|
|
74
|
-
persistSession?: boolean;
|
|
75
|
-
includePartialMessages?: boolean;
|
|
76
|
-
settingSources?: ClaudeSettingSource[];
|
|
77
|
-
maxTurns?: number;
|
|
78
|
-
abortSignal?: AbortSignal;
|
|
79
|
-
}
|
|
80
|
-
export interface ClaudeSessionRunResult {
|
|
81
|
-
sessionId?: string;
|
|
82
|
-
events: ClaudeSessionEvent[];
|
|
83
|
-
finalText: string;
|
|
84
|
-
turns?: number;
|
|
85
|
-
totalCostUsd?: number;
|
|
86
|
-
inputTokens?: number;
|
|
87
|
-
outputTokens?: number;
|
|
88
|
-
contextWindowSize?: number;
|
|
89
|
-
}
|
|
90
|
-
export interface ClaudeSessionSummary {
|
|
91
|
-
sessionId: string;
|
|
92
|
-
summary: string;
|
|
93
|
-
cwd?: string;
|
|
94
|
-
gitBranch?: string;
|
|
95
|
-
createdAt?: number;
|
|
96
|
-
lastModified: number;
|
|
97
|
-
}
|
|
98
|
-
export interface ClaudeSessionTranscriptMessage {
|
|
99
|
-
role: 'user' | 'assistant';
|
|
100
|
-
sessionId: string;
|
|
101
|
-
messageId: string;
|
|
102
|
-
text: string;
|
|
103
|
-
}
|
|
104
|
-
export interface ClaudeCapabilitySnapshot {
|
|
105
|
-
commands: ClaudeCommandMetadata[];
|
|
106
|
-
agents: ClaudeAgentMetadata[];
|
|
107
|
-
models: string[];
|
|
108
|
-
}
|
|
109
|
-
export type ContextWarningLevel = 'ok' | 'moderate' | 'high' | 'critical';
|
|
110
|
-
export interface SessionContextSnapshot {
|
|
111
|
-
sessionId: string | null;
|
|
112
|
-
totalTurns: number;
|
|
113
|
-
totalCostUsd: number;
|
|
114
|
-
latestInputTokens: number | null;
|
|
115
|
-
latestOutputTokens: number | null;
|
|
116
|
-
contextWindowSize: number | null;
|
|
117
|
-
estimatedContextPercent: number | null;
|
|
118
|
-
warningLevel: ContextWarningLevel;
|
|
119
|
-
compactionCount: number;
|
|
120
|
-
}
|
|
121
|
-
export interface GitDiffResult {
|
|
122
|
-
hasDiff: boolean;
|
|
123
|
-
diffText: string;
|
|
124
|
-
stats: {
|
|
125
|
-
filesChanged: number;
|
|
126
|
-
insertions: number;
|
|
127
|
-
deletions: number;
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
export interface GitOperationResult {
|
|
131
|
-
success: boolean;
|
|
132
|
-
output: string;
|
|
133
|
-
error?: string;
|
|
134
|
-
}
|
|
135
|
-
export interface ActiveSessionState {
|
|
136
|
-
sessionId: string;
|
|
137
|
-
cwd: string;
|
|
138
|
-
startedAt: string;
|
|
139
|
-
totalTurns: number;
|
|
140
|
-
totalCostUsd: number;
|
|
141
|
-
estimatedContextPercent: number | null;
|
|
142
|
-
contextWindowSize: number | null;
|
|
143
|
-
latestInputTokens: number | null;
|
|
144
|
-
}
|
|
145
|
-
export type PersistentRunStatus = 'running' | 'completed' | 'failed';
|
|
146
|
-
export interface PersistentRunMessageRecord {
|
|
147
|
-
timestamp: string;
|
|
148
|
-
direction: 'sent' | 'received';
|
|
149
|
-
text: string;
|
|
150
|
-
turns?: number;
|
|
151
|
-
totalCostUsd?: number;
|
|
152
|
-
inputTokens?: number;
|
|
153
|
-
outputTokens?: number;
|
|
154
|
-
}
|
|
155
|
-
export interface PersistentRunActionRecord {
|
|
156
|
-
timestamp: string;
|
|
157
|
-
type: 'git_diff' | 'git_commit' | 'git_reset' | 'compact' | 'clear';
|
|
158
|
-
result: string;
|
|
159
|
-
}
|
|
160
|
-
export interface PersistentRunRecord {
|
|
161
|
-
id: string;
|
|
162
|
-
cwd: string;
|
|
163
|
-
task: string;
|
|
164
|
-
status: PersistentRunStatus;
|
|
165
|
-
createdAt: string;
|
|
166
|
-
updatedAt: string;
|
|
167
|
-
sessionId: string | null;
|
|
168
|
-
sessionHistory: string[];
|
|
169
|
-
messages: PersistentRunMessageRecord[];
|
|
170
|
-
actions: PersistentRunActionRecord[];
|
|
171
|
-
commits: string[];
|
|
172
|
-
context: SessionContextSnapshot;
|
|
173
|
-
finalSummary?: string;
|
|
174
|
-
}
|
|
175
|
-
export interface PersistentRunResult {
|
|
176
|
-
run: PersistentRunRecord;
|
|
177
|
-
}
|
|
178
|
-
export interface LiveTailEvent {
|
|
179
|
-
type: 'line' | 'error' | 'end';
|
|
180
|
-
sessionId: string;
|
|
181
|
-
data?: unknown;
|
|
182
|
-
rawLine?: string;
|
|
183
|
-
error?: string;
|
|
184
|
-
}
|
|
185
|
-
export interface ToolOutputPreview {
|
|
186
|
-
toolUseId: string;
|
|
187
|
-
content: string;
|
|
188
|
-
isError: boolean;
|
|
189
|
-
}
|
|
190
|
-
export interface ToolApprovalRule {
|
|
191
|
-
id: string;
|
|
192
|
-
description?: string;
|
|
193
|
-
/** Tool name — exact match or glob with * wildcard */
|
|
194
|
-
toolPattern: string;
|
|
195
|
-
/** Optional substring match against JSON-serialized tool input */
|
|
196
|
-
inputPattern?: string;
|
|
197
|
-
action: 'allow' | 'deny';
|
|
198
|
-
denyMessage?: string;
|
|
199
|
-
}
|
|
200
|
-
export interface ToolApprovalPolicy {
|
|
201
|
-
rules: ToolApprovalRule[];
|
|
202
|
-
defaultAction: 'allow' | 'deny';
|
|
203
|
-
defaultDenyMessage?: string;
|
|
204
|
-
enabled: boolean;
|
|
205
|
-
}
|
|
206
|
-
export interface ToolApprovalDecision {
|
|
207
|
-
timestamp: string;
|
|
208
|
-
toolName: string;
|
|
209
|
-
inputPreview: string;
|
|
210
|
-
title?: string;
|
|
211
|
-
matchedRuleId: string;
|
|
212
|
-
action: 'allow' | 'deny';
|
|
213
|
-
denyMessage?: string;
|
|
214
|
-
agentId?: string;
|
|
215
|
-
}
|
package/dist/types/contracts.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/util/fs-helpers.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { promises as fs } from 'node:fs';
|
|
3
|
-
export async function writeJsonAtomically(filePath, data) {
|
|
4
|
-
const tempPath = `${filePath}.${randomUUID()}.tmp`;
|
|
5
|
-
await fs.writeFile(tempPath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
|
|
6
|
-
await fs.rename(tempPath, filePath);
|
|
7
|
-
}
|
|
8
|
-
export function isFileNotFoundError(error) {
|
|
9
|
-
return (error instanceof Error &&
|
|
10
|
-
'code' in error &&
|
|
11
|
-
error.code === 'ENOENT');
|
|
12
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ClaudeSessionEvent } from '../types/contracts.js';
|
|
2
|
-
export declare function stripTrailingPartials(events: ClaudeSessionEvent[]): ClaudeSessionEvent[];
|
|
3
|
-
/**
|
|
4
|
-
* Append transcript events for run-state persistence: at most one trailing
|
|
5
|
-
* `partial`, dropped whenever a non-partial event is appended.
|
|
6
|
-
*/
|
|
7
|
-
export declare function appendTranscriptEvents(events: ClaudeSessionEvent[], incoming: ClaudeSessionEvent[]): ClaudeSessionEvent[];
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
export function stripTrailingPartials(events) {
|
|
2
|
-
let end = events.length;
|
|
3
|
-
while (end > 0 && events[end - 1].type === 'partial') {
|
|
4
|
-
end -= 1;
|
|
5
|
-
}
|
|
6
|
-
return end === events.length ? events : events.slice(0, end);
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Append transcript events for run-state persistence: at most one trailing
|
|
10
|
-
* `partial`, dropped whenever a non-partial event is appended.
|
|
11
|
-
*/
|
|
12
|
-
export function appendTranscriptEvents(events, incoming) {
|
|
13
|
-
let next = events;
|
|
14
|
-
for (const event of incoming) {
|
|
15
|
-
if (event.type === 'partial') {
|
|
16
|
-
if (next.length > 0 && next[next.length - 1].type === 'partial') {
|
|
17
|
-
next = [...next.slice(0, -1), event];
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
next = [...next, event];
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
else {
|
|
24
|
-
next = stripTrailingPartials(next);
|
|
25
|
-
next = [...next, event];
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return next;
|
|
29
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { WorktreeAssignment } from '../types/contracts.js';
|
|
2
|
-
export interface GitCommandRunner {
|
|
3
|
-
run(args: string[], cwd: string): Promise<{
|
|
4
|
-
stdout: string;
|
|
5
|
-
stderr: string;
|
|
6
|
-
}>;
|
|
7
|
-
}
|
|
8
|
-
export declare class WorktreeCoordinator {
|
|
9
|
-
private readonly gitRunner;
|
|
10
|
-
private readonly storageDirectoryName;
|
|
11
|
-
constructor(gitRunner?: GitCommandRunner, storageDirectoryName?: string);
|
|
12
|
-
prepareAssignment(input: {
|
|
13
|
-
cwd: string;
|
|
14
|
-
runId: string;
|
|
15
|
-
title: string;
|
|
16
|
-
useWorktree: boolean;
|
|
17
|
-
}): Promise<WorktreeAssignment>;
|
|
18
|
-
cleanupAssignment(assignment: WorktreeAssignment): Promise<void>;
|
|
19
|
-
isGitRepository(cwd: string): Promise<boolean>;
|
|
20
|
-
private getRepositoryRoot;
|
|
21
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { execFile } from 'node:child_process';
|
|
2
|
-
import { promises as fs } from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import { promisify } from 'node:util';
|
|
5
|
-
const execFileAsync = promisify(execFile);
|
|
6
|
-
const defaultGitRunner = {
|
|
7
|
-
run(args, cwd) {
|
|
8
|
-
return execFileAsync('git', args, { cwd });
|
|
9
|
-
},
|
|
10
|
-
};
|
|
11
|
-
export class WorktreeCoordinator {
|
|
12
|
-
gitRunner;
|
|
13
|
-
storageDirectoryName;
|
|
14
|
-
constructor(gitRunner = defaultGitRunner, storageDirectoryName = '.claude-manager') {
|
|
15
|
-
this.gitRunner = gitRunner;
|
|
16
|
-
this.storageDirectoryName = storageDirectoryName;
|
|
17
|
-
}
|
|
18
|
-
async prepareAssignment(input) {
|
|
19
|
-
const repositoryRoot = await this.getRepositoryRoot(input.cwd);
|
|
20
|
-
if (!input.useWorktree || !repositoryRoot) {
|
|
21
|
-
return {
|
|
22
|
-
mode: 'shared-root',
|
|
23
|
-
cwd: input.cwd,
|
|
24
|
-
rootCwd: input.cwd,
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
const slug = sanitizeSlug(input.title);
|
|
28
|
-
const branchName = `claude-manager/${input.runId}-${slug}`;
|
|
29
|
-
const worktreePath = path.join(repositoryRoot, this.storageDirectoryName, 'worktrees', input.runId, slug);
|
|
30
|
-
await fs.mkdir(path.dirname(worktreePath), { recursive: true });
|
|
31
|
-
await this.gitRunner.run(['worktree', 'add', worktreePath, '-b', branchName], repositoryRoot);
|
|
32
|
-
return {
|
|
33
|
-
mode: 'git-worktree',
|
|
34
|
-
cwd: worktreePath,
|
|
35
|
-
rootCwd: repositoryRoot,
|
|
36
|
-
branchName,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
async cleanupAssignment(assignment) {
|
|
40
|
-
if (assignment.mode !== 'git-worktree') {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
await this.gitRunner.run(['worktree', 'remove', '--force', assignment.cwd], assignment.rootCwd);
|
|
44
|
-
}
|
|
45
|
-
async isGitRepository(cwd) {
|
|
46
|
-
return (await this.getRepositoryRoot(cwd)) !== null;
|
|
47
|
-
}
|
|
48
|
-
async getRepositoryRoot(cwd) {
|
|
49
|
-
try {
|
|
50
|
-
const result = await this.gitRunner.run(['rev-parse', '--show-toplevel'], cwd);
|
|
51
|
-
return result.stdout.trim() || null;
|
|
52
|
-
}
|
|
53
|
-
catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
function sanitizeSlug(value) {
|
|
59
|
-
return (value
|
|
60
|
-
.toLowerCase()
|
|
61
|
-
.replace(/[^a-z0-9]+/g, '-')
|
|
62
|
-
.replace(/^-+|-+$/g, '')
|
|
63
|
-
.slice(0, 40) || 'task');
|
|
64
|
-
}
|