@xingular/harness 1.0.0 → 1.2.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/CHANGELOG.md +46 -5
- package/README.md +75 -21
- package/dist/cli.js +17421 -8711
- package/dist/sdk/accounts/accounts.d.ts +27 -3
- package/dist/sdk/accounts/accounts.js +78 -24
- package/dist/sdk/accounts/secrets.d.ts +12 -0
- package/dist/sdk/accounts/secrets.js +114 -7
- package/dist/sdk/accounts/store.d.ts +26 -1
- package/dist/sdk/accounts/store.js +1 -1
- package/dist/sdk/agents/builtin.d.ts +2 -0
- package/dist/sdk/agents/builtin.js +48 -0
- package/dist/sdk/agents/narrow.d.ts +13 -0
- package/dist/sdk/agents/narrow.js +29 -0
- package/dist/sdk/agents/planResearch.d.ts +5 -0
- package/dist/sdk/agents/planResearch.js +19 -0
- package/dist/sdk/agents/profiles.d.ts +81 -0
- package/dist/sdk/agents/profiles.js +226 -0
- package/dist/sdk/annotations/bridge.d.ts +42 -0
- package/dist/sdk/annotations/bridge.js +264 -0
- package/dist/sdk/annotations/capture.d.ts +116 -0
- package/dist/sdk/annotations/capture.js +308 -0
- package/dist/sdk/annotations/delivery.d.ts +72 -0
- package/dist/sdk/annotations/delivery.js +130 -0
- package/dist/sdk/annotations/inspect.d.ts +10 -0
- package/dist/sdk/annotations/inspect.js +33 -0
- package/dist/sdk/annotations/isolated.d.ts +6 -0
- package/dist/sdk/annotations/isolated.js +51 -0
- package/dist/sdk/annotations/pageScript.d.ts +28 -0
- package/dist/sdk/annotations/pageScript.js +871 -0
- package/dist/sdk/annotations/part.d.ts +10 -0
- package/dist/sdk/annotations/part.js +155 -0
- package/dist/sdk/annotations/queue.d.ts +4 -0
- package/dist/sdk/annotations/queue.js +40 -0
- package/dist/sdk/annotations/serverMethods.d.ts +3 -0
- package/dist/sdk/annotations/serverMethods.js +62 -0
- package/dist/sdk/annotations/store.d.ts +167 -0
- package/dist/sdk/annotations/store.js +394 -0
- package/dist/sdk/browser/backend.d.ts +16 -0
- package/dist/sdk/browser/backend.js +17 -0
- package/dist/sdk/browser/contracts.d.ts +19 -0
- package/dist/sdk/browser/contracts.js +116 -0
- package/dist/sdk/browser/index.d.ts +14 -3
- package/dist/sdk/browser/index.js +11 -4
- package/dist/sdk/browser/serverMethods.d.ts +3 -0
- package/dist/sdk/browser/serverMethods.js +7 -0
- package/dist/sdk/browser/session.d.ts +1 -0
- package/dist/sdk/browser/session.js +45 -9
- package/dist/sdk/browser/tools.d.ts +1 -4
- package/dist/sdk/browser/tools.js +14 -91
- package/dist/sdk/cli.js +24 -15
- package/dist/sdk/commands/list.d.ts +3 -0
- package/dist/sdk/commands/list.js +75 -0
- package/dist/sdk/commands/registry.d.ts +250 -0
- package/dist/sdk/commands/registry.js +47 -0
- package/dist/sdk/commands/routes.d.ts +16 -0
- package/dist/sdk/commands/routes.js +33 -0
- package/dist/sdk/core/bus.js +1 -1
- package/dist/sdk/core/commandBudget.d.ts +23 -0
- package/dist/sdk/core/commandBudget.js +57 -0
- package/dist/sdk/core/env.d.ts +1 -1
- package/dist/sdk/core/env.js +1 -1
- package/dist/sdk/core/index.js +17 -1
- package/dist/sdk/core/interactiveProfile.d.ts +46 -0
- package/dist/sdk/core/interactiveProfile.js +143 -0
- package/dist/sdk/core/workspace.d.ts +13 -0
- package/dist/sdk/core/workspace.js +88 -0
- package/dist/sdk/core/workspaceBashTool.d.ts +4 -0
- package/dist/sdk/core/workspaceBashTool.js +36 -0
- package/dist/sdk/core/workspaceSandbox.d.ts +31 -0
- package/dist/sdk/core/workspaceSandbox.js +320 -0
- package/dist/sdk/core/workspaceWriteOperations.d.ts +22 -0
- package/dist/sdk/core/workspaceWriteOperations.js +206 -0
- package/dist/sdk/doctor/serverMethods.d.ts +3 -0
- package/dist/sdk/doctor/serverMethods.js +8 -0
- package/dist/sdk/doctor/types.d.ts +2 -2
- package/dist/sdk/harness.d.ts +22 -0
- package/dist/sdk/harness.js +84 -5
- package/dist/sdk/history/recall.js +8 -8
- package/dist/sdk/history/serverMethods.d.ts +3 -0
- package/dist/sdk/history/serverMethods.js +8 -0
- package/dist/sdk/hub/cli.d.ts +1 -1
- package/dist/sdk/hub/cli.js +1 -1
- package/dist/sdk/hub/schema.d.ts +1 -1
- package/dist/sdk/hub/serverMethods.d.ts +3 -0
- package/dist/sdk/hub/serverMethods.js +11 -0
- package/dist/sdk/index.d.ts +16 -1
- package/dist/sdk/index.js +10 -0
- package/dist/sdk/mcp/connections.js +14 -7
- package/dist/sdk/mcp/serverMethods.d.ts +3 -0
- package/dist/sdk/mcp/serverMethods.js +22 -0
- package/dist/sdk/pi/runtime.d.ts +2 -1
- package/dist/sdk/pi/runtime.js +2 -2
- package/dist/sdk/plugins/builtin.d.ts +1 -0
- package/dist/sdk/plugins/builtin.js +145 -33
- package/dist/sdk/plugins/builtinRegistry.d.ts +60 -0
- package/dist/sdk/plugins/builtinRegistry.js +71 -0
- package/dist/sdk/plugins/catalogue.js +2 -1
- package/dist/sdk/plugins/cli.d.ts +1 -1
- package/dist/sdk/plugins/cli.js +4 -3
- package/dist/sdk/plugins/commandPrefix.d.ts +8 -0
- package/dist/sdk/plugins/commandPrefix.js +21 -0
- package/dist/sdk/plugins/firstParty.d.ts +1 -1
- package/dist/sdk/plugins/firstParty.js +8 -2
- package/dist/sdk/plugins/inventory.js +4 -3
- package/dist/sdk/plugins/manifest.d.ts +2 -0
- package/dist/sdk/plugins/manifest.js +2 -1
- package/dist/sdk/plugins/surfaces.d.ts +5 -0
- package/dist/sdk/plugins/surfaces.js +11 -0
- package/dist/sdk/plugins/types.d.ts +15 -0
- package/dist/sdk/prompt/compile.d.ts +19 -2
- package/dist/sdk/prompt/compile.js +79 -26
- package/dist/sdk/prompt/standard.d.ts +17 -0
- package/dist/sdk/prompt/standard.js +21 -0
- package/dist/sdk/refine/cli.d.ts +1 -1
- package/dist/sdk/refine/cli.js +2 -2
- package/dist/sdk/refine/serverMethods.d.ts +3 -0
- package/dist/sdk/refine/serverMethods.js +20 -0
- package/dist/sdk/server/methods.js +27 -86
- package/dist/sdk/server/params.d.ts +4 -0
- package/dist/sdk/server/params.js +11 -0
- package/dist/sdk/server/remote.js +36 -11
- package/dist/sdk/sessions/compactionCheckpoint.d.ts +11 -0
- package/dist/sdk/sessions/compactionCheckpoint.js +79 -0
- package/dist/sdk/sessions/continuation.d.ts +3 -0
- package/dist/sdk/sessions/continuation.js +5 -1
- package/dist/sdk/sessions/contracts.d.ts +185 -0
- package/dist/sdk/sessions/contracts.js +101 -4
- package/dist/sdk/sessions/control.d.ts +72 -0
- package/dist/sdk/sessions/control.js +158 -0
- package/dist/sdk/sessions/initialBash.d.ts +7 -0
- package/dist/sdk/sessions/initialBash.js +7 -0
- package/dist/sdk/sessions/planMode.d.ts +18 -4
- package/dist/sdk/sessions/planMode.js +82 -16
- package/dist/sdk/sessions/reasoningSummaries.d.ts +2 -2
- package/dist/sdk/sessions/reasoningSummaries.js +3 -3
- package/dist/sdk/sessions/registry.d.ts +2 -1
- package/dist/sdk/sessions/registry.js +6 -3
- package/dist/sdk/sessions/runIndex.js +7 -7
- package/dist/sdk/sessions/runStore.d.ts +14 -0
- package/dist/sdk/sessions/runStore.js +38 -1
- package/dist/sdk/sessions/runner.d.ts +40 -2
- package/dist/sdk/sessions/runner.js +163 -15
- package/dist/sdk/sessions/sessions.d.ts +40 -8
- package/dist/sdk/sessions/sessions.js +279 -27
- package/dist/sdk/sessions/sideQuestionServerMethods.d.ts +3 -0
- package/dist/sdk/sessions/sideQuestionServerMethods.js +19 -0
- package/dist/sdk/sessions/sideQuestions.d.ts +66 -0
- package/dist/sdk/sessions/sideQuestions.js +290 -0
- package/dist/sdk/sessions/subagentServerMethods.d.ts +3 -0
- package/dist/sdk/sessions/subagentServerMethods.js +41 -0
- package/dist/sdk/sessions/subagentService.d.ts +22 -2
- package/dist/sdk/sessions/subagentService.js +93 -16
- package/dist/sdk/sessions/subagents.d.ts +9 -1
- package/dist/sdk/sessions/subagents.js +19 -0
- package/dist/sdk/sessions/workSlice.d.ts +103 -0
- package/dist/sdk/sessions/workSlice.js +297 -0
- package/dist/sdk/sessions/workspaceBoundary.d.ts +15 -0
- package/dist/sdk/sessions/workspaceBoundary.js +46 -0
- package/dist/sdk/terminal/browser.d.ts +62 -0
- package/dist/sdk/terminal/browser.js +41 -0
- package/dist/sdk/terminal/browserControl.d.ts +29 -0
- package/dist/sdk/terminal/browserControl.js +187 -0
- package/dist/sdk/terminal/commandHelp.d.ts +17 -0
- package/dist/sdk/terminal/commandHelp.js +20 -0
- package/dist/sdk/terminal/controller.d.ts +15 -1
- package/dist/sdk/terminal/controller.js +67 -8
- package/dist/sdk/terminal/opentui/subagentsWidget.d.ts +28 -0
- package/dist/sdk/terminal/opentui/subagentsWidget.js +52 -0
- package/dist/sdk/terminal/opentui/theme.d.ts +43 -0
- package/dist/sdk/terminal/opentui/theme.js +87 -0
- package/dist/sdk/terminal/piExtension.d.ts +6 -1
- package/dist/sdk/terminal/piExtension.js +169 -84
- package/dist/sdk/terminal/socket.d.ts +6 -3
- package/dist/sdk/terminal/socket.js +40 -9
- package/dist/sdk/terminal/standalone.d.ts +9 -0
- package/dist/sdk/terminal/standalone.js +118 -19
- package/dist/sdk/terminal/subagentMonitor.d.ts +47 -0
- package/dist/sdk/terminal/subagentMonitor.js +152 -0
- package/dist/sdk/terminal/terminals.d.ts +60 -7
- package/dist/sdk/terminal/terminals.js +598 -47
- package/dist/sdk/terminal/trajectory.js +2 -2
- package/dist/sdk/terminal/tui/annotateCommand.d.ts +3 -0
- package/dist/sdk/terminal/tui/annotateCommand.js +22 -0
- package/dist/sdk/terminal/tui/commandPages.d.ts +7 -1
- package/dist/sdk/terminal/tui/commandPages.js +57 -6
- package/dist/sdk/terminal/tui/commands.d.ts +10 -4
- package/dist/sdk/terminal/tui/commands.js +269 -65
- package/dist/sdk/terminal/tui/dialogGeometry.d.ts +2 -2
- package/dist/sdk/terminal/tui/dialogGeometry.js +4 -2
- package/dist/sdk/terminal/tui/dialogs.d.ts +6 -1
- package/dist/sdk/terminal/tui/dialogs.js +9 -2
- package/dist/sdk/terminal/tui/list.d.ts +14 -1
- package/dist/sdk/terminal/tui/list.js +96 -14
- package/dist/sdk/terminal/tui/modelPicker.js +1 -6
- package/dist/sdk/terminal/tui/page.d.ts +3 -0
- package/dist/sdk/terminal/tui/pageOverlay.js +27 -7
- package/dist/sdk/terminal/tui/pages/accountsPage.d.ts +26 -4
- package/dist/sdk/terminal/tui/pages/accountsPage.js +264 -36
- package/dist/sdk/terminal/tui/pages/agentsPage.d.ts +74 -0
- package/dist/sdk/terminal/tui/pages/agentsPage.js +190 -0
- package/dist/sdk/terminal/tui/pages/annotatePage.d.ts +94 -0
- package/dist/sdk/terminal/tui/pages/annotatePage.js +341 -0
- package/dist/sdk/terminal/tui/pages/browserPage.d.ts +87 -0
- package/dist/sdk/terminal/tui/pages/browserPage.js +738 -0
- package/dist/sdk/terminal/tui/pages/doctorPage.d.ts +2 -0
- package/dist/sdk/terminal/tui/pages/doctorPage.js +103 -15
- package/dist/sdk/terminal/tui/pages/notesPage.d.ts +75 -0
- package/dist/sdk/terminal/tui/pages/notesPage.js +201 -0
- package/dist/sdk/terminal/tui/pages/pluginsPage.d.ts +0 -5
- package/dist/sdk/terminal/tui/pages/pluginsPage.js +9 -3
- package/dist/sdk/terminal/tui/pages/settingsPage.d.ts +8 -0
- package/dist/sdk/terminal/tui/pages/settingsPage.js +16 -1
- package/dist/sdk/terminal/tui/pages/subagentsPage.d.ts +24 -0
- package/dist/sdk/terminal/tui/pages/subagentsPage.js +152 -0
- package/dist/sdk/terminal/tui/pages/trajectoryPage.d.ts +12 -5
- package/dist/sdk/terminal/tui/pages/trajectoryPage.js +156 -83
- package/dist/sdk/terminal/tui/pages/usagePage.d.ts +43 -0
- package/dist/sdk/terminal/tui/pages/usagePage.js +370 -0
- package/dist/sdk/terminal/tui/pages/worktreesPage.d.ts +72 -0
- package/dist/sdk/terminal/tui/pages/worktreesPage.js +203 -0
- package/dist/sdk/terminal/tui/piAdapter.d.ts +1 -2
- package/dist/sdk/terminal/tui/piAdapter.js +3 -5
- package/dist/sdk/terminal/tui/planMode.d.ts +1 -1
- package/dist/sdk/terminal/tui/planMode.js +1 -1
- package/dist/sdk/terminal/tui/pluginCommands.d.ts +16 -0
- package/dist/sdk/terminal/tui/pluginCommands.js +31 -0
- package/dist/sdk/terminal/tui/questions.d.ts +2 -0
- package/dist/sdk/terminal/tui/runtime.js +27 -5
- package/dist/sdk/terminal/tui/sessionPicker.d.ts +40 -0
- package/dist/sdk/terminal/tui/sessionPicker.js +141 -0
- package/dist/sdk/terminal/tui/settingsModel.d.ts +2 -0
- package/dist/sdk/terminal/tui/settingsModel.js +32 -2
- package/dist/sdk/terminal/tui/sideQuestion.d.ts +26 -26
- package/dist/sdk/terminal/tui/sideQuestion.js +131 -98
- package/dist/sdk/terminal/tui/ui.d.ts +2 -0
- package/dist/sdk/terminal/tui/ui.js +1 -0
- package/dist/sdk/tools/askUser.js +26 -8
- package/dist/sdk/tools/checklist.js +3 -2
- package/dist/sdk/tools/checkpoint.d.ts +27 -0
- package/dist/sdk/tools/checkpoint.js +154 -0
- package/dist/sdk/tools/getCapabilities.d.ts +31 -0
- package/dist/sdk/tools/getCapabilities.js +34 -0
- package/dist/sdk/tools/harnessTools.d.ts +2 -0
- package/dist/sdk/tools/harnessTools.js +1 -1
- package/dist/sdk/tools/spawnSubagent.js +14 -4
- package/dist/sdk/usage/analytics.d.ts +20 -0
- package/dist/sdk/usage/analytics.js +151 -0
- package/dist/sdk/usage/ledger.d.ts +38 -0
- package/dist/sdk/usage/ledger.js +142 -0
- package/dist/sdk/usage/limits/adapters.d.ts +11 -0
- package/dist/sdk/usage/limits/adapters.js +349 -0
- package/dist/sdk/usage/limits/capture.d.ts +8 -0
- package/dist/sdk/usage/limits/capture.js +47 -0
- package/dist/sdk/usage/limits/http.d.ts +12 -0
- package/dist/sdk/usage/limits/http.js +51 -0
- package/dist/sdk/usage/limits/normalize.d.ts +15 -0
- package/dist/sdk/usage/limits/normalize.js +211 -0
- package/dist/sdk/usage/limits/service.d.ts +30 -0
- package/dist/sdk/usage/limits/service.js +176 -0
- package/dist/sdk/usage/limits/types.d.ts +65 -0
- package/dist/sdk/usage/limits/types.js +1 -0
- package/dist/sdk/usage/serverMethods.d.ts +3 -0
- package/dist/sdk/usage/serverMethods.js +22 -0
- package/dist/sdk/usage/service.d.ts +32 -0
- package/dist/sdk/usage/service.js +66 -0
- package/dist/sdk/usage/settings.d.ts +7 -0
- package/dist/sdk/usage/settings.js +28 -0
- package/dist/sdk/usage/types.d.ts +60 -0
- package/dist/sdk/usage/types.js +4 -0
- package/dist/sdk/web/part.d.ts +10 -0
- package/dist/sdk/web/part.js +6 -0
- package/dist/sdk/web/serverMethods.d.ts +3 -0
- package/dist/sdk/web/serverMethods.js +7 -0
- package/dist/sdk/wiki/serverMethods.d.ts +3 -0
- package/dist/sdk/wiki/serverMethods.js +26 -0
- package/dist/sdk/worktrees/cli.d.ts +11 -0
- package/dist/sdk/worktrees/cli.js +146 -0
- package/dist/sdk/worktrees/copy.d.ts +9 -0
- package/dist/sdk/worktrees/copy.js +111 -0
- package/dist/sdk/worktrees/git.d.ts +16 -0
- package/dist/sdk/worktrees/git.js +81 -0
- package/dist/sdk/worktrees/serverMethods.d.ts +3 -0
- package/dist/sdk/worktrees/serverMethods.js +30 -0
- package/dist/sdk/worktrees/service.d.ts +73 -0
- package/dist/sdk/worktrees/service.js +483 -0
- package/dist/sdk/worktrees/setup.d.ts +23 -0
- package/dist/sdk/worktrees/setup.js +65 -0
- package/dist/sdk/worktrees/types.d.ts +91 -0
- package/dist/sdk/worktrees/types.js +1 -0
- package/dist/sdk/world/cli.d.ts +2 -2
- package/dist/sdk/world/cli.js +6 -6
- package/dist/sdk/world/world.d.ts +3 -1
- package/dist/sdk/world/world.js +8 -9
- package/dist/terminal-opentui.js +16456 -5966
- package/dist/terminal-pi.js +1579 -573
- package/docs/README.md +22 -2
- package/docs/architecture/00-overview.md +28 -16
- package/docs/architecture/02-sessions-and-runs.md +184 -25
- package/docs/architecture/03-variants.md +10 -2
- package/docs/architecture/04-prompt.md +65 -7
- package/docs/architecture/06-plugins-and-capabilities.md +57 -4
- package/docs/architecture/07-tools-and-gate.md +112 -17
- package/docs/architecture/08-memory-and-history.md +4 -2
- package/docs/architecture/09-accounts-and-connectors.md +39 -1
- package/docs/architecture/10-server-protocol.md +168 -4
- package/docs/architecture/11-terminal.md +251 -8
- package/docs/architecture/12-storage.md +45 -3
- package/docs/architecture/13-world-tools.md +49 -6
- package/docs/architecture/14-surfaces-and-parity.md +136 -0
- package/docs/architecture/README.md +17 -4
- package/docs/architecture/proposals/PROP-0006-run-checklist.md +4 -2
- package/docs/architecture/proposals/PROP-0013-resource-browser.md +58 -0
- package/docs/architecture/proposals/PROP-0014-fullscreen-browser-tabs.md +58 -0
- package/docs/architecture/proposals/PROP-0015-one-capability-surface.md +88 -0
- package/docs/architecture/proposals/PROP-0016-managed-worktrees.md +156 -0
- package/docs/architecture/proposals/PROP-0017-page-annotations.md +131 -0
- package/docs/architecture/proposals/PROP-0018-annotation-queue-and-app-targets.md +179 -0
- package/docs/architecture/proposals/PROP-0019-contextual-side-questions.md +122 -0
- package/docs/architecture/proposals/PROP-0020-builtin-feature-plugins.md +105 -0
- package/docs/architecture/proposals/PROP-0021-command-namespaces-and-duplicates.md +99 -0
- package/docs/architecture/proposals/PROP-0022-plan-only-questions.md +102 -0
- package/docs/architecture/proposals/PROP-0023-xagent-cli-name.md +61 -0
- package/docs/architecture/proposals/PROP-0024-question-sketch-previews.md +130 -0
- package/docs/architecture/proposals/PROP-0025-contextual-question-wireframes.md +49 -0
- package/docs/architecture/proposals/PROP-0026-connected-sketch-display.md +94 -0
- package/docs/architecture/proposals/PROP-0027-xingular-agent-product-identity.md +60 -0
- package/docs/architecture/proposals/PROP-0028-normalize-question-wireframes.md +55 -0
- package/docs/architecture/proposals/PROP-0029-agent-profiles.md +124 -0
- package/docs/architecture/proposals/PROP-0030-subagent-title.md +86 -0
- package/docs/architecture/proposals/PROP-0031-plugin-command-owner-namespaces.md +54 -0
- package/docs/architecture/proposals/PROP-0032-planning-quality.md +196 -0
- package/docs/architecture/proposals/PROP-0033-compaction-plan-checkpoints.md +75 -0
- package/docs/architecture/proposals/PROP-0034-conversation-fast-mode.md +120 -0
- package/docs/architecture/proposals/PROP-0035-retain-subagent-status.md +47 -0
- package/docs/architecture/proposals/PROP-0036-first-class-harness-commands.md +59 -0
- package/docs/architecture/proposals/PROP-0037-workspace-write-boundary.md +63 -0
- package/docs/architecture/proposals/PROP-0038-annotate-open-shadow-roots.md +73 -0
- package/docs/architecture/proposals/PROP-0039-workspace-boundary-hardening.md +139 -0
- package/docs/architecture/proposals/PROP-0040-one-launch-path.md +87 -0
- package/docs/architecture/proposals/PROP-0041-bounded-work-slices.md +247 -0
- package/docs/architecture/proposals/PROP-0042-usage-and-provider-limits.md +127 -0
- package/docs/architecture/proposals/PROP-0043-read-only-plan-bash.md +74 -0
- package/docs/architecture/proposals/README.md +39 -0
- package/docs/decisions/ADR-0001-owned-terminal.md +1 -1
- package/docs/decisions/ADR-0009-xharness-command.md +6 -5
- package/docs/decisions/ADR-0014-public-release-baseline.md +3 -2
- package/docs/decisions/ADR-0015-resource-browser.md +28 -0
- package/docs/decisions/ADR-0016-fullscreen-browser-tabs.md +31 -0
- package/docs/decisions/ADR-0017-one-capability-surface.md +34 -0
- package/docs/decisions/ADR-0018-builtin-feature-plugins.md +35 -0
- package/docs/decisions/ADR-0019-managed-git-worktrees.md +31 -0
- package/docs/decisions/ADR-0020-page-annotations.md +37 -0
- package/docs/decisions/ADR-0021-required-command-namespaces.md +40 -0
- package/docs/decisions/ADR-0022-plan-only-question-tools.md +34 -0
- package/docs/decisions/ADR-0023-contextual-side-question-runs.md +35 -0
- package/docs/decisions/ADR-0024-xagent-command.md +40 -0
- package/docs/decisions/ADR-0025-question-choice-sketches.md +49 -0
- package/docs/decisions/ADR-0026-contextual-question-wireframes.md +58 -0
- package/docs/decisions/ADR-0027-connected-sketch-display.md +60 -0
- package/docs/decisions/ADR-0028-xingular-agent-product-identity.md +56 -0
- package/docs/decisions/ADR-0029-normalized-question-wireframe-borders.md +33 -0
- package/docs/decisions/ADR-0030-agent-profiles.md +43 -0
- package/docs/decisions/ADR-0031-plugin-command-owner-namespaces.md +37 -0
- package/docs/decisions/ADR-0032-compaction-run-checkpoints.md +33 -0
- package/docs/decisions/ADR-0033-plan-mode-research-delegation.md +47 -0
- package/docs/decisions/ADR-0034-first-class-harness-terminal-commands.md +25 -0
- package/docs/decisions/ADR-0035-one-launch-path.md +40 -0
- package/docs/decisions/ADR-0036-workspace-write-operation-boundary.md +54 -0
- package/docs/decisions/ADR-0037-usage-ledger-and-provider-limits.md +44 -0
- package/docs/decisions/ADR-0038-plan-bash-os-read-only.md +29 -0
- package/docs/doctor.md +10 -4
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime-replication.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/session-runtime.json +420 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-compact.json +376 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-history.json +422 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-question.json +95 -0
- package/docs/experiments/EXP-0003-performance-audit/data/terminal-wide.json +1036 -0
- package/docs/experiments/EXP-0003-performance-audit/plan.md +109 -0
- package/docs/experiments/EXP-0003-performance-audit/results.md +151 -0
- package/docs/features/README.md +26 -0
- package/docs/features/interfaces/README.md +1 -1
- package/docs/future-work.md +48 -0
- package/docs/handoff-2026-10-25-app-parity-and-solo-tabs.md +202 -0
- package/docs/parity.md +134 -0
- package/docs/releases/1.0.0.md +2 -2
- package/docs/releases/1.1.1.md +28 -0
- package/docs/releases/1.2.0.md +49 -0
- package/docs/releases/4.0.0.md +47 -0
- package/docs/releases/README.md +37 -27
- package/docs/study/00-index.md +8 -0
- package/docs/study/STUDY-0003-long-horizon-runs.md +210 -0
- package/docs/study/autonomous-engineering-sources.md +277 -0
- package/docs/study/autonomy-sources.md +147 -0
- package/docs/study/proactive-autonomy.md +408 -0
- package/docs/study/tui-resource-browser.md +78 -0
- package/docs/terminal-tui.md +386 -113
- package/package.json +6 -5
|
@@ -31,6 +31,8 @@ export declare const runEventTypeSchema: z.ZodEnum<{
|
|
|
31
31
|
"reaction.added": "reaction.added";
|
|
32
32
|
"agent.message": "agent.message";
|
|
33
33
|
"checklist.updated": "checklist.updated";
|
|
34
|
+
checkpoint: "checkpoint";
|
|
35
|
+
heartbeat: "heartbeat";
|
|
34
36
|
"artifact.added": "artifact.added";
|
|
35
37
|
"file.changed": "file.changed";
|
|
36
38
|
"usage.updated": "usage.updated";
|
|
@@ -50,10 +52,19 @@ export declare const toolAttachmentRefsSchema: z.ZodArray<z.ZodObject<{
|
|
|
50
52
|
mimeType: z.ZodString;
|
|
51
53
|
}, z.core.$strict>>;
|
|
52
54
|
export type ToolAttachmentRef = z.infer<typeof toolAttachmentRefSchema>;
|
|
55
|
+
export declare const QUESTION_SKETCH_MAX_LINES = 24;
|
|
56
|
+
export declare const QUESTION_SKETCH_MAX_COLUMNS = 80;
|
|
57
|
+
export declare const QUESTION_SKETCH_MAX_LENGTH: number;
|
|
58
|
+
export declare const QUESTION_SKETCH_PATTERN = "^(?:[\\x20-\\x7e]{0,80})(?:\\n[\\x20-\\x7e]{0,80}){0,23}$";
|
|
59
|
+
export declare const questionSketchSchema: z.ZodString;
|
|
60
|
+
export declare function questionSketchError(uiSketch: unknown, options: readonly {
|
|
61
|
+
sketch?: unknown;
|
|
62
|
+
}[]): string | undefined;
|
|
53
63
|
export declare const questionOptionSchema: z.ZodObject<{
|
|
54
64
|
label: z.ZodString;
|
|
55
65
|
description: z.ZodOptional<z.ZodString>;
|
|
56
66
|
recommended: z.ZodOptional<z.ZodBoolean>;
|
|
67
|
+
sketch: z.ZodOptional<z.ZodString>;
|
|
57
68
|
}, z.core.$strip>;
|
|
58
69
|
export type QuestionOption = z.infer<typeof questionOptionSchema>;
|
|
59
70
|
/** One line of the run's checklist. The list has no ids: every update replaces all of it. */
|
|
@@ -67,6 +78,73 @@ export declare const checklistItemSchema: z.ZodObject<{
|
|
|
67
78
|
}, z.core.$strict>;
|
|
68
79
|
export type ChecklistItem = z.infer<typeof checklistItemSchema>;
|
|
69
80
|
export declare const MAX_CHECKLIST_ITEMS = 50;
|
|
81
|
+
export declare const MAX_CHECKPOINT_SUMMARY = 1200;
|
|
82
|
+
export declare const MAX_CHECKPOINT_DONE = 20;
|
|
83
|
+
export declare const MAX_CHECKPOINT_EVIDENCE = 5;
|
|
84
|
+
export declare const MAX_CHECKPOINT_FILES = 20;
|
|
85
|
+
export declare const MAX_CHECKPOINT_CHECKS = 8;
|
|
86
|
+
export declare const MAX_CHECKPOINT_DECISIONS = 8;
|
|
87
|
+
/**
|
|
88
|
+
* The handoff a reply writes when it reaches its work-slice budget. The harness validates and
|
|
89
|
+
* records it; the next slice is told where this one stopped from it (PROP-0041).
|
|
90
|
+
*/
|
|
91
|
+
export declare const checkpointItemSchema: z.ZodObject<{
|
|
92
|
+
item: z.ZodString;
|
|
93
|
+
evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
94
|
+
}, z.core.$strict>;
|
|
95
|
+
export declare const checkpointFileSchema: z.ZodObject<{
|
|
96
|
+
path: z.ZodString;
|
|
97
|
+
why: z.ZodDefault<z.ZodString>;
|
|
98
|
+
}, z.core.$strict>;
|
|
99
|
+
export declare const checkpointCheckSchema: z.ZodObject<{
|
|
100
|
+
command: z.ZodString;
|
|
101
|
+
ok: z.ZodBoolean;
|
|
102
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
103
|
+
}, z.core.$strict>;
|
|
104
|
+
export declare const checkpointDecisionSchema: z.ZodObject<{
|
|
105
|
+
what: z.ZodString;
|
|
106
|
+
why: z.ZodDefault<z.ZodString>;
|
|
107
|
+
}, z.core.$strict>;
|
|
108
|
+
export declare const checkpointReasonSchema: z.ZodEnum<{
|
|
109
|
+
budget: "budget";
|
|
110
|
+
stuck: "stuck";
|
|
111
|
+
"compaction-thrash": "compaction-thrash";
|
|
112
|
+
requested: "requested";
|
|
113
|
+
}>;
|
|
114
|
+
declare const checkpointPayload: z.ZodObject<{
|
|
115
|
+
summary: z.ZodString;
|
|
116
|
+
done: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
117
|
+
item: z.ZodString;
|
|
118
|
+
evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
119
|
+
}, z.core.$strict>>>;
|
|
120
|
+
next: z.ZodDefault<z.ZodString>;
|
|
121
|
+
blocked: z.ZodOptional<z.ZodString>;
|
|
122
|
+
files: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
123
|
+
path: z.ZodString;
|
|
124
|
+
why: z.ZodDefault<z.ZodString>;
|
|
125
|
+
}, z.core.$strict>>>;
|
|
126
|
+
checks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
127
|
+
command: z.ZodString;
|
|
128
|
+
ok: z.ZodBoolean;
|
|
129
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
130
|
+
}, z.core.$strict>>>;
|
|
131
|
+
decisions: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
132
|
+
what: z.ZodString;
|
|
133
|
+
why: z.ZodDefault<z.ZodString>;
|
|
134
|
+
}, z.core.$strict>>>;
|
|
135
|
+
slice: z.ZodNumber;
|
|
136
|
+
reason: z.ZodEnum<{
|
|
137
|
+
budget: "budget";
|
|
138
|
+
stuck: "stuck";
|
|
139
|
+
"compaction-thrash": "compaction-thrash";
|
|
140
|
+
requested: "requested";
|
|
141
|
+
}>;
|
|
142
|
+
}, z.core.$strict>;
|
|
143
|
+
export type Checkpoint = z.infer<typeof checkpointPayload>;
|
|
144
|
+
export type CheckpointItem = z.infer<typeof checkpointItemSchema>;
|
|
145
|
+
export type CheckpointFile = z.infer<typeof checkpointFileSchema>;
|
|
146
|
+
export type CheckpointCheck = z.infer<typeof checkpointCheckSchema>;
|
|
147
|
+
export type CheckpointDecision = z.infer<typeof checkpointDecisionSchema>;
|
|
70
148
|
/** Where a cost figure comes from: Pi reported it, or the tokens were priced at list rates. */
|
|
71
149
|
export declare const costSourceSchema: z.ZodEnum<{
|
|
72
150
|
harness: "harness";
|
|
@@ -148,9 +226,37 @@ export declare const accountLimitSchema: z.ZodObject<{
|
|
|
148
226
|
id: z.ZodString;
|
|
149
227
|
label: z.ZodString;
|
|
150
228
|
usedPercent: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
229
|
+
remainingPercent: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
151
230
|
resetsAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
152
231
|
windowMinutes: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
153
232
|
status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
233
|
+
provider: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
234
|
+
kind: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
235
|
+
error: "error";
|
|
236
|
+
window: "window";
|
|
237
|
+
rate: "rate";
|
|
238
|
+
credit: "credit";
|
|
239
|
+
configured: "configured";
|
|
240
|
+
}>>>;
|
|
241
|
+
unit: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
242
|
+
requests: "requests";
|
|
243
|
+
percent: "percent";
|
|
244
|
+
tokens: "tokens";
|
|
245
|
+
usd: "usd";
|
|
246
|
+
currency: "currency";
|
|
247
|
+
count: "count";
|
|
248
|
+
}>>>;
|
|
249
|
+
used: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
250
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
251
|
+
remaining: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
252
|
+
source: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
253
|
+
error: "error";
|
|
254
|
+
headers: "headers";
|
|
255
|
+
estimate: "estimate";
|
|
256
|
+
provider: "provider";
|
|
257
|
+
}>>>;
|
|
258
|
+
observedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
259
|
+
detail: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
154
260
|
}, z.core.$strip>;
|
|
155
261
|
export type AccountLimit = z.infer<typeof accountLimitSchema>;
|
|
156
262
|
/** Payload schema per discriminant. */
|
|
@@ -277,10 +383,12 @@ export declare const runEventPayloadSchemas: {
|
|
|
277
383
|
questionId: z.ZodString;
|
|
278
384
|
question: z.ZodString;
|
|
279
385
|
summary: z.ZodOptional<z.ZodString>;
|
|
386
|
+
uiSketch: z.ZodOptional<z.ZodLiteral<true>>;
|
|
280
387
|
options: z.ZodArray<z.ZodObject<{
|
|
281
388
|
label: z.ZodString;
|
|
282
389
|
description: z.ZodOptional<z.ZodString>;
|
|
283
390
|
recommended: z.ZodOptional<z.ZodBoolean>;
|
|
391
|
+
sketch: z.ZodOptional<z.ZodString>;
|
|
284
392
|
}, z.core.$strip>>;
|
|
285
393
|
multiSelect: z.ZodBoolean;
|
|
286
394
|
allowText: z.ZodBoolean;
|
|
@@ -334,6 +442,43 @@ export declare const runEventPayloadSchemas: {
|
|
|
334
442
|
}>;
|
|
335
443
|
}, z.core.$strict>>;
|
|
336
444
|
}, z.core.$strict>;
|
|
445
|
+
checkpoint: z.ZodObject<{
|
|
446
|
+
summary: z.ZodString;
|
|
447
|
+
done: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
448
|
+
item: z.ZodString;
|
|
449
|
+
evidence: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
450
|
+
}, z.core.$strict>>>;
|
|
451
|
+
next: z.ZodDefault<z.ZodString>;
|
|
452
|
+
blocked: z.ZodOptional<z.ZodString>;
|
|
453
|
+
files: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
454
|
+
path: z.ZodString;
|
|
455
|
+
why: z.ZodDefault<z.ZodString>;
|
|
456
|
+
}, z.core.$strict>>>;
|
|
457
|
+
checks: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
458
|
+
command: z.ZodString;
|
|
459
|
+
ok: z.ZodBoolean;
|
|
460
|
+
detail: z.ZodOptional<z.ZodString>;
|
|
461
|
+
}, z.core.$strict>>>;
|
|
462
|
+
decisions: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
463
|
+
what: z.ZodString;
|
|
464
|
+
why: z.ZodDefault<z.ZodString>;
|
|
465
|
+
}, z.core.$strict>>>;
|
|
466
|
+
slice: z.ZodNumber;
|
|
467
|
+
reason: z.ZodEnum<{
|
|
468
|
+
budget: "budget";
|
|
469
|
+
stuck: "stuck";
|
|
470
|
+
"compaction-thrash": "compaction-thrash";
|
|
471
|
+
requested: "requested";
|
|
472
|
+
}>;
|
|
473
|
+
}, z.core.$strict>;
|
|
474
|
+
heartbeat: z.ZodObject<{
|
|
475
|
+
steps: z.ZodNumber;
|
|
476
|
+
elapsedMs: z.ZodNumber;
|
|
477
|
+
lastTool: z.ZodNullable<z.ZodString>;
|
|
478
|
+
compactions: z.ZodNumber;
|
|
479
|
+
slice: z.ZodNumber;
|
|
480
|
+
maxToolCalls: z.ZodNumber;
|
|
481
|
+
}, z.core.$strict>;
|
|
337
482
|
'artifact.added': z.ZodObject<{
|
|
338
483
|
artifactId: z.ZodString;
|
|
339
484
|
name: z.ZodString;
|
|
@@ -401,9 +546,37 @@ export declare const runEventPayloadSchemas: {
|
|
|
401
546
|
id: z.ZodString;
|
|
402
547
|
label: z.ZodString;
|
|
403
548
|
usedPercent: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
549
|
+
remainingPercent: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
404
550
|
resetsAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
405
551
|
windowMinutes: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
406
552
|
status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
553
|
+
provider: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
554
|
+
kind: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
555
|
+
error: "error";
|
|
556
|
+
window: "window";
|
|
557
|
+
rate: "rate";
|
|
558
|
+
credit: "credit";
|
|
559
|
+
configured: "configured";
|
|
560
|
+
}>>>;
|
|
561
|
+
unit: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
562
|
+
requests: "requests";
|
|
563
|
+
percent: "percent";
|
|
564
|
+
tokens: "tokens";
|
|
565
|
+
usd: "usd";
|
|
566
|
+
currency: "currency";
|
|
567
|
+
count: "count";
|
|
568
|
+
}>>>;
|
|
569
|
+
used: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
570
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
571
|
+
remaining: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
572
|
+
source: z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
573
|
+
error: "error";
|
|
574
|
+
headers: "headers";
|
|
575
|
+
estimate: "estimate";
|
|
576
|
+
provider: "provider";
|
|
577
|
+
}>>>;
|
|
578
|
+
observedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
579
|
+
detail: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
407
580
|
}, z.core.$strip>>>;
|
|
408
581
|
}, z.core.$strip>;
|
|
409
582
|
'status.changed': z.ZodObject<{
|
|
@@ -452,6 +625,8 @@ export declare const runEventSchema: z.ZodObject<{
|
|
|
452
625
|
"reaction.added": "reaction.added";
|
|
453
626
|
"agent.message": "agent.message";
|
|
454
627
|
"checklist.updated": "checklist.updated";
|
|
628
|
+
checkpoint: "checkpoint";
|
|
629
|
+
heartbeat: "heartbeat";
|
|
455
630
|
"artifact.added": "artifact.added";
|
|
456
631
|
"file.changed": "file.changed";
|
|
457
632
|
"usage.updated": "usage.updated";
|
|
@@ -483,6 +658,8 @@ export interface RunRecord {
|
|
|
483
658
|
sessionId: string;
|
|
484
659
|
nativeSessionId: string | null;
|
|
485
660
|
workingDirectory: string | null;
|
|
661
|
+
/** Canonical filesystem root whose writes this run may make by default. */
|
|
662
|
+
workspaceRoot?: string | null;
|
|
486
663
|
worktreeId: string | null;
|
|
487
664
|
goal: string | null;
|
|
488
665
|
attachmentCount: number;
|
|
@@ -500,6 +677,10 @@ export interface RunRecord {
|
|
|
500
677
|
/** The variant the run used: its scope and version fingerprint. */
|
|
501
678
|
variantScope?: string | null;
|
|
502
679
|
variantVersion?: string | null;
|
|
680
|
+
/** The agent profile a subagent started from (PROP-0029); null for a copy of its parent. */
|
|
681
|
+
profile?: string | null;
|
|
682
|
+
/** The short name a parent gave a subagent, shown in the roster (PROP-0030). */
|
|
683
|
+
title?: string | null;
|
|
503
684
|
}
|
|
504
685
|
export declare const runRecordSchema: z.ZodObject<{
|
|
505
686
|
resumedFromRunId: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
@@ -514,6 +695,7 @@ export declare const runRecordSchema: z.ZodObject<{
|
|
|
514
695
|
sessionId: z.ZodString;
|
|
515
696
|
nativeSessionId: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
516
697
|
workingDirectory: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
698
|
+
workspaceRoot: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
517
699
|
worktreeId: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
518
700
|
goal: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
519
701
|
attachmentCount: z.ZodDefault<z.ZodNumber>;
|
|
@@ -527,8 +709,11 @@ export declare const runRecordSchema: z.ZodObject<{
|
|
|
527
709
|
trigger: z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>;
|
|
528
710
|
variantScope: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
529
711
|
variantVersion: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
712
|
+
profile: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
713
|
+
title: z.ZodOptional<z.ZodPipe<z.ZodOptional<z.ZodNullable<z.ZodString>>, z.ZodTransform<string | null, string | null | undefined>>>;
|
|
530
714
|
}, z.core.$strip>;
|
|
531
715
|
/** Records written before PROP-0009 name the variant `harnessScope` and `harnessVersion`. */
|
|
532
716
|
export declare function upgradeRunRecord(raw: unknown): unknown;
|
|
533
717
|
export declare const ACTIVE_STATUSES: readonly string[];
|
|
534
718
|
export declare function isActiveStatus(status: string): boolean;
|
|
719
|
+
export {};
|
|
@@ -22,6 +22,8 @@ export const runEventTypeSchema = z.enum([
|
|
|
22
22
|
'reaction.added',
|
|
23
23
|
'agent.message',
|
|
24
24
|
'checklist.updated',
|
|
25
|
+
'checkpoint',
|
|
26
|
+
'heartbeat',
|
|
25
27
|
'artifact.added',
|
|
26
28
|
'file.changed',
|
|
27
29
|
'usage.updated',
|
|
@@ -91,7 +93,39 @@ const approvalRequestedPayload = z.object({
|
|
|
91
93
|
automatic: approvalAutomaticSchema.optional()
|
|
92
94
|
});
|
|
93
95
|
const approvalResolvedPayload = z.object({ approvalId: z.string(), decision: z.enum(['approved', 'denied', 'native']), automatic: approvalAutomaticSchema.optional() });
|
|
94
|
-
export const
|
|
96
|
+
export const QUESTION_SKETCH_MAX_LINES = 24;
|
|
97
|
+
export const QUESTION_SKETCH_MAX_COLUMNS = 80;
|
|
98
|
+
export const QUESTION_SKETCH_MAX_LENGTH = QUESTION_SKETCH_MAX_LINES * QUESTION_SKETCH_MAX_COLUMNS + QUESTION_SKETCH_MAX_LINES - 1;
|
|
99
|
+
export const QUESTION_SKETCH_PATTERN = `^(?:[\\x20-\\x7e]{0,${QUESTION_SKETCH_MAX_COLUMNS}})(?:\\n[\\x20-\\x7e]{0,${QUESTION_SKETCH_MAX_COLUMNS}}){0,${QUESTION_SKETCH_MAX_LINES - 1}}$`;
|
|
100
|
+
export const questionSketchSchema = z.string()
|
|
101
|
+
.min(1)
|
|
102
|
+
.max(QUESTION_SKETCH_MAX_LENGTH)
|
|
103
|
+
.regex(new RegExp(QUESTION_SKETCH_PATTERN), 'Sketches use up to 24 LF-separated lines of at most 80 printable ASCII characters.')
|
|
104
|
+
.refine((sketch) => {
|
|
105
|
+
const lines = sketch.split('\n');
|
|
106
|
+
return lines.length <= QUESTION_SKETCH_MAX_LINES &&
|
|
107
|
+
lines.every((line) => line.length <= QUESTION_SKETCH_MAX_COLUMNS && /^[\x20-\x7e]*$/u.test(line)) &&
|
|
108
|
+
/[^ \n]/u.test(sketch);
|
|
109
|
+
}, 'A sketch needs visible content and must use up to 24 LF-separated lines of at most 80 printable ASCII characters.');
|
|
110
|
+
export function questionSketchError(uiSketch, options) {
|
|
111
|
+
if (uiSketch !== undefined && uiSketch !== true)
|
|
112
|
+
return 'Set uiSketch to true to enable question sketches.';
|
|
113
|
+
const sketches = options.map((option) => option.sketch);
|
|
114
|
+
if (uiSketch === true && sketches.some((sketch) => sketch === undefined))
|
|
115
|
+
return 'Sketch mode requires a sketch for every choice.';
|
|
116
|
+
if (uiSketch !== true && sketches.some((sketch) => sketch !== undefined))
|
|
117
|
+
return 'Choice sketches require uiSketch: true.';
|
|
118
|
+
if (sketches.some((sketch) => sketch !== undefined && !questionSketchSchema.safeParse(sketch).success)) {
|
|
119
|
+
return 'Each choice sketch must use 1–24 lines of at most 80 printable ASCII characters and contain a visible character.';
|
|
120
|
+
}
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
export const questionOptionSchema = z.object({
|
|
124
|
+
label: z.string().min(1),
|
|
125
|
+
description: z.string().optional(),
|
|
126
|
+
recommended: z.boolean().optional(),
|
|
127
|
+
sketch: questionSketchSchema.optional()
|
|
128
|
+
});
|
|
95
129
|
const questionBatchFields = {
|
|
96
130
|
batchId: z.string().min(1).optional(),
|
|
97
131
|
batchIndex: z.number().int().min(1).max(5).optional(),
|
|
@@ -110,12 +144,17 @@ const questionRequestedPayload = z.object({
|
|
|
110
144
|
questionId: z.string(),
|
|
111
145
|
question: z.string().min(1),
|
|
112
146
|
summary: z.string().min(1).max(100).optional(),
|
|
147
|
+
uiSketch: z.literal(true).optional(),
|
|
113
148
|
options: z.array(questionOptionSchema),
|
|
114
149
|
multiSelect: z.boolean(),
|
|
115
150
|
allowText: z.boolean(),
|
|
116
151
|
userOnly: z.boolean().optional(),
|
|
117
152
|
...questionBatchFields
|
|
118
|
-
}).superRefine(questionBatchRefinement)
|
|
153
|
+
}).superRefine(questionBatchRefinement).superRefine((value, context) => {
|
|
154
|
+
const error = questionSketchError(value.uiSketch, value.options);
|
|
155
|
+
if (error)
|
|
156
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ['options'], message: error });
|
|
157
|
+
});
|
|
119
158
|
const questionAnsweredPayload = z.object({
|
|
120
159
|
questionId: z.string(),
|
|
121
160
|
selected: z.array(z.string()),
|
|
@@ -140,6 +179,49 @@ export const checklistItemSchema = z.object({ text: z.string().min(1).max(500),
|
|
|
140
179
|
export const MAX_CHECKLIST_ITEMS = 50;
|
|
141
180
|
/** The whole checklist as the model last wrote it; the latest event replaces every earlier one. */
|
|
142
181
|
const checklistPayload = z.object({ items: z.array(checklistItemSchema).max(MAX_CHECKLIST_ITEMS) }).strict();
|
|
182
|
+
export const MAX_CHECKPOINT_SUMMARY = 1_200;
|
|
183
|
+
export const MAX_CHECKPOINT_DONE = 20;
|
|
184
|
+
export const MAX_CHECKPOINT_EVIDENCE = 5;
|
|
185
|
+
export const MAX_CHECKPOINT_FILES = 20;
|
|
186
|
+
export const MAX_CHECKPOINT_CHECKS = 8;
|
|
187
|
+
export const MAX_CHECKPOINT_DECISIONS = 8;
|
|
188
|
+
/**
|
|
189
|
+
* The handoff a reply writes when it reaches its work-slice budget. The harness validates and
|
|
190
|
+
* records it; the next slice is told where this one stopped from it (PROP-0041).
|
|
191
|
+
*/
|
|
192
|
+
export const checkpointItemSchema = z.object({
|
|
193
|
+
item: z.string().min(1).max(300),
|
|
194
|
+
evidence: z.array(z.string().min(1).max(300)).max(MAX_CHECKPOINT_EVIDENCE).default([])
|
|
195
|
+
}).strict();
|
|
196
|
+
export const checkpointFileSchema = z.object({ path: z.string().min(1).max(300), why: z.string().max(200).default('') }).strict();
|
|
197
|
+
export const checkpointCheckSchema = z.object({
|
|
198
|
+
command: z.string().min(1).max(200),
|
|
199
|
+
ok: z.boolean(),
|
|
200
|
+
detail: z.string().max(300).optional()
|
|
201
|
+
}).strict();
|
|
202
|
+
export const checkpointDecisionSchema = z.object({ what: z.string().min(1).max(200), why: z.string().max(300).default('') }).strict();
|
|
203
|
+
export const checkpointReasonSchema = z.enum(['budget', 'stuck', 'compaction-thrash', 'requested']);
|
|
204
|
+
const checkpointPayload = z.object({
|
|
205
|
+
summary: z.string().max(MAX_CHECKPOINT_SUMMARY),
|
|
206
|
+
done: z.array(checkpointItemSchema).max(MAX_CHECKPOINT_DONE).default([]),
|
|
207
|
+
next: z.string().max(500).default(''),
|
|
208
|
+
blocked: z.string().max(500).optional(),
|
|
209
|
+
files: z.array(checkpointFileSchema).max(MAX_CHECKPOINT_FILES).default([]),
|
|
210
|
+
checks: z.array(checkpointCheckSchema).max(MAX_CHECKPOINT_CHECKS).default([]),
|
|
211
|
+
decisions: z.array(checkpointDecisionSchema).max(MAX_CHECKPOINT_DECISIONS).default([]),
|
|
212
|
+
/** Which slice of the session wrote it, from 1. */
|
|
213
|
+
slice: z.number().int().positive(),
|
|
214
|
+
reason: checkpointReasonSchema
|
|
215
|
+
}).strict();
|
|
216
|
+
/** Counters a live reply reports while it works; a person and the watchdog read liveness from it. */
|
|
217
|
+
const heartbeatPayload = z.object({
|
|
218
|
+
steps: z.number().int().nonnegative(),
|
|
219
|
+
elapsedMs: z.number().nonnegative(),
|
|
220
|
+
lastTool: z.string().max(120).nullable(),
|
|
221
|
+
compactions: z.number().int().nonnegative(),
|
|
222
|
+
slice: z.number().int().positive(),
|
|
223
|
+
maxToolCalls: z.number().int().nonnegative()
|
|
224
|
+
}).strict();
|
|
143
225
|
const artifactPayload = z.object({ artifactId: z.string(), name: z.string(), file: z.unknown().optional() });
|
|
144
226
|
const fileChangedPayload = z.object({ path: z.string(), change: z.enum(['added', 'modified', 'deleted']) });
|
|
145
227
|
/** Where a cost figure comes from: Pi reported it, or the tokens were priced at list rates. */
|
|
@@ -191,9 +273,19 @@ export const accountLimitSchema = z.object({
|
|
|
191
273
|
id: z.string(),
|
|
192
274
|
label: z.string(),
|
|
193
275
|
usedPercent: z.number().nullable().optional(),
|
|
276
|
+
remainingPercent: z.number().nullable().optional(),
|
|
194
277
|
resetsAt: z.string().nullable().optional(),
|
|
195
278
|
windowMinutes: z.number().nullable().optional(),
|
|
196
|
-
status: z.string().nullable().optional()
|
|
279
|
+
status: z.string().nullable().optional(),
|
|
280
|
+
provider: z.string().nullable().optional(),
|
|
281
|
+
kind: z.enum(['window', 'rate', 'credit', 'configured', 'error']).nullable().optional(),
|
|
282
|
+
unit: z.enum(['percent', 'requests', 'tokens', 'usd', 'currency', 'count']).nullable().optional(),
|
|
283
|
+
used: z.number().nullable().optional(),
|
|
284
|
+
limit: z.number().nullable().optional(),
|
|
285
|
+
remaining: z.number().nullable().optional(),
|
|
286
|
+
source: z.enum(['headers', 'provider', 'estimate', 'error']).nullable().optional(),
|
|
287
|
+
observedAt: z.string().nullable().optional(),
|
|
288
|
+
detail: z.string().nullable().optional()
|
|
197
289
|
});
|
|
198
290
|
/** Limit snapshots, plan changes, and classified account failures. */
|
|
199
291
|
const accountStatusPayload = z.object({
|
|
@@ -228,6 +320,8 @@ export const runEventPayloadSchemas = {
|
|
|
228
320
|
'reaction.added': reactionAddedPayload,
|
|
229
321
|
'agent.message': agentMessagePayload,
|
|
230
322
|
'checklist.updated': checklistPayload,
|
|
323
|
+
checkpoint: checkpointPayload,
|
|
324
|
+
heartbeat: heartbeatPayload,
|
|
231
325
|
'artifact.added': artifactPayload,
|
|
232
326
|
'file.changed': fileChangedPayload,
|
|
233
327
|
'usage.updated': usagePayloadSchema,
|
|
@@ -269,6 +363,7 @@ export const runRecordSchema = z.object({
|
|
|
269
363
|
sessionId: z.string(),
|
|
270
364
|
nativeSessionId: text,
|
|
271
365
|
workingDirectory: text,
|
|
366
|
+
workspaceRoot: text.optional(),
|
|
272
367
|
worktreeId: text,
|
|
273
368
|
goal: text,
|
|
274
369
|
attachmentCount: z.number().int().nonnegative().default(0),
|
|
@@ -281,7 +376,9 @@ export const runRecordSchema = z.object({
|
|
|
281
376
|
agentId: text,
|
|
282
377
|
trigger: text,
|
|
283
378
|
variantScope: text.optional(),
|
|
284
|
-
variantVersion: text.optional()
|
|
379
|
+
variantVersion: text.optional(),
|
|
380
|
+
profile: text.optional(),
|
|
381
|
+
title: text.optional()
|
|
285
382
|
});
|
|
286
383
|
/** Records written before PROP-0009 name the variant `harnessScope` and `harnessVersion`. */
|
|
287
384
|
export function upgradeRunRecord(raw) {
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/** Which saved history a command acts on: one file in the folder, or the newest there. */
|
|
2
|
+
export interface SessionRef {
|
|
3
|
+
sessionDir: string;
|
|
4
|
+
sessionFile?: string | null;
|
|
5
|
+
/** Recorded in a new history's header. Defaults to the source history's own folder. */
|
|
6
|
+
cwd?: string | null;
|
|
7
|
+
}
|
|
8
|
+
export interface SessionTreeEntry {
|
|
9
|
+
id: string;
|
|
10
|
+
parentId: string | null;
|
|
11
|
+
type: string;
|
|
12
|
+
/** `user`, `assistant`, `toolResult`, ... for a message entry. */
|
|
13
|
+
role?: string;
|
|
14
|
+
/** One line of what the entry says, at most 160 characters. */
|
|
15
|
+
text: string;
|
|
16
|
+
label?: string;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
/** How deep in the tree, for indentation. */
|
|
19
|
+
depth: number;
|
|
20
|
+
}
|
|
21
|
+
export interface SessionTree {
|
|
22
|
+
sessionFile: string;
|
|
23
|
+
leafId: string | null;
|
|
24
|
+
entries: SessionTreeEntry[];
|
|
25
|
+
/** The person's messages on the current branch, newest last: where `/fork` may start. */
|
|
26
|
+
forkPoints: {
|
|
27
|
+
entryId: string;
|
|
28
|
+
text: string;
|
|
29
|
+
}[];
|
|
30
|
+
}
|
|
31
|
+
/** A move without a summary is saved as this entry, so the next turn opens on the chosen branch. */
|
|
32
|
+
export declare const NAVIGATION_ENTRY = "xingular-navigation";
|
|
33
|
+
export declare function tree(ref: SessionRef): SessionTree;
|
|
34
|
+
/**
|
|
35
|
+
* Moves the conversation to another entry without a summary. Choosing one of the person's
|
|
36
|
+
* messages goes to just before it and gives its text back to edit, as the terminal does.
|
|
37
|
+
*/
|
|
38
|
+
export declare function navigate(ref: SessionRef & {
|
|
39
|
+
entryId: string;
|
|
40
|
+
}): {
|
|
41
|
+
leafId: string | null;
|
|
42
|
+
editorText?: string;
|
|
43
|
+
};
|
|
44
|
+
/** A new history in `targetDir` that ends just before one of the person's messages. */
|
|
45
|
+
export declare function fork(ref: SessionRef & {
|
|
46
|
+
entryId: string;
|
|
47
|
+
targetDir: string;
|
|
48
|
+
}): {
|
|
49
|
+
sessionFile: string;
|
|
50
|
+
editorText: string;
|
|
51
|
+
};
|
|
52
|
+
/** A new history in `targetDir` with the whole current branch. */
|
|
53
|
+
export declare function clone(ref: SessionRef & {
|
|
54
|
+
targetDir: string;
|
|
55
|
+
}): {
|
|
56
|
+
sessionFile: string;
|
|
57
|
+
};
|
|
58
|
+
export declare function rename(ref: SessionRef & {
|
|
59
|
+
name: string;
|
|
60
|
+
}): {
|
|
61
|
+
name: string;
|
|
62
|
+
};
|
|
63
|
+
/** The text of the last reply on the current branch, or null before the first. */
|
|
64
|
+
export declare function lastReply(ref: SessionRef): {
|
|
65
|
+
text: string | null;
|
|
66
|
+
};
|
|
67
|
+
/** Writes the current branch as JSONL. HTML needs a live session: see `SessionCommand`. */
|
|
68
|
+
export declare function exportJsonl(ref: SessionRef & {
|
|
69
|
+
path: string;
|
|
70
|
+
}): {
|
|
71
|
+
path: string;
|
|
72
|
+
};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// Session commands that need no model: read the branch tree, move to another branch, fork, clone,
|
|
2
|
+
// name, copy the last reply, and export to JSONL. They act on the saved native history directly,
|
|
3
|
+
// so a host that opens one Pi session per turn offers the same commands as the terminal.
|
|
4
|
+
// Compacting, navigating with a summary and exporting to HTML need a live session: they run as a
|
|
5
|
+
// session command through `sessions.run` (see `SessionCommand`).
|
|
6
|
+
import { existsSync, mkdirSync, realpathSync, writeFileSync } from 'node:fs';
|
|
7
|
+
import { isAbsolute, relative } from 'node:path';
|
|
8
|
+
import { SessionManager } from '@earendil-works/pi-coding-agent';
|
|
9
|
+
import { invalid, notFound } from "../core/errors.js";
|
|
10
|
+
import { sessionFile as newestSessionFile } from "../prompt/compile.js";
|
|
11
|
+
/** A move without a summary is saved as this entry, so the next turn opens on the chosen branch. */
|
|
12
|
+
export const NAVIGATION_ENTRY = 'xingular-navigation';
|
|
13
|
+
function within(dir, file) {
|
|
14
|
+
const path = relative(realpathSync(dir), realpathSync(file));
|
|
15
|
+
return !path.startsWith('..') && !isAbsolute(path);
|
|
16
|
+
}
|
|
17
|
+
function resolveFile(ref) {
|
|
18
|
+
if (!ref.sessionDir || !existsSync(ref.sessionDir))
|
|
19
|
+
throw notFound('This conversation has no saved history yet.');
|
|
20
|
+
const file = ref.sessionFile ?? newestSessionFile(ref.sessionDir);
|
|
21
|
+
if (!file || !existsSync(file))
|
|
22
|
+
throw notFound('This conversation has no saved history yet.');
|
|
23
|
+
if (!file.endsWith('.jsonl') || !within(ref.sessionDir, file))
|
|
24
|
+
throw invalid('The history must be a .jsonl file in the session folder.');
|
|
25
|
+
return realpathSync(file);
|
|
26
|
+
}
|
|
27
|
+
function open(ref, targetDir) {
|
|
28
|
+
const file = resolveFile(ref);
|
|
29
|
+
return { manager: SessionManager.open(file, targetDir ?? ref.sessionDir, ref.cwd ?? undefined), file };
|
|
30
|
+
}
|
|
31
|
+
function contentText(content) {
|
|
32
|
+
if (typeof content === 'string')
|
|
33
|
+
return content;
|
|
34
|
+
if (!Array.isArray(content))
|
|
35
|
+
return '';
|
|
36
|
+
return content.map((part) => part && typeof part === 'object' && part.type === 'text' ? String(part.text ?? '') : '').join(' ');
|
|
37
|
+
}
|
|
38
|
+
function entryText(entry) {
|
|
39
|
+
const record = entry;
|
|
40
|
+
if (entry.type === 'message') {
|
|
41
|
+
const message = record.message;
|
|
42
|
+
return { role: message?.role, text: contentText(message?.content) };
|
|
43
|
+
}
|
|
44
|
+
if (entry.type === 'branch_summary' || entry.type === 'compaction')
|
|
45
|
+
return { text: String(record.summary ?? '') };
|
|
46
|
+
if (entry.type === 'session_info')
|
|
47
|
+
return { text: String(record.name ?? '') };
|
|
48
|
+
if (entry.type === 'model_change')
|
|
49
|
+
return { text: `${record.provider ?? ''}/${record.modelId ?? ''}` };
|
|
50
|
+
return { text: '' };
|
|
51
|
+
}
|
|
52
|
+
const oneLine = (text) => text.replace(/\s+/g, ' ').trim().slice(0, 160);
|
|
53
|
+
function flatten(nodes, depth, out) {
|
|
54
|
+
for (const node of nodes) {
|
|
55
|
+
const entry = node.entry;
|
|
56
|
+
const { role, text } = entryText(entry);
|
|
57
|
+
if (entry.type === 'custom' || entry.type === 'label') {
|
|
58
|
+
flatten(node.children, depth, out);
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
out.push({
|
|
62
|
+
id: entry.id,
|
|
63
|
+
parentId: entry.parentId ?? null,
|
|
64
|
+
type: entry.type,
|
|
65
|
+
...(role ? { role } : {}),
|
|
66
|
+
text: oneLine(text),
|
|
67
|
+
...(node.label ? { label: node.label } : {}),
|
|
68
|
+
timestamp: entry.timestamp,
|
|
69
|
+
depth
|
|
70
|
+
});
|
|
71
|
+
flatten(node.children, node.children.length > 1 ? depth + 1 : depth, out);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export function tree(ref) {
|
|
75
|
+
const { manager, file } = open(ref);
|
|
76
|
+
const entries = [];
|
|
77
|
+
flatten(manager.getTree(), 0, entries);
|
|
78
|
+
const forkPoints = manager.getBranch()
|
|
79
|
+
.filter((entry) => entry.type === 'message' && entryText(entry).role === 'user')
|
|
80
|
+
.map((entry) => ({ entryId: entry.id, text: oneLine(entryText(entry).text) }));
|
|
81
|
+
return { sessionFile: file, leafId: manager.getLeafId(), entries, forkPoints };
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Moves the conversation to another entry without a summary. Choosing one of the person's
|
|
85
|
+
* messages goes to just before it and gives its text back to edit, as the terminal does.
|
|
86
|
+
*/
|
|
87
|
+
export function navigate(ref) {
|
|
88
|
+
const { manager } = open(ref);
|
|
89
|
+
const entry = manager.getEntry(ref.entryId);
|
|
90
|
+
if (!entry)
|
|
91
|
+
throw notFound(`No entry ${ref.entryId} in this conversation.`);
|
|
92
|
+
const { role, text } = entryText(entry);
|
|
93
|
+
const userMessage = entry.type === 'message' && role === 'user';
|
|
94
|
+
const target = userMessage ? entry.parentId ?? null : entry.id;
|
|
95
|
+
if (target)
|
|
96
|
+
manager.branch(target);
|
|
97
|
+
else
|
|
98
|
+
manager.resetLeaf();
|
|
99
|
+
manager.appendCustomEntry(NAVIGATION_ENTRY, { to: target });
|
|
100
|
+
return { leafId: target, ...(userMessage ? { editorText: text } : {}) };
|
|
101
|
+
}
|
|
102
|
+
/** A new history in `targetDir` that ends just before one of the person's messages. */
|
|
103
|
+
export function fork(ref) {
|
|
104
|
+
const { manager } = open(ref, ensureDir(ref.targetDir));
|
|
105
|
+
const entry = manager.getEntry(ref.entryId);
|
|
106
|
+
const { role, text } = entry ? entryText(entry) : { text: '' };
|
|
107
|
+
if (!entry || entry.type !== 'message' || role !== 'user')
|
|
108
|
+
throw invalid('Fork from one of your messages.');
|
|
109
|
+
const sessionFile = entry.parentId
|
|
110
|
+
? manager.createBranchedSession(entry.parentId)
|
|
111
|
+
: SessionManager.create(manager.getCwd(), ref.targetDir).getSessionFile();
|
|
112
|
+
if (!sessionFile)
|
|
113
|
+
throw invalid('The fork could not be saved.');
|
|
114
|
+
return { sessionFile, editorText: text };
|
|
115
|
+
}
|
|
116
|
+
/** A new history in `targetDir` with the whole current branch. */
|
|
117
|
+
export function clone(ref) {
|
|
118
|
+
const { manager } = open(ref, ensureDir(ref.targetDir));
|
|
119
|
+
const leaf = manager.getLeafId();
|
|
120
|
+
if (!leaf)
|
|
121
|
+
throw invalid('Nothing to clone yet.');
|
|
122
|
+
const sessionFile = manager.createBranchedSession(leaf);
|
|
123
|
+
if (!sessionFile)
|
|
124
|
+
throw invalid('The clone could not be saved.');
|
|
125
|
+
return { sessionFile };
|
|
126
|
+
}
|
|
127
|
+
export function rename(ref) {
|
|
128
|
+
const name = ref.name.trim();
|
|
129
|
+
if (!name)
|
|
130
|
+
throw invalid('A session name cannot be empty.');
|
|
131
|
+
open(ref).manager.appendSessionInfo(name);
|
|
132
|
+
return { name };
|
|
133
|
+
}
|
|
134
|
+
/** The text of the last reply on the current branch, or null before the first. */
|
|
135
|
+
export function lastReply(ref) {
|
|
136
|
+
const branch = open(ref).manager.getBranch();
|
|
137
|
+
for (let index = branch.length - 1; index >= 0; index -= 1) {
|
|
138
|
+
const { role, text } = entryText(branch[index]);
|
|
139
|
+
if (branch[index].type === 'message' && role === 'assistant' && text.trim())
|
|
140
|
+
return { text: text.trim() };
|
|
141
|
+
}
|
|
142
|
+
return { text: null };
|
|
143
|
+
}
|
|
144
|
+
/** Writes the current branch as JSONL. HTML needs a live session: see `SessionCommand`. */
|
|
145
|
+
export function exportJsonl(ref) {
|
|
146
|
+
if (!isAbsolute(ref.path) || !ref.path.endsWith('.jsonl'))
|
|
147
|
+
throw invalid('Export to an absolute .jsonl path.');
|
|
148
|
+
const { manager } = open(ref);
|
|
149
|
+
const lines = [manager.getHeader(), ...manager.getBranch()].filter(Boolean).map((entry) => JSON.stringify(entry));
|
|
150
|
+
writeFileSync(ref.path, `${lines.join('\n')}\n`, 'utf8');
|
|
151
|
+
return { path: ref.path };
|
|
152
|
+
}
|
|
153
|
+
function ensureDir(dir) {
|
|
154
|
+
if (!isAbsolute(dir))
|
|
155
|
+
throw invalid('The new history folder must be an absolute path.');
|
|
156
|
+
mkdirSync(dir, { recursive: true });
|
|
157
|
+
return dir;
|
|
158
|
+
}
|