praxis-agent 0.38.0 → 0.40.0
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 +44 -67
- package/dist/application/background-agent-manager.js +7 -4
- package/dist/application/background-bash-manager.d.ts +2 -2
- package/dist/application/background-bash-manager.js +6 -6
- package/dist/application/claude-project-purge.js +36 -74
- package/dist/application/native-session-transcript.d.ts +14 -3
- package/dist/application/native-session-transcript.js +30 -9
- package/dist/application/scheduled-prompt-manager.d.ts +2 -2
- package/dist/application/scheduled-prompt-manager.js +3 -3
- package/dist/application/session-memory.d.ts +2 -5
- package/dist/application/session-memory.js +4 -7
- package/dist/application/session-service.d.ts +19 -32
- package/dist/application/session-service.js +1085 -1785
- package/dist/application/session-worktree.d.ts +2 -3
- package/dist/application/session-worktree.js +3 -3
- package/dist/application/subagent-service.d.ts +2 -5
- package/dist/application/subagent-service.js +152 -319
- package/dist/application/top-level-agent-manager.js +19 -37
- package/dist/application/transcript-projection.js +18 -2
- package/dist/application/workflow-manager.d.ts +1 -1
- package/dist/application/workflow-manager.js +11 -19
- package/dist/cli/controls.d.ts +10 -6
- package/dist/cli/controls.js +28 -6
- package/dist/cli/interactive.d.ts +6 -4
- package/dist/cli/interactive.js +98 -82
- package/dist/cli/protocol.d.ts +1 -1
- package/dist/cli/protocol.js +0 -13
- package/dist/cli/tui/ansi-frame-renderer.d.ts +24 -0
- package/dist/cli/tui/ansi-frame-renderer.js +120 -0
- package/dist/cli/tui/ansi-surface.d.ts +26 -0
- package/dist/cli/tui/ansi-surface.js +187 -0
- package/dist/cli/tui/ansi-theme.d.ts +3 -0
- package/dist/cli/tui/ansi-theme.js +83 -0
- package/dist/cli/tui/claude-style.d.ts +2 -4
- package/dist/cli/tui/claude-style.js +6 -7
- package/dist/cli/tui/config-settings.js +5 -14
- package/dist/cli/tui/doctor-dashboard.js +1 -1
- package/dist/cli/tui/hook-settings.d.ts +2 -2
- package/dist/cli/tui/kernel/tui-effect-runner.d.ts +21 -0
- package/dist/cli/tui/kernel/tui-effect-runner.js +90 -0
- package/dist/cli/tui/kernel/tui-runtime-kernel.d.ts +23 -0
- package/dist/cli/tui/kernel/tui-runtime-kernel.js +35 -0
- package/dist/cli/tui/kernel/tui-store.d.ts +22 -0
- package/dist/cli/tui/kernel/tui-store.js +37 -0
- package/dist/cli/tui/mcp-panel.d.ts +1 -3
- package/dist/cli/tui/mcp-panel.js +5 -8
- package/dist/cli/tui/memory-files.d.ts +3 -5
- package/dist/cli/tui/memory-files.js +12 -30
- package/dist/cli/tui/permission-settings.d.ts +6 -9
- package/dist/cli/tui/permission-settings.js +9 -15
- package/dist/cli/tui/praxis-logo.d.ts +5 -0
- package/dist/cli/tui/praxis-logo.js +17 -0
- package/dist/cli/tui/sandbox-settings.d.ts +3 -5
- package/dist/cli/tui/sandbox-settings.js +5 -9
- package/dist/cli/tui/slash-commands.js +1 -1
- package/dist/cli/tui/status-line.d.ts +5 -5
- package/dist/cli/tui/status-line.js +12 -30
- package/dist/cli/tui/terminal-setup.js +2 -4
- package/dist/cli/tui/theme.d.ts +2 -2
- package/dist/cli/tui/tool-permission.d.ts +1 -1
- package/dist/cli/tui/tool-permission.js +13 -15
- package/dist/cli/tui/transcript-viewport.d.ts +1 -0
- package/dist/cli/tui/transcript-viewport.js +3 -0
- package/dist/cli/tui/tui-focus-stack.d.ts +19 -0
- package/dist/cli/tui/tui-focus-stack.js +72 -0
- package/dist/cli/tui/tui-row-ir.d.ts +19 -0
- package/dist/cli/tui/tui-row-ir.js +126 -0
- package/dist/cli/tui/tui-screen-model.d.ts +2 -0
- package/dist/cli/tui/tui-screen-model.js +6 -0
- package/dist/cli-runtime.d.ts +1 -1
- package/dist/cli-runtime.js +94 -397
- package/dist/{compatibility/claude → core}/agent-color.d.ts +1 -2
- package/dist/core/project-memory.d.ts +4 -3
- package/dist/core/project-memory.js +2 -4
- package/dist/core/transcript-event.d.ts +4 -0
- package/dist/core/transcript-event.js +11 -1
- package/dist/extensions/claude-extensions.d.ts +5 -6
- package/dist/extensions/claude-extensions.js +13 -27
- package/dist/extensions/claude-init-command.d.ts +2 -3
- package/dist/extensions/claude-init-command.js +7 -70
- package/dist/hooks/claude-hooks.d.ts +4 -4
- package/dist/maintenance/doctor-diagnostic.d.ts +0 -1
- package/dist/maintenance/doctor-diagnostic.js +0 -4
- package/dist/maintenance/doctor.d.ts +8 -4
- package/dist/maintenance/doctor.js +10 -63
- package/dist/mcp/claude-mcp-management.d.ts +3 -3
- package/dist/mcp/claude-mcp-management.js +16 -37
- package/dist/mcp/claude-mcp-oauth.js +1 -1
- package/dist/mcp/claude-mcp-tools.d.ts +4 -4
- package/dist/mcp/claude-mcp-tools.js +1 -3
- package/dist/{compatibility/claude → native}/compaction.d.ts +4 -4
- package/dist/{compatibility/claude → native}/context.d.ts +6 -2
- package/dist/{compatibility/claude → native}/context.js +21 -9
- package/dist/native/file-history.d.ts +14 -0
- package/dist/{compatibility/claude → native}/fork.d.ts +3 -3
- package/dist/{compatibility/claude → native}/fork.js +4 -4
- package/dist/{compatibility/claude → native}/history.d.ts +6 -6
- package/dist/{compatibility/claude → native}/interruption.d.ts +3 -3
- package/dist/{compatibility/claude → native}/ownership.d.ts +17 -17
- package/dist/{compatibility/claude → native}/ownership.js +17 -17
- package/dist/{compatibility/claude → native}/paths.d.ts +8 -8
- package/dist/{compatibility/claude → native}/paths.js +23 -26
- package/dist/{compatibility/claude → native}/pr-links.d.ts +2 -2
- package/dist/{compatibility/claude → native}/projection.d.ts +8 -8
- package/dist/native/schema.d.ts +14 -0
- package/dist/native/schema.js +24 -0
- package/dist/{compatibility/claude → native}/session-metadata.d.ts +6 -6
- package/dist/{compatibility/claude → native}/sidechain.d.ts +4 -4
- package/dist/{compatibility/claude → native}/tool-links.d.ts +5 -5
- package/dist/{compatibility/claude → native}/translation.d.ts +10 -10
- package/dist/{compatibility/claude → native}/translation.js +17 -7
- package/dist/permissions/bash-path-safety.js +2 -4
- package/dist/permissions/bypass-immune-paths.d.ts +0 -2
- package/dist/permissions/bypass-immune-paths.js +2 -2
- package/dist/permissions/claude-auto-classifier.d.ts +2 -2
- package/dist/permissions/claude-permission-resolver.d.ts +3 -3
- package/dist/permissions/claude-permission-resolver.js +9 -13
- package/dist/persistence/claude-cost-state-store.js +1 -2
- package/dist/persistence/claude-workflow-store.d.ts +26 -4
- package/dist/persistence/claude-workflow-store.js +47 -2
- package/dist/persistence/data-plane-adapter.d.ts +1 -2
- package/dist/persistence/data-plane.d.ts +2 -3
- package/dist/persistence/data-plane.js +15 -12
- package/dist/persistence/in-memory-sidechain-store.d.ts +24 -7
- package/dist/persistence/in-memory-sidechain-store.js +23 -19
- package/dist/persistence/in-memory-transcript-store.d.ts +13 -6
- package/dist/persistence/in-memory-transcript-store.js +38 -58
- package/dist/persistence/native-resources.js +63 -7
- package/dist/persistence/{claude-scheduled-task-store.d.ts → native-scheduled-task-store.d.ts} +10 -10
- package/dist/persistence/{claude-scheduled-task-store.js → native-scheduled-task-store.js} +14 -14
- package/dist/persistence/native-transcript-reader.d.ts +6 -6
- package/dist/persistence/native-transcript-reader.js +2 -2
- package/dist/persistence/native-transcript-store.d.ts +9 -0
- package/dist/persistence/native-transcript-store.js +47 -5
- package/dist/persistence/subagent-lifecycle-store.js +3 -4
- package/dist/persistence/unknown-cost-sidecar.d.ts +2 -2
- package/dist/persistence/unknown-cost-sidecar.js +2 -2
- package/dist/platform/project-memory-paths.d.ts +3 -4
- package/dist/platform/project-memory-paths.js +4 -5
- package/dist/plugins/claude-plugin-marketplace.js +3 -2
- package/dist/plugins/claude-plugin-mcpb.js +3 -4
- package/dist/plugins/claude-plugin-runtime.d.ts +6 -6
- package/dist/providers/anthropic-prompt-cache.d.ts +1 -1
- package/dist/providers/anthropic-prompt-cache.js +3 -26
- package/dist/sandbox/claude-sandbox-settings.d.ts +5 -6
- package/dist/sandbox/claude-sandbox-settings.js +5 -5
- package/dist/tools/claude-interactive-tools.d.ts +1 -2
- package/dist/tools/claude-interactive-tools.js +3 -1
- package/dist/tools/claude-scheduled-tools.js +6 -7
- package/dist/tools/claude-workflow-tools.d.ts +0 -2
- package/dist/tools/claude-workflow-tools.js +4 -4
- package/dist/tools/claude-worktree-tools.js +3 -5
- package/dist/tools/local-tools.d.ts +2 -1
- package/dist/tools/local-tools.js +1 -4
- package/dist/tools/team-lead-tools.d.ts +1 -15
- package/dist/tools/team-lead-tools.js +2 -124
- package/package.json +4 -67
- package/dist/compatibility/claude/data-plane-adapter.d.ts +0 -9
- package/dist/compatibility/claude/data-plane-adapter.js +0 -44
- package/dist/compatibility/claude/file-history.d.ts +0 -14
- package/dist/compatibility/claude/schema.d.ts +0 -26
- package/dist/compatibility/claude/schema.js +0 -1071
- package/dist/compatibility/claude/shared-resources.d.ts +0 -27
- package/dist/compatibility/claude/shared-resources.js +0 -459
- package/dist/compatibility/claude/team.d.ts +0 -77
- package/dist/compatibility/claude/team.js +0 -219
- package/dist/compatibility/claude/transcript-codec.d.ts +0 -21
- package/dist/compatibility/claude/transcript-codec.js +0 -518
- package/dist/persistence/claude-migration.d.ts +0 -5
- package/dist/persistence/claude-migration.js +0 -225
- package/dist/persistence/claude-session-index.d.ts +0 -39
- package/dist/persistence/claude-session-index.js +0 -175
- package/dist/persistence/claude-sidechain-store.d.ts +0 -18
- package/dist/persistence/claude-sidechain-store.js +0 -123
- package/dist/persistence/claude-transcript-store.d.ts +0 -90
- package/dist/persistence/claude-transcript-store.js +0 -469
- package/dist/persistence/native-transcript-migration.d.ts +0 -37
- package/dist/persistence/native-transcript-migration.js +0 -430
- package/dist/platform/claude-version.d.ts +0 -5
- package/dist/platform/claude-version.js +0 -18
- /package/dist/{compatibility/claude → core}/agent-color.js +0 -0
- /package/dist/{compatibility/claude → native}/compaction.js +0 -0
- /package/dist/{compatibility/claude → native}/dynamic-context.d.ts +0 -0
- /package/dist/{compatibility/claude → native}/dynamic-context.js +0 -0
- /package/dist/{compatibility/claude → native}/file-history.js +0 -0
- /package/dist/{compatibility/claude → native}/file-resources.d.ts +0 -0
- /package/dist/{compatibility/claude → native}/file-resources.js +0 -0
- /package/dist/{compatibility/claude → native}/history.js +0 -0
- /package/dist/{compatibility/claude → native}/interruption.js +0 -0
- /package/dist/{compatibility/claude → native}/pr-links.js +0 -0
- /package/dist/{compatibility/claude → native}/projection.js +0 -0
- /package/dist/{compatibility/claude → native}/session-metadata.js +0 -0
- /package/dist/{compatibility/claude → native}/sidechain.js +0 -0
- /package/dist/{compatibility/claude → native}/tool-links.js +0 -0
- /package/dist/{compatibility/claude → native}/workflow-replay.d.ts +0 -0
- /package/dist/{compatibility/claude → native}/workflow-replay.js +0 -0
- /package/dist/{compatibility/claude → native}/workflow.d.ts +0 -0
- /package/dist/{compatibility/claude → native}/workflow.js +0 -0
package/README.md
CHANGED
|
@@ -17,15 +17,10 @@ Anthropic/OpenAI-compatible model access. Praxis deliberately excludes
|
|
|
17
17
|
accounts, organizations, billing, managed enterprise policy, remote control,
|
|
18
18
|
IDE surfaces, and telemetry control planes.
|
|
19
19
|
|
|
20
|
-
Claude Code 2.1.208 remains
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
the existing enterprise, authentication, hosted, and client surfaces plus the
|
|
25
|
-
explicitly classified subscription-bound integration, campaign, hidden
|
|
26
|
-
maintainer diagnostic, and build-experimental commands. A similar Praxis
|
|
27
|
-
surface is not a substitute for the corresponding Claude command or runtime
|
|
28
|
-
contract.
|
|
20
|
+
Claude Code 2.1.208 remains a clean-room behavioral reference for the
|
|
21
|
+
developer-facing CLI surface. It is not a runtime dependency or a data source:
|
|
22
|
+
Praxis runs one native data plane and does not read or write Claude Code
|
|
23
|
+
sessions, configuration, or compatibility directories.
|
|
29
24
|
|
|
30
25
|
## Requirements
|
|
31
26
|
|
|
@@ -34,13 +29,12 @@ contract.
|
|
|
34
29
|
- [`ripgrep`](https://github.com/BurntSushi/ripgrep) (`rg`) for the Grep tool
|
|
35
30
|
- an API key and model ID for an Anthropic or OpenAI-compatible provider
|
|
36
31
|
|
|
37
|
-
Praxis does not use Claude subscription authentication. Claude
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
Praxis does not use Claude subscription authentication. Claude-shaped message,
|
|
33
|
+
tool, and CLI protocol forms remain supported where they are part of the
|
|
34
|
+
public surface, while all persisted state is Praxis-native.
|
|
40
35
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Team surfaces are rejected rather than silently simplified.
|
|
36
|
+
Team operations are local-only and opt-in. Unsupported or lossy Team payloads
|
|
37
|
+
are rejected rather than silently simplified.
|
|
44
38
|
|
|
45
39
|
## Install
|
|
46
40
|
|
|
@@ -89,14 +83,15 @@ praxis doctor
|
|
|
89
83
|
|
|
90
84
|
See
|
|
91
85
|
[Getting Started](https://github.com/Forest-Isle/Praxis/blob/main/docs/GETTING_STARTED.md)
|
|
92
|
-
for provider setup, shared
|
|
86
|
+
for provider setup, shared Praxis state, permissions, updating, and
|
|
93
87
|
troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
94
88
|
|
|
95
89
|
## What Praxis provides
|
|
96
90
|
|
|
97
91
|
- **Local agent runtime** — Claude-style responsive TUI with a fixed fullscreen
|
|
98
92
|
viewport, non-shrinking composer/status area, and complete bounded welcome
|
|
99
|
-
surface
|
|
93
|
+
surface with the reusable P-loop + spark Praxis mark and ANSI/no-color
|
|
94
|
+
fallbacks, plus a shared-command
|
|
100
95
|
slash palette, tabbed help and shortcut surfaces, searchable resume picker,
|
|
101
96
|
restored active-branch conversation history, streaming and expandable
|
|
102
97
|
thinking, grouped multi-file reads, globally expandable tool results,
|
|
@@ -111,12 +106,34 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
111
106
|
skills/hooks flow, provider-free per-session `/color` prompt-bar styling,
|
|
112
107
|
`/mcp`, `/memory` shared instruction and auto-memory
|
|
113
108
|
access, and live extension-reload controls,
|
|
109
|
+
plus a framework-free runtime kernel that atomically publishes streaming
|
|
110
|
+
frames and keeps status/busy transitions deterministic, with a unified
|
|
111
|
+
framework-free TuiStore that retains runtime and composer state together,
|
|
112
|
+
with a shared semantic transcript Row IR for renderer-neutral layout and
|
|
113
|
+
stable incremental updates,
|
|
114
|
+
backed by the authoritative grapheme/Markdown viewport layout so narrow and
|
|
115
|
+
Unicode-heavy transcripts wrap consistently across renderers,
|
|
116
|
+
and an independent ANSI fullscreen frame renderer with alternate-screen
|
|
117
|
+
lifecycle, synchronized output, and dirty-row diffing,
|
|
118
|
+
opt-in TTY wiring with automatic Ink fallback on renderer failure,
|
|
119
|
+
with complex overlays and dialogs intentionally remaining on the mature Ink
|
|
120
|
+
surface until their semantic ANSI projections are complete,
|
|
121
|
+
while welcome and identity intros also remain on Ink for a complete first
|
|
122
|
+
frame,
|
|
123
|
+
and a pure FocusStack that centralizes overlay/dialog precedence and Esc
|
|
124
|
+
cancellation routing,
|
|
125
|
+
plus a generation-aware effect runner that drops stale asynchronous results
|
|
126
|
+
and aborts cleanly on replacement or unmount,
|
|
127
|
+
with ANSI fullscreen text styles derived from the active semantic theme and
|
|
128
|
+
automatic no-color/screen-reader suppression,
|
|
114
129
|
cursor/history composer, provider-free `/cost` usage and pricing summaries,
|
|
130
|
+
with a hermetic PTY smoke covering real `runInteractive` ANSI entry,
|
|
131
|
+
resize-safe lifecycle, and Ctrl-C restoration,
|
|
115
132
|
interactive `/doctor` diagnostics, per-session model/effort/permission controls,
|
|
116
133
|
context/status/skill/task dashboards, prompt stash and continuation shortcuts,
|
|
117
134
|
filterable `@` file and agent references, composer undo, `Ctrl+G` external
|
|
118
135
|
editing, shared `/keybindings` creation/editing and supported-action remapping,
|
|
119
|
-
shared built-in and
|
|
136
|
+
shared built-in and custom `/theme` profiles with immediate
|
|
120
137
|
semantic recoloring, token editing/reset, deletion, and persisted syntax
|
|
121
138
|
toggles across transcript code and diff views,
|
|
122
139
|
shared runtime preferences for reduced motion, spinner tips, progress and
|
|
@@ -174,16 +191,12 @@ troubleshooting. Run `praxis --help` for the authoritative command surface.
|
|
|
174
191
|
Lead Decision queue with provenance. Coordinator leads are restricted to
|
|
175
192
|
orchestration, and custom Team agents receive no MCP capability. The native
|
|
176
193
|
CLI also exposes `praxis team status`, `logs`, and `attach` in human or JSON
|
|
177
|
-
form; durable-local attach does not require tmux.
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
shutdown, and plan-response shapes; native task, notification, context, and
|
|
182
|
-
Team resume/inbox seams are implemented, while their Claude-facing zero-skip
|
|
183
|
-
qualification remains explicitly separate.
|
|
184
|
-
- **Claude-compatible ecosystem** — shared instructions with recursive `@`
|
|
194
|
+
form; durable-local attach does not require tmux. Native task, notification,
|
|
195
|
+
context, and Team resume/inbox seams are implemented with fail-closed
|
|
196
|
+
validation for unsupported payloads.
|
|
197
|
+
- **Native resource ecosystem** — shared Praxis instructions with recursive `@`
|
|
185
198
|
imports, memory, skills, commands, agents, hooks, settings, MCP servers,
|
|
186
|
-
plugins, and transcript
|
|
199
|
+
plugins, and append-only `praxis.transcript` JSONL sessions under `~/.praxis`.
|
|
187
200
|
- **Provider-neutral models** — native Anthropic Messages and OpenAI-compatible
|
|
188
201
|
streaming adapters with explicit capability checks and metering controls.
|
|
189
202
|
|
|
@@ -191,39 +204,6 @@ Detailed feature status and executable evidence live in the
|
|
|
191
204
|
[parity matrix](https://github.com/Forest-Isle/Praxis/blob/main/docs/PARITY_MATRIX.md),
|
|
192
205
|
not in this entry-point README.
|
|
193
206
|
|
|
194
|
-
## Claude Code interoperability
|
|
195
|
-
|
|
196
|
-
Praxis uses an independent local data plane by default:
|
|
197
|
-
|
|
198
|
-
```text
|
|
199
|
-
Praxis ─── ~/.praxis (or PRAXIS_HOME)
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
Use `praxis --data-plane claude` when you need the legacy shared Claude Code
|
|
203
|
-
layout (`~/.claude` or `CLAUDE_CONFIG_DIR`). Praxis can resume Claude Code
|
|
204
|
-
sessions in that mode, and Claude Code can resume compatible sessions written
|
|
205
|
-
there. Every semver-like Claude Code producer version is
|
|
206
|
-
structurally validated and is read/write compatible when its entry shape is
|
|
207
|
-
supported; schema adapters are selected from transcript entry structure rather
|
|
208
|
-
than an installed or fixed producer version, and malformed or unsupported
|
|
209
|
-
shapes fail closed before any write. Each transcript record keeps its original
|
|
210
|
-
producer version, so supported shapes may be mixed across versions in one
|
|
211
|
-
session. Native fork creation is a separate restricted lossless copy path that
|
|
212
|
-
preserves each existing source record's producer version, so it can copy
|
|
213
|
-
specific black-box-verified foreign shapes such as the observed Claude Code
|
|
214
|
-
2.1.233 records; unsupported record shapes and unverified versions still fail
|
|
215
|
-
closed and remain read-only. Maintainers can prove mixed-version Claude JSONL interoperability with
|
|
216
|
-
`npm run test:cross-version-session-compat`, `test:cross-version-fork-compat`,
|
|
217
|
-
`test:cross-version-sidechain-compat`, `test:cross-version-compaction-compat`,
|
|
218
|
-
and `test:cross-version-resume-at-compat`, covering linear resume, native fork,
|
|
219
|
-
foreground sidechain, compaction, and `--resume-session-at` branch projection.
|
|
220
|
-
Each requires `PRAXIS_CLAUDE_BINARY` (Claude Code 2.1.208) and
|
|
221
|
-
`PRAXIS_CLAUDE_CROSS_VERSION_BINARY` (a different Claude Code version).
|
|
222
|
-
|
|
223
|
-
See the
|
|
224
|
-
[compatibility contract](https://github.com/Forest-Isle/Praxis/blob/main/docs/COMPATIBILITY.md)
|
|
225
|
-
for exact shared data, version boundaries, exclusions, and verification gates.
|
|
226
|
-
|
|
227
207
|
## Documentation
|
|
228
208
|
|
|
229
209
|
| Need | Document |
|
|
@@ -268,15 +248,12 @@ npm ci
|
|
|
268
248
|
npm run check
|
|
269
249
|
```
|
|
270
250
|
|
|
271
|
-
`npm run build:native` compiles the
|
|
272
|
-
|
|
251
|
+
`npm run build:native` compiles the Praxis-owned core, provider, native
|
|
252
|
+
transcript, and session profile.
|
|
273
253
|
`npm run test:native:deletion` adds an emitted-output deletion gate. These are
|
|
274
254
|
implemented profile checks, not qualification of the full native package.
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
publication, text/JSON idempotence, rollback, and Claude-data-plane exclusion.
|
|
278
|
-
The isolated active-stream regression proof is available through
|
|
279
|
-
`npm run test:performance:active-stream`; the product p95 budget remains 50 ms.
|
|
255
|
+
`npm run test:performance` runs the native projection scaling and regression
|
|
256
|
+
budgets; the retained-render p95 budget remains 50 ms.
|
|
280
257
|
`npm run check` also enforces the corresponding source dependency direction.
|
|
281
258
|
`npm run test:core-completion` runs the 56-story #402 audit and reports
|
|
282
259
|
implemented, qualified, blocked, deferred, and out-of-scope states separately;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import { isTerminalLifecycleState, } from '../core/agent-orchestration.js';
|
|
3
|
-
import { isClaudeAgentId } from '../compatibility/claude/sidechain.js';
|
|
4
3
|
const MAX_TIMEOUT_MS = 600_000;
|
|
5
4
|
const DEFAULT_CLOSE_DRAIN_MS = 5_000;
|
|
5
|
+
const NATIVE_AGENT_ID_PATTERN = /^a[0-9a-f]{16}$/u;
|
|
6
|
+
function isNativeAgentId(agentId) {
|
|
7
|
+
return NATIVE_AGENT_ID_PATTERN.test(agentId);
|
|
8
|
+
}
|
|
6
9
|
export class BackgroundAgentRunError extends Error {
|
|
7
10
|
result;
|
|
8
11
|
constructor(message, result, cause) {
|
|
@@ -37,7 +40,7 @@ function notificationWireStatus(status) {
|
|
|
37
40
|
return null;
|
|
38
41
|
}
|
|
39
42
|
function assertAgentId(agentId) {
|
|
40
|
-
if (!
|
|
43
|
+
if (!isNativeAgentId(agentId)) {
|
|
41
44
|
throw new Error(`Invalid background agent ID: ${agentId}`);
|
|
42
45
|
}
|
|
43
46
|
}
|
|
@@ -625,7 +628,7 @@ export class BackgroundAgentManager {
|
|
|
625
628
|
return { task, created: true };
|
|
626
629
|
}
|
|
627
630
|
resolveOptional(identifier) {
|
|
628
|
-
if (
|
|
631
|
+
if (isNativeAgentId(identifier))
|
|
629
632
|
return identifier;
|
|
630
633
|
return this.names.get(identifier);
|
|
631
634
|
}
|
|
@@ -669,7 +672,7 @@ export class BackgroundAgentManager {
|
|
|
669
672
|
}
|
|
670
673
|
resolveRequired(identifier) {
|
|
671
674
|
const resolved = this.resolveOptional(identifier);
|
|
672
|
-
if (!
|
|
675
|
+
if (!isNativeAgentId(identifier) &&
|
|
673
676
|
!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/u.test(identifier)) {
|
|
674
677
|
assertAgentId(identifier);
|
|
675
678
|
}
|
|
@@ -32,8 +32,8 @@ export interface BackgroundBashToolResult {
|
|
|
32
32
|
task?: Record<string, unknown>;
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
-
export declare function
|
|
36
|
-
export declare function
|
|
35
|
+
export declare function nativeBackgroundTaskParent(cwd: string): string;
|
|
36
|
+
export declare function nativeBackgroundTaskRoot(cwd: string, sessionId: string): string;
|
|
37
37
|
export declare class BackgroundBashManager {
|
|
38
38
|
private readonly options;
|
|
39
39
|
private readonly tasks;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
|
-
import {
|
|
3
|
+
import { sanitizeProjectPath } from '../platform/project-path-key.js';
|
|
4
4
|
import { writeFileAtomically } from '../platform/atomic-write.js';
|
|
5
5
|
import { BoundedProcessRunner, } from '../platform/bounded-process-runner.js';
|
|
6
6
|
import { commandShell, commandShellArguments, } from '../platform/command-shell.js';
|
|
7
7
|
import { assertBackgroundBashTaskId, backgroundBashTaskIdFromStateFile, createBackgroundBashTaskId, } from './background-task-id.js';
|
|
8
|
-
export function
|
|
8
|
+
export function nativeBackgroundTaskParent(cwd) {
|
|
9
9
|
const uid = process.getuid?.() ?? 'unknown';
|
|
10
|
-
return resolve('/tmp', `
|
|
10
|
+
return resolve('/tmp', `praxis-${uid}`, sanitizeProjectPath(resolve(cwd)));
|
|
11
11
|
}
|
|
12
|
-
export function
|
|
13
|
-
return resolve(
|
|
12
|
+
export function nativeBackgroundTaskRoot(cwd, sessionId) {
|
|
13
|
+
return resolve(nativeBackgroundTaskParent(cwd), sessionId, 'tasks');
|
|
14
14
|
}
|
|
15
15
|
function parsePersistedTask(source, taskId, outputFile) {
|
|
16
16
|
let value;
|
|
@@ -65,7 +65,7 @@ export class BackgroundBashManager {
|
|
|
65
65
|
cwd: options.cwd,
|
|
66
66
|
maxOutputBytes: options.maxOutputBytes ?? 128 * 1024,
|
|
67
67
|
});
|
|
68
|
-
this.outputRoot =
|
|
68
|
+
this.outputRoot = nativeBackgroundTaskRoot(options.cwd, options.sessionId);
|
|
69
69
|
this.sessionStateRoot = resolve(options.stateRoot, options.sessionId);
|
|
70
70
|
}
|
|
71
71
|
has(taskId) {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { lstat, readFile, readdir, realpath, rm } from 'node:fs/promises';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep, } from 'node:path';
|
|
4
|
-
import {
|
|
5
|
-
import { resolveClaudeProjectIdentity } from '../compatibility/claude/shared-resources.js';
|
|
4
|
+
import { isSessionId } from '../core/session.js';
|
|
6
5
|
import { writeFileAtomically } from '../platform/atomic-write.js';
|
|
6
|
+
import { resolveProjectIdentity } from '../platform/project-identity.js';
|
|
7
|
+
import { sanitizeProjectPath } from '../platform/project-path-key.js';
|
|
7
8
|
const MAX_ATOMIC_UPDATE_RETRIES = 8;
|
|
8
9
|
function errorCode(error) {
|
|
9
10
|
return error.code;
|
|
@@ -182,17 +183,17 @@ async function discoverSessionIds(projectRoot) {
|
|
|
182
183
|
for (const entry of entries) {
|
|
183
184
|
if (entry.isFile() && entry.name.endsWith('.jsonl')) {
|
|
184
185
|
const sessionId = entry.name.slice(0, -'.jsonl'.length);
|
|
185
|
-
if (
|
|
186
|
+
if (isSessionId(sessionId))
|
|
186
187
|
sessionIds.add(sessionId);
|
|
187
188
|
}
|
|
188
|
-
if (entry.isDirectory() &&
|
|
189
|
+
if (entry.isDirectory() && isSessionId(entry.name)) {
|
|
189
190
|
sessionIds.add(entry.name);
|
|
190
191
|
}
|
|
191
192
|
}
|
|
192
193
|
return [...sessionIds].sort();
|
|
193
194
|
}
|
|
194
|
-
async function discoverProjectRoots(configRoot, targetPaths
|
|
195
|
-
const projectsRoot = join(configRoot,
|
|
195
|
+
async function discoverProjectRoots(configRoot, targetPaths) {
|
|
196
|
+
const projectsRoot = join(configRoot, 'sessions');
|
|
196
197
|
if (!(await pathExists(projectsRoot)))
|
|
197
198
|
return [];
|
|
198
199
|
await assertSafePurgePath(configRoot, projectsRoot);
|
|
@@ -206,8 +207,8 @@ async function discoverProjectRoots(configRoot, targetPaths, dataPlane) {
|
|
|
206
207
|
}
|
|
207
208
|
throw error;
|
|
208
209
|
}
|
|
209
|
-
const targetKeys = targetPaths.map(
|
|
210
|
-
const worktreeSegment =
|
|
210
|
+
const targetKeys = targetPaths.map(sanitizeProjectPath);
|
|
211
|
+
const worktreeSegment = '--praxis-worktrees-';
|
|
211
212
|
return entries
|
|
212
213
|
.filter((entry) => targetKeys.some((targetKey) => entry.name === targetKey ||
|
|
213
214
|
entry.name.startsWith(`${targetKey}${worktreeSegment}`)))
|
|
@@ -231,32 +232,18 @@ async function addExistingPath(items, configRoot, item) {
|
|
|
231
232
|
items.push(item);
|
|
232
233
|
}
|
|
233
234
|
export async function planClaudeProjectPurge(options) {
|
|
235
|
+
void options.dataPlane;
|
|
234
236
|
if (options.all && options.path !== undefined) {
|
|
235
237
|
throw new Error('Cannot specify both a path and --all');
|
|
236
238
|
}
|
|
237
239
|
const configuredRoot = options.configRoot ??
|
|
238
|
-
(process.env.
|
|
240
|
+
(process.env.PRAXIS_HOME || join(homedir(), '.praxis'));
|
|
239
241
|
const configRoot = await canonicalPath(configuredRoot);
|
|
240
|
-
const
|
|
241
|
-
const homeDirectory = options.homeDirectory ?? homedir();
|
|
242
|
-
const legacyClaudeStatePath = resolve(homeDirectory, '.claude.json');
|
|
243
|
-
const legacyClaudeConfigRoot = await canonicalPath(resolve(homeDirectory, '.claude'));
|
|
244
|
-
const defaultStatePath = dataPlane === 'native'
|
|
245
|
-
? join(configRoot, 'state.json')
|
|
246
|
-
: options.configRoot !== undefined ||
|
|
247
|
-
Boolean(process.env.CLAUDE_CONFIG_DIR)
|
|
248
|
-
? join(configRoot, '.claude.json')
|
|
249
|
-
: legacyClaudeStatePath;
|
|
242
|
+
const defaultStatePath = join(configRoot, 'state.json');
|
|
250
243
|
const statePath = resolve(options.statePath ?? defaultStatePath);
|
|
251
|
-
const usesLegacyDefaultClaudeState = dataPlane === 'claude' &&
|
|
252
|
-
!process.env.CLAUDE_CONFIG_DIR &&
|
|
253
|
-
configRoot === legacyClaudeConfigRoot &&
|
|
254
|
-
statePath === legacyClaudeStatePath;
|
|
255
244
|
const canonicalStateParent = await canonicalPath(dirname(statePath));
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
}
|
|
259
|
-
await assertMutableRegularFile(statePath, usesLegacyDefaultClaudeState ? canonicalStateParent : configRoot);
|
|
245
|
+
assertLexicallyContained(configRoot, join(canonicalStateParent, basename(statePath)));
|
|
246
|
+
await assertMutableRegularFile(statePath, configRoot);
|
|
260
247
|
const state = parseState(await readOptionalFile(statePath), statePath);
|
|
261
248
|
const projects = stateProjects(state);
|
|
262
249
|
const items = [];
|
|
@@ -264,30 +251,22 @@ export async function planClaudeProjectPurge(options) {
|
|
|
264
251
|
const roots = [
|
|
265
252
|
{
|
|
266
253
|
kind: 'project',
|
|
267
|
-
name:
|
|
268
|
-
description:
|
|
269
|
-
|
|
270
|
-
|
|
254
|
+
name: 'sessions',
|
|
255
|
+
description: 'all project transcripts',
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
kind: 'memory',
|
|
259
|
+
name: 'memory',
|
|
260
|
+
description: 'all project memory',
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
kind: 'scheduled',
|
|
264
|
+
name: 'scheduled',
|
|
265
|
+
description: 'all project scheduled prompts',
|
|
271
266
|
},
|
|
272
|
-
...(dataPlane === 'native'
|
|
273
|
-
? [
|
|
274
|
-
{
|
|
275
|
-
kind: 'memory',
|
|
276
|
-
name: 'memory',
|
|
277
|
-
description: 'all project memory',
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
kind: 'scheduled',
|
|
281
|
-
name: 'scheduled',
|
|
282
|
-
description: 'all project scheduled prompts',
|
|
283
|
-
},
|
|
284
|
-
]
|
|
285
|
-
: []),
|
|
286
267
|
{
|
|
287
268
|
kind: 'memory',
|
|
288
|
-
name:
|
|
289
|
-
? join('state', 'project-memory')
|
|
290
|
-
: join('praxis', 'project-memory'),
|
|
269
|
+
name: join('state', 'project-memory'),
|
|
291
270
|
description: 'all private Project-memory operational state',
|
|
292
271
|
},
|
|
293
272
|
{
|
|
@@ -330,9 +309,6 @@ export async function planClaudeProjectPurge(options) {
|
|
|
330
309
|
mode: 'all',
|
|
331
310
|
configRoot,
|
|
332
311
|
statePath,
|
|
333
|
-
...(usesLegacyDefaultClaudeState
|
|
334
|
-
? { allowStateOutsideConfigRoot: true }
|
|
335
|
-
: {}),
|
|
336
312
|
projectRootPaths: [],
|
|
337
313
|
sessionIds: [],
|
|
338
314
|
items,
|
|
@@ -341,10 +317,8 @@ export async function planClaudeProjectPurge(options) {
|
|
|
341
317
|
const requestedPath = resolve(options.path ?? options.cwd);
|
|
342
318
|
const targetPath = await canonicalPath(requestedPath);
|
|
343
319
|
const targetPaths = [...new Set([requestedPath, targetPath])];
|
|
344
|
-
const projectIdentity = await
|
|
345
|
-
|
|
346
|
-
});
|
|
347
|
-
const projectRootPaths = await discoverProjectRoots(configRoot, targetPaths, dataPlane);
|
|
320
|
+
const projectIdentity = await resolveProjectIdentity(targetPath);
|
|
321
|
+
const projectRootPaths = await discoverProjectRoots(configRoot, targetPaths);
|
|
348
322
|
const sessionIdSet = new Set();
|
|
349
323
|
for (const projectRoot of projectRootPaths) {
|
|
350
324
|
await assertSafePurgePath(configRoot, projectRoot);
|
|
@@ -359,26 +333,17 @@ export async function planClaudeProjectPurge(options) {
|
|
|
359
333
|
await addExistingPath(items, configRoot, removePathItem('file-history', join(configRoot, 'file-history', sessionId), `file edit history for session ${sessionId}`));
|
|
360
334
|
}
|
|
361
335
|
const projectKeys = new Set([
|
|
362
|
-
...targetPaths.map(
|
|
336
|
+
...targetPaths.map(sanitizeProjectPath),
|
|
363
337
|
...projectRootPaths.map((path) => basename(path)),
|
|
364
|
-
|
|
338
|
+
sanitizeProjectPath(projectIdentity),
|
|
365
339
|
]);
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
await addExistingPath(items, configRoot, removePathItem('scheduled', join(configRoot, 'scheduled', `${projectKey}.json`), `scheduled prompts for project ${projectKey}`));
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
for (const projectKey of projectKeys) {
|
|
375
|
-
await addExistingPath(items, configRoot, removePathItem('memory', join(configRoot, 'praxis', 'project-memory', projectKey), `private Project-memory state for project ${projectKey}`));
|
|
376
|
-
}
|
|
340
|
+
for (const projectKey of projectKeys) {
|
|
341
|
+
await addExistingPath(items, configRoot, removePathItem('memory', join(configRoot, 'memory', projectKey), `memory for project ${projectKey}`));
|
|
342
|
+
await addExistingPath(items, configRoot, removePathItem('memory', join(configRoot, 'state', 'project-memory', projectKey), `private Project-memory state for project ${projectKey}`));
|
|
343
|
+
await addExistingPath(items, configRoot, removePathItem('scheduled', join(configRoot, 'scheduled', `${projectKey}.json`), `scheduled prompts for project ${projectKey}`));
|
|
377
344
|
}
|
|
378
345
|
for (const projectRoot of projectRootPaths) {
|
|
379
|
-
await addExistingPath(items, configRoot, removePathItem('project', projectRoot,
|
|
380
|
-
? 'project transcripts'
|
|
381
|
-
: 'project transcripts and memory'));
|
|
346
|
+
await addExistingPath(items, configRoot, removePathItem('project', projectRoot, 'project transcripts'));
|
|
382
347
|
}
|
|
383
348
|
const historyPath = join(configRoot, 'history.jsonl');
|
|
384
349
|
const historyExists = await pathExists(historyPath);
|
|
@@ -420,9 +385,6 @@ export async function planClaudeProjectPurge(options) {
|
|
|
420
385
|
mode: 'project',
|
|
421
386
|
configRoot,
|
|
422
387
|
statePath,
|
|
423
|
-
...(usesLegacyDefaultClaudeState
|
|
424
|
-
? { allowStateOutsideConfigRoot: true }
|
|
425
|
-
: {}),
|
|
426
388
|
targetPath,
|
|
427
389
|
projectIdentity,
|
|
428
390
|
projectRootPaths,
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { ModelMessage, ModelToolCall, ToolExecutionResult } from '../core/runtime.js';
|
|
2
|
-
import type { TranscriptMessagesEvent } from '../core/transcript-event.js';
|
|
3
|
-
import type {
|
|
2
|
+
import type { TranscriptEvent, TranscriptMessagesEvent } from '../core/transcript-event.js';
|
|
3
|
+
import type { NativeTranscriptLease, NativeTranscriptLeaseResult } from '../persistence/native-transcript-store.js';
|
|
4
|
+
/** Minimal transcript-store contract required by the native session facade. */
|
|
5
|
+
export interface NativeSessionTranscriptStore {
|
|
6
|
+
withLease<T>(operation: (lease: NativeTranscriptLease) => Promise<T>): Promise<NativeTranscriptLeaseResult<T>>;
|
|
7
|
+
}
|
|
4
8
|
export type NativeTranscriptActivation = {
|
|
5
9
|
readonly kind: 'start';
|
|
6
10
|
} | {
|
|
@@ -19,6 +23,11 @@ export interface NativeCompactionAppend {
|
|
|
19
23
|
readonly postTokens: number;
|
|
20
24
|
readonly durationMs: number;
|
|
21
25
|
readonly preservedMessages?: readonly ModelMessage[];
|
|
26
|
+
/** Optional parent in the active branch when compacting a selected range. */
|
|
27
|
+
readonly logicalParentId?: string;
|
|
28
|
+
readonly direction?: 'from' | 'up_to';
|
|
29
|
+
readonly messagesSummarized?: number;
|
|
30
|
+
readonly preservePrefix?: boolean;
|
|
22
31
|
}
|
|
23
32
|
export type NativeInterruption = {
|
|
24
33
|
readonly kind: 'complete' | 'none';
|
|
@@ -35,6 +44,8 @@ export type NativeInterruption = {
|
|
|
35
44
|
readonly callIds: readonly string[];
|
|
36
45
|
};
|
|
37
46
|
export interface NativeSessionTranscriptLease {
|
|
47
|
+
/** Events on the currently selected active branch, in parent order. */
|
|
48
|
+
activeEvents(): TranscriptEvent[];
|
|
38
49
|
activeMessages(): ModelMessage[];
|
|
39
50
|
interruption(): NativeInterruption;
|
|
40
51
|
beginToolExecution(callId: string): Promise<void>;
|
|
@@ -56,7 +67,7 @@ export interface NativeForkOptions {
|
|
|
56
67
|
}
|
|
57
68
|
export interface NativeSessionTranscriptOptions {
|
|
58
69
|
readonly sessionId: string;
|
|
59
|
-
readonly store:
|
|
70
|
+
readonly store: NativeSessionTranscriptStore;
|
|
60
71
|
readonly createId?: () => string;
|
|
61
72
|
readonly now?: () => string;
|
|
62
73
|
}
|
|
@@ -83,6 +83,14 @@ export class NativeSessionTranscript {
|
|
|
83
83
|
const initial = prepared;
|
|
84
84
|
const currentId = selectedId ?? initial.records.at(-1)?.event.id ?? null;
|
|
85
85
|
const records = [...initial.records];
|
|
86
|
+
const usedIds = new Set(records.map((record) => record.event.id));
|
|
87
|
+
const createUniqueId = () => {
|
|
88
|
+
let id = this.createId();
|
|
89
|
+
while (usedIds.has(id))
|
|
90
|
+
id = this.createId();
|
|
91
|
+
usedIds.add(id);
|
|
92
|
+
return id;
|
|
93
|
+
};
|
|
86
94
|
let tail = currentId === null
|
|
87
95
|
? initial.tail
|
|
88
96
|
: { ...initial.tail, branchParentId: currentId };
|
|
@@ -94,6 +102,7 @@ export class NativeSessionTranscript {
|
|
|
94
102
|
return result;
|
|
95
103
|
};
|
|
96
104
|
const lease = {
|
|
105
|
+
activeEvents: () => activeEvents(records.map((record) => record.event), activeId ?? undefined).slice(),
|
|
97
106
|
activeMessages: () => projectActiveMessages(records.map((record) => record.event), activeId ?? undefined).slice(),
|
|
98
107
|
interruption: () => {
|
|
99
108
|
const events = activeEvents(records.map((record) => record.event), activeId ?? undefined);
|
|
@@ -166,7 +175,7 @@ export class NativeSessionTranscript {
|
|
|
166
175
|
throw new Error(`Native tool call already claimed: ${callId}`);
|
|
167
176
|
const event = {
|
|
168
177
|
kind: 'tool-execution-started',
|
|
169
|
-
id:
|
|
178
|
+
id: createUniqueId(),
|
|
170
179
|
parentId: activeId,
|
|
171
180
|
sessionId: this.sessionId,
|
|
172
181
|
timestamp: this.now(),
|
|
@@ -196,7 +205,7 @@ export class NativeSessionTranscript {
|
|
|
196
205
|
throw new Error(`Native tool call is already resolved: ${callId}`);
|
|
197
206
|
const event = {
|
|
198
207
|
kind: 'messages',
|
|
199
|
-
id:
|
|
208
|
+
id: createUniqueId(),
|
|
200
209
|
parentId: activeId,
|
|
201
210
|
sessionId: this.sessionId,
|
|
202
211
|
timestamp: this.now(),
|
|
@@ -232,7 +241,7 @@ export class NativeSessionTranscript {
|
|
|
232
241
|
throw new Error('native transcript cannot append empty messages');
|
|
233
242
|
const event = {
|
|
234
243
|
kind: 'messages',
|
|
235
|
-
id:
|
|
244
|
+
id: createUniqueId(),
|
|
236
245
|
parentId: activeId,
|
|
237
246
|
sessionId: this.sessionId,
|
|
238
247
|
timestamp: this.now(),
|
|
@@ -266,19 +275,28 @@ export class NativeSessionTranscript {
|
|
|
266
275
|
const events = records.map((record) => record.event);
|
|
267
276
|
if (unresolvedActiveToolCallIds(projectActiveMessages(events, activeId)).length > 0)
|
|
268
277
|
throw new Error('Cannot compact a native transcript with unresolved tool calls');
|
|
269
|
-
const boundaryId =
|
|
270
|
-
const summaryId =
|
|
278
|
+
const boundaryId = createUniqueId();
|
|
279
|
+
const summaryId = createUniqueId();
|
|
271
280
|
const boundary = {
|
|
272
281
|
kind: 'context-boundary',
|
|
273
282
|
id: boundaryId,
|
|
274
283
|
parentId: null,
|
|
275
284
|
sessionId: this.sessionId,
|
|
276
285
|
timestamp: this.now(),
|
|
277
|
-
logicalParentId: activeId,
|
|
286
|
+
logicalParentId: input.logicalParentId ?? activeId,
|
|
278
287
|
trigger: input.trigger,
|
|
279
288
|
preTokens: input.preTokens,
|
|
280
289
|
postTokens: input.postTokens,
|
|
281
290
|
durationMs: input.durationMs,
|
|
291
|
+
...(input.direction === undefined
|
|
292
|
+
? {}
|
|
293
|
+
: { direction: input.direction }),
|
|
294
|
+
...(input.messagesSummarized === undefined
|
|
295
|
+
? {}
|
|
296
|
+
: { messagesSummarized: input.messagesSummarized }),
|
|
297
|
+
...(input.preservePrefix === undefined
|
|
298
|
+
? {}
|
|
299
|
+
: { preservePrefix: input.preservePrefix }),
|
|
282
300
|
};
|
|
283
301
|
const summary = {
|
|
284
302
|
kind: 'context-summary',
|
|
@@ -294,9 +312,12 @@ export class NativeSessionTranscript {
|
|
|
294
312
|
if (message.role !== 'assistant')
|
|
295
313
|
continue;
|
|
296
314
|
for (const call of message.toolCalls ?? [])
|
|
297
|
-
replayToolCallIds.set(call.id,
|
|
315
|
+
replayToolCallIds.set(call.id, createUniqueId());
|
|
298
316
|
}
|
|
299
|
-
const replaySuffix = suffix
|
|
317
|
+
const replaySuffix = suffix
|
|
318
|
+
.filter((message) => message.role !== 'tool' ||
|
|
319
|
+
replayToolCallIds.has(message.toolCallId))
|
|
320
|
+
.map((message) => {
|
|
300
321
|
if (message.role === 'assistant')
|
|
301
322
|
return {
|
|
302
323
|
...message,
|
|
@@ -320,7 +341,7 @@ export class NativeSessionTranscript {
|
|
|
320
341
|
const suffixEvent = replaySuffix.length
|
|
321
342
|
? {
|
|
322
343
|
kind: 'messages',
|
|
323
|
-
id:
|
|
344
|
+
id: createUniqueId(),
|
|
324
345
|
parentId: summaryId,
|
|
325
346
|
sessionId: this.sessionId,
|
|
326
347
|
timestamp: this.now(),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type NativeScheduledTask } from '../persistence/native-scheduled-task-store.js';
|
|
2
2
|
export declare const MAX_JOBS = 50;
|
|
3
3
|
export declare class ScheduledJobLimitError extends Error {
|
|
4
4
|
readonly maxJobs: number;
|
|
@@ -24,7 +24,7 @@ export interface ScheduledPrompt {
|
|
|
24
24
|
id: string;
|
|
25
25
|
prompt: string;
|
|
26
26
|
}
|
|
27
|
-
export interface ListedScheduledPrompt extends
|
|
27
|
+
export interface ListedScheduledPrompt extends NativeScheduledTask {
|
|
28
28
|
durable: boolean;
|
|
29
29
|
}
|
|
30
30
|
export interface DynamicWakeupResult {
|
|
@@ -2,7 +2,7 @@ import { execFile } from 'node:child_process';
|
|
|
2
2
|
import { randomBytes } from 'node:crypto';
|
|
3
3
|
import { promisify } from 'node:util';
|
|
4
4
|
import { CronExpressionParser } from 'cron-parser';
|
|
5
|
-
import {
|
|
5
|
+
import { NativeScheduledTaskLimitError, NativeScheduledTaskStore, } from '../persistence/native-scheduled-task-store.js';
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
7
|
const RECURRING_LIFETIME_MS = 7 * 24 * 60 * 60 * 1_000;
|
|
8
8
|
const MIN_DYNAMIC_WAKEUP_SECONDS = 60;
|
|
@@ -111,7 +111,7 @@ export class ScheduledPromptManager {
|
|
|
111
111
|
initialization;
|
|
112
112
|
closed = false;
|
|
113
113
|
constructor(options) {
|
|
114
|
-
this.store = new
|
|
114
|
+
this.store = new NativeScheduledTaskStore({
|
|
115
115
|
filePath: options.filePath,
|
|
116
116
|
lockFile: options.lockFile,
|
|
117
117
|
});
|
|
@@ -145,7 +145,7 @@ export class ScheduledPromptManager {
|
|
|
145
145
|
task = await this.store.create(base, { maxJobs: MAX_JOBS });
|
|
146
146
|
}
|
|
147
147
|
catch (error) {
|
|
148
|
-
if (error instanceof
|
|
148
|
+
if (error instanceof NativeScheduledTaskLimitError) {
|
|
149
149
|
throw new ScheduledJobLimitError(MAX_JOBS);
|
|
150
150
|
}
|
|
151
151
|
throw error;
|