praxis-agent 0.43.0 → 0.43.1
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 +24 -37
- package/dist/application/native-session-projection.d.ts +4 -0
- package/dist/application/native-session-projection.js +135 -0
- package/dist/application/session-service.d.ts +0 -1
- package/dist/application/session-service.js +9 -170
- package/dist/cli/interactive.js +112 -156
- package/dist/cli/tui/ansi-frame-renderer.d.ts +2 -0
- package/dist/cli/tui/ansi-frame-renderer.js +109 -21
- package/dist/cli/tui/ansi-surface.d.ts +6 -22
- package/dist/cli/tui/ansi-surface.js +6 -126
- package/dist/cli/tui/ansi-theme.d.ts +3 -2
- package/dist/cli/tui/ansi-theme.js +22 -1
- package/dist/cli/tui/quiet-choice-rows.d.ts +26 -0
- package/dist/cli/tui/quiet-choice-rows.js +302 -0
- package/dist/cli/tui/quiet-frame-adapter.d.ts +18 -0
- package/dist/cli/tui/quiet-frame-adapter.js +90 -0
- package/dist/cli/tui/quiet-frame.d.ts +43 -0
- package/dist/cli/tui/quiet-frame.js +346 -0
- package/dist/cli/tui/quiet-operational-rows.d.ts +17 -0
- package/dist/cli/tui/quiet-operational-rows.js +413 -0
- package/dist/cli/tui/quiet-screen-projector.d.ts +25 -0
- package/dist/cli/tui/quiet-screen-projector.js +110 -0
- package/dist/cli/tui/quiet-settings-rows.d.ts +17 -0
- package/dist/cli/tui/quiet-settings-rows.js +490 -0
- package/dist/cli/tui/status-line.d.ts +15 -9
- package/dist/cli/tui/status-line.js +15 -6
- package/dist/cli/tui/theme.js +20 -20
- package/dist/cli/tui/transcript-viewport.d.ts +5 -0
- package/dist/cli/tui/transcript-viewport.js +213 -78
- package/dist/cli/tui/tui-row-ir.js +4 -4
- package/dist/persistence/in-memory-transcript-store.js +1 -7
- package/dist/persistence/native-transcript-store.d.ts +0 -9
- package/dist/persistence/native-transcript-store.js +4 -38
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -89,10 +89,13 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
89
89
|
|
|
90
90
|
## What Praxis provides
|
|
91
91
|
|
|
92
|
-
- **Local agent runtime** —
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
92
|
+
- **Local agent runtime** — C+ Quiet Operator responsive TUI with a linear
|
|
93
|
+
`you>`/`praxis>` conversation, compact stable tool rows, responsive density,
|
|
94
|
+
terminal-native background, and a minimal composer/status row. Interactive
|
|
95
|
+
surfaces share the same presentation across terminals, with English
|
|
96
|
+
permission/configuration choices and a taught `❯` / Up/Down / Enter / Esc
|
|
97
|
+
interaction grammar, plus a
|
|
98
|
+
shared-command
|
|
96
99
|
slash palette, tabbed help and shortcut surfaces, searchable resume picker,
|
|
97
100
|
restored active-branch conversation history, streaming and expandable
|
|
98
101
|
thinking, grouped multi-file reads, globally expandable tool results,
|
|
@@ -107,26 +110,8 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
107
110
|
skills/hooks flow, provider-free per-session `/color` prompt-bar styling,
|
|
108
111
|
`/mcp`, `/memory` shared instruction and auto-memory
|
|
109
112
|
access, and live extension-reload controls,
|
|
110
|
-
plus
|
|
111
|
-
|
|
112
|
-
framework-free TuiStore that retains runtime and composer state together,
|
|
113
|
-
with a shared semantic transcript Row IR for renderer-neutral layout and
|
|
114
|
-
stable incremental updates,
|
|
115
|
-
backed by the authoritative grapheme/Markdown viewport layout so narrow and
|
|
116
|
-
Unicode-heavy transcripts wrap consistently across renderers,
|
|
117
|
-
and an independent ANSI fullscreen frame renderer with alternate-screen
|
|
118
|
-
lifecycle, synchronized output, and dirty-row diffing,
|
|
119
|
-
opt-in TTY wiring with automatic Ink fallback on renderer failure,
|
|
120
|
-
with complex overlays and dialogs intentionally remaining on the mature Ink
|
|
121
|
-
surface until their semantic ANSI projections are complete,
|
|
122
|
-
while welcome and identity intros also remain on Ink for a complete first
|
|
123
|
-
frame,
|
|
124
|
-
and a pure FocusStack that centralizes overlay/dialog precedence and Esc
|
|
125
|
-
cancellation routing,
|
|
126
|
-
plus a generation-aware effect runner that drops stale asynchronous results
|
|
127
|
-
and aborts cleanly on replacement or unmount,
|
|
128
|
-
with ANSI fullscreen text styles derived from the active semantic theme and
|
|
129
|
-
automatic no-color/screen-reader suppression,
|
|
113
|
+
plus automatic fallback when a terminal renderer fails, screen-reader
|
|
114
|
+
support, and no-color output,
|
|
130
115
|
cursor/history composer, provider-free `/cost` usage and pricing summaries,
|
|
131
116
|
with a hermetic PTY smoke covering real `runInteractive` ANSI entry,
|
|
132
117
|
resize-safe lifecycle, and Ctrl-C restoration,
|
|
@@ -215,17 +200,17 @@ not in this entry-point README.
|
|
|
215
200
|
|
|
216
201
|
## Documentation
|
|
217
202
|
|
|
218
|
-
| Need | Document
|
|
219
|
-
| ------------------------------------------ |
|
|
220
|
-
| Install and run the first session | [Getting Started](https://github.com/Forest-Isle/Praxis/blob/main/docs/GETTING_STARTED.md)
|
|
221
|
-
| Common commands and environment variables | [CLI Reference](https://github.com/Forest-Isle/Praxis/blob/main/docs/CLI_REFERENCE.md)
|
|
222
|
-
| Find all user and maintainer documentation | [Documentation Index](https://github.com/Forest-Isle/Praxis/blob/main/docs/README.md)
|
|
223
|
-
| Understand module and data-flow boundaries | [Architecture](https://github.com/Forest-Isle/Praxis/blob/main/docs/ARCHITECTURE.md)
|
|
224
|
-
| Review security assumptions | [Threat Model](https://github.com/Forest-Isle/Praxis/blob/main/docs/THREAT_MODEL.md)
|
|
225
|
-
| Check Claude Code parity | [Parity Matrix](https://github.com/Forest-Isle/Praxis/blob/main/docs/PARITY_MATRIX.md)
|
|
226
|
-
| Review interactive TUI design and evidence | [
|
|
227
|
-
| Build, test, and contribute | [Contributing](https://github.com/Forest-Isle/Praxis/blob/main/CONTRIBUTING.md)
|
|
228
|
-
| Verify release and supply-chain controls | [Release Contract](https://github.com/Forest-Isle/Praxis/blob/main/docs/RELEASE.md)
|
|
203
|
+
| Need | Document |
|
|
204
|
+
| ------------------------------------------ | ------------------------------------------------------------------------------------------------ |
|
|
205
|
+
| Install and run the first session | [Getting Started](https://github.com/Forest-Isle/Praxis/blob/main/docs/GETTING_STARTED.md) |
|
|
206
|
+
| Common commands and environment variables | [CLI Reference](https://github.com/Forest-Isle/Praxis/blob/main/docs/CLI_REFERENCE.md) |
|
|
207
|
+
| Find all user and maintainer documentation | [Documentation Index](https://github.com/Forest-Isle/Praxis/blob/main/docs/README.md) |
|
|
208
|
+
| Understand module and data-flow boundaries | [Architecture](https://github.com/Forest-Isle/Praxis/blob/main/docs/ARCHITECTURE.md) |
|
|
209
|
+
| Review security assumptions | [Threat Model](https://github.com/Forest-Isle/Praxis/blob/main/docs/THREAT_MODEL.md) |
|
|
210
|
+
| Check Claude Code parity | [Parity Matrix](https://github.com/Forest-Isle/Praxis/blob/main/docs/PARITY_MATRIX.md) |
|
|
211
|
+
| Review interactive TUI design and evidence | [Quiet Operator Spec](https://github.com/Forest-Isle/Praxis/blob/main/docs/TUI_REDESIGN_SPEC.md) |
|
|
212
|
+
| Build, test, and contribute | [Contributing](https://github.com/Forest-Isle/Praxis/blob/main/CONTRIBUTING.md) |
|
|
213
|
+
| Verify release and supply-chain controls | [Release Contract](https://github.com/Forest-Isle/Praxis/blob/main/docs/RELEASE.md) |
|
|
229
214
|
|
|
230
215
|
## Project boundary
|
|
231
216
|
|
|
@@ -261,8 +246,10 @@ npm run check
|
|
|
261
246
|
transcript, and session profile.
|
|
262
247
|
`npm run test:native:deletion` adds an emitted-output deletion gate. These are
|
|
263
248
|
implemented profile checks, not qualification of the full native package.
|
|
264
|
-
`npm run test:performance`
|
|
265
|
-
|
|
249
|
+
`npm run test:performance` enforces TUI projection scaling, doubling ratios
|
|
250
|
+
`<=3.25`, the absolute 120k median budget of `<1000 ms`, and deterministic
|
|
251
|
+
injected regression protection, plus Quiet Operator input echo `<50 ms` and
|
|
252
|
+
normal/low-capability full-frame p95 budgets of `<16.7/<33 ms`.
|
|
266
253
|
`npm run check` also enforces the corresponding source dependency direction.
|
|
267
254
|
`npm run test:core-completion` runs the 56-story #402 audit and reports
|
|
268
255
|
implemented, qualified, blocked, deferred, and out-of-scope states separately;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { TranscriptEvent } from '../core/transcript-event.js';
|
|
2
|
+
import type { NativeTranscriptEntry } from '../native/schema.js';
|
|
3
|
+
export declare function projectNativeSessionEntries(events: readonly TranscriptEvent[]): NativeTranscriptEntry[];
|
|
4
|
+
//# sourceMappingURL=native-session-projection.d.ts.map
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
export function projectNativeSessionEntries(events) {
|
|
2
|
+
const entries = [];
|
|
3
|
+
for (const event of events) {
|
|
4
|
+
if (event.kind === 'context-boundary') {
|
|
5
|
+
entries.push({
|
|
6
|
+
type: 'system',
|
|
7
|
+
uuid: event.id,
|
|
8
|
+
parentUuid: event.parentId,
|
|
9
|
+
subtype: 'compact_boundary',
|
|
10
|
+
logicalParentUuid: event.logicalParentId,
|
|
11
|
+
compactMetadata: {
|
|
12
|
+
trigger: event.trigger,
|
|
13
|
+
preTokens: event.preTokens,
|
|
14
|
+
postTokens: event.postTokens,
|
|
15
|
+
durationMs: event.durationMs,
|
|
16
|
+
},
|
|
17
|
+
});
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (event.kind === 'context-summary') {
|
|
21
|
+
entries.push({
|
|
22
|
+
type: 'user',
|
|
23
|
+
uuid: event.id,
|
|
24
|
+
parentUuid: event.parentId,
|
|
25
|
+
isCompactSummary: true,
|
|
26
|
+
message: { role: 'user', content: event.summary },
|
|
27
|
+
});
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (event.kind !== 'messages')
|
|
31
|
+
continue;
|
|
32
|
+
let parentUuid = event.parentId;
|
|
33
|
+
event.messages.forEach((message, index) => {
|
|
34
|
+
const uuid = index === event.messages.length - 1 ? event.id : `${event.id}:${index}`;
|
|
35
|
+
if (message.role === 'user' && typeof message.content === 'string') {
|
|
36
|
+
const agentMatch = message.content.match(/^<praxis-agent-setting>([^<]+)<\/praxis-agent-setting>$/u);
|
|
37
|
+
if (agentMatch?.[1]) {
|
|
38
|
+
entries.push({
|
|
39
|
+
type: 'agent-setting',
|
|
40
|
+
agentSetting: agentMatch[1],
|
|
41
|
+
uuid,
|
|
42
|
+
parentUuid,
|
|
43
|
+
sessionId: event.sessionId,
|
|
44
|
+
});
|
|
45
|
+
parentUuid = uuid;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const nameMatch = message.content.match(/^<praxis-session-name>([^<]+)<\/praxis-session-name>$/u);
|
|
49
|
+
if (nameMatch?.[1]) {
|
|
50
|
+
entries.push({
|
|
51
|
+
type: 'custom-title',
|
|
52
|
+
customTitle: nameMatch[1],
|
|
53
|
+
uuid,
|
|
54
|
+
parentUuid,
|
|
55
|
+
sessionId: event.sessionId,
|
|
56
|
+
});
|
|
57
|
+
parentUuid = uuid;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const match = message.content.match(/^<praxis-file-history>([\s\S]*)<\/praxis-file-history>$/u);
|
|
61
|
+
if (match?.[1]) {
|
|
62
|
+
try {
|
|
63
|
+
const operational = JSON.parse(match[1]);
|
|
64
|
+
if (operational &&
|
|
65
|
+
typeof operational === 'object' &&
|
|
66
|
+
typeof operational.type === 'string' &&
|
|
67
|
+
(operational.type === 'file-history-snapshot' ||
|
|
68
|
+
operational.type === 'file-history-delta')) {
|
|
69
|
+
entries.push({
|
|
70
|
+
...operational,
|
|
71
|
+
uuid,
|
|
72
|
+
parentUuid,
|
|
73
|
+
sessionId: event.sessionId,
|
|
74
|
+
});
|
|
75
|
+
parentUuid = uuid;
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// Keep malformed operational markers visible as ordinary native user messages.
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (message.role === 'tool') {
|
|
85
|
+
entries.push({
|
|
86
|
+
type: 'user',
|
|
87
|
+
uuid,
|
|
88
|
+
parentUuid,
|
|
89
|
+
message: {
|
|
90
|
+
role: 'user',
|
|
91
|
+
content: [
|
|
92
|
+
{
|
|
93
|
+
type: 'tool_result',
|
|
94
|
+
tool_use_id: message.toolCallId,
|
|
95
|
+
content: message.content,
|
|
96
|
+
is_error: message.isError,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
parentUuid = uuid;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (message.role === 'assistant') {
|
|
105
|
+
const content = [];
|
|
106
|
+
if (message.content)
|
|
107
|
+
content.push({ type: 'text', text: message.content });
|
|
108
|
+
for (const call of message.toolCalls ?? [])
|
|
109
|
+
content.push({
|
|
110
|
+
type: 'tool_use',
|
|
111
|
+
id: call.id,
|
|
112
|
+
name: call.name,
|
|
113
|
+
input: call.input,
|
|
114
|
+
});
|
|
115
|
+
entries.push({
|
|
116
|
+
type: 'assistant',
|
|
117
|
+
uuid,
|
|
118
|
+
parentUuid,
|
|
119
|
+
message: { role: 'assistant', content },
|
|
120
|
+
});
|
|
121
|
+
parentUuid = uuid;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
entries.push({
|
|
125
|
+
type: message.role,
|
|
126
|
+
uuid,
|
|
127
|
+
parentUuid,
|
|
128
|
+
message: { role: message.role, content: message.content },
|
|
129
|
+
});
|
|
130
|
+
parentUuid = uuid;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
return entries;
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=native-session-projection.js.map
|
|
@@ -299,7 +299,6 @@ export declare class ClaudeSessionService {
|
|
|
299
299
|
compact(sessionId: string, signal?: AbortSignal, selection?: ManualCompactSelection): Promise<ManualCompactResult>;
|
|
300
300
|
fork(parentSessionId: string, sessionId?: string, resumeSessionAt?: string): Promise<ForkResult>;
|
|
301
301
|
ensureFork(parentSessionId: string, sessionId: string, checkpoint?: SessionForkCheckpoint): Promise<ForkResult>;
|
|
302
|
-
private nativeForkEntries;
|
|
303
302
|
rewindFiles(sessionId: string, userMessageId: string): Promise<void>;
|
|
304
303
|
rewindPoints(sessionId: string): Promise<RewindPoint[]>;
|
|
305
304
|
setPermissionMode(sessionId: string, permissionMode: ClaudePermissionMode): Promise<void>;
|
|
@@ -8,10 +8,10 @@ import { formatClaudeCompactSummary } from '../native/compaction.js';
|
|
|
8
8
|
import { isClaudeAgentId } from '../native/sidechain.js';
|
|
9
9
|
import { assertNativeDataPlane, resolveDataPlanePaths, resolveScheduledTaskFile, } from '../persistence/data-plane.js';
|
|
10
10
|
import { downloadClaudeFileResources, } from '../native/file-resources.js';
|
|
11
|
-
import { createClaudeNativeFork } from '../native/fork.js';
|
|
12
11
|
import { selectClaudeActiveTranscript } from '../native/history.js';
|
|
13
12
|
import { ClaudeFileHistory } from '../native/file-history.js';
|
|
14
13
|
import { getClaudeAgentSetting, projectClaudeModelMessages, } from '../native/projection.js';
|
|
14
|
+
import { projectNativeSessionEntries } from './native-session-projection.js';
|
|
15
15
|
import { classifyClaudeInterruption, } from '../native/interruption.js';
|
|
16
16
|
import { findUnresolvedClaudeToolCalls, getClaudeContentBlocks, } from '../native/tool-links.js';
|
|
17
17
|
import { createClaudeAgentSettingEntry, createClaudeHookAttachmentEntries, createClaudeLastPromptEntry, createClaudeRuleAttachmentEntry, translateProviderEvents, } from '../native/translation.js';
|
|
@@ -21,146 +21,6 @@ import { BackgroundTaskRuntime, } from './background-task-runtime.js';
|
|
|
21
21
|
import { backgroundAgentNotificationMarkers, } from './background-agent-manager.js';
|
|
22
22
|
import { usageCostUsd } from '../core/usage.js';
|
|
23
23
|
import { isSessionId } from '../core/session.js';
|
|
24
|
-
/** Project authoritative native events for legacy-only session helpers. */
|
|
25
|
-
function projectNativeEvents(events) {
|
|
26
|
-
const entries = [];
|
|
27
|
-
for (const event of events) {
|
|
28
|
-
if (event.kind === 'context-boundary') {
|
|
29
|
-
entries.push({
|
|
30
|
-
type: 'system',
|
|
31
|
-
uuid: event.id,
|
|
32
|
-
parentUuid: event.parentId,
|
|
33
|
-
subtype: 'compact_boundary',
|
|
34
|
-
logicalParentUuid: event.logicalParentId,
|
|
35
|
-
compactMetadata: {
|
|
36
|
-
trigger: event.trigger,
|
|
37
|
-
preTokens: event.preTokens,
|
|
38
|
-
postTokens: event.postTokens,
|
|
39
|
-
durationMs: event.durationMs,
|
|
40
|
-
},
|
|
41
|
-
});
|
|
42
|
-
continue;
|
|
43
|
-
}
|
|
44
|
-
if (event.kind === 'context-summary') {
|
|
45
|
-
entries.push({
|
|
46
|
-
type: 'user',
|
|
47
|
-
uuid: event.id,
|
|
48
|
-
parentUuid: event.parentId,
|
|
49
|
-
isCompactSummary: true,
|
|
50
|
-
message: { role: 'user', content: event.summary },
|
|
51
|
-
});
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (event.kind !== 'messages')
|
|
55
|
-
continue;
|
|
56
|
-
let parentUuid = event.parentId;
|
|
57
|
-
event.messages.forEach((message, index) => {
|
|
58
|
-
// Native event parent links target the event ID. Assign that ID to the
|
|
59
|
-
// final projected message so the next event and memory watermark attach
|
|
60
|
-
// to the visible tail of this event; intermediate messages get stable
|
|
61
|
-
// derived IDs within the event.
|
|
62
|
-
const uuid = index === event.messages.length - 1 ? event.id : `${event.id}:${index}`;
|
|
63
|
-
if (message.role === 'user' && typeof message.content === 'string') {
|
|
64
|
-
const agentMatch = message.content.match(/^<praxis-agent-setting>([^<]+)<\/praxis-agent-setting>$/u);
|
|
65
|
-
if (agentMatch?.[1]) {
|
|
66
|
-
entries.push({
|
|
67
|
-
type: 'agent-setting',
|
|
68
|
-
agentSetting: agentMatch[1],
|
|
69
|
-
uuid,
|
|
70
|
-
parentUuid,
|
|
71
|
-
sessionId: event.sessionId,
|
|
72
|
-
});
|
|
73
|
-
parentUuid = uuid;
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
const nameMatch = message.content.match(/^<praxis-session-name>([^<]+)<\/praxis-session-name>$/u);
|
|
77
|
-
if (nameMatch?.[1]) {
|
|
78
|
-
entries.push({
|
|
79
|
-
type: 'custom-title',
|
|
80
|
-
customTitle: nameMatch[1],
|
|
81
|
-
uuid,
|
|
82
|
-
parentUuid,
|
|
83
|
-
sessionId: event.sessionId,
|
|
84
|
-
});
|
|
85
|
-
parentUuid = uuid;
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const match = message.content.match(/^<praxis-file-history>([\s\S]*)<\/praxis-file-history>$/u);
|
|
89
|
-
if (match?.[1]) {
|
|
90
|
-
try {
|
|
91
|
-
const operational = JSON.parse(match[1]);
|
|
92
|
-
if (operational &&
|
|
93
|
-
typeof operational === 'object' &&
|
|
94
|
-
typeof operational.type === 'string' &&
|
|
95
|
-
(operational.type === 'file-history-snapshot' ||
|
|
96
|
-
operational.type === 'file-history-delta')) {
|
|
97
|
-
entries.push({
|
|
98
|
-
...operational,
|
|
99
|
-
uuid,
|
|
100
|
-
parentUuid,
|
|
101
|
-
sessionId: event.sessionId,
|
|
102
|
-
});
|
|
103
|
-
parentUuid = uuid;
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
// Keep malformed operational markers visible as ordinary native
|
|
109
|
-
// user messages; the authoritative transcript remains valid.
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (message.role === 'tool') {
|
|
114
|
-
entries.push({
|
|
115
|
-
type: 'user',
|
|
116
|
-
uuid,
|
|
117
|
-
parentUuid,
|
|
118
|
-
message: {
|
|
119
|
-
role: 'user',
|
|
120
|
-
content: [
|
|
121
|
-
{
|
|
122
|
-
type: 'tool_result',
|
|
123
|
-
tool_use_id: message.toolCallId,
|
|
124
|
-
content: message.content,
|
|
125
|
-
is_error: message.isError,
|
|
126
|
-
},
|
|
127
|
-
],
|
|
128
|
-
},
|
|
129
|
-
});
|
|
130
|
-
parentUuid = uuid;
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
if (message.role === 'assistant') {
|
|
134
|
-
const content = [];
|
|
135
|
-
if (message.content)
|
|
136
|
-
content.push({ type: 'text', text: message.content });
|
|
137
|
-
for (const call of message.toolCalls ?? [])
|
|
138
|
-
content.push({
|
|
139
|
-
type: 'tool_use',
|
|
140
|
-
id: call.id,
|
|
141
|
-
name: call.name,
|
|
142
|
-
input: call.input,
|
|
143
|
-
});
|
|
144
|
-
entries.push({
|
|
145
|
-
type: 'assistant',
|
|
146
|
-
uuid,
|
|
147
|
-
parentUuid,
|
|
148
|
-
message: { role: 'assistant', content },
|
|
149
|
-
});
|
|
150
|
-
parentUuid = uuid;
|
|
151
|
-
return;
|
|
152
|
-
}
|
|
153
|
-
entries.push({
|
|
154
|
-
type: message.role,
|
|
155
|
-
uuid,
|
|
156
|
-
parentUuid,
|
|
157
|
-
message: { role: message.role, content: message.content },
|
|
158
|
-
});
|
|
159
|
-
parentUuid = uuid;
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
return entries;
|
|
163
|
-
}
|
|
164
24
|
import { ContextBudget, estimateModelRequestTokens, isPromptTooLongError, } from '../core/context-budget.js';
|
|
165
25
|
import { ContextEngine } from './context-engine.js';
|
|
166
26
|
import { TurnMemoryCoordinator } from './turn-memory-coordinator.js';
|
|
@@ -1935,7 +1795,7 @@ export class ClaudeSessionService {
|
|
|
1935
1795
|
const sourceStore = this.store(sessionId);
|
|
1936
1796
|
const relocated = await sourceStore.withLease(async (lease) => {
|
|
1937
1797
|
const snapshot = await lease.load();
|
|
1938
|
-
if (snapshot.
|
|
1798
|
+
if (snapshot.records.length === 0) {
|
|
1939
1799
|
throw new Error(`Claude session not found: ${sessionId}`);
|
|
1940
1800
|
}
|
|
1941
1801
|
await mkdir(targetPaths.projectRoot, { recursive: true });
|
|
@@ -2112,7 +1972,7 @@ export class ClaudeSessionService {
|
|
|
2112
1972
|
: branchEvents[targetIndex - 1])?.id;
|
|
2113
1973
|
}
|
|
2114
1974
|
else {
|
|
2115
|
-
memorySelection = await this.selectMemoryPreservedCompact(sessionId,
|
|
1975
|
+
memorySelection = await this.selectMemoryPreservedCompact(sessionId, projectNativeSessionEntries(branchEvents));
|
|
2116
1976
|
if (memorySelection) {
|
|
2117
1977
|
messages = [
|
|
2118
1978
|
memorySelection.memoryMessage,
|
|
@@ -2311,35 +2171,13 @@ export class ClaudeSessionService {
|
|
|
2311
2171
|
return { sessionId, parentSessionId };
|
|
2312
2172
|
}
|
|
2313
2173
|
}
|
|
2314
|
-
async nativeForkEntries(parentSessionId, sessionId, resumeSessionAt, sourceEntryCount) {
|
|
2315
|
-
const sourceResult = await this.store(parentSessionId).withLease((lease) => lease.load());
|
|
2316
|
-
if (sourceResult.status === 'conflict') {
|
|
2317
|
-
throw new Error(`Claude transcript fork conflict: ${sourceResult.reason}`);
|
|
2318
|
-
}
|
|
2319
|
-
const source = sourceResult.value;
|
|
2320
|
-
if (source.entries.length === 0) {
|
|
2321
|
-
throw new Error(`Claude session not found: ${parentSessionId}`);
|
|
2322
|
-
}
|
|
2323
|
-
if (sourceEntryCount !== undefined &&
|
|
2324
|
-
(sourceEntryCount <= 0 || sourceEntryCount > source.entries.length)) {
|
|
2325
|
-
throw new Error('Claude handoff source checkpoint is no longer available');
|
|
2326
|
-
}
|
|
2327
|
-
return createClaudeNativeFork({
|
|
2328
|
-
source: sourceEntryCount === undefined
|
|
2329
|
-
? source.entries
|
|
2330
|
-
: source.entries.slice(0, sourceEntryCount),
|
|
2331
|
-
sourceSessionId: parentSessionId,
|
|
2332
|
-
sessionId,
|
|
2333
|
-
...(resumeSessionAt === undefined ? {} : { resumeSessionAt }),
|
|
2334
|
-
});
|
|
2335
|
-
}
|
|
2336
2174
|
async rewindFiles(sessionId, userMessageId) {
|
|
2337
2175
|
const transcript = new NativeSessionTranscript({
|
|
2338
2176
|
sessionId,
|
|
2339
2177
|
store: this.store(sessionId),
|
|
2340
2178
|
});
|
|
2341
2179
|
await transcript.withLease({ kind: 'resume' }, async (lease) => {
|
|
2342
|
-
const projected =
|
|
2180
|
+
const projected = projectNativeSessionEntries(lease.activeEvents()).filter((entry) => entry.type === 'file-history-snapshot' ||
|
|
2343
2181
|
entry.type === 'file-history-delta');
|
|
2344
2182
|
if (projected.length === 0)
|
|
2345
2183
|
throw new Error(`Native session has no file history: ${sessionId}`);
|
|
@@ -2641,7 +2479,7 @@ export class ClaudeSessionService {
|
|
|
2641
2479
|
const runUnderLease = async (lease, nativeLease) => {
|
|
2642
2480
|
const loadedSnapshot = await lease.load();
|
|
2643
2481
|
let snapshot = {
|
|
2644
|
-
entries:
|
|
2482
|
+
entries: projectNativeSessionEntries(nativeLease.activeEvents()),
|
|
2645
2483
|
tail: loadedSnapshot.tail,
|
|
2646
2484
|
};
|
|
2647
2485
|
const activeTurnMessages = () => {
|
|
@@ -2649,7 +2487,7 @@ export class ClaudeSessionService {
|
|
|
2649
2487
|
// after each append so memory/compaction sees the live branch.
|
|
2650
2488
|
snapshot = {
|
|
2651
2489
|
...snapshot,
|
|
2652
|
-
entries:
|
|
2490
|
+
entries: projectNativeSessionEntries(nativeLease.activeEvents()),
|
|
2653
2491
|
};
|
|
2654
2492
|
return nativeLease.activeMessages();
|
|
2655
2493
|
};
|
|
@@ -3654,7 +3492,7 @@ export class ClaudeSessionService {
|
|
|
3654
3492
|
}
|
|
3655
3493
|
}
|
|
3656
3494
|
const memorySelection = sessionMemory
|
|
3657
|
-
? await this.selectMemoryPreservedCompact(sessionId,
|
|
3495
|
+
? await this.selectMemoryPreservedCompact(sessionId, projectNativeSessionEntries(activeNativeLease.activeEvents()))
|
|
3658
3496
|
: null;
|
|
3659
3497
|
if (memorySelection) {
|
|
3660
3498
|
compactableMessages = [
|
|
@@ -4350,7 +4188,8 @@ export class ClaudeSessionService {
|
|
|
4350
4188
|
}
|
|
4351
4189
|
const memorySnapshot = activeTurnMessages();
|
|
4352
4190
|
const nativeMemoryMessageId = nativeLease
|
|
4353
|
-
?
|
|
4191
|
+
? projectNativeSessionEntries(nativeLease.activeEvents()).at(-1)
|
|
4192
|
+
?.uuid
|
|
4354
4193
|
: undefined;
|
|
4355
4194
|
const providerVisibleMessages = [
|
|
4356
4195
|
...contextMessages,
|