praxis-agent 0.46.0 → 0.46.2

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.
@@ -1,260 +0,0 @@
1
- import { getClaudeContentBlocks } from './tool-links.js';
2
- import { getClaudePreservedMessageUuids } from './compaction.js';
3
- import { selectClaudeActiveTranscript, selectClaudeTranscriptAtMessage, } from './history.js';
4
- import { copyNativeEntryWithSessionId, isNativeForkableEntryType, } from './schema.js';
5
- const TRANSIENT_ENTRY_TYPES = new Set([
6
- 'atis-latch',
7
- 'file-history-delta',
8
- 'file-history-snapshot',
9
- 'queue-operation',
10
- 'relocated',
11
- ]);
12
- function advancesLogicalTail(entry) {
13
- if (entry.type === 'system' && entry.subtype === 'compact_boundary') {
14
- return false;
15
- }
16
- if (entry.type !== 'attachment')
17
- return true;
18
- const attachment = entry.attachment;
19
- if (typeof attachment !== 'object' || attachment === null)
20
- return true;
21
- const attachmentType = attachment.type;
22
- return (attachmentType !== 'hook_success' &&
23
- attachmentType !== 'hook_error' &&
24
- attachmentType !== 'hook_additional_context');
25
- }
26
- function validateNativeHistory(entries) {
27
- const entriesByUuid = new Map();
28
- const toolCalls = new Map();
29
- for (const entry of entries) {
30
- if (typeof entry.uuid !== 'string')
31
- continue;
32
- if (entriesByUuid.has(entry.uuid)) {
33
- throw new Error(`Claude fork source has duplicate UUID ${entry.uuid}`);
34
- }
35
- entriesByUuid.set(entry.uuid, entry);
36
- if (entry.type !== 'assistant')
37
- continue;
38
- for (const block of getClaudeContentBlocks(entry)) {
39
- if (block.type !== 'tool_use')
40
- continue;
41
- const id = block.id;
42
- if (typeof id !== 'string')
43
- continue;
44
- if (toolCalls.has(id)) {
45
- throw new Error(`Claude fork source has duplicate tool_use ${id}`);
46
- }
47
- toolCalls.set(id, entry.uuid);
48
- }
49
- }
50
- const childParentUuids = new Set();
51
- const externalParentUuids = new Set();
52
- let externalParentReferenceCount = 0;
53
- const completedToolCalls = new Set();
54
- let ordinaryRootCount = 0;
55
- let compactBoundary;
56
- let logicalTailUuid;
57
- for (const entry of entries) {
58
- const isCompactSummary = entry.isCompactSummary === true;
59
- if (compactBoundary && !isCompactSummary) {
60
- throw new Error('Claude compact boundary has no adjacent summary');
61
- }
62
- if (isCompactSummary) {
63
- if (!compactBoundary || entry.parentUuid !== compactBoundary.uuid) {
64
- throw new Error('Claude compact summary has no matching boundary');
65
- }
66
- compactBoundary = undefined;
67
- }
68
- else if (entry.type === 'system' &&
69
- entry.subtype === 'compact_boundary') {
70
- const metadata = entry.compactMetadata;
71
- const preservedSegment = typeof metadata === 'object' && metadata !== null
72
- ? metadata.preservedSegment
73
- : undefined;
74
- const preservedUuids = getClaudePreservedMessageUuids(entry);
75
- const segment = typeof preservedSegment === 'object' && preservedSegment !== null
76
- ? preservedSegment
77
- : {};
78
- const segmentMatchesLogicalTail = segment.headUuid === logicalTailUuid &&
79
- segment.tailUuid === logicalTailUuid;
80
- const segmentMatchesPreserved = segment.headUuid === preservedUuids[0] &&
81
- segment.tailUuid === preservedUuids[preservedUuids.length - 1];
82
- if (typeof preservedSegment !== 'object' ||
83
- preservedSegment === null ||
84
- entry.logicalParentUuid !== logicalTailUuid ||
85
- (!segmentMatchesLogicalTail && !segmentMatchesPreserved)) {
86
- throw new Error('Claude compact boundary has invalid logical parent');
87
- }
88
- compactBoundary = entry;
89
- }
90
- if (typeof entry.uuid === 'string') {
91
- if (entry.parentUuid === null &&
92
- !(entry.type === 'system' && entry.subtype === 'compact_boundary')) {
93
- ordinaryRootCount += 1;
94
- }
95
- else if (typeof entry.parentUuid === 'string') {
96
- if (entriesByUuid.has(entry.parentUuid)) {
97
- childParentUuids.add(entry.parentUuid);
98
- }
99
- else {
100
- externalParentUuids.add(entry.parentUuid);
101
- externalParentReferenceCount += 1;
102
- }
103
- }
104
- }
105
- if (typeof entry.uuid === 'string' && advancesLogicalTail(entry)) {
106
- logicalTailUuid = entry.uuid;
107
- }
108
- for (const block of getClaudeContentBlocks(entry)) {
109
- if (entry.type !== 'user' || block.type !== 'tool_result')
110
- continue;
111
- const id = block.tool_use_id;
112
- if (typeof id !== 'string' ||
113
- typeof entry.sourceToolAssistantUUID !== 'string' ||
114
- toolCalls.get(id) !== entry.sourceToolAssistantUUID) {
115
- throw new Error('Claude fork source has an unmatched tool_result');
116
- }
117
- if (completedToolCalls.has(id)) {
118
- throw new Error(`Claude fork source has duplicate tool_result ${id}`);
119
- }
120
- completedToolCalls.add(id);
121
- }
122
- }
123
- if (compactBoundary) {
124
- throw new Error('Claude compact boundary has no adjacent summary');
125
- }
126
- const omittedSeedUserParent = externalParentUuids.size === 1 ? [...externalParentUuids][0] : undefined;
127
- const firstEntry = entries[0];
128
- const isOmittedSeedUserChain = externalParentUuids.size === 1 &&
129
- ordinaryRootCount === 0 &&
130
- externalParentReferenceCount === 1 &&
131
- firstEntry?.type === 'assistant' &&
132
- firstEntry?.parentUuid === omittedSeedUserParent;
133
- if ((externalParentUuids.size > 0 && !isOmittedSeedUserChain) ||
134
- ordinaryRootCount > 1) {
135
- throw new Error('Claude fork source has a dangling parentUuid');
136
- }
137
- const states = new Map();
138
- for (const startUuid of entriesByUuid.keys()) {
139
- if (states.get(startUuid) === 'visited')
140
- continue;
141
- const path = [];
142
- let uuid = startUuid;
143
- while (uuid !== undefined && entriesByUuid.has(uuid)) {
144
- const state = states.get(uuid);
145
- if (state === 'visiting') {
146
- throw new Error('Claude fork source parentUuid graph has a cycle');
147
- }
148
- if (state === 'visited')
149
- break;
150
- states.set(uuid, 'visiting');
151
- path.push(uuid);
152
- const parentUuid = entriesByUuid.get(uuid)?.parentUuid;
153
- uuid = typeof parentUuid === 'string' ? parentUuid : undefined;
154
- }
155
- for (const pathUuid of path)
156
- states.set(pathUuid, 'visited');
157
- }
158
- for (let index = entries.length - 1; index >= 0; index -= 1) {
159
- const uuid = entries[index]?.uuid;
160
- if (typeof uuid === 'string' && !childParentUuids.has(uuid))
161
- return uuid;
162
- }
163
- return undefined;
164
- }
165
- export function createClaudeNativeFork({ source, sourceSessionId, sessionId, resumeSessionAt, }) {
166
- const agentColors = [];
167
- const titles = [];
168
- const modes = [];
169
- const permissionModes = [];
170
- const prLinks = [];
171
- const history = [];
172
- const nativeHistory = [];
173
- let lastPrompt;
174
- let nativeLastPrompt;
175
- const hasSelectiveSummary = source.some((entry) => {
176
- if (entry.isCompactSummary !== true)
177
- return false;
178
- const metadata = entry.summarizeMetadata;
179
- return (typeof metadata === 'object' &&
180
- metadata !== null &&
181
- (metadata.direction === 'from' ||
182
- metadata.direction === 'up_to'));
183
- });
184
- const hasCompactHistory = source.some((entry) => entry.isCompactSummary === true ||
185
- (entry.type === 'system' && entry.subtype === 'compact_boundary'));
186
- const activeSource = resumeSessionAt === undefined
187
- ? hasCompactHistory || hasSelectiveSummary
188
- ? selectClaudeActiveTranscript(source)
189
- : source
190
- : selectClaudeTranscriptAtMessage(source, resumeSessionAt);
191
- for (const entry of activeSource) {
192
- if (TRANSIENT_ENTRY_TYPES.has(entry.type)) {
193
- if ((entry.type === 'queue-operation' &&
194
- entry.sessionId !== sourceSessionId) ||
195
- (entry.type !== 'queue-operation' &&
196
- entry.sessionId !== undefined &&
197
- entry.sessionId !== sourceSessionId)) {
198
- throw new Error('Claude fork source entry has the wrong sessionId');
199
- }
200
- continue;
201
- }
202
- if (entry.isSidechain === true) {
203
- if (!isNativeForkableEntryType(entry.type)) {
204
- throw new Error(`Claude transcript entry type ${entry.type} is not forkable by Praxis`);
205
- }
206
- if (typeof entry.sessionId !== 'string' || entry.sessionId.length === 0) {
207
- throw new Error('Claude fork entry has no sessionId');
208
- }
209
- continue;
210
- }
211
- if (!isNativeForkableEntryType(entry.type)) {
212
- throw new Error(`Claude transcript entry type ${entry.type} is not forkable by Praxis`);
213
- }
214
- if (typeof entry.sessionId !== 'string' || entry.sessionId.length === 0) {
215
- throw new Error('Claude fork entry has no sessionId');
216
- }
217
- if (entry.sessionId !== sourceSessionId) {
218
- throw new Error('Claude fork source entry has the wrong sessionId');
219
- }
220
- const copied = copyNativeEntryWithSessionId(entry, sessionId);
221
- if (entry.type === 'agent-color')
222
- agentColors.push(copied);
223
- else if (entry.type === 'ai-title')
224
- titles.push(copied);
225
- else if (entry.type === 'mode')
226
- modes.push(copied);
227
- else if (entry.type === 'permission-mode')
228
- permissionModes.push(copied);
229
- else if (entry.type === 'pr-link')
230
- prLinks.push(copied);
231
- else if (entry.type === 'last-prompt') {
232
- lastPrompt = copied;
233
- nativeLastPrompt = entry;
234
- }
235
- else {
236
- history.push(copied);
237
- nativeHistory.push(entry);
238
- }
239
- }
240
- if (!nativeHistory.some((entry) => typeof entry.uuid === 'string')) {
241
- throw new Error('Claude session has no native history to fork');
242
- }
243
- const logicalTailUuid = validateNativeHistory(nativeHistory);
244
- if (nativeLastPrompt &&
245
- (typeof nativeLastPrompt.leafUuid !== 'string' ||
246
- nativeLastPrompt.leafUuid !== logicalTailUuid)) {
247
- nativeLastPrompt = undefined;
248
- lastPrompt = undefined;
249
- }
250
- return [
251
- ...agentColors.slice(-1),
252
- ...titles.slice(-1),
253
- ...modes.slice(-1),
254
- ...permissionModes.slice(-1),
255
- ...prLinks.slice(-1),
256
- ...history,
257
- ...(lastPrompt ? [lastPrompt] : []),
258
- ];
259
- }
260
- //# sourceMappingURL=fork.js.map