@zergai/ztc 0.4.0-beta.1 → 0.5.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +398 -45
- package/RUST_THIRD_PARTY_LICENSES.txt +1080 -822
- package/THIRD_PARTY_NOTICES.md +273 -12
- package/bin/zmux-darwin-arm64 +0 -0
- package/bin/ztc-audio-darwin-arm64 +0 -0
- package/bin/ztc-capture-darwin-arm64 +0 -0
- package/bin/ztc-computer-darwin-arm64 +0 -0
- package/bin/ztc-llm-darwin-arm64 +0 -0
- package/bin/ztc-tts-darwin-arm64 +0 -0
- package/bin/ztc-tui-darwin-arm64 +0 -0
- package/bin/ztc-zlicky-overlay-darwin-arm64 +0 -0
- package/bin/zterm-darwin-arm64 +0 -0
- package/dist/App.js +1206 -209
- package/dist/agent/agent.d.ts +74 -8
- package/dist/agent/agent.js +1073 -184
- package/dist/agent/backends/account_rotation.d.ts +4 -0
- package/dist/agent/backends/account_rotation.js +8 -2
- package/dist/agent/backends/anthropic.d.ts +13 -0
- package/dist/agent/backends/anthropic.js +169 -28
- package/dist/agent/backends/claude_cli.js +18 -8
- package/dist/agent/backends/codex_app_server.d.ts +1 -0
- package/dist/agent/backends/codex_app_server.js +55 -3
- package/dist/agent/backends/codex_auth.d.ts +1 -0
- package/dist/agent/backends/codex_auth.js +67 -13
- package/dist/agent/backends/codex_buffered_recovery.d.ts +27 -0
- package/dist/agent/backends/codex_buffered_recovery.js +293 -0
- package/dist/agent/backends/gemini.js +3 -1
- package/dist/agent/backends/http_error.d.ts +26 -0
- package/dist/agent/backends/http_error.js +221 -0
- package/dist/agent/backends/index.d.ts +9 -2
- package/dist/agent/backends/index.js +22 -2
- package/dist/agent/backends/openai.d.ts +0 -6
- package/dist/agent/backends/openai.js +5 -2
- package/dist/agent/backends/openai_compatible.d.ts +5 -4
- package/dist/agent/backends/openai_compatible.js +26 -19
- package/dist/agent/backends/openai_responses.d.ts +8 -3
- package/dist/agent/backends/openai_responses.js +77 -33
- package/dist/agent/backends/provider_ids.d.ts +1 -0
- package/dist/agent/backends/provider_ids.js +4 -0
- package/dist/agent/backends/request_metrics.js +12 -2
- package/dist/agent/backends/types.d.ts +109 -6
- package/dist/agent/backends/types.js +5 -1
- package/dist/agent/backends/zrouter_stream.d.ts +6 -1
- package/dist/agent/backends/zrouter_stream.js +160 -42
- package/dist/agent/background_registry.d.ts +2 -0
- package/dist/agent/background_registry.js +1 -0
- package/dist/agent/claim_observation.d.ts +6 -0
- package/dist/agent/claim_observation.js +54 -0
- package/dist/agent/commands/accounts.js +46 -177
- package/dist/agent/commands/attention.d.ts +2 -0
- package/dist/agent/commands/attention.js +67 -0
- package/dist/agent/commands/auth.js +18 -2
- package/dist/agent/commands/board.d.ts +2 -0
- package/dist/agent/commands/board.js +169 -0
- package/dist/agent/commands/clipboard.js +50 -1
- package/dist/agent/commands/compact.js +21 -13
- package/dist/agent/commands/config.js +4 -1
- package/dist/agent/commands/context.js +6 -1
- package/dist/agent/commands/desktop.d.ts +2 -0
- package/dist/agent/commands/desktop.js +29 -0
- package/dist/agent/commands/effort.js +14 -6
- package/dist/agent/commands/environment.d.ts +3 -0
- package/dist/agent/commands/environment.js +109 -0
- package/dist/agent/commands/evidence.d.ts +2 -0
- package/dist/agent/commands/evidence.js +9 -0
- package/dist/agent/commands/fork.js +4 -3
- package/dist/agent/commands/goal.d.ts +33 -1
- package/dist/agent/commands/goal.js +174 -14
- package/dist/agent/commands/goal_exit.d.ts +36 -0
- package/dist/agent/commands/goal_exit.js +120 -0
- package/dist/agent/commands/help.js +3 -1
- package/dist/agent/commands/history.js +3 -1
- package/dist/agent/commands/inbox.d.ts +2 -0
- package/dist/agent/commands/inbox.js +148 -0
- package/dist/agent/commands/index.js +16 -1
- package/dist/agent/commands/input_mode.js +8 -6
- package/dist/agent/commands/job.d.ts +2 -0
- package/dist/agent/commands/job.js +93 -0
- package/dist/agent/commands/keybindings.js +4 -1
- package/dist/agent/commands/label.d.ts +2 -0
- package/dist/agent/commands/label.js +77 -0
- package/dist/agent/commands/layout.d.ts +2 -0
- package/dist/agent/commands/layout.js +20 -0
- package/dist/agent/commands/mirror.js +16 -1
- package/dist/agent/commands/model.js +12 -2
- package/dist/agent/commands/permissions.d.ts +3 -1
- package/dist/agent/commands/permissions.js +79 -89
- package/dist/agent/commands/plan.js +5 -15
- package/dist/agent/commands/profile.js +21 -2
- package/dist/agent/commands/provider_selection.js +20 -1
- package/dist/agent/commands/rename.js +1 -1
- package/dist/agent/commands/resources.d.ts +2 -0
- package/dist/agent/commands/resources.js +67 -0
- package/dist/agent/commands/rewind.d.ts +3 -0
- package/dist/agent/commands/rewind.js +16 -0
- package/dist/agent/commands/runbooks.d.ts +2 -0
- package/dist/agent/commands/runbooks.js +73 -0
- package/dist/agent/commands/runbooks_lazy.d.ts +2 -0
- package/dist/agent/commands/runbooks_lazy.js +8 -0
- package/dist/agent/commands/sessions.d.ts +1 -1
- package/dist/agent/commands/sessions.js +33 -5
- package/dist/agent/commands/settings.js +185 -39
- package/dist/agent/commands/setup.d.ts +2 -0
- package/dist/agent/commands/setup.js +78 -0
- package/dist/agent/commands/share.d.ts +2 -0
- package/dist/agent/commands/share.js +64 -0
- package/dist/agent/commands/status.js +14 -2
- package/dist/agent/commands/types.d.ts +99 -6
- package/dist/agent/commands/update.js +8 -0
- package/dist/agent/commands/usage.d.ts +2 -0
- package/dist/agent/commands/usage.js +8 -0
- package/dist/agent/factory.d.ts +11 -0
- package/dist/agent/factory.js +113 -88
- package/dist/agent/loop_policy.d.ts +6 -3
- package/dist/agent/loop_policy.js +12 -3
- package/dist/agent/measurement_guidance.d.ts +2 -0
- package/dist/agent/measurement_guidance.js +5 -0
- package/dist/agent/request_encoder.d.ts +8 -1
- package/dist/agent/request_encoder.js +95 -23
- package/dist/agent/runtime/benchmark_comparison.d.ts +30 -0
- package/dist/agent/runtime/benchmark_comparison.js +94 -0
- package/dist/agent/runtime/benchmark_contract.d.ts +48 -0
- package/dist/agent/runtime/benchmark_contract.js +90 -0
- package/dist/agent/runtime/checked_commands.d.ts +32 -0
- package/dist/agent/runtime/checked_commands.js +119 -0
- package/dist/agent/runtime/command_execution_policy.d.ts +26 -0
- package/dist/agent/runtime/command_execution_policy.js +91 -0
- package/dist/agent/runtime/command_jobs.d.ts +36 -18
- package/dist/agent/runtime/command_jobs.js +151 -13
- package/dist/agent/runtime/command_panes.d.ts +59 -0
- package/dist/agent/runtime/command_panes.js +398 -0
- package/dist/agent/runtime/command_wait.d.ts +19 -0
- package/dist/agent/runtime/command_wait.js +167 -0
- package/dist/agent/runtime/cpu_benchmark.d.ts +30 -0
- package/dist/agent/runtime/cpu_benchmark.js +126 -0
- package/dist/agent/runtime/delegated_evidence.d.ts +26 -0
- package/dist/agent/runtime/delegated_evidence.js +80 -0
- package/dist/agent/runtime/evidence.d.ts +127 -0
- package/dist/agent/runtime/evidence.js +468 -0
- package/dist/agent/runtime/execution_context.d.ts +7 -0
- package/dist/agent/runtime/execution_context.js +39 -3
- package/dist/agent/runtime/json_verifier_recipe.d.ts +8 -0
- package/dist/agent/runtime/json_verifier_recipe.js +66 -0
- package/dist/agent/runtime/measurements.d.ts +110 -0
- package/dist/agent/runtime/measurements.js +317 -0
- package/dist/agent/runtime/policy.d.ts +4 -0
- package/dist/agent/runtime/policy.js +31 -20
- package/dist/agent/runtime/provider_native_evidence.d.ts +20 -0
- package/dist/agent/runtime/provider_native_evidence.js +86 -0
- package/dist/agent/runtime/recovery.d.ts +2 -0
- package/dist/agent/runtime/recovery.js +45 -2
- package/dist/agent/runtime/remote_broker_transport.d.ts +10 -0
- package/dist/agent/runtime/remote_broker_transport.js +84 -0
- package/dist/agent/runtime/remote_deletion_receipts.d.ts +3 -0
- package/dist/agent/runtime/remote_deletion_receipts.js +43 -0
- package/dist/agent/runtime/remote_journal_replay.d.ts +13 -0
- package/dist/agent/runtime/remote_journal_replay.js +233 -0
- package/dist/agent/runtime/remote_mutation_journal.d.ts +25 -0
- package/dist/agent/runtime/remote_mutation_journal.js +208 -0
- package/dist/agent/runtime/remote_resource_endpoint.d.ts +7 -0
- package/dist/agent/runtime/remote_resource_endpoint.js +6 -0
- package/dist/agent/runtime/remote_resource_errors.d.ts +5 -0
- package/dist/agent/runtime/remote_resource_errors.js +9 -0
- package/dist/agent/runtime/remote_resource_script.d.ts +2 -0
- package/dist/agent/runtime/remote_resource_script.js +1009 -0
- package/dist/agent/runtime/remote_resources.d.ts +29 -0
- package/dist/agent/runtime/remote_resources.js +160 -0
- package/dist/agent/runtime/source_verification.d.ts +12 -0
- package/dist/agent/runtime/source_verification.js +210 -0
- package/dist/agent/runtime/source_verification_contract.d.ts +75 -0
- package/dist/agent/runtime/source_verification_contract.js +203 -0
- package/dist/agent/runtime/tool_checkpoints.d.ts +11 -0
- package/dist/agent/runtime/tool_checkpoints.js +26 -0
- package/dist/agent/runtime/tool_effects.d.ts +5 -0
- package/dist/agent/runtime/tool_progress.d.ts +12 -0
- package/dist/agent/runtime/tool_progress.js +76 -0
- package/dist/agent/runtime/tool_runtime.d.ts +16 -1
- package/dist/agent/runtime/tool_runtime.js +204 -10
- package/dist/agent/runtime/tracing.d.ts +1 -1
- package/dist/agent/runtime/verifier_capture.d.ts +9 -0
- package/dist/agent/runtime/verifier_capture.js +100 -0
- package/dist/agent/runtime/verifier_contract.d.ts +24 -0
- package/dist/agent/runtime/verifier_contract.js +41 -0
- package/dist/agent/subagent.d.ts +20 -10
- package/dist/agent/subagent.js +266 -29
- package/dist/agent/tool_response_directory.d.ts +24 -0
- package/dist/agent/tool_response_directory.js +61 -0
- package/dist/agent/tool_response_source.d.ts +8 -0
- package/dist/agent/tool_response_source.js +49 -0
- package/dist/agent/tool_response_store.d.ts +75 -4
- package/dist/agent/tool_response_store.js +583 -64
- package/dist/agent/tools/ask_user.d.ts +3 -1
- package/dist/agent/tools/ask_user.js +30 -11
- package/dist/agent/tools/background.js +1 -0
- package/dist/agent/tools/benchmark_cpu.d.ts +2 -0
- package/dist/agent/tools/benchmark_cpu.js +102 -0
- package/dist/agent/tools/compare_benchmarks.d.ts +2 -0
- package/dist/agent/tools/compare_benchmarks.js +53 -0
- package/dist/agent/tools/deferred.js +1 -0
- package/dist/agent/tools/delegate.js +18 -2
- package/dist/agent/tools/helper_requirements.d.ts +7 -0
- package/dist/agent/tools/helper_requirements.js +19 -0
- package/dist/agent/tools/index.d.ts +1 -0
- package/dist/agent/tools/index.js +3 -0
- package/dist/agent/tools/measurement_report.d.ts +22 -0
- package/dist/agent/tools/measurement_report.js +190 -0
- package/dist/agent/tools/pane.d.ts +0 -7
- package/dist/agent/tools/pane.js +5 -4
- package/dist/agent/tools/project_context.d.ts +3 -0
- package/dist/agent/tools/project_context.js +45 -0
- package/dist/agent/tools/recall_tool_response.d.ts +3 -5
- package/dist/agent/tools/recall_tool_response.js +19 -29
- package/dist/agent/tools/registry.d.ts +1 -0
- package/dist/agent/tools/registry.js +23 -0
- package/dist/agent/tools/related_sessions.d.ts +2 -0
- package/dist/agent/tools/related_sessions.js +156 -0
- package/dist/agent/tools/routine.js +13 -3
- package/dist/agent/tools/session_evidence.d.ts +3 -0
- package/dist/agent/tools/session_evidence.js +72 -0
- package/dist/agent/tools/shell.d.ts +4 -3
- package/dist/agent/tools/shell.js +174 -47
- package/dist/agent/tools/tool_search.js +3 -2
- package/dist/agent/tools/types.d.ts +28 -0
- package/dist/agent/tools/verify_artifact.d.ts +2 -0
- package/dist/agent/tools/verify_artifact.js +60 -0
- package/dist/agent/tools/workflow.js +1 -0
- package/dist/app/activity.d.ts +6 -1
- package/dist/app/activity.js +81 -12
- package/dist/app/agent_runner.d.ts +6 -1
- package/dist/app/agent_runner.js +34 -19
- package/dist/app/command_context.js +106 -10
- package/dist/app/controller.d.ts +15 -4
- package/dist/app/controller.js +29 -3
- package/dist/app/escape_stop.d.ts +11 -0
- package/dist/app/escape_stop.js +15 -0
- package/dist/app/liveness.d.ts +6 -4
- package/dist/app/liveness.js +13 -3
- package/dist/app/model_catalog_cache.d.ts +5 -0
- package/dist/app/model_catalog_cache.js +138 -0
- package/dist/app/ordered_transcript.js +43 -4
- package/dist/app/prompt_turn.d.ts +14 -0
- package/dist/app/prompt_turn.js +53 -0
- package/dist/app/recap.d.ts +3 -0
- package/dist/app/recap.js +9 -3
- package/dist/app/restart.d.ts +3 -2
- package/dist/app/restart.js +22 -7
- package/dist/app/rewind.d.ts +3 -3
- package/dist/app/rewind.js +3 -3
- package/dist/app/selection_completion.d.ts +17 -2
- package/dist/app/selection_completion.js +84 -9
- package/dist/app/session_manager.d.ts +38 -6
- package/dist/app/session_manager.js +263 -60
- package/dist/app/session_messages.d.ts +3 -0
- package/dist/app/session_messages.js +60 -0
- package/dist/app/task_scope_router.d.ts +20 -0
- package/dist/app/task_scope_router.js +173 -0
- package/dist/app/transcript_window.d.ts +2 -0
- package/dist/app/transcript_window.js +4 -0
- package/dist/app/workspace_admission_details.d.ts +3 -0
- package/dist/app/workspace_admission_details.js +26 -0
- package/dist/app/workspace_layout_controller.d.ts +11 -0
- package/dist/app/workspace_layout_controller.js +88 -0
- package/dist/app/workspace_monitor.d.ts +1 -0
- package/dist/app/workspace_monitor.js +216 -0
- package/dist/app/workspace_presets.d.ts +29 -0
- package/dist/app/workspace_presets.js +192 -0
- package/dist/attention/queue.d.ts +37 -0
- package/dist/attention/queue.js +183 -0
- package/dist/bench/rf_shared.d.ts +2 -0
- package/dist/board/binding.d.ts +42 -0
- package/dist/board/binding.js +38 -0
- package/dist/board/client.d.ts +42 -0
- package/dist/board/client.js +60 -0
- package/dist/cli.js +1 -1
- package/dist/cli_args.js +19 -17
- package/dist/cli_main.js +110 -13
- package/dist/cli_ratatui.d.ts +183 -16
- package/dist/cli_ratatui.js +3989 -1255
- package/dist/components/ActivityLine.d.ts +3 -2
- package/dist/components/ActivityLine.js +2 -2
- package/dist/components/InputArea.d.ts +19 -1
- package/dist/components/InputArea.js +264 -190
- package/dist/components/MessageList.d.ts +2 -0
- package/dist/components/MessageList.js +3 -1
- package/dist/components/SingleMessage.d.ts +2 -0
- package/dist/components/SingleMessage.js +4 -2
- package/dist/components/StatusBar.d.ts +4 -2
- package/dist/components/StatusBar.js +3 -1
- package/dist/conductor_branch.js +3 -0
- package/dist/config/api_retry.d.ts +6 -1
- package/dist/config/api_retry.js +19 -1
- package/dist/config/defaults.d.ts +2 -1
- package/dist/config/defaults.js +9 -2
- package/dist/config/message_display.d.ts +1 -0
- package/dist/config/message_display.js +17 -2
- package/dist/config/permissions.d.ts +21 -0
- package/dist/config/permissions.js +89 -0
- package/dist/config/resolved.d.ts +2 -2
- package/dist/config/types.d.ts +32 -5
- package/dist/config.d.ts +38 -4
- package/dist/config.js +290 -42
- package/dist/context/project_intelligence.d.ts +44 -0
- package/dist/context/project_intelligence.js +246 -0
- package/dist/desktop/cli_launch.d.ts +8 -0
- package/dist/desktop/cli_launch.js +6 -0
- package/dist/desktop/cli_shim.d.ts +8 -0
- package/dist/desktop/cli_shim.js +120 -0
- package/dist/desktop/runtime.d.ts +16 -0
- package/dist/desktop/runtime.js +161 -0
- package/dist/desktop/worker_launch.d.ts +7 -0
- package/dist/desktop/worker_launch.js +7 -0
- package/dist/diagnostics/cargo_mutants_selection.d.ts +27 -0
- package/dist/diagnostics/cargo_mutants_selection.js +48 -0
- package/dist/diagnostics/native_terminal_benchmark.d.ts +58 -0
- package/dist/diagnostics/native_terminal_benchmark.js +1247 -0
- package/dist/diagnostics/session_evidence_package.d.ts +40 -0
- package/dist/diagnostics/session_evidence_package.js +234 -0
- package/dist/diagnostics/session_export.d.ts +93 -0
- package/dist/diagnostics/session_export.js +634 -0
- package/dist/emulation/tool_adapters.js +48 -18
- package/dist/emulation/ztc_addendum.d.ts +1 -0
- package/dist/emulation/ztc_addendum.js +13 -12
- package/dist/environment/service_runner.d.ts +1 -0
- package/dist/environment/service_runner.js +68 -0
- package/dist/environment/store.d.ts +120 -0
- package/dist/environment/store.js +387 -0
- package/dist/events.d.ts +40 -1
- package/dist/events.js +10 -17
- package/dist/goal_contract.d.ts +25 -0
- package/dist/goal_contract.js +44 -0
- package/dist/headless.d.ts +31 -0
- package/dist/headless.js +578 -70
- package/dist/headless_cli.js +8 -0
- package/dist/headless_cli_args.d.ts +1 -0
- package/dist/headless_cli_args.js +1 -0
- package/dist/intake/cli.d.ts +1 -0
- package/dist/intake/cli.js +33 -0
- package/dist/intake/format.d.ts +2 -0
- package/dist/intake/format.js +14 -0
- package/dist/intake/notifications.d.ts +16 -0
- package/dist/intake/notifications.js +132 -0
- package/dist/intake/store.d.ts +56 -0
- package/dist/intake/store.js +238 -0
- package/dist/library.d.ts +8 -0
- package/dist/library.js +19 -10
- package/dist/mcp/client.d.ts +1 -0
- package/dist/mcp/client.js +20 -0
- package/dist/modes/builtin/plan.yaml +2 -2
- package/dist/modes/handlers.js +1 -1
- package/dist/onboarding/first_run.d.ts +3 -0
- package/dist/onboarding/first_run.js +33 -25
- package/dist/onboarding/setup.d.ts +32 -0
- package/dist/onboarding/setup.js +133 -0
- package/dist/onboarding/setup_agent_health.d.ts +17 -0
- package/dist/onboarding/setup_agent_health.js +79 -0
- package/dist/onboarding/setup_environment.d.ts +66 -0
- package/dist/onboarding/setup_environment.js +219 -0
- package/dist/onboarding/setup_workspace.d.ts +17 -0
- package/dist/onboarding/setup_workspace.js +129 -0
- package/dist/optimize/adapters/index.d.ts +4 -1
- package/dist/optimize/adapters/index.js +7 -0
- package/dist/optimize/adapters/kernelbench.js +14 -5
- package/dist/optimize/adapters/popcorn.js +3 -2
- package/dist/optimize/adapters/profile_benchmark.js +13 -7
- package/dist/optimize/adapters/rfbench.js +25 -14
- package/dist/optimize/adapters/types.d.ts +3 -0
- package/dist/optimize/adapters/zergpod.js +5 -2
- package/dist/optimize/baseline.js +10 -21
- package/dist/optimize/branch.js +9 -12
- package/dist/optimize/combine.js +2 -3
- package/dist/optimize/executor.js +34 -48
- package/dist/optimize/measurements.d.ts +55 -0
- package/dist/optimize/measurements.js +173 -0
- package/dist/optimize/results.d.ts +1 -0
- package/dist/optimize/results.js +11 -33
- package/dist/optimize/tge.js +2 -1
- package/dist/panes/initial_input.d.ts +19 -0
- package/dist/panes/initial_input.js +206 -0
- package/dist/panes/labels.d.ts +16 -0
- package/dist/panes/labels.js +42 -0
- package/dist/panes/model_catalog.d.ts +3 -3
- package/dist/panes/model_catalog.js +28 -4
- package/dist/panes/pane_registry.js +6 -2
- package/dist/panes/types.d.ts +3 -0
- package/dist/panes/ztc_launch.js +19 -0
- package/dist/plugin/optimization.d.ts +2 -0
- package/dist/plugin/optimization.js +1 -0
- package/dist/plugin/runtime.d.ts +2 -0
- package/dist/plugin/simulation.d.ts +6 -1
- package/dist/plugin/simulation_contract.d.ts +836 -1
- package/dist/plugin/simulation_documents.d.ts +22 -0
- package/dist/plugin/simulation_documents.js +1 -0
- package/dist/plugin/simulation_interventions.d.ts +103 -0
- package/dist/plugin/simulation_interventions.js +1 -0
- package/dist/plugin/simulation_living.d.ts +1 -0
- package/dist/plugin/simulation_living.js +3 -0
- package/dist/plugin/simulation_meetings.d.ts +121 -0
- package/dist/plugin/simulation_meetings.js +1 -0
- package/dist/plugin/simulation_story_review.d.ts +111 -0
- package/dist/plugin/simulation_story_review.js +1 -0
- package/dist/plugin/simulation_storyteller.d.ts +91 -0
- package/dist/plugin/simulation_storyteller.js +1 -0
- package/dist/plugin/simulation_structured.d.ts +2 -0
- package/dist/plugin/simulation_structured.js +2 -0
- package/dist/plugin/simulation_toolkit.d.ts +21 -0
- package/dist/plugin/simulation_toolkit.js +24 -0
- package/dist/prompts/tool_delegate_task.j2 +1 -1
- package/dist/remote-broker/Dockerfile +10 -0
- package/dist/remote-broker/archive.py +1227 -0
- package/dist/remote-broker/cutover.py +761 -0
- package/dist/remote-broker/requirements.txt +5 -0
- package/dist/remote-broker/resources.json +6 -0
- package/dist/remote-broker/resources.write-staging.example.json +18 -0
- package/dist/remote-broker/retained.py +686 -0
- package/dist/remote-broker/retained_cleanup.py +550 -0
- package/dist/remote-broker/server.py +648 -0
- package/dist/remote-broker/worker.py +1007 -0
- package/dist/router_auth.d.ts +31 -0
- package/dist/router_auth.js +155 -9
- package/dist/runbooks/catalog.d.ts +3 -0
- package/dist/runbooks/catalog.js +26 -0
- package/dist/runbooks/library.d.ts +11 -0
- package/dist/runbooks/library.js +95 -0
- package/dist/runbooks/package.d.ts +43 -0
- package/dist/runbooks/package.js +102 -0
- package/dist/session.d.ts +65 -13
- package/dist/session.js +548 -43
- package/dist/session_handoff.d.ts +25 -0
- package/dist/session_handoff.js +322 -0
- package/dist/session_handoff_contract.d.ts +89 -0
- package/dist/session_handoff_contract.js +179 -0
- package/dist/session_media.d.ts +41 -0
- package/dist/session_media.js +357 -0
- package/dist/session_ownership.d.ts +16 -0
- package/dist/session_ownership.js +221 -0
- package/dist/session_public.d.ts +10 -2
- package/dist/session_public.js +6 -1
- package/dist/simulation/dynamic_history.d.ts +42 -0
- package/dist/simulation/dynamic_history.js +173 -0
- package/dist/simulation/engines/swarm/pane_manager.js +7 -6
- package/dist/simulation/inference.d.ts +3 -1
- package/dist/simulation/inference.js +19 -1
- package/dist/simulation/intervention_generation.d.ts +27 -0
- package/dist/simulation/intervention_generation.js +246 -0
- package/dist/simulation/intervention_material.d.ts +4 -0
- package/dist/simulation/intervention_material.js +81 -0
- package/dist/simulation/living/context.d.ts +3130 -0
- package/dist/simulation/living/context.js +944 -0
- package/dist/simulation/living/definer.d.ts +12 -0
- package/dist/simulation/living/definer.js +223 -0
- package/dist/simulation/living/definition.d.ts +257 -0
- package/dist/simulation/living/definition.js +341 -0
- package/dist/simulation/living/frame.d.ts +259 -0
- package/dist/simulation/living/frame.js +223 -0
- package/dist/simulation/living/identifiers.d.ts +2 -0
- package/dist/simulation/living/identifiers.js +12 -0
- package/dist/simulation/living/index.d.ts +15 -0
- package/dist/simulation/living/index.js +15 -0
- package/dist/simulation/living/inference.d.ts +219 -0
- package/dist/simulation/living/inference.js +576 -0
- package/dist/simulation/living/mechanics.d.ts +54 -0
- package/dist/simulation/living/mechanics.js +588 -0
- package/dist/simulation/living/model-input.d.ts +25 -0
- package/dist/simulation/living/model-input.js +215 -0
- package/dist/simulation/living/open-world.d.ts +257 -0
- package/dist/simulation/living/open-world.js +102 -0
- package/dist/simulation/living/projection.d.ts +7 -0
- package/dist/simulation/living/projection.js +31 -0
- package/dist/simulation/living/recall.d.ts +17 -0
- package/dist/simulation/living/recall.js +25 -0
- package/dist/simulation/living/reduce.d.ts +15 -0
- package/dist/simulation/living/reduce.js +1853 -0
- package/dist/simulation/living/replay.d.ts +6 -0
- package/dist/simulation/living/replay.js +22 -0
- package/dist/simulation/living/runtime.d.ts +140 -0
- package/dist/simulation/living/runtime.js +3020 -0
- package/dist/simulation/living/shared-kinds.d.ts +24 -0
- package/dist/simulation/living/shared-kinds.js +96 -0
- package/dist/simulation/living/types.d.ts +2785 -0
- package/dist/simulation/living/types.js +669 -0
- package/dist/simulation/llm.d.ts +3 -1
- package/dist/simulation/llm.js +90 -30
- package/dist/simulation/memory/embedding.d.ts +1 -1
- package/dist/simulation/memory/embedding.js +9 -3
- package/dist/simulation/memory/filesystem.d.ts +2 -0
- package/dist/simulation/memory/filesystem.js +5 -1
- package/dist/simulation/memory/filesystem_file_tree.d.ts +4 -1
- package/dist/simulation/memory/filesystem_file_tree.js +41 -10
- package/dist/simulation/memory/filesystem_invariants.js +1 -2
- package/dist/simulation/memory/filesystem_types.d.ts +1 -0
- package/dist/simulation/memory/memory.d.ts +2 -0
- package/dist/simulation/memory/memory.js +5 -1
- package/dist/simulation/orchestration/intent.js +0 -2
- package/dist/simulation/orchestration/lifecycle.js +0 -2
- package/dist/simulation/plugin_host.d.ts +25 -1
- package/dist/simulation/plugin_host.js +334 -17
- package/dist/simulation/session_documents.d.ts +20 -0
- package/dist/simulation/session_documents.js +62 -0
- package/dist/simulation/session_input_validation.d.ts +43 -0
- package/dist/simulation/session_input_validation.js +364 -0
- package/dist/simulation/session_inputs.d.ts +32 -0
- package/dist/simulation/session_inputs.js +154 -0
- package/dist/simulation/telemetry.d.ts +11 -14
- package/dist/simulation/telemetry.js +177 -54
- package/dist/simulation/toolkit/bounded_turns.d.ts +13 -0
- package/dist/simulation/toolkit/bounded_turns.js +80 -0
- package/dist/simulation/toolkit/dynamic_agents.d.ts +25 -0
- package/dist/simulation/toolkit/dynamic_agents.js +218 -0
- package/dist/simulation/toolkit/dynamic_digest.d.ts +1 -0
- package/dist/simulation/toolkit/dynamic_digest.js +8 -0
- package/dist/simulation/toolkit/dynamic_documents.d.ts +7 -0
- package/dist/simulation/toolkit/dynamic_documents.js +71 -0
- package/dist/simulation/toolkit/dynamic_driver.d.ts +8 -0
- package/dist/simulation/toolkit/dynamic_driver.js +269 -0
- package/dist/simulation/toolkit/dynamic_game.d.ts +53 -0
- package/dist/simulation/toolkit/dynamic_game.js +805 -0
- package/dist/simulation/toolkit/dynamic_knowledge.d.ts +15 -0
- package/dist/simulation/toolkit/dynamic_knowledge.js +91 -0
- package/dist/simulation/toolkit/dynamic_mechanics.d.ts +22 -0
- package/dist/simulation/toolkit/dynamic_mechanics.js +910 -0
- package/dist/simulation/toolkit/dynamic_meetings.d.ts +239 -0
- package/dist/simulation/toolkit/dynamic_meetings.js +350 -0
- package/dist/simulation/toolkit/dynamic_progress.d.ts +131 -0
- package/dist/simulation/toolkit/dynamic_progress.js +214 -0
- package/dist/simulation/toolkit/dynamic_projection.d.ts +9 -0
- package/dist/simulation/toolkit/dynamic_projection.js +219 -0
- package/dist/simulation/toolkit/dynamic_runtime.d.ts +412 -0
- package/dist/simulation/toolkit/dynamic_runtime.js +6536 -0
- package/dist/simulation/toolkit/dynamic_state.d.ts +111 -0
- package/dist/simulation/toolkit/dynamic_state.js +1967 -0
- package/dist/simulation/toolkit/dynamic_story_review.d.ts +508 -0
- package/dist/simulation/toolkit/dynamic_story_review.js +333 -0
- package/dist/simulation/toolkit/dynamic_storyteller.d.ts +77 -0
- package/dist/simulation/toolkit/dynamic_storyteller.js +114 -0
- package/dist/simulation/toolkit/dynamic_storyteller_runtime.d.ts +26 -0
- package/dist/simulation/toolkit/dynamic_storyteller_runtime.js +126 -0
- package/dist/simulation/toolkit/dynamic_world.d.ts +22 -0
- package/dist/simulation/toolkit/dynamic_world.js +377 -0
- package/dist/simulation/toolkit/structured_output.d.ts +5 -0
- package/dist/simulation/toolkit/structured_output.js +321 -0
- package/dist/simulation/types/world.d.ts +2 -0
- package/dist/simulation/world/artifact_store.js +1 -1
- package/dist/simulation/world/memory_manager.d.ts +5 -0
- package/dist/simulation/world/memory_manager.js +17 -2
- package/dist/simulation/world/state.d.ts +3 -2
- package/dist/simulation/world/state.js +15 -5
- package/dist/skills/bundled/measurement-validation/SKILL.md +144 -0
- package/dist/terminal_attach.d.ts +1 -0
- package/dist/terminal_attach.js +113 -0
- package/dist/tool_progress.d.ts +3 -0
- package/dist/tool_progress.js +27 -0
- package/dist/types.d.ts +145 -10
- package/dist/types.js +3 -0
- package/dist/ui/core/input.d.ts +3 -0
- package/dist/ui/core/input_segments.d.ts +18 -1
- package/dist/ui/core/input_segments.js +131 -47
- package/dist/ui/core/input_state.d.ts +12 -0
- package/dist/ui/core/layout_yoga.d.ts +1 -1
- package/dist/ui/core/turn_metadata.d.ts +5 -0
- package/dist/ui/core/turn_metadata.js +22 -0
- package/dist/ui/ink/render.d.ts +2 -1
- package/dist/ui/ink/render.js +6 -5
- package/dist/ui/ratatui/headless_pane_manager.d.ts +14 -1
- package/dist/ui/ratatui/headless_pane_manager.js +293 -104
- package/dist/ui/ratatui/index.d.ts +1 -0
- package/dist/ui/ratatui/input.d.ts +4 -0
- package/dist/ui/ratatui/input.js +15 -0
- package/dist/ui/ratatui/ipc_path.d.ts +2 -0
- package/dist/ui/ratatui/ipc_path.js +29 -1
- package/dist/ui/ratatui/mux_persistence.d.ts +3 -1
- package/dist/ui/ratatui/mux_persistence.js +139 -1
- package/dist/ui/ratatui/pane_relay.d.ts +1 -1
- package/dist/ui/ratatui/pane_relay.js +55 -27
- package/dist/ui/ratatui/process.d.ts +17 -1
- package/dist/ui/ratatui/process.js +80 -7
- package/dist/ui/ratatui/protocol.d.ts +236 -1
- package/dist/ui/ratatui/protocol.js +90 -0
- package/dist/ui/scrollback.d.ts +2 -1
- package/dist/ui/scrollback.js +9 -4
- package/dist/ui/stream_typewriter.d.ts +8 -3
- package/dist/ui/stream_typewriter.js +30 -1
- package/dist/ui/streaming_scrollback.d.ts +1 -0
- package/dist/ui/streaming_scrollback.js +1 -1
- package/dist/ui/transcript_render_cache.js +10 -0
- package/dist/ui/views/activity_line.d.ts +5 -3
- package/dist/ui/views/activity_line.js +65 -7
- package/dist/ui/views/app.d.ts +6 -3
- package/dist/ui/views/app.js +17 -6
- package/dist/ui/views/completion_menu.js +10 -5
- package/dist/ui/views/input_area.d.ts +7 -3
- package/dist/ui/views/input_area.js +15 -9
- package/dist/ui/views/message_list.d.ts +4 -1
- package/dist/ui/views/message_list.js +89 -19
- package/dist/ui/views/queue_panel.d.ts +3 -1
- package/dist/ui/views/queue_panel.js +9 -2
- package/dist/ui/views/status_bar.d.ts +4 -2
- package/dist/ui/views/status_bar.js +28 -13
- package/dist/ui/views/theme.d.ts +2 -0
- package/dist/ui/views/theme.js +2 -0
- package/dist/ui/widgets/color_panel.js +18 -0
- package/dist/ui/widgets/form.js +8 -0
- package/dist/ui/widgets/log_view.js +7 -0
- package/dist/ui/widgets/navigator_panel.js +8 -0
- package/dist/ui/widgets/prompt_viewer.js +2 -0
- package/dist/ui/widgets/questionnaire.d.ts +2 -0
- package/dist/ui/widgets/questionnaire.js +79 -16
- package/dist/ui/widgets/resume_panel.d.ts +2 -0
- package/dist/ui/widgets/resume_panel.js +26 -15
- package/dist/ui/widgets/rewind_panel.d.ts +2 -2
- package/dist/ui/widgets/rewind_panel.js +4 -2
- package/dist/ui/widgets/select.js +16 -27
- package/dist/ui/widgets/settings_panel.js +16 -0
- package/dist/ui/widgets/status_line_panel.d.ts +1 -0
- package/dist/ui/widgets/status_line_panel.js +30 -4
- package/dist/ui/widgets/text_input.d.ts +2 -0
- package/dist/ui/widgets/text_input.js +15 -1
- package/dist/ui/widgets/types.d.ts +2 -0
- package/dist/usage_projection.d.ts +24 -0
- package/dist/usage_projection.js +130 -0
- package/dist/usage_snapshot.d.ts +36 -0
- package/dist/usage_snapshot.js +131 -0
- package/dist/utils/assistant_message.d.ts +2 -0
- package/dist/utils/assistant_message.js +5 -0
- package/dist/utils/atomic_write.d.ts +6 -2
- package/dist/utils/atomic_write.js +29 -4
- package/dist/utils/checked_shell.d.ts +25 -0
- package/dist/utils/checked_shell.js +107 -0
- package/dist/utils/compaction.d.ts +4 -1
- package/dist/utils/compaction.js +31 -7
- package/dist/utils/context.d.ts +4 -4
- package/dist/utils/context.js +14 -12
- package/dist/utils/deepseek.d.ts +2 -2
- package/dist/utils/deepseek.js +13 -5
- package/dist/utils/ephemeral.js +4 -0
- package/dist/utils/ephemeral_tools.d.ts +18 -0
- package/dist/utils/ephemeral_tools.js +97 -0
- package/dist/utils/jev_client.d.ts +4 -0
- package/dist/utils/jev_client.js +15 -0
- package/dist/utils/model_cache.d.ts +15 -0
- package/dist/utils/model_cache.js +143 -0
- package/dist/utils/models.d.ts +4 -2
- package/dist/utils/models.js +12 -16
- package/dist/utils/reasoning.d.ts +8 -1
- package/dist/utils/reasoning.js +31 -11
- package/dist/utils/router_catalog.d.ts +49 -0
- package/dist/utils/router_catalog.js +271 -0
- package/dist/utils/sandbox.d.ts +9 -0
- package/dist/utils/sandbox.js +118 -15
- package/dist/utils/shell.d.ts +7 -0
- package/dist/utils/shell.js +98 -34
- package/dist/utils/subprocess_env.d.ts +3 -0
- package/dist/utils/subprocess_env.js +27 -1
- package/dist/web/accounts_mirror.d.ts +3 -1
- package/dist/web/accounts_mirror.js +13 -9
- package/dist/web/child_publication.d.ts +17 -0
- package/dist/web/child_publication.js +45 -0
- package/dist/web/mirror_authenticator.d.ts +31 -11
- package/dist/web/mirror_authenticator.js +67 -17
- package/dist/web/mirror_client.d.ts +31 -4
- package/dist/web/mirror_client.js +189 -23
- package/dist/web/mirror_stream.d.ts +84 -22
- package/dist/web/mirror_stream.js +676 -95
- package/dist/web/observer_query_redaction.d.ts +6 -0
- package/dist/web/observer_query_redaction.js +58 -0
- package/dist/web/pane_registry.d.ts +2 -0
- package/dist/web/pane_registry.js +86 -22
- package/dist/web/tool_image.d.ts +6 -0
- package/dist/web/tool_image.js +17 -0
- package/dist/web/view_plugin.d.ts +14 -0
- package/dist/web/view_plugin.js +23 -1
- package/dist/worker/executor.js +31 -12
- package/dist/worker/index.d.ts +1 -0
- package/dist/worker/toolsets.js +3 -1
- package/dist/worker/types.d.ts +12 -1
- package/dist/workflows/registry.js +1 -0
- package/dist/workflows/registry_handle.d.ts +2 -0
- package/dist/workflows/runtime.d.ts +2 -0
- package/dist/workflows/runtime.js +1 -0
- package/dist/workspace_agent.d.ts +7 -0
- package/dist/workspace_agent.js +36 -0
- package/dist/workspace_collision.d.ts +76 -0
- package/dist/workspace_collision.js +688 -0
- package/dist/workspace_layout.d.ts +18 -0
- package/dist/workspace_layout.js +121 -0
- package/dist/workspace_runtime.d.ts +44 -0
- package/dist/workspace_runtime.js +82 -0
- package/dist/workspace_session_context.d.ts +62 -0
- package/dist/workspace_session_context.js +160 -0
- package/dist/zlm-embed.mjs +32518 -9615
- package/dist/zlm.js +1 -0
- package/node_modules/@zerg/model-contracts/LICENSE.md +375 -0
- package/node_modules/@zerg/model-contracts/README.md +90 -0
- package/node_modules/@zerg/model-contracts/index.d.ts +20 -0
- package/node_modules/@zerg/model-contracts/index.js +223 -0
- package/node_modules/@zerg/model-contracts/package.json +8 -0
- package/node_modules/glob/node_modules/brace-expansion/index.js +78 -22
- package/node_modules/glob/node_modules/brace-expansion/package.json +1 -1
- package/node_modules/readdir-glob/node_modules/brace-expansion/index.js +78 -22
- package/node_modules/readdir-glob/node_modules/brace-expansion/package.json +1 -1
- package/package.json +45 -24
- package/packages/model-contracts/LICENSE.md +375 -0
- package/packages/model-contracts/README.md +90 -0
- package/packages/model-contracts/index.d.ts +20 -0
- package/packages/model-contracts/index.js +223 -0
- package/packages/model-contracts/package.json +8 -0
- package/remote-broker/Dockerfile +10 -0
- package/remote-broker/README.md +308 -0
- package/remote-broker/archive.py +1227 -0
- package/remote-broker/cutover.py +761 -0
- package/remote-broker/requirements.txt +5 -0
- package/remote-broker/resources.example.json +6 -0
- package/remote-broker/resources.write-staging.example.json +18 -0
- package/remote-broker/retained.py +686 -0
- package/remote-broker/retained_cleanup.py +550 -0
- package/remote-broker/server.py +648 -0
- package/scripts/build-remote-broker.mjs +13 -0
- package/scripts/ensure-local-packages.mjs +6 -0
- package/scripts/node-pty-helpers.mjs +103 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Session } from './session.js';
|
|
2
|
+
import type { Message } from './types.js';
|
|
3
|
+
import { type TaskHandoffInput, type TaskHandoffSnapshot } from './session_handoff_contract.js';
|
|
4
|
+
export type TaskHandoffAdmissionReason = 'invalid_handoff' | 'unsupported_handoff_version' | 'handoff_fingerprint_mismatch';
|
|
5
|
+
export declare class TaskHandoffAdmissionError extends Error {
|
|
6
|
+
readonly reason: TaskHandoffAdmissionReason;
|
|
7
|
+
constructor(reason: TaskHandoffAdmissionReason, message: string);
|
|
8
|
+
}
|
|
9
|
+
type Checkpoint = Pick<Session, 'metadata' | 'messages' | 'evidence'>;
|
|
10
|
+
/** Cwd association is canonical filesystem identity when available, never a pane ID. */
|
|
11
|
+
export declare function canonicalHandoffCwd(cwd: string): string;
|
|
12
|
+
/** Fingerprints cover exactly the normalized persisted checkpoint, including delivery metadata. */
|
|
13
|
+
export declare function taskHandoffFingerprints(session: Checkpoint): {
|
|
14
|
+
messagesSha256: string;
|
|
15
|
+
evidenceSha256: string;
|
|
16
|
+
};
|
|
17
|
+
/** Parse and bind a snapshot to its original complete session payload. No fuzzy transplant. */
|
|
18
|
+
export declare function admitTaskHandoff(value: unknown, session: Checkpoint): TaskHandoffSnapshot;
|
|
19
|
+
/**
|
|
20
|
+
* Derive host facts only; narrated completion and inferred next actions remain unavailable.
|
|
21
|
+
* previousMessages belongs to the same admitted predecessor as previous. A
|
|
22
|
+
* retained Clear event is consumed there, even if compaction rewrites row IDs.
|
|
23
|
+
*/
|
|
24
|
+
export declare function deriveTaskHandoff(session: Checkpoint, input?: TaskHandoffInput, previous?: TaskHandoffSnapshot, previousMessages?: readonly Message[]): TaskHandoffSnapshot | null;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
|
+
import { SESSION_MEDIA_LIMITS } from './session_media.js';
|
|
5
|
+
import { stripEphemeralMessages } from './utils/ephemeral.js';
|
|
6
|
+
import { parseEvidenceSnapshot } from './agent/runtime/evidence.js';
|
|
7
|
+
import { parseTaskHandoffSnapshot, TASK_HANDOFF_MAX_BYTES, TASK_HANDOFF_MAX_CORRECTIONS, TASK_HANDOFF_MAX_REFERENCES, TASK_HANDOFF_MAX_TEXT_BYTES, } from './session_handoff_contract.js';
|
|
8
|
+
export class TaskHandoffAdmissionError extends Error {
|
|
9
|
+
reason;
|
|
10
|
+
constructor(reason, message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.reason = reason;
|
|
13
|
+
this.name = 'TaskHandoffAdmissionError';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function correctionSourceText(session, correction) {
|
|
17
|
+
const message = session.messages.find(item => item.id === correction.sourceMessageId);
|
|
18
|
+
if (!message)
|
|
19
|
+
return null;
|
|
20
|
+
if (message.role === 'user' && !message.metadata?.synthetic && !message.metadata?.toolResult && !message.metadata?.compactionSummary)
|
|
21
|
+
return message.content;
|
|
22
|
+
const raw = message.metadata?.taskHandoffCorrection;
|
|
23
|
+
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
24
|
+
return null;
|
|
25
|
+
const source = raw;
|
|
26
|
+
return source.id === correction.id && typeof source.text === 'string' ? source.text : null;
|
|
27
|
+
}
|
|
28
|
+
/** Image-only intent requires its exact source, not a vacuous empty preview. */
|
|
29
|
+
function hasMediaOnlySource(session, correction) {
|
|
30
|
+
const message = session.messages.find(item => item.id === correction.sourceMessageId);
|
|
31
|
+
if (!message || (message.role !== 'user' && message.role !== 'system')
|
|
32
|
+
|| message.metadata?.synthetic || message.metadata?.toolResult || message.metadata?.compactionSummary)
|
|
33
|
+
return false;
|
|
34
|
+
const source = correctionSourceText(session, correction);
|
|
35
|
+
if (source === null || source.trim()
|
|
36
|
+
|| (source !== correction.text && (Buffer.byteLength(source) <= TASK_HANDOFF_MAX_TEXT_BYTES
|
|
37
|
+
|| boundedText(source, { corrections: 0, completedObservations: 0, unresolvedCalls: 0, textBytes: 0 }) !== correction.text)))
|
|
38
|
+
return false;
|
|
39
|
+
if (!Array.isArray(message.attachments))
|
|
40
|
+
return false;
|
|
41
|
+
return message.attachments.some(attachment => {
|
|
42
|
+
if (!attachment || attachment.kind !== 'image' || typeof attachment.id !== 'string'
|
|
43
|
+
|| !attachment.id || Buffer.byteLength(attachment.id) > 256 || /[\u0000-\u001f\u007f]/u.test(attachment.id)
|
|
44
|
+
|| typeof attachment.name !== 'string' || typeof attachment.mediaType !== 'string'
|
|
45
|
+
|| !Number.isSafeInteger(attachment.size) || attachment.size <= 0 || attachment.size > SESSION_MEDIA_LIMITS.imageBytes)
|
|
46
|
+
return false;
|
|
47
|
+
const ref = attachment.durable;
|
|
48
|
+
if (!ref || typeof ref !== 'object' || Array.isArray(ref) || Object.keys(ref).length !== 4 || ref.version !== 1
|
|
49
|
+
|| typeof ref.sessionFile !== 'string' || !/^(?:\/|[A-Za-z]:[\\/]|\\\\)/u.test(ref.sessionFile)
|
|
50
|
+
|| /[\u0000-\u001f\u007f]/u.test(ref.sessionFile) || typeof ref.sha256 !== 'string'
|
|
51
|
+
|| !/^[a-f0-9]{64}$/u.test(ref.sha256) || typeof ref.file !== 'string')
|
|
52
|
+
return false;
|
|
53
|
+
const file = /^g-[a-f0-9]{32}\/([a-f0-9]{64})\.(png|jpg|gif|webp)$/u.exec(ref.file);
|
|
54
|
+
const mediaTypes = { png: 'image/png', jpg: 'image/jpeg', gif: 'image/gif', webp: 'image/webp' };
|
|
55
|
+
return file !== null && file[1] === ref.sha256 && mediaTypes[file[2]] === attachment.mediaType;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/** Cwd association is canonical filesystem identity when available, never a pane ID. */
|
|
59
|
+
export function canonicalHandoffCwd(cwd) {
|
|
60
|
+
const absolute = resolve(cwd);
|
|
61
|
+
try {
|
|
62
|
+
return realpathSync(absolute);
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
if (error.code === 'ENOENT')
|
|
66
|
+
return absolute;
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function canonicalJson(value) {
|
|
71
|
+
const normalized = JSON.parse(JSON.stringify(value ?? null));
|
|
72
|
+
const sorted = (item) => {
|
|
73
|
+
if (Array.isArray(item))
|
|
74
|
+
return item.map(sorted);
|
|
75
|
+
if (item && typeof item === 'object')
|
|
76
|
+
return Object.fromEntries(Object.entries(item).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, child]) => [key, sorted(child)]));
|
|
77
|
+
return item;
|
|
78
|
+
};
|
|
79
|
+
return JSON.stringify(sorted(normalized));
|
|
80
|
+
}
|
|
81
|
+
/** Fingerprints cover exactly the normalized persisted checkpoint, including delivery metadata. */
|
|
82
|
+
export function taskHandoffFingerprints(session) {
|
|
83
|
+
const digest = (value) => createHash('sha256').update(canonicalJson(value)).digest('hex');
|
|
84
|
+
return { messagesSha256: digest(stripEphemeralMessages(session.messages)), evidenceSha256: digest(session.evidence === undefined ? null : parseEvidenceSnapshot(session.evidence)) };
|
|
85
|
+
}
|
|
86
|
+
/** Parse and bind a snapshot to its original complete session payload. No fuzzy transplant. */
|
|
87
|
+
export function admitTaskHandoff(value, session) {
|
|
88
|
+
if (value && typeof value === 'object' && 'schemaVersion' in value && value.schemaVersion !== 1) {
|
|
89
|
+
throw new TaskHandoffAdmissionError('unsupported_handoff_version', 'Saved task handoff declares an unsupported schema version. The original checkpoint was not changed.');
|
|
90
|
+
}
|
|
91
|
+
const snapshot = parseTaskHandoffSnapshot(value);
|
|
92
|
+
if (!snapshot)
|
|
93
|
+
throw new TaskHandoffAdmissionError('invalid_handoff', 'Saved task handoff is malformed or exceeds its bounds. The original checkpoint was not changed.');
|
|
94
|
+
const expectedTaskId = snapshot.objective.kind === 'goal'
|
|
95
|
+
? `goal:${snapshot.objective.goalId}` : `request:${snapshot.objective.sourceMessageId}`;
|
|
96
|
+
if (snapshot.taskId !== expectedTaskId) {
|
|
97
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved task handoff task identity does not match its original objective source. The original checkpoint was not changed.');
|
|
98
|
+
}
|
|
99
|
+
const hashes = taskHandoffFingerprints(session);
|
|
100
|
+
if (snapshot.source.sessionId !== session.metadata.id || snapshot.source.cwd !== canonicalHandoffCwd(session.metadata.cwd)
|
|
101
|
+
|| snapshot.source.messagesSha256 !== hashes.messagesSha256 || snapshot.source.evidenceSha256 !== hashes.evidenceSha256) {
|
|
102
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved task handoff does not match its source session, cwd, messages or evidence. The original checkpoint was not changed.');
|
|
103
|
+
}
|
|
104
|
+
const evidence = session.evidence === undefined ? null : parseEvidenceSnapshot(session.evidence);
|
|
105
|
+
if (snapshot.objective.kind === 'goal') {
|
|
106
|
+
const goal = session.metadata.goal;
|
|
107
|
+
if (!goal || goal.goalId !== snapshot.objective.goalId || goal.status !== snapshot.taskStatus || !goal.objective.startsWith(snapshot.objective.text)) {
|
|
108
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved task handoff goal identity, status or objective does not match its source goal. The original checkpoint was not changed.');
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const message = session.messages.find(item => item.id === snapshot.objective.sourceMessageId && item.role === 'user' && !item.metadata?.synthetic && !item.metadata?.compactionSummary && !item.metadata?.toolResult);
|
|
113
|
+
const instruction = evidence?.records.find(item => item.kind === 'user_instruction' && item.source.messageId === snapshot.objective.sourceMessageId);
|
|
114
|
+
const present = Boolean(message || instruction);
|
|
115
|
+
if ((snapshot.objective.sourceAvailability === 'present') !== present || (message && !message.content.startsWith(snapshot.objective.text))) {
|
|
116
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved task handoff opening-request source identity or availability does not match its checkpoint. The original checkpoint was not changed.');
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
for (const blocker of snapshot.blockers) {
|
|
120
|
+
const goal = session.metadata.goal;
|
|
121
|
+
if (!goal || goal.goalId !== blocker.sourceGoalId || typeof goal.blockedReason !== 'string' || !goal.blockedReason.startsWith(blocker.text)) {
|
|
122
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved blocker text does not match its original goal source. The original checkpoint was not changed.');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (snapshot.nextAction.availability === 'recorded') {
|
|
126
|
+
const message = session.messages.find(item => item.id === snapshot.nextAction.sourceMessageId && item.role === 'user'
|
|
127
|
+
&& !item.metadata?.synthetic && !item.metadata?.toolResult && !item.metadata?.compactionSummary && !item.metadata?.managedCommandObservation);
|
|
128
|
+
if (!message || !message.content.startsWith(snapshot.nextAction.text)) {
|
|
129
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved next-action text does not match its original authored message source. The original checkpoint was not changed.');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const correction of snapshot.corrections)
|
|
133
|
+
if (correction.sourceMessageId !== null) {
|
|
134
|
+
if (!correction.text.trim() && !hasMediaOnlySource(session, correction)) {
|
|
135
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved image-only correction does not match its exact owned image source. The original checkpoint was not changed.');
|
|
136
|
+
}
|
|
137
|
+
const source = correctionSourceText(session, correction);
|
|
138
|
+
if (source === null || !source.startsWith(correction.text))
|
|
139
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved correction preview does not match its original transcript source. The original checkpoint was not changed.');
|
|
140
|
+
}
|
|
141
|
+
for (const row of snapshot.completedObservations) {
|
|
142
|
+
const observation = evidence?.records.find(item => item.kind === 'observation' && item.id === row.observationId && item.source.origin === 'host_receipt');
|
|
143
|
+
const job = observation?.source.job;
|
|
144
|
+
if (!observation || !job || job.sessionId !== session.metadata.id || observation.source.toolCallId !== row.toolCallId
|
|
145
|
+
|| job.jobId !== row.jobId || job.status !== row.status || job.exitCode !== row.exitCode || !job.endedAt) {
|
|
146
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved terminal process reference does not match its host receipt. The original checkpoint was not changed.');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
for (const row of snapshot.unresolvedCalls) {
|
|
150
|
+
const call = session.messages.find(message => message.id === row.sourceMessageId)?.toolCalls?.find(item => item.id === row.toolCallId);
|
|
151
|
+
if (!call || call.name !== row.name || (call.status !== 'pending' && call.status !== 'running' && (call.result !== undefined || call.error !== undefined))) {
|
|
152
|
+
throw new TaskHandoffAdmissionError('handoff_fingerprint_mismatch', 'Saved unresolved call does not match its source tool call. The original checkpoint was not changed.');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return snapshot;
|
|
156
|
+
}
|
|
157
|
+
function boundedText(value, omitted) {
|
|
158
|
+
let size = 0;
|
|
159
|
+
let kept = '';
|
|
160
|
+
for (const char of value) {
|
|
161
|
+
const length = Buffer.byteLength(char);
|
|
162
|
+
if (size + length > TASK_HANDOFF_MAX_TEXT_BYTES)
|
|
163
|
+
break;
|
|
164
|
+
kept += char;
|
|
165
|
+
size += length;
|
|
166
|
+
}
|
|
167
|
+
omitted.textBytes += Buffer.byteLength(value) - size;
|
|
168
|
+
return kept;
|
|
169
|
+
}
|
|
170
|
+
function taskHandoffResetId(message) {
|
|
171
|
+
const value = message.metadata?.taskHandoffReset;
|
|
172
|
+
return message.role === 'system' && typeof value === 'string'
|
|
173
|
+
&& /^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/u.test(value)
|
|
174
|
+
? value : null;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Derive host facts only; narrated completion and inferred next actions remain unavailable.
|
|
178
|
+
* previousMessages belongs to the same admitted predecessor as previous. A
|
|
179
|
+
* retained Clear event is consumed there, even if compaction rewrites row IDs.
|
|
180
|
+
*/
|
|
181
|
+
export function deriveTaskHandoff(session, input, previous, previousMessages) {
|
|
182
|
+
const messages = stripEphemeralMessages(session.messages);
|
|
183
|
+
const goal = session.metadata.goal;
|
|
184
|
+
const usableGoal = goal && typeof goal.goalId === 'string' && typeof goal.objective === 'string' && goal.objective.trim()
|
|
185
|
+
&& ['active', 'paused', 'blocked', 'budget_limited', 'complete'].includes(goal.status) ? goal : null;
|
|
186
|
+
let resetIndex = -1;
|
|
187
|
+
let resetId = null;
|
|
188
|
+
messages.forEach((message, index) => {
|
|
189
|
+
const event = taskHandoffResetId(message);
|
|
190
|
+
if (event !== null) {
|
|
191
|
+
resetIndex = index;
|
|
192
|
+
resetId = event;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
const resetConsumed = resetId !== null && stripEphemeralMessages(previousMessages ?? [])
|
|
196
|
+
.some(message => taskHandoffResetId(message) === resetId);
|
|
197
|
+
const opening = messages.find((message, index) => index > resetIndex && message.role === 'user' && typeof message.content === 'string' && message.content.trim()
|
|
198
|
+
&& !message.metadata?.synthetic && !message.metadata?.toolResult && !message.metadata?.steering
|
|
199
|
+
&& !message.metadata?.compactionSummary && !message.metadata?.managedCommandObservation);
|
|
200
|
+
const prior = previous?.source.sessionId === session.metadata.id && previous.source.cwd === canonicalHandoffCwd(session.metadata.cwd) ? previous : undefined;
|
|
201
|
+
const retainOpening = !usableGoal && prior?.objective.kind === 'opening_request' && messages.length > 0
|
|
202
|
+
&& (resetIndex < 0 || resetConsumed);
|
|
203
|
+
if (!usableGoal && !opening && !retainOpening)
|
|
204
|
+
return null;
|
|
205
|
+
const omitted = { corrections: 0, completedObservations: 0, unresolvedCalls: 0, textBytes: 0 };
|
|
206
|
+
const objective = usableGoal
|
|
207
|
+
? { kind: 'goal', text: boundedText(usableGoal.objective, omitted), sourceMessageId: null, goalId: usableGoal.goalId, sourceAvailability: 'present' }
|
|
208
|
+
: retainOpening ? { ...prior.objective }
|
|
209
|
+
: { kind: 'opening_request', text: boundedText(opening.content, omitted), sourceMessageId: opening.id, goalId: null, sourceAvailability: 'present' };
|
|
210
|
+
const taskId = usableGoal ? `goal:${usableGoal.goalId}` : retainOpening ? prior.taskId : `request:${opening.id}`;
|
|
211
|
+
const sameTask = prior?.taskId === taskId;
|
|
212
|
+
const corrections = input?.corrections ?? (sameTask ? prior.corrections : []);
|
|
213
|
+
const applicableCorrections = corrections.filter(correction => !usableGoal || correction.deliveryState !== 'delivered'
|
|
214
|
+
|| !Number.isFinite(usableGoal.createdAt) || Date.parse(correction.queuedAt) >= usableGoal.createdAt);
|
|
215
|
+
const recordedOrder = (a, b) => {
|
|
216
|
+
if (a.queuedPosition !== undefined && b.queuedPosition !== undefined) {
|
|
217
|
+
const difference = a.queuedPosition - b.queuedPosition;
|
|
218
|
+
if (difference !== 0)
|
|
219
|
+
return difference;
|
|
220
|
+
}
|
|
221
|
+
else if (a.queuedPosition !== undefined)
|
|
222
|
+
return -1;
|
|
223
|
+
else if (b.queuedPosition !== undefined)
|
|
224
|
+
return 1;
|
|
225
|
+
return a.queuedAt.localeCompare(b.queuedAt) || a.id.localeCompare(b.id);
|
|
226
|
+
};
|
|
227
|
+
const uncertain = applicableCorrections.filter(correction => correction.deliveryState !== 'delivered').sort(recordedOrder);
|
|
228
|
+
const delivered = applicableCorrections.filter(correction => correction.deliveryState === 'delivered').sort(recordedOrder);
|
|
229
|
+
const pendingPreview = uncertain.slice(0, TASK_HANDOFF_MAX_CORRECTIONS);
|
|
230
|
+
const deliveredSlots = TASK_HANDOFF_MAX_CORRECTIONS - pendingPreview.length;
|
|
231
|
+
const selectedCorrections = [...pendingPreview, ...(deliveredSlots > 0 ? delivered.slice(-deliveredSlots) : [])];
|
|
232
|
+
const snapshot = {
|
|
233
|
+
schemaVersion: 1, revision: prior ? prior.revision + 1 : 1, taskId,
|
|
234
|
+
taskStatus: usableGoal?.status ?? 'unknown',
|
|
235
|
+
source: { sessionId: session.metadata.id, cwd: canonicalHandoffCwd(session.metadata.cwd), capturedAt: session.metadata.updatedAt, ...taskHandoffFingerprints(session) },
|
|
236
|
+
objective,
|
|
237
|
+
owner: input ? { ...input.owner } : sameTask ? { ...prior.owner } : { pid: null, paneId: null },
|
|
238
|
+
corrections: selectedCorrections.map(correction => {
|
|
239
|
+
if (!correction.text.trim() && !hasMediaOnlySource(session, correction)) {
|
|
240
|
+
throw new TaskHandoffAdmissionError('invalid_handoff', 'Image-only correction requires its exact authored source and owned image metadata; the previous checkpoint was not changed.');
|
|
241
|
+
}
|
|
242
|
+
const source = correction.sourceMessageId === null ? null : correctionSourceText(session, correction);
|
|
243
|
+
let sourceMessageId = correction.sourceMessageId;
|
|
244
|
+
if (sourceMessageId !== null && source === null) {
|
|
245
|
+
const historical = sameTask && prior.corrections.some(row => row.id === correction.id
|
|
246
|
+
&& row.deliveryState === 'delivered' && row.text === correction.text && row.sourceMessageId === sourceMessageId);
|
|
247
|
+
if (correction.deliveryState !== 'delivered' || !historical) {
|
|
248
|
+
throw new TaskHandoffAdmissionError('invalid_handoff', 'Pending correction original source is unavailable; the previous checkpoint was not changed.');
|
|
249
|
+
}
|
|
250
|
+
// A delivered, admitted preview remains descriptive historical context;
|
|
251
|
+
// it must not pretend that its missing exact source is retrievable.
|
|
252
|
+
sourceMessageId = null;
|
|
253
|
+
}
|
|
254
|
+
else if (source !== null && !source.startsWith(correction.text)) {
|
|
255
|
+
throw new TaskHandoffAdmissionError('invalid_handoff', 'Correction text does not match its original transcript source; the previous checkpoint was not changed.');
|
|
256
|
+
}
|
|
257
|
+
if (Buffer.byteLength(correction.text) > TASK_HANDOFF_MAX_TEXT_BYTES && correctionSourceText(session, correction) !== correction.text) {
|
|
258
|
+
throw new TaskHandoffAdmissionError('invalid_handoff', 'Oversized correction requires its exact full transcript source before a bounded preview can be saved.');
|
|
259
|
+
}
|
|
260
|
+
// A route save may retain an admitted preview rather than a live queue.
|
|
261
|
+
// Rebind it to available exact source text so clipping remains explicit.
|
|
262
|
+
return { ...correction, sourceMessageId, text: boundedText(source ?? correction.text, omitted) };
|
|
263
|
+
}),
|
|
264
|
+
completedObservations: [], unresolvedCalls: [], blockers: [],
|
|
265
|
+
nextAction: { text: null, sourceMessageId: null, availability: 'unavailable' }, omitted,
|
|
266
|
+
};
|
|
267
|
+
omitted.corrections = Math.max(0, corrections.length - snapshot.corrections.length);
|
|
268
|
+
const evidence = session.evidence === undefined ? null : parseEvidenceSnapshot(session.evidence);
|
|
269
|
+
if (objective.kind === 'opening_request')
|
|
270
|
+
objective.sourceAvailability = messages.some(message => message.id === objective.sourceMessageId)
|
|
271
|
+
|| (evidence?.records.some(item => item.kind === 'user_instruction' && item.source.messageId === objective.sourceMessageId) ?? false)
|
|
272
|
+
? 'present' : 'historical_checkpoint';
|
|
273
|
+
const terminal = new Set(['completed', 'failed', 'cancelled', 'timed_out', 'interrupted']);
|
|
274
|
+
for (const observation of evidence?.records ?? []) {
|
|
275
|
+
if (observation.kind !== 'observation' || observation.source.origin !== 'host_receipt')
|
|
276
|
+
continue;
|
|
277
|
+
const job = observation.source.job;
|
|
278
|
+
if (!job || job.sessionId !== session.metadata.id || !terminal.has(job.status) || !job.endedAt || !observation.source.toolCallId)
|
|
279
|
+
continue;
|
|
280
|
+
const row = { observationId: observation.id, toolCallId: observation.source.toolCallId,
|
|
281
|
+
jobId: job.jobId, status: job.status, exitCode: job.exitCode, verification: 'unknown' };
|
|
282
|
+
if (snapshot.completedObservations.length < TASK_HANDOFF_MAX_REFERENCES)
|
|
283
|
+
snapshot.completedObservations.push(row);
|
|
284
|
+
else
|
|
285
|
+
omitted.completedObservations += 1;
|
|
286
|
+
}
|
|
287
|
+
const seen = new Set();
|
|
288
|
+
for (const message of messages)
|
|
289
|
+
for (const call of message.toolCalls ?? []) {
|
|
290
|
+
if (seen.has(call.id) || (call.status !== 'pending' && call.status !== 'running' && (call.result !== undefined || call.error !== undefined)))
|
|
291
|
+
continue;
|
|
292
|
+
seen.add(call.id);
|
|
293
|
+
if (snapshot.unresolvedCalls.length < TASK_HANDOFF_MAX_REFERENCES)
|
|
294
|
+
snapshot.unresolvedCalls.push({ toolCallId: call.id, name: call.name, sourceMessageId: message.id, outcome: 'unknown' });
|
|
295
|
+
else
|
|
296
|
+
omitted.unresolvedCalls += 1;
|
|
297
|
+
}
|
|
298
|
+
if (usableGoal?.blockedReason)
|
|
299
|
+
snapshot.blockers.push({ text: boundedText(usableGoal.blockedReason, omitted), sourceGoalId: usableGoal.goalId });
|
|
300
|
+
// Drop complete rows only when aggregate JSON escaping exceeds the bound.
|
|
301
|
+
// Correction text is never silently clipped: an oversized required row rejects the save.
|
|
302
|
+
while (Buffer.byteLength(JSON.stringify(snapshot)) > TASK_HANDOFF_MAX_BYTES) {
|
|
303
|
+
if (snapshot.completedObservations.length) {
|
|
304
|
+
snapshot.completedObservations.pop();
|
|
305
|
+
omitted.completedObservations += 1;
|
|
306
|
+
}
|
|
307
|
+
else if (snapshot.unresolvedCalls.length) {
|
|
308
|
+
snapshot.unresolvedCalls.pop();
|
|
309
|
+
omitted.unresolvedCalls += 1;
|
|
310
|
+
}
|
|
311
|
+
else if (snapshot.corrections.length) {
|
|
312
|
+
snapshot.corrections.pop();
|
|
313
|
+
omitted.corrections += 1;
|
|
314
|
+
}
|
|
315
|
+
else
|
|
316
|
+
break;
|
|
317
|
+
}
|
|
318
|
+
const parsed = parseTaskHandoffSnapshot(snapshot);
|
|
319
|
+
if (!parsed)
|
|
320
|
+
throw new TaskHandoffAdmissionError('invalid_handoff', 'Task handoff input or captured source identity is invalid or exceeds its bounds; no checkpoint was written.');
|
|
321
|
+
return parsed;
|
|
322
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/** Portable source-qualified task checkpoints. Historical facts never grant ownership. */
|
|
2
|
+
export declare const TASK_HANDOFF_MAX_BYTES: number;
|
|
3
|
+
export declare const TASK_HANDOFF_MAX_TEXT_BYTES = 2048;
|
|
4
|
+
export declare const TASK_HANDOFF_MAX_CORRECTIONS = 10;
|
|
5
|
+
export declare const TASK_HANDOFF_MAX_REFERENCES = 16;
|
|
6
|
+
export interface TaskHandoffCorrection {
|
|
7
|
+
id: string;
|
|
8
|
+
text: string;
|
|
9
|
+
delivery: 'subturn' | 'end-of-turn';
|
|
10
|
+
deliveryState: 'pending' | 'delivered' | 'unknown';
|
|
11
|
+
queuedAt: string;
|
|
12
|
+
sourceMessageId: string | null;
|
|
13
|
+
/** Historical captured queue order only; never proof of current dispatch ownership. */
|
|
14
|
+
queuedPosition?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface TaskHandoffInput {
|
|
17
|
+
corrections: TaskHandoffCorrection[];
|
|
18
|
+
owner: {
|
|
19
|
+
pid: number;
|
|
20
|
+
paneId: number | null;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface TaskHandoffSnapshot {
|
|
24
|
+
schemaVersion: 1;
|
|
25
|
+
revision: number;
|
|
26
|
+
taskId: string;
|
|
27
|
+
taskStatus: 'active' | 'paused' | 'blocked' | 'budget_limited' | 'complete' | 'unknown';
|
|
28
|
+
source: {
|
|
29
|
+
sessionId: string;
|
|
30
|
+
cwd: string;
|
|
31
|
+
capturedAt: string;
|
|
32
|
+
messagesSha256: string;
|
|
33
|
+
evidenceSha256: string;
|
|
34
|
+
};
|
|
35
|
+
objective: {
|
|
36
|
+
kind: 'goal' | 'opening_request';
|
|
37
|
+
text: string;
|
|
38
|
+
sourceMessageId: string | null;
|
|
39
|
+
goalId: string | null;
|
|
40
|
+
sourceAvailability: 'present' | 'historical_checkpoint';
|
|
41
|
+
};
|
|
42
|
+
owner: {
|
|
43
|
+
pid: number | null;
|
|
44
|
+
paneId: number | null;
|
|
45
|
+
};
|
|
46
|
+
corrections: TaskHandoffCorrection[];
|
|
47
|
+
completedObservations: Array<{
|
|
48
|
+
observationId: string;
|
|
49
|
+
toolCallId: string;
|
|
50
|
+
jobId: string;
|
|
51
|
+
status: 'completed' | 'failed' | 'cancelled' | 'timed_out' | 'interrupted';
|
|
52
|
+
exitCode: number | null;
|
|
53
|
+
verification: 'unknown';
|
|
54
|
+
}>;
|
|
55
|
+
unresolvedCalls: Array<{
|
|
56
|
+
toolCallId: string;
|
|
57
|
+
name: string;
|
|
58
|
+
sourceMessageId: string;
|
|
59
|
+
outcome: 'unknown';
|
|
60
|
+
}>;
|
|
61
|
+
blockers: Array<{
|
|
62
|
+
text: string;
|
|
63
|
+
sourceGoalId: string;
|
|
64
|
+
}>;
|
|
65
|
+
nextAction: {
|
|
66
|
+
text: string | null;
|
|
67
|
+
sourceMessageId: string | null;
|
|
68
|
+
availability: 'recorded' | 'unavailable';
|
|
69
|
+
};
|
|
70
|
+
omitted: {
|
|
71
|
+
corrections: number;
|
|
72
|
+
completedObservations: number;
|
|
73
|
+
unresolvedCalls: number;
|
|
74
|
+
textBytes: number;
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
export interface TaskHandoffProjection {
|
|
78
|
+
snapshot: TaskHandoffSnapshot;
|
|
79
|
+
resumeCommand: string;
|
|
80
|
+
provenance: 'validated_session_checkpoint';
|
|
81
|
+
ownerLiveness: 'unknown';
|
|
82
|
+
asOf: string;
|
|
83
|
+
}
|
|
84
|
+
/** Admission is strict; malformed checkpoints remain unavailable rather than partially authoritative. */
|
|
85
|
+
export declare function parseTaskHandoffSnapshot(value: unknown): TaskHandoffSnapshot | null;
|
|
86
|
+
export declare function parseTaskHandoffProjection(value: unknown): TaskHandoffProjection | null;
|
|
87
|
+
export declare function projectTaskHandoff(snapshot: TaskHandoffSnapshot): TaskHandoffProjection;
|
|
88
|
+
/** Historical checkpoint context; display alone never resumes or repeats an operation. */
|
|
89
|
+
export declare function formatTaskHandoffContext(snapshot: TaskHandoffSnapshot): string;
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/** Portable source-qualified task checkpoints. Historical facts never grant ownership. */
|
|
2
|
+
export const TASK_HANDOFF_MAX_BYTES = 32 * 1024;
|
|
3
|
+
export const TASK_HANDOFF_MAX_TEXT_BYTES = 2048;
|
|
4
|
+
export const TASK_HANDOFF_MAX_CORRECTIONS = 10;
|
|
5
|
+
export const TASK_HANDOFF_MAX_REFERENCES = 16;
|
|
6
|
+
const encoder = new TextEncoder();
|
|
7
|
+
const bytes = (value) => encoder.encode(value).length;
|
|
8
|
+
const record = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
9
|
+
const exact = (value, names) => Object.keys(value).length === names.length && names.every(name => Object.prototype.hasOwnProperty.call(value, name));
|
|
10
|
+
const integer = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;
|
|
11
|
+
const identity = (value) => typeof value === 'string' && value.length > 0 && bytes(value) <= 256 && !/[\u0000-\u001f\u007f]/u.test(value);
|
|
12
|
+
const text = (value) => typeof value === 'string' && value.trim().length > 0 && bytes(value) <= TASK_HANDOFF_MAX_TEXT_BYTES;
|
|
13
|
+
const nullableIdentity = (value) => value === null || identity(value);
|
|
14
|
+
const sha = (value) => typeof value === 'string' && /^[a-f0-9]{64}$/.test(value);
|
|
15
|
+
const timestamp = (value) => typeof value === 'string' && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
|
|
16
|
+
const unique = (values, key) => new Set(values.map(value => value[key])).size === values.length;
|
|
17
|
+
const detached = (value) => JSON.parse(JSON.stringify(value));
|
|
18
|
+
/** Admission is strict; malformed checkpoints remain unavailable rather than partially authoritative. */
|
|
19
|
+
export function parseTaskHandoffSnapshot(value) {
|
|
20
|
+
try {
|
|
21
|
+
if (!record(value) || bytes(JSON.stringify(value)) > TASK_HANDOFF_MAX_BYTES
|
|
22
|
+
|| !exact(value, ['schemaVersion', 'revision', 'taskId', 'taskStatus', 'source', 'objective', 'owner', 'corrections', 'completedObservations', 'unresolvedCalls', 'blockers', 'nextAction', 'omitted'])
|
|
23
|
+
|| value.schemaVersion !== 1 || !integer(value.revision) || value.revision === 0 || !identity(value.taskId)
|
|
24
|
+
|| typeof value.taskStatus !== 'string' || !['active', 'paused', 'blocked', 'budget_limited', 'complete', 'unknown'].includes(value.taskStatus))
|
|
25
|
+
return null;
|
|
26
|
+
const source = value.source;
|
|
27
|
+
if (!record(source) || !exact(source, ['sessionId', 'cwd', 'capturedAt', 'messagesSha256', 'evidenceSha256'])
|
|
28
|
+
|| !identity(source.sessionId) || typeof source.cwd !== 'string' || bytes(source.cwd) > 4096
|
|
29
|
+
|| !/^(?:\/|[A-Za-z]:[\\/]|\\\\)/u.test(source.cwd) || /[\u0000-\u001f\u007f]/u.test(source.cwd)
|
|
30
|
+
|| !timestamp(source.capturedAt) || !sha(source.messagesSha256) || !sha(source.evidenceSha256))
|
|
31
|
+
return null;
|
|
32
|
+
const objective = value.objective;
|
|
33
|
+
if (!record(objective) || !exact(objective, ['kind', 'text', 'sourceMessageId', 'goalId', 'sourceAvailability']) || !text(objective.text)
|
|
34
|
+
|| typeof objective.sourceAvailability !== 'string' || !['present', 'historical_checkpoint'].includes(objective.sourceAvailability))
|
|
35
|
+
return null;
|
|
36
|
+
if (objective.kind === 'goal') {
|
|
37
|
+
if (!identity(objective.goalId) || objective.sourceMessageId !== null || value.taskStatus === 'unknown' || objective.sourceAvailability !== 'present')
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
else if (objective.kind === 'opening_request') {
|
|
41
|
+
if (!identity(objective.sourceMessageId) || objective.goalId !== null || value.taskStatus !== 'unknown')
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
else
|
|
45
|
+
return null;
|
|
46
|
+
const owner = value.owner;
|
|
47
|
+
if (!record(owner) || !exact(owner, ['pid', 'paneId'])
|
|
48
|
+
|| !(owner.pid === null || (integer(owner.pid) && owner.pid > 0))
|
|
49
|
+
|| !(owner.paneId === null || integer(owner.paneId)))
|
|
50
|
+
return null;
|
|
51
|
+
const corrections = value.corrections;
|
|
52
|
+
if (!Array.isArray(corrections) || corrections.length > TASK_HANDOFF_MAX_CORRECTIONS)
|
|
53
|
+
return null;
|
|
54
|
+
for (const correction of corrections) {
|
|
55
|
+
const hasPosition = record(correction) && Object.prototype.hasOwnProperty.call(correction, 'queuedPosition');
|
|
56
|
+
if (!record(correction) || !exact(correction, ['id', 'text', 'delivery', 'deliveryState', 'queuedAt', 'sourceMessageId', ...(hasPosition ? ['queuedPosition'] : [])])
|
|
57
|
+
|| !identity(correction.id) || typeof correction.text !== 'string' || bytes(correction.text) > TASK_HANDOFF_MAX_TEXT_BYTES
|
|
58
|
+
|| (!correction.text.trim() && !identity(correction.sourceMessageId))
|
|
59
|
+
|| typeof correction.delivery !== 'string' || !['subturn', 'end-of-turn'].includes(correction.delivery)
|
|
60
|
+
|| typeof correction.deliveryState !== 'string' || !['pending', 'delivered', 'unknown'].includes(correction.deliveryState)
|
|
61
|
+
|| !timestamp(correction.queuedAt) || !nullableIdentity(correction.sourceMessageId)
|
|
62
|
+
|| (hasPosition && (!integer(correction.queuedPosition) || correction.queuedPosition >= TASK_HANDOFF_MAX_CORRECTIONS)))
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (!unique(corrections, 'id'))
|
|
66
|
+
return null;
|
|
67
|
+
const positions = corrections.map(correction => correction.queuedPosition).filter(position => position !== undefined);
|
|
68
|
+
if (new Set(positions).size !== positions.length)
|
|
69
|
+
return null;
|
|
70
|
+
const completed = value.completedObservations;
|
|
71
|
+
if (!Array.isArray(completed) || completed.length > TASK_HANDOFF_MAX_REFERENCES)
|
|
72
|
+
return null;
|
|
73
|
+
for (const observation of completed) {
|
|
74
|
+
if (!record(observation) || !exact(observation, ['observationId', 'toolCallId', 'jobId', 'status', 'exitCode', 'verification'])
|
|
75
|
+
|| !identity(observation.observationId) || !identity(observation.toolCallId) || !identity(observation.jobId)
|
|
76
|
+
|| typeof observation.status !== 'string' || !['completed', 'failed', 'cancelled', 'timed_out', 'interrupted'].includes(observation.status)
|
|
77
|
+
|| !(observation.exitCode === null || (integer(observation.exitCode) && observation.exitCode <= 255))
|
|
78
|
+
|| observation.verification !== 'unknown')
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
if (!unique(completed, 'observationId'))
|
|
82
|
+
return null;
|
|
83
|
+
const unresolved = value.unresolvedCalls;
|
|
84
|
+
if (!Array.isArray(unresolved) || unresolved.length > TASK_HANDOFF_MAX_REFERENCES)
|
|
85
|
+
return null;
|
|
86
|
+
for (const call of unresolved) {
|
|
87
|
+
if (!record(call) || !exact(call, ['toolCallId', 'name', 'sourceMessageId', 'outcome'])
|
|
88
|
+
|| !identity(call.toolCallId) || !identity(call.name) || !identity(call.sourceMessageId) || call.outcome !== 'unknown')
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
if (!unique(unresolved, 'toolCallId'))
|
|
92
|
+
return null;
|
|
93
|
+
const blockers = value.blockers;
|
|
94
|
+
if (!Array.isArray(blockers) || blockers.length > TASK_HANDOFF_MAX_REFERENCES)
|
|
95
|
+
return null;
|
|
96
|
+
for (const blocker of blockers) {
|
|
97
|
+
if (!record(blocker) || !exact(blocker, ['text', 'sourceGoalId']) || !text(blocker.text)
|
|
98
|
+
|| blocker.sourceGoalId !== objective.goalId || objective.kind !== 'goal')
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
const next = value.nextAction;
|
|
102
|
+
if (!record(next) || !exact(next, ['text', 'sourceMessageId', 'availability']))
|
|
103
|
+
return null;
|
|
104
|
+
if (next.availability === 'unavailable') {
|
|
105
|
+
if (next.text !== null || next.sourceMessageId !== null)
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
else if (next.availability === 'recorded') {
|
|
109
|
+
if (!text(next.text) || !identity(next.sourceMessageId))
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
else
|
|
113
|
+
return null;
|
|
114
|
+
const omitted = value.omitted;
|
|
115
|
+
if (!record(omitted) || !exact(omitted, ['corrections', 'completedObservations', 'unresolvedCalls', 'textBytes'])
|
|
116
|
+
|| Object.values(omitted).some(count => !integer(count)))
|
|
117
|
+
return null;
|
|
118
|
+
return detached(value);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function resumeSelector(sessionId) {
|
|
125
|
+
const argument = /^[A-Za-z0-9_.-]+$/u.test(sessionId) ? sessionId : `'${sessionId.replace(/'/g, "'\\''")}'`;
|
|
126
|
+
return `ztc resume ${argument}`;
|
|
127
|
+
}
|
|
128
|
+
export function parseTaskHandoffProjection(value) {
|
|
129
|
+
if (!record(value) || !exact(value, ['snapshot', 'resumeCommand', 'provenance', 'ownerLiveness', 'asOf']))
|
|
130
|
+
return null;
|
|
131
|
+
const snapshot = parseTaskHandoffSnapshot(value.snapshot);
|
|
132
|
+
if (!snapshot || value.provenance !== 'validated_session_checkpoint' || value.ownerLiveness !== 'unknown'
|
|
133
|
+
|| value.asOf !== snapshot.source.capturedAt || value.resumeCommand !== resumeSelector(snapshot.source.sessionId))
|
|
134
|
+
return null;
|
|
135
|
+
return { snapshot, resumeCommand: value.resumeCommand, provenance: 'validated_session_checkpoint', ownerLiveness: 'unknown', asOf: snapshot.source.capturedAt };
|
|
136
|
+
}
|
|
137
|
+
export function projectTaskHandoff(snapshot) {
|
|
138
|
+
const parsed = parseTaskHandoffSnapshot(snapshot);
|
|
139
|
+
if (!parsed)
|
|
140
|
+
throw new TypeError('Invalid task handoff checkpoint');
|
|
141
|
+
return { snapshot: parsed, resumeCommand: resumeSelector(parsed.source.sessionId), provenance: 'validated_session_checkpoint', ownerLiveness: 'unknown', asOf: parsed.source.capturedAt };
|
|
142
|
+
}
|
|
143
|
+
/** Historical checkpoint context; display alone never resumes or repeats an operation. */
|
|
144
|
+
export function formatTaskHandoffContext(snapshot) {
|
|
145
|
+
const projection = projectTaskHandoff(snapshot);
|
|
146
|
+
// Rendering removes terminal control bytes without changing saved authored data.
|
|
147
|
+
const display = (value) => value.replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/gu, char => char === '\n' ? ' ↵ ' : ' ');
|
|
148
|
+
const value = projection.snapshot;
|
|
149
|
+
const lines = [
|
|
150
|
+
'[Saved task handoff — source-qualified checkpoint]',
|
|
151
|
+
`Objective: ${display(value.objective.text)}`,
|
|
152
|
+
`Task: ${display(value.taskId)}; recorded status: ${value.taskStatus}${value.objective.kind === 'opening_request' ? ' (opening request; current task lifecycle unknown)' : ''}.`,
|
|
153
|
+
`Source session: ${display(value.source.sessionId)}; checkpoint as-of ${projection.asOf}; revision ${value.revision}.`,
|
|
154
|
+
`Resume: ${display(projection.resumeCommand)} (source directory: ${display(value.source.cwd)}).`,
|
|
155
|
+
`Historical owner: PID ${value.owner.pid ?? 'unknown'}, pane ${value.owner.paneId ?? 'unknown'}; current owner liveness unknown. Recorded identity does not establish current ownership.`,
|
|
156
|
+
value.objective.sourceAvailability === 'historical_checkpoint'
|
|
157
|
+
? `Objective source: historical checkpoint only; original message ${display(value.objective.sourceMessageId ?? '')} is unavailable.`
|
|
158
|
+
: `Objective source: ${display(value.objective.goalId ?? value.objective.sourceMessageId ?? '')}; source identity present in this checkpoint.`,
|
|
159
|
+
'This checkpoint does not authorize new actions or prove semantic completion. Inspect unresolved outcomes and uncertain delivery; never automatically replay them.',
|
|
160
|
+
];
|
|
161
|
+
for (const row of value.completedObservations)
|
|
162
|
+
lines.push(`Recorded terminal process: ${display(row.observationId)}; call ${display(row.toolCallId)}; job ${display(row.jobId)}; ${row.status}, exit ${row.exitCode ?? 'unknown'}; semantic verification unknown; current task applicability unconfirmed.`);
|
|
163
|
+
if (!value.completedObservations.length)
|
|
164
|
+
lines.push('Recorded terminal observations: unavailable.');
|
|
165
|
+
for (const row of value.unresolvedCalls)
|
|
166
|
+
lines.push(`Unresolved call: ${display(row.toolCallId)} (${display(row.name)}); outcome unknown; source message ${display(row.sourceMessageId)}.`);
|
|
167
|
+
for (const row of value.corrections) {
|
|
168
|
+
const authoredText = row.deliveryState === 'pending' ? 'deferred authored text withheld until delivery' : display(row.text);
|
|
169
|
+
lines.push(`Recorded correction ${display(row.id)}: ${row.delivery}, recorded delivery ${row.deliveryState}; current dispatch state unknown; current task applicability unconfirmed; ${authoredText}${row.sourceMessageId ? ` (source ${display(row.sourceMessageId)})` : ' (source reference unavailable)'}.`);
|
|
170
|
+
}
|
|
171
|
+
for (const row of value.blockers)
|
|
172
|
+
lines.push(`Recorded blocker (goal ${display(row.sourceGoalId)}; unverified): ${display(row.text)}`);
|
|
173
|
+
if (!value.blockers.length)
|
|
174
|
+
lines.push('Blockers: unavailable in this source checkpoint.');
|
|
175
|
+
lines.push(value.nextAction.availability === 'unavailable' ? 'Next action: unavailable in this source checkpoint.' : `Recorded next action (unverified; source ${display(value.nextAction.sourceMessageId ?? '')}): ${display(value.nextAction.text ?? '')}`);
|
|
176
|
+
const omitted = value.omitted;
|
|
177
|
+
lines.push(`Omitted from summary: ${omitted.corrections} corrections, ${omitted.completedObservations} process observations, ${omitted.unresolvedCalls} unresolved calls, ${omitted.textBytes} text bytes. Recall original source messages and result handles for omitted data.`);
|
|
178
|
+
return lines.join('\n');
|
|
179
|
+
}
|