@doingdev/opencode-claude-manager-plugin 0.1.65 → 0.1.66
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/index.d.ts +1 -1
- package/dist/manager/team-orchestrator.js +1 -1
- package/dist/plugin/agents/common.d.ts +2 -2
- package/dist/plugin/agents/common.js +5 -0
- package/dist/plugin/claude-manager.plugin.js +104 -0
- package/dist/plugin/inbox-ops.d.ts +50 -0
- package/dist/plugin/inbox-ops.js +166 -0
- package/dist/types/contracts.d.ts +18 -0
- package/package.json +1 -1
- package/dist/claude/session-live-tailer.d.ts +0 -51
- package/dist/claude/session-live-tailer.js +0 -269
- package/dist/manager/session-controller.d.ts +0 -41
- package/dist/manager/session-controller.js +0 -97
- 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/orchestrator.plugin.d.ts +0 -2
- package/dist/plugin/orchestrator.plugin.js +0 -116
- package/dist/providers/claude-code-wrapper.d.ts +0 -13
- package/dist/providers/claude-code-wrapper.js +0 -13
- package/dist/safety/bash-safety.d.ts +0 -21
- package/dist/safety/bash-safety.js +0 -62
- package/dist/src/claude/claude-agent-sdk-adapter.d.ts +0 -28
- package/dist/src/claude/claude-agent-sdk-adapter.js +0 -559
- package/dist/src/claude/claude-session.service.d.ts +0 -9
- package/dist/src/claude/claude-session.service.js +0 -15
- package/dist/src/claude/session-live-tailer.d.ts +0 -51
- package/dist/src/claude/session-live-tailer.js +0 -269
- package/dist/src/claude/tool-approval-manager.d.ts +0 -30
- package/dist/src/claude/tool-approval-manager.js +0 -279
- package/dist/src/index.d.ts +0 -5
- package/dist/src/index.js +0 -3
- package/dist/src/manager/context-tracker.d.ts +0 -32
- package/dist/src/manager/context-tracker.js +0 -103
- package/dist/src/manager/git-operations.d.ts +0 -18
- package/dist/src/manager/git-operations.js +0 -86
- package/dist/src/manager/persistent-manager.d.ts +0 -39
- package/dist/src/manager/persistent-manager.js +0 -44
- package/dist/src/manager/session-controller.d.ts +0 -41
- package/dist/src/manager/session-controller.js +0 -97
- package/dist/src/manager/team-orchestrator.d.ts +0 -81
- package/dist/src/manager/team-orchestrator.js +0 -612
- package/dist/src/plugin/agent-hierarchy.d.ts +0 -1
- package/dist/src/plugin/agent-hierarchy.js +0 -2
- package/dist/src/plugin/agents/browser-qa.d.ts +0 -14
- package/dist/src/plugin/agents/browser-qa.js +0 -31
- package/dist/src/plugin/agents/common.d.ts +0 -36
- package/dist/src/plugin/agents/common.js +0 -59
- package/dist/src/plugin/agents/cto.d.ts +0 -9
- package/dist/src/plugin/agents/cto.js +0 -39
- package/dist/src/plugin/agents/engineers.d.ts +0 -9
- package/dist/src/plugin/agents/engineers.js +0 -11
- package/dist/src/plugin/agents/index.d.ts +0 -5
- package/dist/src/plugin/agents/index.js +0 -5
- package/dist/src/plugin/agents/team-planner.d.ts +0 -10
- package/dist/src/plugin/agents/team-planner.js +0 -23
- package/dist/src/plugin/claude-manager.plugin.d.ts +0 -10
- package/dist/src/plugin/claude-manager.plugin.js +0 -950
- package/dist/src/plugin/service-factory.d.ts +0 -38
- package/dist/src/plugin/service-factory.js +0 -101
- package/dist/src/prompts/registry.d.ts +0 -2
- package/dist/src/prompts/registry.js +0 -210
- package/dist/src/state/file-run-state-store.d.ts +0 -14
- package/dist/src/state/file-run-state-store.js +0 -85
- package/dist/src/state/team-state-store.d.ts +0 -14
- package/dist/src/state/team-state-store.js +0 -88
- package/dist/src/state/transcript-store.d.ts +0 -15
- package/dist/src/state/transcript-store.js +0 -44
- package/dist/src/team/roster.d.ts +0 -5
- package/dist/src/team/roster.js +0 -40
- package/dist/src/types/contracts.d.ts +0 -261
- package/dist/src/types/contracts.js +0 -2
- package/dist/src/util/fs-helpers.d.ts +0 -8
- package/dist/src/util/fs-helpers.js +0 -21
- package/dist/src/util/project-context.d.ts +0 -10
- package/dist/src/util/project-context.js +0 -105
- package/dist/src/util/transcript-append.d.ts +0 -7
- package/dist/src/util/transcript-append.js +0 -29
- package/dist/state/file-run-state-store.d.ts +0 -14
- package/dist/state/file-run-state-store.js +0 -85
- package/dist/test/claude-agent-sdk-adapter.test.d.ts +0 -1
- package/dist/test/claude-agent-sdk-adapter.test.js +0 -707
- package/dist/test/claude-manager.plugin.test.d.ts +0 -1
- package/dist/test/claude-manager.plugin.test.js +0 -316
- package/dist/test/context-tracker.test.d.ts +0 -1
- package/dist/test/context-tracker.test.js +0 -130
- package/dist/test/cto-active-team.test.d.ts +0 -1
- package/dist/test/cto-active-team.test.js +0 -199
- package/dist/test/file-run-state-store.test.d.ts +0 -1
- package/dist/test/file-run-state-store.test.js +0 -82
- package/dist/test/fs-helpers.test.d.ts +0 -1
- package/dist/test/fs-helpers.test.js +0 -56
- package/dist/test/git-operations.test.d.ts +0 -1
- package/dist/test/git-operations.test.js +0 -133
- package/dist/test/persistent-manager.test.d.ts +0 -1
- package/dist/test/persistent-manager.test.js +0 -48
- package/dist/test/project-context.test.d.ts +0 -1
- package/dist/test/project-context.test.js +0 -92
- package/dist/test/prompt-registry.test.d.ts +0 -1
- package/dist/test/prompt-registry.test.js +0 -117
- package/dist/test/report-claude-event.test.d.ts +0 -1
- package/dist/test/report-claude-event.test.js +0 -304
- package/dist/test/session-controller.test.d.ts +0 -1
- package/dist/test/session-controller.test.js +0 -149
- package/dist/test/session-live-tailer.test.d.ts +0 -1
- package/dist/test/session-live-tailer.test.js +0 -313
- package/dist/test/team-orchestrator.test.d.ts +0 -1
- package/dist/test/team-orchestrator.test.js +0 -583
- package/dist/test/team-state-store.test.d.ts +0 -1
- package/dist/test/team-state-store.test.js +0 -54
- package/dist/test/tool-approval-manager.test.d.ts +0 -1
- package/dist/test/tool-approval-manager.test.js +0 -260
- package/dist/test/transcript-append.test.d.ts +0 -1
- package/dist/test/transcript-append.test.js +0 -37
- package/dist/test/transcript-store.test.d.ts +0 -1
- package/dist/test/transcript-store.test.js +0 -50
- package/dist/test/undo-propagation.test.d.ts +0 -1
- package/dist/test/undo-propagation.test.js +0 -837
- package/dist/util/project-context.d.ts +0 -10
- package/dist/util/project-context.js +0 -105
- package/dist/vitest.config.d.ts +0 -2
- package/dist/vitest.config.js +0 -11
package/dist/src/team/roster.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_ENGINEER_NAMES, PLANNER_ELIGIBLE_ENGINEERS, } from '../types/contracts.js';
|
|
2
|
-
const TEAM_ENGINEERS = DEFAULT_ENGINEER_NAMES;
|
|
3
|
-
export { PLANNER_ELIGIBLE_ENGINEERS };
|
|
4
|
-
export function isEngineerName(value) {
|
|
5
|
-
return TEAM_ENGINEERS.includes(value);
|
|
6
|
-
}
|
|
7
|
-
export function createEmptyTeamRecord(teamId, cwd) {
|
|
8
|
-
const timestamp = new Date().toISOString();
|
|
9
|
-
return {
|
|
10
|
-
id: teamId,
|
|
11
|
-
cwd,
|
|
12
|
-
createdAt: timestamp,
|
|
13
|
-
updatedAt: timestamp,
|
|
14
|
-
engineers: TEAM_ENGINEERS.map((name) => createEmptyEngineerRecord(name)),
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
export function createEmptyEngineerRecord(name) {
|
|
18
|
-
return {
|
|
19
|
-
name,
|
|
20
|
-
wrapperSessionId: null,
|
|
21
|
-
claudeSessionId: null,
|
|
22
|
-
busy: false,
|
|
23
|
-
busySince: null,
|
|
24
|
-
lastMode: null,
|
|
25
|
-
lastTaskSummary: null,
|
|
26
|
-
lastUsedAt: null,
|
|
27
|
-
wrapperHistory: [],
|
|
28
|
-
context: {
|
|
29
|
-
sessionId: null,
|
|
30
|
-
totalTurns: 0,
|
|
31
|
-
totalCostUsd: 0,
|
|
32
|
-
latestInputTokens: null,
|
|
33
|
-
latestOutputTokens: null,
|
|
34
|
-
contextWindowSize: null,
|
|
35
|
-
estimatedContextPercent: null,
|
|
36
|
-
warningLevel: 'ok',
|
|
37
|
-
compactionCount: 0,
|
|
38
|
-
},
|
|
39
|
-
};
|
|
40
|
-
}
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
export interface ManagerPromptRegistry {
|
|
2
|
-
ctoSystemPrompt: string;
|
|
3
|
-
engineerAgentPrompt: string;
|
|
4
|
-
engineerSessionPrompt: string;
|
|
5
|
-
/** Prompt prepended to the user prompt of the synthesis runTask call inside plan_with_team. */
|
|
6
|
-
planSynthesisPrompt: string;
|
|
7
|
-
/** Visible subagent prompt for teamPlanner — thin wrapper that calls plan_with_team. */
|
|
8
|
-
teamPlannerPrompt: string;
|
|
9
|
-
/** Visible subagent prompt for browserQa — thin wrapper that calls claude tool for browser verification. */
|
|
10
|
-
browserQaAgentPrompt: string;
|
|
11
|
-
/** Prompt prepended to browser verification task prompts in Claude Code sessions. */
|
|
12
|
-
browserQaSessionPrompt: string;
|
|
13
|
-
contextWarnings: {
|
|
14
|
-
moderate: string;
|
|
15
|
-
high: string;
|
|
16
|
-
critical: string;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
export type SessionMode = 'plan' | 'free';
|
|
20
|
-
export declare const DEFAULT_ENGINEER_NAMES: readonly ["Tom", "John", "Maya", "Sara", "Alex", "BrowserQA"];
|
|
21
|
-
export declare const PLANNER_ELIGIBLE_ENGINEERS: readonly ["Tom", "John", "Maya", "Sara", "Alex"];
|
|
22
|
-
export type EngineerName = (typeof DEFAULT_ENGINEER_NAMES)[number];
|
|
23
|
-
export type EngineerWorkMode = 'explore' | 'implement' | 'verify';
|
|
24
|
-
export interface WrapperHistoryEntry {
|
|
25
|
-
timestamp: string;
|
|
26
|
-
type: 'assignment' | 'result';
|
|
27
|
-
mode?: EngineerWorkMode;
|
|
28
|
-
text: string;
|
|
29
|
-
}
|
|
30
|
-
interface ClaudeCommandMetadata {
|
|
31
|
-
name: string;
|
|
32
|
-
description: string;
|
|
33
|
-
argumentHint?: string;
|
|
34
|
-
source: 'sdk' | 'skill' | 'command';
|
|
35
|
-
path?: string;
|
|
36
|
-
}
|
|
37
|
-
interface ClaudeAgentMetadata {
|
|
38
|
-
name: string;
|
|
39
|
-
description: string;
|
|
40
|
-
model?: string;
|
|
41
|
-
source: 'sdk' | 'filesystem';
|
|
42
|
-
}
|
|
43
|
-
export interface ClaudeSessionEvent {
|
|
44
|
-
type: 'init' | 'assistant' | 'partial' | 'user' | 'tool_call' | 'tool_progress' | 'tool_summary' | 'status' | 'system' | 'result' | 'error';
|
|
45
|
-
sessionId?: string;
|
|
46
|
-
text: string;
|
|
47
|
-
turns?: number;
|
|
48
|
-
totalCostUsd?: number;
|
|
49
|
-
/** Present on live SDK-normalized events; omitted when compact-persisted to save space. */
|
|
50
|
-
rawType?: string;
|
|
51
|
-
}
|
|
52
|
-
export interface RunClaudeSessionInput {
|
|
53
|
-
cwd: string;
|
|
54
|
-
prompt: string;
|
|
55
|
-
systemPrompt?: string;
|
|
56
|
-
model?: string;
|
|
57
|
-
effort?: 'low' | 'medium' | 'high' | 'max';
|
|
58
|
-
mode?: SessionMode;
|
|
59
|
-
permissionMode?: 'default' | 'acceptEdits' | 'plan' | 'dontAsk';
|
|
60
|
-
/**
|
|
61
|
-
* When true, the canUseTool callback denies write tools (Edit, Write, MultiEdit,
|
|
62
|
-
* NotebookEdit) and destructive bash commands. Used instead of SDK plan mode so
|
|
63
|
-
* the agent can still exit plan mode if needed.
|
|
64
|
-
*/
|
|
65
|
-
restrictWriteTools?: boolean;
|
|
66
|
-
/** Merged with `Skill` by the SDK adapter unless `Skill` appears in `disallowedTools`. */
|
|
67
|
-
allowedTools?: string[];
|
|
68
|
-
disallowedTools?: string[];
|
|
69
|
-
continueSession?: boolean;
|
|
70
|
-
resumeSessionId?: string;
|
|
71
|
-
forkSession?: boolean;
|
|
72
|
-
persistSession?: boolean;
|
|
73
|
-
includePartialMessages?: boolean;
|
|
74
|
-
settingSources?: Array<'user' | 'project' | 'local'>;
|
|
75
|
-
maxTurns?: number;
|
|
76
|
-
abortSignal?: AbortSignal;
|
|
77
|
-
}
|
|
78
|
-
export interface ClaudeSessionRunResult {
|
|
79
|
-
sessionId?: string;
|
|
80
|
-
events: ClaudeSessionEvent[];
|
|
81
|
-
finalText: string;
|
|
82
|
-
turns?: number;
|
|
83
|
-
totalCostUsd?: number;
|
|
84
|
-
inputTokens?: number;
|
|
85
|
-
outputTokens?: number;
|
|
86
|
-
contextWindowSize?: number;
|
|
87
|
-
}
|
|
88
|
-
export interface ClaudeSessionSummary {
|
|
89
|
-
sessionId: string;
|
|
90
|
-
summary: string;
|
|
91
|
-
cwd?: string;
|
|
92
|
-
gitBranch?: string;
|
|
93
|
-
createdAt?: number;
|
|
94
|
-
lastModified: number;
|
|
95
|
-
}
|
|
96
|
-
export interface ClaudeSessionTranscriptMessage {
|
|
97
|
-
role: 'user' | 'assistant';
|
|
98
|
-
sessionId: string;
|
|
99
|
-
messageId: string;
|
|
100
|
-
text: string;
|
|
101
|
-
}
|
|
102
|
-
export interface ClaudeCapabilitySnapshot {
|
|
103
|
-
commands: ClaudeCommandMetadata[];
|
|
104
|
-
agents: ClaudeAgentMetadata[];
|
|
105
|
-
models: string[];
|
|
106
|
-
}
|
|
107
|
-
export type ContextWarningLevel = 'ok' | 'moderate' | 'high' | 'critical';
|
|
108
|
-
export interface SessionContextSnapshot {
|
|
109
|
-
sessionId: string | null;
|
|
110
|
-
totalTurns: number;
|
|
111
|
-
totalCostUsd: number;
|
|
112
|
-
latestInputTokens: number | null;
|
|
113
|
-
latestOutputTokens: number | null;
|
|
114
|
-
contextWindowSize: number | null;
|
|
115
|
-
estimatedContextPercent: number | null;
|
|
116
|
-
warningLevel: ContextWarningLevel;
|
|
117
|
-
compactionCount: number;
|
|
118
|
-
}
|
|
119
|
-
export type TaskSize = 'trivial' | 'simple' | 'large';
|
|
120
|
-
export interface PlanSlice {
|
|
121
|
-
index: number;
|
|
122
|
-
description: string;
|
|
123
|
-
status: 'pending' | 'in_progress' | 'done' | 'skipped';
|
|
124
|
-
completedAt?: string;
|
|
125
|
-
}
|
|
126
|
-
export interface ActivePlan {
|
|
127
|
-
id: string;
|
|
128
|
-
summary: string;
|
|
129
|
-
taskSize: TaskSize;
|
|
130
|
-
createdAt: string;
|
|
131
|
-
confirmedAt: string | null;
|
|
132
|
-
preAuthorized: boolean;
|
|
133
|
-
slices: PlanSlice[];
|
|
134
|
-
/** Null when the plan has no slices (trivial/simple tasks). */
|
|
135
|
-
currentSliceIndex: number | null;
|
|
136
|
-
}
|
|
137
|
-
export interface TeamEngineerRecord {
|
|
138
|
-
name: EngineerName;
|
|
139
|
-
wrapperSessionId: string | null;
|
|
140
|
-
claudeSessionId: string | null;
|
|
141
|
-
busy: boolean;
|
|
142
|
-
busySince: string | null;
|
|
143
|
-
lastMode: EngineerWorkMode | null;
|
|
144
|
-
lastTaskSummary: string | null;
|
|
145
|
-
lastUsedAt: string | null;
|
|
146
|
-
wrapperHistory: WrapperHistoryEntry[];
|
|
147
|
-
context: SessionContextSnapshot;
|
|
148
|
-
}
|
|
149
|
-
export type EngineerFailureKind = 'sdkError' | 'contextExhausted' | 'toolDenied' | 'modeNotSupported' | 'aborted' | 'engineerBusy' | 'unknown';
|
|
150
|
-
export interface EngineerFailureResult {
|
|
151
|
-
teamId: string;
|
|
152
|
-
engineer: EngineerName;
|
|
153
|
-
mode: EngineerWorkMode;
|
|
154
|
-
failureKind: EngineerFailureKind;
|
|
155
|
-
message: string;
|
|
156
|
-
}
|
|
157
|
-
export interface TeamRecord {
|
|
158
|
-
id: string;
|
|
159
|
-
cwd: string;
|
|
160
|
-
createdAt: string;
|
|
161
|
-
updatedAt: string;
|
|
162
|
-
engineers: TeamEngineerRecord[];
|
|
163
|
-
activePlan?: ActivePlan;
|
|
164
|
-
}
|
|
165
|
-
export interface EngineerTaskResult {
|
|
166
|
-
teamId: string;
|
|
167
|
-
engineer: EngineerName;
|
|
168
|
-
mode: EngineerWorkMode;
|
|
169
|
-
sessionId?: string;
|
|
170
|
-
finalText: string;
|
|
171
|
-
turns?: number;
|
|
172
|
-
totalCostUsd?: number;
|
|
173
|
-
inputTokens?: number;
|
|
174
|
-
outputTokens?: number;
|
|
175
|
-
contextWindowSize?: number;
|
|
176
|
-
context: SessionContextSnapshot;
|
|
177
|
-
}
|
|
178
|
-
export interface PlanDraft extends EngineerTaskResult {
|
|
179
|
-
request: string;
|
|
180
|
-
}
|
|
181
|
-
export interface SynthesizedPlanResult {
|
|
182
|
-
teamId: string;
|
|
183
|
-
request: string;
|
|
184
|
-
leadEngineer: EngineerName;
|
|
185
|
-
challengerEngineer: EngineerName;
|
|
186
|
-
drafts: [PlanDraft, PlanDraft];
|
|
187
|
-
synthesis: string;
|
|
188
|
-
recommendedQuestion: string | null;
|
|
189
|
-
recommendedAnswer: string | null;
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Per-worker capability config for behavior that differs from the standard engineer path.
|
|
193
|
-
* Keyed by EngineerName in a Partial<Record<EngineerName, WorkerCapabilities>> map;
|
|
194
|
-
* absent entries use default behavior.
|
|
195
|
-
*/
|
|
196
|
-
export interface WorkerCapabilities {
|
|
197
|
-
/** Override the session system prompt for this worker. Absent = use standard engineer prompt. */
|
|
198
|
-
sessionPrompt?: string;
|
|
199
|
-
/** Always restrict write tools regardless of mode. Default: false. */
|
|
200
|
-
restrictWriteTools?: boolean;
|
|
201
|
-
/** Skip mode instructions in the task prompt. Default: false. */
|
|
202
|
-
skipModeInstructions?: boolean;
|
|
203
|
-
/** Allow this worker in plan_with_team. Absent or true = eligible. False = excluded. */
|
|
204
|
-
plannerEligible?: boolean;
|
|
205
|
-
/** Returns true if the final output indicates the required runtime is unavailable. */
|
|
206
|
-
isRuntimeUnavailableResponse?: (finalText: string) => boolean;
|
|
207
|
-
/** Metadata title for the runtime-unavailable event. */
|
|
208
|
-
runtimeUnavailableTitle?: string;
|
|
209
|
-
/**
|
|
210
|
-
* Explicit SDK-level pre-approval list for this worker's inner Claude Code session.
|
|
211
|
-
* Tools in this list bypass interactive confirmation prompts (they are still subject to
|
|
212
|
-
* the `canUseTool` write-restriction and approval-policy filters).
|
|
213
|
-
* Absent = falls back to `['Skill']` via the default adapter behaviour.
|
|
214
|
-
*/
|
|
215
|
-
sessionAllowedTools?: string[];
|
|
216
|
-
}
|
|
217
|
-
export interface GitDiffResult {
|
|
218
|
-
hasDiff: boolean;
|
|
219
|
-
diffText: string;
|
|
220
|
-
stats: {
|
|
221
|
-
filesChanged: number;
|
|
222
|
-
insertions: number;
|
|
223
|
-
deletions: number;
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
export interface GitOperationResult {
|
|
227
|
-
success: boolean;
|
|
228
|
-
output: string;
|
|
229
|
-
error?: string;
|
|
230
|
-
}
|
|
231
|
-
export interface ToolApprovalRule {
|
|
232
|
-
id: string;
|
|
233
|
-
description?: string;
|
|
234
|
-
/** Tool name — exact match or glob with * wildcard */
|
|
235
|
-
toolPattern: string;
|
|
236
|
-
/** Optional substring match against JSON-serialized tool input */
|
|
237
|
-
inputPattern?: string;
|
|
238
|
-
action: 'allow' | 'deny';
|
|
239
|
-
denyMessage?: string;
|
|
240
|
-
}
|
|
241
|
-
export interface ToolApprovalPolicy {
|
|
242
|
-
rules: ToolApprovalRule[];
|
|
243
|
-
/**
|
|
244
|
-
* Always `allow`: tools that do not match any rule are allowed.
|
|
245
|
-
* Blocking is done only with explicit `deny` rules (deny-list contract).
|
|
246
|
-
*/
|
|
247
|
-
defaultAction: 'allow';
|
|
248
|
-
defaultDenyMessage?: string;
|
|
249
|
-
enabled: boolean;
|
|
250
|
-
}
|
|
251
|
-
export interface ToolApprovalDecision {
|
|
252
|
-
timestamp: string;
|
|
253
|
-
toolName: string;
|
|
254
|
-
inputPreview: string;
|
|
255
|
-
title?: string;
|
|
256
|
-
matchedRuleId: string;
|
|
257
|
-
action: 'allow' | 'deny';
|
|
258
|
-
denyMessage?: string;
|
|
259
|
-
agentId?: string;
|
|
260
|
-
}
|
|
261
|
-
export {};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export declare function writeJsonAtomically(filePath: string, data: unknown): Promise<void>;
|
|
2
|
-
export declare function isFileNotFoundError(error: unknown): error is NodeJS.ErrnoException;
|
|
3
|
-
/**
|
|
4
|
-
* Appends a single NDJSON line to a debug log file.
|
|
5
|
-
* Creates the parent directory if it does not exist.
|
|
6
|
-
* A `ts` (ISO timestamp) field is injected automatically.
|
|
7
|
-
*/
|
|
8
|
-
export declare function appendDebugLog(logPath: string, entry: Record<string, unknown>): Promise<void>;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { promises as fs } from 'node:fs';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
export async function writeJsonAtomically(filePath, data) {
|
|
5
|
-
const tempPath = `${filePath}.${randomUUID()}.tmp`;
|
|
6
|
-
await fs.writeFile(tempPath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
|
|
7
|
-
await fs.rename(tempPath, filePath);
|
|
8
|
-
}
|
|
9
|
-
export function isFileNotFoundError(error) {
|
|
10
|
-
return (error instanceof Error && 'code' in error && error.code === 'ENOENT');
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Appends a single NDJSON line to a debug log file.
|
|
14
|
-
* Creates the parent directory if it does not exist.
|
|
15
|
-
* A `ts` (ISO timestamp) field is injected automatically.
|
|
16
|
-
*/
|
|
17
|
-
export async function appendDebugLog(logPath, entry) {
|
|
18
|
-
const line = JSON.stringify({ ...entry, ts: new Date().toISOString() }) + '\n';
|
|
19
|
-
await fs.mkdir(path.dirname(logPath), { recursive: true });
|
|
20
|
-
await fs.appendFile(logPath, line, 'utf8');
|
|
21
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { DiscoveredClaudeFile } from '../types/contracts.js';
|
|
2
|
-
/**
|
|
3
|
-
* Recursively discover all project-level Claude files:
|
|
4
|
-
* - every `CLAUDE.md` found anywhere in the repo tree
|
|
5
|
-
* - every file under `.claude/` recursively
|
|
6
|
-
*
|
|
7
|
-
* Returns a de-duplicated, deterministically sorted array of
|
|
8
|
-
* { relativePath, content } entries. Empty/blank files are skipped.
|
|
9
|
-
*/
|
|
10
|
-
export declare function discoverProjectClaudeFiles(cwd: string): Promise<DiscoveredClaudeFile[]>;
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { readFile, readdir } from 'node:fs/promises';
|
|
2
|
-
import { join, relative } from 'node:path';
|
|
3
|
-
import { isFileNotFoundError } from './fs-helpers.js';
|
|
4
|
-
/**
|
|
5
|
-
* Recursively discover all project-level Claude files:
|
|
6
|
-
* - every `CLAUDE.md` found anywhere in the repo tree
|
|
7
|
-
* - every file under `.claude/` recursively
|
|
8
|
-
*
|
|
9
|
-
* Returns a de-duplicated, deterministically sorted array of
|
|
10
|
-
* { relativePath, content } entries. Empty/blank files are skipped.
|
|
11
|
-
*/
|
|
12
|
-
export async function discoverProjectClaudeFiles(cwd) {
|
|
13
|
-
const seen = new Set();
|
|
14
|
-
const results = [];
|
|
15
|
-
// 1. Walk the entire tree for CLAUDE.md files.
|
|
16
|
-
await walkForClaudeMd(cwd, cwd, seen, results);
|
|
17
|
-
// 2. Walk .claude/ recursively for any file.
|
|
18
|
-
await walkDotClaudeDir(cwd, seen, results);
|
|
19
|
-
// Deterministic: sort by relativePath (lexicographic).
|
|
20
|
-
results.sort((a, b) => a.relativePath < b.relativePath ? -1 : a.relativePath > b.relativePath ? 1 : 0);
|
|
21
|
-
return results;
|
|
22
|
-
}
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
// Internal helpers
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
/** Recursively walk `dir` looking for files named `CLAUDE.md`. */
|
|
27
|
-
async function walkForClaudeMd(root, dir, seen, out) {
|
|
28
|
-
let entries;
|
|
29
|
-
try {
|
|
30
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
if (isFileNotFoundError(err))
|
|
34
|
-
return;
|
|
35
|
-
throw err;
|
|
36
|
-
}
|
|
37
|
-
for (const entry of entries) {
|
|
38
|
-
const fullPath = join(dir, entry.name);
|
|
39
|
-
if (entry.isDirectory()) {
|
|
40
|
-
// Skip node_modules, .git, and hidden dirs other than .claude
|
|
41
|
-
if (entry.name === 'node_modules' || entry.name === '.git')
|
|
42
|
-
continue;
|
|
43
|
-
await walkForClaudeMd(root, fullPath, seen, out);
|
|
44
|
-
}
|
|
45
|
-
else if (entry.name === 'CLAUDE.md') {
|
|
46
|
-
const rel = toForwardSlash(relative(root, fullPath));
|
|
47
|
-
if (seen.has(rel))
|
|
48
|
-
continue;
|
|
49
|
-
const content = await tryReadText(fullPath);
|
|
50
|
-
if (content !== null) {
|
|
51
|
-
seen.add(rel);
|
|
52
|
-
out.push({ relativePath: rel, content });
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/** Recursively walk `.claude/` and collect every file. */
|
|
58
|
-
async function walkDotClaudeDir(root, seen, out) {
|
|
59
|
-
const dotClaudeDir = join(root, '.claude');
|
|
60
|
-
await walkAllFiles(root, dotClaudeDir, seen, out);
|
|
61
|
-
}
|
|
62
|
-
/** Recursively collect all files under `dir`. */
|
|
63
|
-
async function walkAllFiles(root, dir, seen, out) {
|
|
64
|
-
let entries;
|
|
65
|
-
try {
|
|
66
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
if (isFileNotFoundError(err))
|
|
70
|
-
return;
|
|
71
|
-
throw err;
|
|
72
|
-
}
|
|
73
|
-
for (const entry of entries) {
|
|
74
|
-
const fullPath = join(dir, entry.name);
|
|
75
|
-
if (entry.isDirectory()) {
|
|
76
|
-
await walkAllFiles(root, fullPath, seen, out);
|
|
77
|
-
}
|
|
78
|
-
else if (entry.isFile()) {
|
|
79
|
-
const rel = toForwardSlash(relative(root, fullPath));
|
|
80
|
-
if (seen.has(rel))
|
|
81
|
-
continue;
|
|
82
|
-
const content = await tryReadText(fullPath);
|
|
83
|
-
if (content !== null) {
|
|
84
|
-
seen.add(rel);
|
|
85
|
-
out.push({ relativePath: rel, content });
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
/** Read a file as UTF-8, returning trimmed content or null if empty/missing. */
|
|
91
|
-
async function tryReadText(filePath) {
|
|
92
|
-
try {
|
|
93
|
-
const raw = await readFile(filePath, 'utf-8');
|
|
94
|
-
const trimmed = raw.trim();
|
|
95
|
-
return trimmed.length > 0 ? trimmed : null;
|
|
96
|
-
}
|
|
97
|
-
catch (err) {
|
|
98
|
-
if (isFileNotFoundError(err))
|
|
99
|
-
return null;
|
|
100
|
-
throw err;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
function toForwardSlash(p) {
|
|
104
|
-
return p.replace(/\\/g, '/');
|
|
105
|
-
}
|
|
@@ -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,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,85 +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.catch(() => undefined).then(operation);
|
|
74
|
-
const settledPromise = resultPromise.then(() => undefined, () => undefined);
|
|
75
|
-
this.writeQueues.set(key, settledPromise);
|
|
76
|
-
try {
|
|
77
|
-
return await resultPromise;
|
|
78
|
-
}
|
|
79
|
-
finally {
|
|
80
|
-
if (this.writeQueues.get(key) === settledPromise) {
|
|
81
|
-
this.writeQueues.delete(key);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|