@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
package/dist/headless.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { environmentOperationInProgress } from './agent/commands/environment.js';
|
|
2
|
+
import { getEnvironment, openEnvironment, releaseEnvironment, describeEnvironmentForAgent, isEnvironmentWorkspacePath, EnvironmentRecoveryError } from './environment/store.js';
|
|
3
|
+
import { inferAgentPaneTitle, readPaneLabels } from './panes/labels.js';
|
|
4
|
+
import { listCommandJobs, shutdownCommandJobs, subscribeCommandJobs } from './agent/runtime/command_jobs.js';
|
|
5
|
+
import { ToolResponseStore } from './agent/tool_response_store.js';
|
|
6
|
+
import { projectGoal } from './goal_contract.js';
|
|
2
7
|
/**
|
|
3
8
|
* Headless Mode for ZTC
|
|
4
9
|
*
|
|
@@ -17,14 +22,17 @@ import { shutdownCommandJobs, subscribeCommandJobs } from './agent/runtime/comma
|
|
|
17
22
|
* echo "build a JIRA connector" | ztc --headless --mode ~/dcaig/ztc/modes/dcaig.yaml
|
|
18
23
|
* echo '{"prompt": "...", "session_id": "..."}' | ztc --headless --json
|
|
19
24
|
*/
|
|
25
|
+
import { randomUUID } from 'node:crypto';
|
|
20
26
|
import { writeFile } from 'fs/promises';
|
|
21
27
|
import { configStore } from './config.js';
|
|
28
|
+
import { formatTaskHandoffContext, projectTaskHandoff } from './session_handoff_contract.js';
|
|
22
29
|
import { RouterConfigurationError } from './router_auth.js';
|
|
23
30
|
import { registerInstance, deregisterInstance } from './instance_registry.js';
|
|
24
31
|
import { ContextOverflowError, isContextOverflowMessage } from './agent/agent.js';
|
|
25
32
|
import { dumpContextOverflow } from './agent/contextDump.js';
|
|
26
33
|
import { registerToolCallbacks } from './app/tool_callbacks.js';
|
|
27
34
|
import { createAgentWithConfig } from './app/agent_runner.js';
|
|
35
|
+
import { mergeToolCheckpointMessages } from './agent/runtime/tool_checkpoints.js';
|
|
28
36
|
import { clearWorkerExecutor } from './worker/index.js';
|
|
29
37
|
import { commands, refreshPluginCommands } from './agent/commands/index.js';
|
|
30
38
|
import { goalManager, goalPinTask, detectGoalCompletion, detectGoalBlocked, goalBlockedReason, goalFinalNote, turnProducedText, turnToolOutcomes, shouldAccountFinalTurn, snapshotGoalForTurn } from './agent/commands/goal.js';
|
|
@@ -33,13 +41,16 @@ import { allocatePlanArtifact, findPlanContent, readPlanArtifactSafely, } from '
|
|
|
33
41
|
import { initModeRegistry, registerBuiltinHandlers, getModeRegistry } from './modes/index.js';
|
|
34
42
|
import { loadEmulationProfiles, getEmulationProfile } from './emulation/catalog.js';
|
|
35
43
|
import { resolve } from 'path';
|
|
36
|
-
import {
|
|
44
|
+
import { homedir } from 'node:os';
|
|
45
|
+
import { applyAccountOp } from './web/accounts_mirror.js';
|
|
46
|
+
import { loadSessionByIdOrName, loadSessionFromFile, generateSessionId, getSessionPathForCwd, SessionLoadError, bindToolResponseStoreToSession, } from './session.js';
|
|
37
47
|
import { clearStaleTodosOnBoot } from './app/todo_state.js';
|
|
38
48
|
import { runtimeDiag } from './utils/debug_log.js';
|
|
39
49
|
import { rename as renameFile } from 'fs/promises';
|
|
40
50
|
import { buildModelsController, buildSkillsController, buildShellController, buildStubShellController, buildAutoSelectWidgets, routeUserInput, getPlanModeCommandDenial } from './app/command_context.js';
|
|
41
51
|
import { isToolAllowed } from './app/modes.js';
|
|
42
52
|
import { SessionManager } from './app/session_manager.js';
|
|
53
|
+
import { LocalWorkspaceCoordinator } from './workspace_collision.js';
|
|
43
54
|
import { HeadlessPaneManager } from './ui/ratatui/headless_pane_manager.js';
|
|
44
55
|
import { setPaneToolsTuiProcess, clearPaneToolsTuiProcess, setBusTransport, clearBusTransport, getBackgroundRegistry, clearBackgroundRegistry, resetAskUserTurnFlag, setTodoUpdateCallback } from './agent/tools/index.js';
|
|
45
56
|
import { PaneRelayServer, generateRelaySocketPath } from './ui/ratatui/pane_relay.js';
|
|
@@ -98,6 +109,11 @@ export function classifyPaneChildLine(line) {
|
|
|
98
109
|
}
|
|
99
110
|
case 'cancel':
|
|
100
111
|
return { kind: 'cancel' };
|
|
112
|
+
case 'ask_user_answer':
|
|
113
|
+
if (typeof cmd.question_id !== 'string' || !cmd.question_id || typeof cmd.answer !== 'string' || !cmd.answer.trim()) {
|
|
114
|
+
return { kind: 'malformed_cmd', raw: trimmed };
|
|
115
|
+
}
|
|
116
|
+
return { kind: 'ask_user_answer', questionId: cmd.question_id, answer: cmd.answer };
|
|
101
117
|
default:
|
|
102
118
|
return { kind: 'unknown_cmd', cmd: typeof cmd.__ztc_cmd === 'string' ? cmd.__ztc_cmd : String(cmd.__ztc_cmd) };
|
|
103
119
|
}
|
|
@@ -291,10 +307,13 @@ export class HeadlessApp {
|
|
|
291
307
|
messages = [];
|
|
292
308
|
sessionId;
|
|
293
309
|
sessionName;
|
|
310
|
+
sessionLabels = {};
|
|
294
311
|
agentBuiltForMode = null;
|
|
295
312
|
/** Plan artifact captured by the current agent's prompt/write guard. */
|
|
296
313
|
agentBuiltForPlanFile = null;
|
|
297
314
|
/** Binding barrier for agents created by synchronous mode-change callbacks. */
|
|
315
|
+
sessionToolResponseStore = new ToolResponseStore();
|
|
316
|
+
sessionToolResponseBinding = null;
|
|
298
317
|
pendingAgentBind = null;
|
|
299
318
|
/** Sticky failure for the current agent generation; a settled rejected bind
|
|
300
319
|
* must not be forgotten before the next turn awaits it. */
|
|
@@ -327,13 +346,22 @@ export class HeadlessApp {
|
|
|
327
346
|
lastResponse = null;
|
|
328
347
|
taskCompleted = false;
|
|
329
348
|
sessionManager;
|
|
349
|
+
workspaceCoordinator = null;
|
|
350
|
+
taskHandoff = null;
|
|
351
|
+
restoredHandoffCorrections = [];
|
|
330
352
|
paneManager = null;
|
|
331
353
|
askUserAutoAnswered = false;
|
|
354
|
+
pendingQuestionId = null;
|
|
332
355
|
paneRelay = null;
|
|
333
356
|
// Auto-started loopback mirror so this headless instance is reachable from
|
|
334
357
|
// other ZTC navigators. Silent — no banner, no browser auto-open.
|
|
335
358
|
autoMirror = null;
|
|
336
359
|
shellCwd;
|
|
360
|
+
startupCatalogController = new AbortController();
|
|
361
|
+
environmentRecord = null;
|
|
362
|
+
environmentReturnCwd = process.cwd();
|
|
363
|
+
environmentSessionCwd = null;
|
|
364
|
+
environmentReleased = false;
|
|
337
365
|
shellMode;
|
|
338
366
|
backgroundEventUnsub = null;
|
|
339
367
|
batchEventUnsub = null;
|
|
@@ -346,6 +374,9 @@ export class HeadlessApp {
|
|
|
346
374
|
* AbortController()`, cleared in that run's finally.
|
|
347
375
|
*/
|
|
348
376
|
activeRunController = null;
|
|
377
|
+
turnAdmissionCount = 0;
|
|
378
|
+
runtimeMutationDone = null;
|
|
379
|
+
accountReloadPending = false;
|
|
349
380
|
/**
|
|
350
381
|
* Set by cancelActiveRun so the run's catch can tell a user cancel apart from
|
|
351
382
|
* the timeout path (which aborts the same controller) and from real errors —
|
|
@@ -364,6 +395,7 @@ export class HeadlessApp {
|
|
|
364
395
|
activityState = { status: 'idle' };
|
|
365
396
|
lastEmittedStatus = null;
|
|
366
397
|
lastEmittedVerb = null;
|
|
398
|
+
lastEmittedWaiting = null;
|
|
367
399
|
hookLifecycle;
|
|
368
400
|
constructor(options) {
|
|
369
401
|
this.options = {
|
|
@@ -383,12 +415,13 @@ export class HeadlessApp {
|
|
|
383
415
|
this.shellMode = resolve_headless_shell_mode();
|
|
384
416
|
this.sessionManager = new SessionManager({
|
|
385
417
|
sessionId: this.sessionId,
|
|
418
|
+
getSessionCwd: () => this.environmentSessionCwd ?? process.cwd(),
|
|
386
419
|
sessionFile: options.sessionFile,
|
|
387
420
|
getMessages: () => this.messages,
|
|
388
421
|
setMessages: (msgs) => { this.messages = msgs; },
|
|
389
422
|
addMessage: (msg) => {
|
|
390
423
|
this.messages.push({
|
|
391
|
-
id: `msg_${
|
|
424
|
+
id: `msg_${randomUUID()}`,
|
|
392
425
|
role: msg.role,
|
|
393
426
|
content: msg.content,
|
|
394
427
|
timestamp: new Date(),
|
|
@@ -403,11 +436,29 @@ export class HeadlessApp {
|
|
|
403
436
|
// Without mode + artifact, a resumed headless plan silently becomes a
|
|
404
437
|
// normal full-tool agent even though its transcript says it is planning.
|
|
405
438
|
getRuntimeState: () => ({
|
|
439
|
+
environment: this.environmentRecord ? { id: this.environmentRecord.id, name: this.environmentRecord.name } : null,
|
|
440
|
+
evidence: this.agent?.getEvidenceSnapshot(),
|
|
441
|
+
usage: this.agent?.getUsageSessionId() === this.sessionId ? this.agent.getUsageSnapshot() : undefined,
|
|
442
|
+
diagnostics: this.agent?.getDiagnosticSessionId() === this.sessionId
|
|
443
|
+
? this.agent.getDiagnosticSnapshot() : undefined,
|
|
406
444
|
mode: this.currentMode,
|
|
407
445
|
planFile: this.currentMode === 'plan' ? this.artifactPath : null,
|
|
408
446
|
artifactPath: this.artifactPath,
|
|
409
447
|
goal: goalManager.serialize(),
|
|
448
|
+
taskHandoffInput: { corrections: this.restoredHandoffCorrections.map(correction => {
|
|
449
|
+
const source = this.messages.find(message => message.id === correction.sourceMessageId);
|
|
450
|
+
const raw = source?.metadata?.taskHandoffCorrection;
|
|
451
|
+
const text = source?.role === 'user' ? source.content
|
|
452
|
+
: raw && typeof raw === 'object' && 'text' in raw && typeof raw.text === 'string' ? raw.text : correction.text;
|
|
453
|
+
return { ...correction, text };
|
|
454
|
+
}), owner: { pid: process.pid, paneId: null } },
|
|
410
455
|
}),
|
|
456
|
+
flushToolResponses: async () => { await this.agent?.toolResponseStore.flush(); },
|
|
457
|
+
onCheckpoint: session => {
|
|
458
|
+
this.taskHandoff = session.task_handoff ? projectTaskHandoff(session.task_handoff) : null;
|
|
459
|
+
this.agent?.setTaskHandoff(this.taskHandoff);
|
|
460
|
+
this.publishTaskHandoff();
|
|
461
|
+
},
|
|
411
462
|
debugLog: (msg) => {
|
|
412
463
|
if (this.options.verbose) {
|
|
413
464
|
this.output({ type: 'status', timestamp: new Date().toISOString(), data: { status: 'debug', message: msg } });
|
|
@@ -449,14 +500,16 @@ export class HeadlessApp {
|
|
|
449
500
|
if (this.options.paneChild) {
|
|
450
501
|
// A human is watching this pane in the web mirror. Surface the question
|
|
451
502
|
// instead of auto-answering: emit an 'ask_user' event that the cli_ratatui
|
|
452
|
-
// relay
|
|
453
|
-
//
|
|
454
|
-
//
|
|
455
|
-
|
|
503
|
+
// relay forwards with its original request ID. The turn then ends (no
|
|
504
|
+
// re-run flag), and the human's answer returns through the identified
|
|
505
|
+
// control channel, checked against this pane's pending question.
|
|
506
|
+
this.pendingQuestionId = randomUUID();
|
|
456
507
|
this.output({
|
|
457
508
|
type: 'ask_user',
|
|
458
509
|
timestamp: new Date().toISOString(),
|
|
459
510
|
data: {
|
|
511
|
+
question_id: this.pendingQuestionId,
|
|
512
|
+
origin_session_id: this.sessionId,
|
|
460
513
|
questions: questions.map(q => ({
|
|
461
514
|
question: q.question,
|
|
462
515
|
options: q.options,
|
|
@@ -478,7 +531,7 @@ export class HeadlessApp {
|
|
|
478
531
|
? answers[0]
|
|
479
532
|
: JSON.stringify(questions.map((q, i) => ({ question: q.question, answer: answers[i] })));
|
|
480
533
|
this.messages.push({
|
|
481
|
-
id: `msg_${
|
|
534
|
+
id: `msg_${randomUUID()}`,
|
|
482
535
|
role: 'user',
|
|
483
536
|
content: answerText,
|
|
484
537
|
timestamp: new Date(),
|
|
@@ -486,19 +539,29 @@ export class HeadlessApp {
|
|
|
486
539
|
this.askUserAutoAnswered = true;
|
|
487
540
|
return null;
|
|
488
541
|
}
|
|
542
|
+
dismissPendingQuestion() {
|
|
543
|
+
if (!this.pendingQuestionId)
|
|
544
|
+
return;
|
|
545
|
+
this.output({ type: 'question_dismiss', timestamp: new Date().toISOString(),
|
|
546
|
+
data: { question_id: this.pendingQuestionId, origin_session_id: this.sessionId } });
|
|
547
|
+
this.pendingQuestionId = null;
|
|
548
|
+
}
|
|
489
549
|
emitHeadlessStatus() {
|
|
490
550
|
const projected = buildActivityDisplayState(this.activityState, 'Thinking');
|
|
491
551
|
const verb = projected.verb ?? null;
|
|
492
|
-
|
|
552
|
+
const waitingKey = projected.waiting ? JSON.stringify(projected.waiting) : null;
|
|
553
|
+
if (projected.wireStatus === this.lastEmittedStatus && verb === this.lastEmittedVerb && waitingKey === this.lastEmittedWaiting)
|
|
493
554
|
return;
|
|
494
555
|
this.lastEmittedStatus = projected.wireStatus;
|
|
495
556
|
this.lastEmittedVerb = verb;
|
|
557
|
+
this.lastEmittedWaiting = waitingKey;
|
|
496
558
|
this.output({
|
|
497
559
|
type: 'status',
|
|
498
560
|
timestamp: new Date().toISOString(),
|
|
499
561
|
data: {
|
|
500
562
|
status: projected.wireStatus,
|
|
501
563
|
...(verb ? { verb } : {}),
|
|
564
|
+
...(projected.waiting ? { waiting: projected.waiting } : {}),
|
|
502
565
|
},
|
|
503
566
|
});
|
|
504
567
|
}
|
|
@@ -531,11 +594,31 @@ export class HeadlessApp {
|
|
|
531
594
|
subscribeAgentEvents() {
|
|
532
595
|
if (!this.agent)
|
|
533
596
|
throw new Error('Agent not initialized');
|
|
534
|
-
this.activityState = { status: 'thinking', startedAt: new Date()
|
|
597
|
+
this.activityState = { status: 'thinking', startedAt: new Date(), taskHandoff: this.activityState.taskHandoff,
|
|
598
|
+
workspaceCollision: this.activityState.workspaceCollision };
|
|
599
|
+
void this.workspaceCoordinator?.setActivity('running').catch(() => {
|
|
600
|
+
runtimeDiag('warn', '[ztc] Local workspace activity evidence could not be refreshed.');
|
|
601
|
+
});
|
|
535
602
|
this.emitHeadlessStatus();
|
|
603
|
+
this.output({ type: 'evidence', timestamp: new Date().toISOString(),
|
|
604
|
+
data: { session_id: this.sessionId, snapshot: this.agent.getEvidenceSnapshot() } });
|
|
536
605
|
const unsubscribe = this.agent.on((event) => {
|
|
537
606
|
this.activityState = applyAgentEventToState(this.activityState, event);
|
|
538
607
|
switch (event.type) {
|
|
608
|
+
case 'request_usage':
|
|
609
|
+
this.output({ type: 'request_usage', timestamp: new Date().toISOString(), data: { session_id: this.sessionId, receipt: event.receipt } });
|
|
610
|
+
this.autoMirror?.publish({ type: 'request_usage', data: { sessionId: this.sessionId, receipt: event.receipt } });
|
|
611
|
+
break;
|
|
612
|
+
case 'evidence':
|
|
613
|
+
this.output({ type: 'evidence', timestamp: new Date().toISOString(),
|
|
614
|
+
data: { session_id: event.sessionId, snapshot: event.snapshot } });
|
|
615
|
+
break;
|
|
616
|
+
case 'command_wait':
|
|
617
|
+
case 'command_wait_end':
|
|
618
|
+
goalManager.observeHostWait(event);
|
|
619
|
+
this.publishCurrentGoal();
|
|
620
|
+
this.emitHeadlessStatus();
|
|
621
|
+
break;
|
|
539
622
|
case 'thinking_start':
|
|
540
623
|
this.emitHeadlessStatus();
|
|
541
624
|
break;
|
|
@@ -692,7 +775,11 @@ export class HeadlessApp {
|
|
|
692
775
|
});
|
|
693
776
|
return () => {
|
|
694
777
|
unsubscribe();
|
|
695
|
-
this.activityState = { status: 'idle'
|
|
778
|
+
this.activityState = { status: 'idle', taskHandoff: this.activityState.taskHandoff,
|
|
779
|
+
workspaceCollision: this.activityState.workspaceCollision };
|
|
780
|
+
void this.workspaceCoordinator?.setActivity('idle').catch(() => {
|
|
781
|
+
runtimeDiag('warn', '[ztc] Local workspace activity evidence could not be refreshed.');
|
|
782
|
+
});
|
|
696
783
|
this.emitHeadlessStatus();
|
|
697
784
|
};
|
|
698
785
|
}
|
|
@@ -711,6 +798,13 @@ export class HeadlessApp {
|
|
|
711
798
|
/**
|
|
712
799
|
* Output a message in the appropriate format
|
|
713
800
|
*/
|
|
801
|
+
publishTaskHandoff() {
|
|
802
|
+
this.publishCurrentGoal();
|
|
803
|
+
this.activityState = applyAgentEventToState(this.activityState, { type: 'task_handoff', sessionId: this.sessionId, projection: this.taskHandoff });
|
|
804
|
+
this.output({ type: 'task_handoff', timestamp: new Date().toISOString(),
|
|
805
|
+
data: { sessionId: this.sessionId, projection: this.taskHandoff } });
|
|
806
|
+
this.autoMirror?.publishTaskHandoff(this.taskHandoff, this.sessionId);
|
|
807
|
+
}
|
|
714
808
|
output(data) {
|
|
715
809
|
if (this.options.json) {
|
|
716
810
|
console.log(JSON.stringify(data));
|
|
@@ -748,11 +842,19 @@ export class HeadlessApp {
|
|
|
748
842
|
if (!this.options.quiet || this.options.verbose)
|
|
749
843
|
console.log(`${ts}[commands] ${JSON.stringify(data.data.jobs)}`);
|
|
750
844
|
break;
|
|
845
|
+
case 'evidence':
|
|
846
|
+
if (!this.options.quiet || this.options.verbose)
|
|
847
|
+
console.log(`${ts}[evidence] Retained source-linked observations; inspect with /evidence.`);
|
|
848
|
+
break;
|
|
849
|
+
case 'task_handoff':
|
|
850
|
+
if (this.taskHandoff && (!this.options.quiet || this.options.verbose))
|
|
851
|
+
console.log(formatTaskHandoffContext(this.taskHandoff.snapshot));
|
|
852
|
+
break;
|
|
751
853
|
case 'status':
|
|
752
854
|
// In quiet mode, skip status unless verbose
|
|
753
855
|
if (this.options.quiet && !this.options.verbose)
|
|
754
856
|
break;
|
|
755
|
-
console.log(`${ts}[status] ${data.data.status}`);
|
|
857
|
+
console.log(`${ts}[status] ${data.data.waiting ? 'Waiting for command' : data.data.status}`);
|
|
756
858
|
break;
|
|
757
859
|
case 'artifact':
|
|
758
860
|
console.log(`${ts}[artifact] ${data.data.path}`);
|
|
@@ -1008,8 +1110,9 @@ export class HeadlessApp {
|
|
|
1008
1110
|
// whose real credential (for example a Codex subscription auth.json) is on
|
|
1009
1111
|
// disk. `load()` is idempotent, so the CLI path is unaffected.
|
|
1010
1112
|
await configStore.load();
|
|
1011
|
-
//
|
|
1012
|
-
|
|
1113
|
+
// Hosted native Messages supplies its own scoped transport bearer. The
|
|
1114
|
+
// backend factory validates it; provider-key discovery must not gate it.
|
|
1115
|
+
if (!configStore.get().nativeAnthropicMessagesRouter && !configStore.hasApiKey() && !configStore.isAuthenticated()) {
|
|
1013
1116
|
this.output({
|
|
1014
1117
|
type: 'error',
|
|
1015
1118
|
timestamp: new Date().toISOString(),
|
|
@@ -1182,6 +1285,27 @@ export class HeadlessApp {
|
|
|
1182
1285
|
});
|
|
1183
1286
|
}
|
|
1184
1287
|
}
|
|
1288
|
+
const savedEnvironment = loadedSession?.metadata.environment;
|
|
1289
|
+
if (savedEnvironment && this.options.detachEnvironment) {
|
|
1290
|
+
this.output({ type: 'status', timestamp: new Date().toISOString(), data: { status: 'environment_detached', message: `Environment ${savedEnvironment.name} detached by launch option; conversation resumed in ${this.shellCwd}.` } });
|
|
1291
|
+
}
|
|
1292
|
+
if (savedEnvironment && !this.options.detachEnvironment) {
|
|
1293
|
+
try {
|
|
1294
|
+
this.environmentSessionCwd = loadedSession.metadata.cwd;
|
|
1295
|
+
this.environmentReturnCwd = this.environmentSessionCwd;
|
|
1296
|
+
const before = await getEnvironment(savedEnvironment.name);
|
|
1297
|
+
if (before.id !== savedEnvironment.id)
|
|
1298
|
+
throw new Error('The saved environment was replaced; inspect it before recovery.');
|
|
1299
|
+
const record = await openEnvironment(savedEnvironment.name, this.sessionId);
|
|
1300
|
+
this.environmentReleased = false;
|
|
1301
|
+
this.environmentRecord = record;
|
|
1302
|
+
this.shellCwd = record.workspacePath;
|
|
1303
|
+
process.chdir(record.workspacePath);
|
|
1304
|
+
}
|
|
1305
|
+
catch (error) {
|
|
1306
|
+
throw new EnvironmentRecoveryError(`Environment ${savedEnvironment.name} could not resume: ${error instanceof Error ? error.message : String(error)}. To resume the conversation in the current project, add --detach-environment.`);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1185
1309
|
if (explicitMode) {
|
|
1186
1310
|
if (explicitMode.name === 'plan') {
|
|
1187
1311
|
const resumePath = loadedSession?.metadata.mode === 'plan'
|
|
@@ -1217,6 +1341,7 @@ export class HeadlessApp {
|
|
|
1217
1341
|
executeCommand: (cmd, args, origin) => this.executeCommand(cmd, args, origin),
|
|
1218
1342
|
getMode: () => this.currentMode,
|
|
1219
1343
|
setMode: (mode) => {
|
|
1344
|
+
this.sessionManager.recordHostDiagnostic('mode', { mode, previousMode: this.currentMode, source: 'host_mode_change' });
|
|
1220
1345
|
this.currentMode = mode;
|
|
1221
1346
|
this.hookLifecycle.onModeChange();
|
|
1222
1347
|
},
|
|
@@ -1253,14 +1378,15 @@ export class HeadlessApp {
|
|
|
1253
1378
|
// Set up pane tools for mux mode
|
|
1254
1379
|
if (this.options.muxMode) {
|
|
1255
1380
|
this.paneManager = new HeadlessPaneManager();
|
|
1256
|
-
this.paneManager.setHostTitle(
|
|
1381
|
+
this.paneManager.setHostTitle(inferAgentPaneTitle({ cwd: this.options.cwd ?? process.cwd(), sessionId: this.sessionId, paneId: 0 }));
|
|
1382
|
+
this.paneManager.send({ type: 'set_pane_labels', pane_id: 0, labels: this.sessionLabels, if_newer: true });
|
|
1257
1383
|
await this.paneManager.start({ mux: true });
|
|
1258
1384
|
setPaneToolsTuiProcess(this.paneManager);
|
|
1259
1385
|
// Start pane relay server so child panes (--pane) can connect and use pane tools
|
|
1260
1386
|
const relayPath = generateRelaySocketPath();
|
|
1261
1387
|
process.env.ZTC_PANE_RELAY = relayPath;
|
|
1262
1388
|
this.paneRelay = new PaneRelayServer(this.paneManager, relayPath);
|
|
1263
|
-
this.paneRelay.start();
|
|
1389
|
+
await this.paneRelay.start();
|
|
1264
1390
|
await runtimePluginRegistry.runMuxStartHooks({
|
|
1265
1391
|
paneManager: this.paneManager,
|
|
1266
1392
|
relayPath,
|
|
@@ -1290,6 +1416,13 @@ export class HeadlessApp {
|
|
|
1290
1416
|
if (!this.options.deferJsonStdinStartup) {
|
|
1291
1417
|
this.outputHeadlessShellMode();
|
|
1292
1418
|
}
|
|
1419
|
+
// Discover current Router controls before the first backend snapshots them.
|
|
1420
|
+
try {
|
|
1421
|
+
if (configStore.resolveLLMBackendConfig().useProxy) {
|
|
1422
|
+
void buildModelsController(configStore).catalog(this.startupCatalogController.signal, { refresh: 'startup' }).catch(() => { });
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
catch { /* Offline startup keeps the account-scoped cached catalog. */ }
|
|
1293
1426
|
// Create agent
|
|
1294
1427
|
this.agent = this.createAgent();
|
|
1295
1428
|
if (!this.agent) {
|
|
@@ -1319,6 +1452,7 @@ export class HeadlessApp {
|
|
|
1319
1452
|
// Web `use` (switch account) hot-swaps this headless instance's live
|
|
1320
1453
|
// agent, matching the CLI /accounts use path.
|
|
1321
1454
|
this.autoMirror.setAccountReloadHook(() => this.reloadAgentInPlace());
|
|
1455
|
+
this.autoMirror.setAccountOperationHook(body => this.applyAccountOperation(body));
|
|
1322
1456
|
mirrorPort = this.autoMirror.getPort();
|
|
1323
1457
|
}
|
|
1324
1458
|
catch (err) {
|
|
@@ -1344,49 +1478,61 @@ export class HeadlessApp {
|
|
|
1344
1478
|
hidden: false,
|
|
1345
1479
|
cwd: process.cwd(),
|
|
1346
1480
|
});
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1481
|
+
}
|
|
1482
|
+
// Visibility only controls navigator registration, never process cleanup.
|
|
1483
|
+
let cleanedUp = false;
|
|
1484
|
+
const cleanup = () => {
|
|
1485
|
+
if (cleanedUp)
|
|
1486
|
+
return;
|
|
1487
|
+
cleanedUp = true;
|
|
1488
|
+
if (!this.options.navigatorHidden) {
|
|
1352
1489
|
try {
|
|
1353
1490
|
deregisterInstance(process.pid);
|
|
1354
1491
|
}
|
|
1355
|
-
catch { /* ignore */ }
|
|
1356
|
-
try {
|
|
1357
|
-
this.autoMirror?.stop();
|
|
1358
|
-
}
|
|
1359
1492
|
catch { /* best effort */ }
|
|
1360
|
-
}
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1493
|
+
}
|
|
1494
|
+
try {
|
|
1495
|
+
this.autoMirror?.stop();
|
|
1496
|
+
}
|
|
1497
|
+
catch { /* best effort */ }
|
|
1498
|
+
this.workspaceCoordinator?.closeSync();
|
|
1499
|
+
};
|
|
1500
|
+
// Fatal-signal exit must also reap detached shell-tool children. They are
|
|
1501
|
+
// spawned in their own process group, so an ordinary ztc exit orphans any
|
|
1502
|
+
// `npm run dev` / test runner / install still running — the cell Stop /
|
|
1503
|
+
// Archive / Quit and supervisor shutdown only SIGTERM this top-level process.
|
|
1504
|
+
// SIGTERM the groups, give them a brief moment, then SIGKILL stragglers and
|
|
1505
|
+
// exit. The 200ms is well under the supervisor's 2s SIGKILL-escalation on us,
|
|
1506
|
+
// so we still exit promptly.
|
|
1507
|
+
let fatalExitRequested = false;
|
|
1508
|
+
const fatalExit = (code) => {
|
|
1509
|
+
if (fatalExitRequested)
|
|
1510
|
+
return;
|
|
1511
|
+
fatalExitRequested = true;
|
|
1512
|
+
cleanup();
|
|
1513
|
+
const killed = terminateActiveShellChildren('SIGTERM');
|
|
1514
|
+
const forceExit = setTimeout(() => {
|
|
1515
|
+
terminateActiveShellChildren('SIGKILL');
|
|
1516
|
+
process.exit(code);
|
|
1517
|
+
}, 200);
|
|
1518
|
+
// Wait for an already admitted presence publication to retire before
|
|
1519
|
+
// exit. The same bounded fallback covers a stuck filesystem request.
|
|
1520
|
+
void (this.workspaceCoordinator?.close() ?? Promise.resolve()).catch(() => { }).then(() => {
|
|
1371
1521
|
if (killed.length === 0) {
|
|
1522
|
+
clearTimeout(forceExit);
|
|
1372
1523
|
process.exit(code);
|
|
1373
|
-
return;
|
|
1374
1524
|
}
|
|
1375
|
-
setTimeout(() => {
|
|
1376
|
-
terminateActiveShellChildren('SIGKILL');
|
|
1377
|
-
process.exit(code);
|
|
1378
|
-
}, 200).unref();
|
|
1379
|
-
};
|
|
1380
|
-
process.on('exit', cleanup);
|
|
1381
|
-
process.on('SIGINT', () => fatalExit(130));
|
|
1382
|
-
process.on('SIGTERM', () => fatalExit(143));
|
|
1383
|
-
process.on('SIGHUP', () => fatalExit(129));
|
|
1384
|
-
process.on('uncaughtException', (err) => {
|
|
1385
|
-
cleanup();
|
|
1386
|
-
console.error(err);
|
|
1387
|
-
process.exit(1);
|
|
1388
1525
|
});
|
|
1389
|
-
}
|
|
1526
|
+
};
|
|
1527
|
+
process.on('exit', cleanup);
|
|
1528
|
+
process.on('SIGINT', () => fatalExit(130));
|
|
1529
|
+
process.on('SIGTERM', () => fatalExit(143));
|
|
1530
|
+
process.on('SIGHUP', () => fatalExit(129));
|
|
1531
|
+
process.on('uncaughtException', (err) => {
|
|
1532
|
+
cleanup();
|
|
1533
|
+
console.error(err);
|
|
1534
|
+
process.exit(1);
|
|
1535
|
+
});
|
|
1390
1536
|
// A pane child receives the web mirror's stop button as SIGUSR2 (see
|
|
1391
1537
|
// HeadlessPaneManager.cancelPane): its stdin loop AWAITS the running turn, so
|
|
1392
1538
|
// a signal is the only mid-turn cancel channel. SIGUSR2, not SIGUSR1 — Node
|
|
@@ -1412,21 +1558,44 @@ export class HeadlessApp {
|
|
|
1412
1558
|
this.outputBackgroundEvent(event);
|
|
1413
1559
|
});
|
|
1414
1560
|
}
|
|
1561
|
+
// Navigator visibility does not change local workspace ownership evidence.
|
|
1562
|
+
// Hidden workers and pane children must remain discoverable by sibling UIs.
|
|
1563
|
+
this.workspaceCoordinator = new LocalWorkspaceCoordinator({
|
|
1564
|
+
sessionId: this.sessionId,
|
|
1565
|
+
getCwd: () => this.shellCwd,
|
|
1566
|
+
getWork: () => ({ sessionId: this.sessionId, messages: this.messages,
|
|
1567
|
+
goal: goalManager.get(), jobs: listCommandJobs(this.sessionId), taskHandoff: this.taskHandoff }),
|
|
1568
|
+
kind: process.env.ZTC_COLONY_CHILD ? 'colony_child' : 'headless',
|
|
1569
|
+
onSnapshot: (snapshot) => {
|
|
1570
|
+
this.activityState = { ...this.activityState, workspaceCollision: snapshot };
|
|
1571
|
+
},
|
|
1572
|
+
});
|
|
1573
|
+
await this.workspaceCoordinator.start();
|
|
1415
1574
|
return true;
|
|
1416
1575
|
}
|
|
1417
1576
|
/**
|
|
1418
1577
|
* Create the agent
|
|
1419
1578
|
*/
|
|
1420
1579
|
commandJobsUnsubscribe;
|
|
1421
|
-
createAgent() {
|
|
1580
|
+
createAgent(options = {}) {
|
|
1581
|
+
const diagnostics = this.sessionManager.getDiagnostics();
|
|
1582
|
+
this.sessionManager.recordHostDiagnostic('runtime', {
|
|
1583
|
+
renderer: 'headless', rendererVersion: null, nativeCapabilities: null, source: 'host_launch',
|
|
1584
|
+
});
|
|
1585
|
+
this.sessionManager.recordHostDiagnostic('mode', { mode: this.currentMode, source: 'agent_construction' });
|
|
1422
1586
|
this.commandJobsUnsubscribe?.();
|
|
1423
1587
|
this.commandJobsUnsubscribe = subscribeCommandJobs(this.sessionId, jobs => {
|
|
1588
|
+
for (const job of jobs)
|
|
1589
|
+
this.sessionManager.recordCommandJob(job);
|
|
1424
1590
|
this.output({ type: 'command_jobs', timestamp: new Date().toISOString(), data: { jobs } });
|
|
1425
1591
|
this.autoMirror?.publish({ type: 'command_jobs', data: { jobs } });
|
|
1592
|
+
void this.workspaceCoordinator?.refresh().catch(error => runtimeDiag('warn', `[ztc] Local workspace command evidence could not be refreshed: ${String(error)}`));
|
|
1426
1593
|
});
|
|
1427
1594
|
const isEvolveMode = this.currentMode === 'evolved-swarm';
|
|
1428
1595
|
const hookDispatcher = this.hookLifecycle.refresh();
|
|
1429
1596
|
const agent = createAgentWithConfig({
|
|
1597
|
+
allowUnavailableRouterAuth: options.allowUnavailableRouterAuth,
|
|
1598
|
+
environmentContext: this.environmentRecord ? describeEnvironmentForAgent(this.environmentRecord) : undefined,
|
|
1430
1599
|
autoContinue: true, // Always auto-continue in headless mode
|
|
1431
1600
|
maxConsecutiveAutoContinues: configStore.getMaxConsecutiveAutoContinues(),
|
|
1432
1601
|
maxIterations: isEvolveMode ? 200 : (this.options.maxIterations ?? Infinity),
|
|
@@ -1443,8 +1612,25 @@ export class HeadlessApp {
|
|
|
1443
1612
|
cwdProvider: () => this.shellCwd || process.cwd(),
|
|
1444
1613
|
hookDispatcher,
|
|
1445
1614
|
hookApprovalRequester: (request) => this.requestHookApproval(request),
|
|
1615
|
+
toolResponseStore: this.sessionToolResponseStore,
|
|
1616
|
+
onLocalFileChange: async (paths, cwd) => {
|
|
1617
|
+
await this.workspaceCoordinator?.recordObservedPaths(paths, cwd);
|
|
1618
|
+
},
|
|
1619
|
+
toolCheckpoint: async (checkpoint) => {
|
|
1620
|
+
if (checkpoint.sessionId !== this.sessionId) {
|
|
1621
|
+
throw new Error('Tool checkpoint session identity does not match the active headless session.');
|
|
1622
|
+
}
|
|
1623
|
+
const merged = mergeToolCheckpointMessages(this.messages, checkpoint.messages);
|
|
1624
|
+
// Agent.run shares this array. Preserve that identity and any accepted
|
|
1625
|
+
// live correction sources while applying the canonical tool outcome.
|
|
1626
|
+
this.messages.splice(0, this.messages.length, ...merged);
|
|
1627
|
+
await this.sessionManager.save({ required: true });
|
|
1628
|
+
},
|
|
1446
1629
|
});
|
|
1447
1630
|
if (agent) {
|
|
1631
|
+
agent.restoreDiagnosticSnapshot(diagnostics);
|
|
1632
|
+
agent.restoreUsageSnapshot(this.sessionManager.getUsageSnapshot());
|
|
1633
|
+
agent.setTaskHandoff(this.taskHandoff);
|
|
1448
1634
|
this.agentBindFailure = null;
|
|
1449
1635
|
const bind = this.bindAgentStore(agent);
|
|
1450
1636
|
this.pendingAgentBind = bind;
|
|
@@ -1467,12 +1653,20 @@ export class HeadlessApp {
|
|
|
1467
1653
|
return agent;
|
|
1468
1654
|
}
|
|
1469
1655
|
async bindAgentStore(agent) {
|
|
1470
|
-
|
|
1656
|
+
const storeConfig = {
|
|
1657
|
+
offloadEnabled: configStore.getOffloadEnabled(),
|
|
1658
|
+
inlineSizeThresholdTokens: configStore.getInlineSizeThresholdTokens(),
|
|
1659
|
+
inlineAgeTurns: configStore.getInlineAgeTurns(),
|
|
1660
|
+
toolCompression: configStore.getToolCompression(),
|
|
1661
|
+
};
|
|
1662
|
+
agent.toolResponseStore.setConfig(storeConfig);
|
|
1663
|
+
this.sessionToolResponseBinding ??= bindToolResponseStoreToSession(agent.toolResponseStore, agent.discoveredTools, this.environmentSessionCwd ?? process.cwd(), this.sessionId, {
|
|
1471
1664
|
offloadEnabled: configStore.getOffloadEnabled(),
|
|
1472
1665
|
inlineSizeThresholdTokens: configStore.getInlineSizeThresholdTokens(),
|
|
1473
1666
|
inlineAgeTurns: configStore.getInlineAgeTurns(),
|
|
1474
1667
|
toolCompression: configStore.getToolCompression(),
|
|
1475
1668
|
}, this.options.sessionFile);
|
|
1669
|
+
await this.sessionToolResponseBinding;
|
|
1476
1670
|
agent.refreshSystemPrompt();
|
|
1477
1671
|
}
|
|
1478
1672
|
async awaitAgentBind() {
|
|
@@ -1497,6 +1691,11 @@ export class HeadlessApp {
|
|
|
1497
1691
|
*/
|
|
1498
1692
|
replaceAgent(next) {
|
|
1499
1693
|
const previous = this.agent;
|
|
1694
|
+
const diagnostics = this.sessionManager.getDiagnostics();
|
|
1695
|
+
if (next?.getDiagnosticSessionId() === this.sessionId)
|
|
1696
|
+
next.restoreDiagnosticSnapshot(diagnostics);
|
|
1697
|
+
if (next?.getUsageSessionId() === this.sessionId)
|
|
1698
|
+
next.restoreUsageSnapshot(this.sessionManager.getUsageSnapshot());
|
|
1500
1699
|
this.agent = next;
|
|
1501
1700
|
if (previous && previous !== next)
|
|
1502
1701
|
previous.dispose();
|
|
@@ -1542,6 +1741,145 @@ export class HeadlessApp {
|
|
|
1542
1741
|
this.replaceAgent(nextAgent);
|
|
1543
1742
|
this.hookLifecycle.ensureWatcher();
|
|
1544
1743
|
}
|
|
1744
|
+
/** Activate a config profile without replacing the conversation or its storage. */
|
|
1745
|
+
async switchConfigProfileInPlace(name, duplicateSource) {
|
|
1746
|
+
if (process.env.ZTC_HOSTED === '1' || process.env.ZTC_HOST_RUNTIME?.trim()) {
|
|
1747
|
+
throw new Error('Hosted thread settings cannot be replaced by a local config profile.');
|
|
1748
|
+
}
|
|
1749
|
+
if (this.activeRunController) {
|
|
1750
|
+
throw new Error('Wait for the current turn to finish before switching profiles.');
|
|
1751
|
+
}
|
|
1752
|
+
await this.awaitAgentBind();
|
|
1753
|
+
const previousMcp = JSON.stringify(configStore.get().mcpServers ?? {});
|
|
1754
|
+
const previousColonyMcp = process.env.ZTC_COLONY_MCP;
|
|
1755
|
+
const previousColonyOwned = process.env.ZTC_COLONY_MCP_CONFIG_OWNED;
|
|
1756
|
+
let runtimeTouched = false;
|
|
1757
|
+
let mcpChanged = false;
|
|
1758
|
+
const reloadMcp = async () => {
|
|
1759
|
+
const { closeMcpServers, colonyOptIn } = await import('./mcp/registry.js');
|
|
1760
|
+
await closeMcpServers();
|
|
1761
|
+
const servers = configStore.get().mcpServers;
|
|
1762
|
+
if ((servers && Object.keys(servers).length > 0) || colonyOptIn()) {
|
|
1763
|
+
const { initMcpServers } = await import('./mcp/client.js');
|
|
1764
|
+
await initMcpServers(servers);
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
const reloadSkills = async () => {
|
|
1768
|
+
const { invalidateSkillsCache, preloadSkillsManifest } = await import('./skills/registry.js');
|
|
1769
|
+
invalidateSkillsCache();
|
|
1770
|
+
await preloadSkillsManifest();
|
|
1771
|
+
};
|
|
1772
|
+
const rebuild = async () => {
|
|
1773
|
+
const next = this.createAgent({ allowUnavailableRouterAuth: true });
|
|
1774
|
+
try {
|
|
1775
|
+
if (next)
|
|
1776
|
+
await this.awaitAgentBind();
|
|
1777
|
+
}
|
|
1778
|
+
catch (error) {
|
|
1779
|
+
next?.dispose();
|
|
1780
|
+
throw error;
|
|
1781
|
+
}
|
|
1782
|
+
this.replaceAgent(next);
|
|
1783
|
+
this.hookLifecycle.ensureWatcher();
|
|
1784
|
+
};
|
|
1785
|
+
try {
|
|
1786
|
+
const activate = async () => {
|
|
1787
|
+
runtimeTouched = true;
|
|
1788
|
+
if (process.env.ZTC_COLONY_MCP_CONFIG_OWNED === '1') {
|
|
1789
|
+
delete process.env.ZTC_COLONY_MCP;
|
|
1790
|
+
delete process.env.ZTC_COLONY_MCP_CONFIG_OWNED;
|
|
1791
|
+
}
|
|
1792
|
+
if (configStore.get().mcp?.colonyAutoAttach && !process.env.ZTC_COLONY_MCP) {
|
|
1793
|
+
process.env.ZTC_COLONY_MCP = '1';
|
|
1794
|
+
process.env.ZTC_COLONY_MCP_CONFIG_OWNED = '1';
|
|
1795
|
+
}
|
|
1796
|
+
mcpChanged = previousMcp !== JSON.stringify(configStore.get().mcpServers ?? {})
|
|
1797
|
+
|| previousColonyMcp !== process.env.ZTC_COLONY_MCP;
|
|
1798
|
+
if (mcpChanged)
|
|
1799
|
+
await reloadMcp();
|
|
1800
|
+
await reloadSkills();
|
|
1801
|
+
await rebuild();
|
|
1802
|
+
await this.sessionManager.save({ persistEmpty: true, required: true });
|
|
1803
|
+
};
|
|
1804
|
+
if (duplicateSource === undefined)
|
|
1805
|
+
await configStore.switchProfile(name, activate);
|
|
1806
|
+
else
|
|
1807
|
+
await configStore.duplicateProfile(name, duplicateSource, activate);
|
|
1808
|
+
}
|
|
1809
|
+
catch (error) {
|
|
1810
|
+
if (previousColonyMcp === undefined)
|
|
1811
|
+
delete process.env.ZTC_COLONY_MCP;
|
|
1812
|
+
else
|
|
1813
|
+
process.env.ZTC_COLONY_MCP = previousColonyMcp;
|
|
1814
|
+
if (previousColonyOwned === undefined)
|
|
1815
|
+
delete process.env.ZTC_COLONY_MCP_CONFIG_OWNED;
|
|
1816
|
+
else
|
|
1817
|
+
process.env.ZTC_COLONY_MCP_CONFIG_OWNED = previousColonyOwned;
|
|
1818
|
+
if (runtimeTouched) {
|
|
1819
|
+
try {
|
|
1820
|
+
if (mcpChanged)
|
|
1821
|
+
await reloadMcp();
|
|
1822
|
+
await reloadSkills();
|
|
1823
|
+
await rebuild();
|
|
1824
|
+
}
|
|
1825
|
+
catch (restoreError) {
|
|
1826
|
+
throw new Error('Profile switch failed: ' + error.message
|
|
1827
|
+
+ '. Restoring the previous runtime also failed: ' + restoreError.message);
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
throw error;
|
|
1831
|
+
}
|
|
1832
|
+
this.autoMirror?.setSuperuser(configStore.isSuperuser());
|
|
1833
|
+
if (!this.agent) {
|
|
1834
|
+
let notice = 'This profile has no usable provider yet. Configure one with /config or /auth.';
|
|
1835
|
+
try {
|
|
1836
|
+
configStore.resolveLLMBackendConfig({ cwd: this.shellCwd });
|
|
1837
|
+
}
|
|
1838
|
+
catch (error) {
|
|
1839
|
+
if (error instanceof RouterConfigurationError && error.needsSignIn) {
|
|
1840
|
+
notice = 'This profile needs a Router sign-in. Use /auth login to sign in for this profile; your session and conversation are retained.';
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
this.emitPaneChildNotice(notice);
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
async reloadAccountAgent() {
|
|
1847
|
+
if (this.turnAdmissionCount > 0 || this.activeRunController || this.runtimeMutationDone) {
|
|
1848
|
+
this.accountReloadPending = true;
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
this.reloadAgentInPlace();
|
|
1852
|
+
await this.awaitAgentBind();
|
|
1853
|
+
}
|
|
1854
|
+
async applyAccountOperation(body) {
|
|
1855
|
+
if (this.turnAdmissionCount > 0 || this.activeRunController || this.runtimeMutationDone)
|
|
1856
|
+
return { ok: false, blocked: true, error: 'An agent turn or tool is active; wait before switching accounts.' };
|
|
1857
|
+
let release;
|
|
1858
|
+
this.runtimeMutationDone = new Promise(resolve => { release = resolve; });
|
|
1859
|
+
let operationOpen = true;
|
|
1860
|
+
try {
|
|
1861
|
+
return await applyAccountOp(body, configStore, async () => {
|
|
1862
|
+
if (!operationOpen) {
|
|
1863
|
+
await this.reloadAccountAgent();
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
this.reloadAgentInPlace();
|
|
1867
|
+
await this.awaitAgentBind();
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
finally {
|
|
1871
|
+
operationOpen = false;
|
|
1872
|
+
this.runtimeMutationDone = null;
|
|
1873
|
+
release();
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
async finishTurnAdmission() {
|
|
1877
|
+
this.turnAdmissionCount--;
|
|
1878
|
+
if (this.turnAdmissionCount === 0 && this.accountReloadPending) {
|
|
1879
|
+
this.accountReloadPending = false;
|
|
1880
|
+
await this.reloadAccountAgent();
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1545
1883
|
/** Rebuild a backend invalidated by logout before either headless turn path. */
|
|
1546
1884
|
async ensureAgentForTurn() {
|
|
1547
1885
|
if (this.agent)
|
|
@@ -1596,10 +1934,11 @@ export class HeadlessApp {
|
|
|
1596
1934
|
addMessage: (msg) => {
|
|
1597
1935
|
capturedMessages.push(msg.content);
|
|
1598
1936
|
this.messages.push({
|
|
1599
|
-
id: `msg_${
|
|
1937
|
+
id: `msg_${randomUUID()}`,
|
|
1600
1938
|
role: msg.role,
|
|
1601
1939
|
content: msg.content,
|
|
1602
1940
|
timestamp: new Date(),
|
|
1941
|
+
...(msg.metadata ? { metadata: msg.metadata } : {}),
|
|
1603
1942
|
});
|
|
1604
1943
|
this.output({
|
|
1605
1944
|
type: 'message',
|
|
@@ -1608,11 +1947,24 @@ export class HeadlessApp {
|
|
|
1608
1947
|
});
|
|
1609
1948
|
},
|
|
1610
1949
|
clearMessages: () => { this.messages = []; },
|
|
1950
|
+
setMessages: (messages) => { this.messages = messages; },
|
|
1611
1951
|
// /clear-only reset (never /compact): drop the R7 pinned task so a fresh
|
|
1612
1952
|
// conversation re-pins its own first message instead of re-running the
|
|
1613
1953
|
// pre-clear prompt. clearMessages above is shared with /compact and must
|
|
1614
1954
|
// keep the pin, so the reset lives here.
|
|
1615
|
-
clearTransientState: () => {
|
|
1955
|
+
clearTransientState: () => {
|
|
1956
|
+
this.taskHandoff = null;
|
|
1957
|
+
this.restoredHandoffCorrections = [];
|
|
1958
|
+
this.agent?.setTaskHandoff(null);
|
|
1959
|
+
this.publishTaskHandoff();
|
|
1960
|
+
this.agent?.clearPinnedTask();
|
|
1961
|
+
if (this.agent) {
|
|
1962
|
+
this.agent.toolResponseStore.evidence.clear();
|
|
1963
|
+
const snapshot = this.agent.getEvidenceSnapshot();
|
|
1964
|
+
this.activityState = applyAgentEventToState(this.activityState, { type: 'evidence', sessionId: this.sessionId, snapshot });
|
|
1965
|
+
this.output({ type: 'evidence', timestamp: new Date().toISOString(), data: { session_id: this.sessionId, snapshot } });
|
|
1966
|
+
}
|
|
1967
|
+
},
|
|
1616
1968
|
getMessages: () => this.messages,
|
|
1617
1969
|
setAgentState: () => { },
|
|
1618
1970
|
// Authoritative context for /context + /compact (matches the bar): the
|
|
@@ -1624,6 +1976,13 @@ export class HeadlessApp {
|
|
|
1624
1976
|
// and /context use the reduced size.
|
|
1625
1977
|
setContextUsage: (used) => { this.lastContextTokens = used; },
|
|
1626
1978
|
reloadAgent: (options) => this.reloadAgentInPlace(options?.defer),
|
|
1979
|
+
switchConfigProfile: (name) => this.switchConfigProfileInPlace(name),
|
|
1980
|
+
duplicateProfile: async (name, source) => {
|
|
1981
|
+
await this.switchConfigProfileInPlace(name, source);
|
|
1982
|
+
return name;
|
|
1983
|
+
},
|
|
1984
|
+
applyAccountOperation: body => this.applyAccountOperation(body),
|
|
1985
|
+
getUsageSnapshot: () => this.sessionManager.getUsageSnapshot(),
|
|
1627
1986
|
setRuntimeModelOverride: (provider, model) => {
|
|
1628
1987
|
configStore.setCliOverride('provider', provider);
|
|
1629
1988
|
configStore.setCliOverride('model', model);
|
|
@@ -1631,16 +1990,57 @@ export class HeadlessApp {
|
|
|
1631
1990
|
},
|
|
1632
1991
|
setDebug: () => { },
|
|
1633
1992
|
getSessionId: () => this.sessionId,
|
|
1993
|
+
getSessionCwd: () => this.environmentSessionCwd ?? this.shellCwd,
|
|
1994
|
+
environmentAvailable: () => this.shellMode === 'real',
|
|
1995
|
+
isAgentRunning: () => this.activeRunController !== null,
|
|
1996
|
+
getEnvironment: () => this.environmentRecord,
|
|
1997
|
+
environmentChanged: async (name, returnCwd) => {
|
|
1998
|
+
if (returnCwd) {
|
|
1999
|
+
this.environmentReturnCwd = returnCwd;
|
|
2000
|
+
this.environmentSessionCwd ??= returnCwd;
|
|
2001
|
+
}
|
|
2002
|
+
if (name) {
|
|
2003
|
+
this.environmentRecord = await getEnvironment(name);
|
|
2004
|
+
this.environmentReleased = false;
|
|
2005
|
+
}
|
|
2006
|
+
else {
|
|
2007
|
+
const previous = this.environmentRecord;
|
|
2008
|
+
this.environmentRecord = null;
|
|
2009
|
+
this.shellCwd = previous && isEnvironmentWorkspacePath(previous.workspacePath, this.environmentReturnCwd) ? homedir() : this.environmentReturnCwd;
|
|
2010
|
+
}
|
|
2011
|
+
process.chdir(this.shellCwd);
|
|
2012
|
+
await this.sessionManager.save({ persistEmpty: true, required: true });
|
|
2013
|
+
},
|
|
1634
2014
|
getExecutionContext: () => this.agent?.getExecutionContext(),
|
|
2015
|
+
getOwnPaneId: () => this.paneManager ? 0 : null,
|
|
2016
|
+
getPaneLabels: this.paneManager ? async (paneId = 0) => readPaneLabels(this.paneManager, paneId) : undefined,
|
|
2017
|
+
setPaneLabels: async (labels, paneId) => {
|
|
2018
|
+
if (paneId !== undefined && !this.paneManager)
|
|
2019
|
+
throw new Error('Pane mux is unavailable.');
|
|
2020
|
+
if (paneId === undefined) {
|
|
2021
|
+
this.sessionName = labels.manual_title;
|
|
2022
|
+
this.sessionLabels = { ...labels };
|
|
2023
|
+
}
|
|
2024
|
+
this.paneManager?.send({ type: 'set_pane_labels', pane_id: paneId ?? 0, labels });
|
|
2025
|
+
},
|
|
2026
|
+
checkpointSession: async () => {
|
|
2027
|
+
await this.sessionManager.save({ required: true, persistEmpty: true });
|
|
2028
|
+
return this.options.sessionFile ?? getSessionPathForCwd(process.cwd(), this.sessionId);
|
|
2029
|
+
},
|
|
2030
|
+
getDiagnostics: () => this.sessionManager.getDiagnostics(),
|
|
2031
|
+
getEvidenceSnapshot: () => this.agent?.getEvidenceSnapshot(),
|
|
1635
2032
|
getSessionName: () => this.sessionName,
|
|
1636
2033
|
setSessionName: (name) => {
|
|
1637
2034
|
this.sessionName = name && name.length > 0 ? name : undefined;
|
|
2035
|
+
this.sessionLabels.manual_title = this.sessionName;
|
|
2036
|
+
this.paneManager?.send({ type: 'set_pane_labels', pane_id: 0, labels: this.sessionLabels });
|
|
1638
2037
|
},
|
|
1639
2038
|
retry: () => { },
|
|
1640
2039
|
exit: () => { process.exit(0); },
|
|
1641
2040
|
config: configStore,
|
|
1642
2041
|
emulation: { list: loadEmulationProfiles, get: getEmulationProfile },
|
|
1643
2042
|
setMode: (mode) => {
|
|
2043
|
+
this.sessionManager.recordHostDiagnostic('mode', { mode, previousMode: this.currentMode, source: 'host_mode_change' });
|
|
1644
2044
|
this.currentMode = mode;
|
|
1645
2045
|
this.hookLifecycle.onModeChange();
|
|
1646
2046
|
},
|
|
@@ -1677,7 +2077,7 @@ export class HeadlessApp {
|
|
|
1677
2077
|
...autoWidgets,
|
|
1678
2078
|
embedded: this.embeddedController || undefined,
|
|
1679
2079
|
bench: this.benchController || undefined,
|
|
1680
|
-
getInputMode: () => '
|
|
2080
|
+
getInputMode: () => 'steer',
|
|
1681
2081
|
setInputMode: () => { },
|
|
1682
2082
|
triggerAgentTurn: () => {
|
|
1683
2083
|
agentTurnPromise = this.runAgentOnCurrentMessages();
|
|
@@ -1699,6 +2099,8 @@ export class HeadlessApp {
|
|
|
1699
2099
|
return denial;
|
|
1700
2100
|
}
|
|
1701
2101
|
// Global command lookup first — global commands may have richer behavior than mode handlers
|
|
2102
|
+
if (cmd.toLowerCase() === 'model' && (this.turnAdmissionCount > 0 || this.activeRunController || this.runtimeMutationDone))
|
|
2103
|
+
return 'Cannot switch model while an active agent turn or account change is running.';
|
|
1702
2104
|
const command = commands.find(c => c.name === cmd.toLowerCase());
|
|
1703
2105
|
if (command) {
|
|
1704
2106
|
try {
|
|
@@ -1739,6 +2141,21 @@ export class HeadlessApp {
|
|
|
1739
2141
|
* Run a single prompt through the agent
|
|
1740
2142
|
*/
|
|
1741
2143
|
async runPrompt(prompt, opts = {}) {
|
|
2144
|
+
if (routeUserInput(prompt).type === 'command') {
|
|
2145
|
+
await this.runPromptAdmitted(prompt, opts);
|
|
2146
|
+
return;
|
|
2147
|
+
}
|
|
2148
|
+
if (this.runtimeMutationDone)
|
|
2149
|
+
await this.runtimeMutationDone;
|
|
2150
|
+
this.turnAdmissionCount++;
|
|
2151
|
+
try {
|
|
2152
|
+
await this.runPromptAdmitted(prompt, opts);
|
|
2153
|
+
}
|
|
2154
|
+
finally {
|
|
2155
|
+
await this.finishTurnAdmission();
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
async runPromptAdmitted(prompt, opts = {}) {
|
|
1742
2159
|
// Route input: slash command or regular message
|
|
1743
2160
|
const route = routeUserInput(prompt);
|
|
1744
2161
|
if (route.type === 'command') {
|
|
@@ -1753,6 +2170,11 @@ export class HeadlessApp {
|
|
|
1753
2170
|
}
|
|
1754
2171
|
return;
|
|
1755
2172
|
}
|
|
2173
|
+
if (this.environmentRecord?.status === 'paused' || environmentOperationInProgress(this.sessionId)) {
|
|
2174
|
+
this.hadHeadlessError = true;
|
|
2175
|
+
this.output({ type: 'error', timestamp: new Date().toISOString(), data: { message: this.environmentRecord?.status === 'paused' ? 'Environment paused. Use /environment resume before starting an agent turn.' : 'Wait for the environment operation to finish before starting an agent turn.' } });
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
1756
2178
|
if (!await this.ensureAgentForTurn())
|
|
1757
2179
|
return;
|
|
1758
2180
|
if (route.type === 'shell') {
|
|
@@ -1770,12 +2192,19 @@ export class HeadlessApp {
|
|
|
1770
2192
|
}
|
|
1771
2193
|
// Add user message
|
|
1772
2194
|
const userMsg = {
|
|
1773
|
-
id: `msg_${
|
|
2195
|
+
id: `msg_${randomUUID()}`,
|
|
1774
2196
|
role: 'user',
|
|
1775
2197
|
content: prompt,
|
|
1776
2198
|
timestamp: new Date(),
|
|
1777
2199
|
};
|
|
1778
2200
|
this.messages.push(userMsg);
|
|
2201
|
+
if (!opts.automaticGoalTurn) {
|
|
2202
|
+
const sustained = goalManager.adoptUserIntent(userMsg, { configuredMaxTurns: configStore.get().goalMaxTurns });
|
|
2203
|
+
if (sustained) {
|
|
2204
|
+
this.agent?.setPinnedTask(goalPinTask(sustained));
|
|
2205
|
+
this.emitGoalNote(`Sustained goal recorded: ${sustained.objective}`);
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
1779
2208
|
this.output({
|
|
1780
2209
|
type: 'message',
|
|
1781
2210
|
timestamp: new Date().toISOString(),
|
|
@@ -1785,6 +2214,7 @@ export class HeadlessApp {
|
|
|
1785
2214
|
try {
|
|
1786
2215
|
this.ensureAgentMatchesMode();
|
|
1787
2216
|
await this.awaitAgentBind();
|
|
2217
|
+
await this.sessionManager.save({ required: true });
|
|
1788
2218
|
cleanup = this.subscribeAgentEvents();
|
|
1789
2219
|
}
|
|
1790
2220
|
catch (error) {
|
|
@@ -1844,11 +2274,12 @@ export class HeadlessApp {
|
|
|
1844
2274
|
// `automatic`); a user turn taken while a goal is active resets it instead.
|
|
1845
2275
|
this.lastTurnAutomaticGoal = opts.automaticGoalTurn === true;
|
|
1846
2276
|
// Add assistant response
|
|
1847
|
-
if (response.content) {
|
|
2277
|
+
if (response.content || response.reasoning?.trim()) {
|
|
1848
2278
|
const assistantMsg = {
|
|
1849
|
-
id: `msg_${
|
|
2279
|
+
id: `msg_${randomUUID()}`,
|
|
1850
2280
|
role: 'assistant',
|
|
1851
2281
|
content: response.content,
|
|
2282
|
+
...(response.nativeContent ? { nativeContent: response.nativeContent, nativeModel: response.nativeModel, nativeContextId: response.nativeContextId } : {}),
|
|
1852
2283
|
timestamp: new Date(),
|
|
1853
2284
|
// Reasoning models expect their trace replayed with the assistant
|
|
1854
2285
|
// message on later turns; dropping it strips the history.
|
|
@@ -1993,7 +2424,7 @@ export class HeadlessApp {
|
|
|
1993
2424
|
return;
|
|
1994
2425
|
}
|
|
1995
2426
|
const userMsg = {
|
|
1996
|
-
id: `msg_${
|
|
2427
|
+
id: `msg_${randomUUID()}`,
|
|
1997
2428
|
role: 'user',
|
|
1998
2429
|
content: prompt,
|
|
1999
2430
|
timestamp: new Date(),
|
|
@@ -2029,7 +2460,7 @@ export class HeadlessApp {
|
|
|
2029
2460
|
}
|
|
2030
2461
|
const content = toolResult.content;
|
|
2031
2462
|
const assistantMsg = {
|
|
2032
|
-
id: `msg_${
|
|
2463
|
+
id: `msg_${randomUUID()}`,
|
|
2033
2464
|
role: 'assistant',
|
|
2034
2465
|
content,
|
|
2035
2466
|
timestamp: new Date(),
|
|
@@ -2082,6 +2513,22 @@ export class HeadlessApp {
|
|
|
2082
2513
|
* Used when commitPlan already added messages and we just need the agent to act on them.
|
|
2083
2514
|
*/
|
|
2084
2515
|
async runAgentOnCurrentMessages() {
|
|
2516
|
+
if (this.environmentRecord?.status === 'paused' || environmentOperationInProgress(this.sessionId)) {
|
|
2517
|
+
this.hadHeadlessError = true;
|
|
2518
|
+
this.output({ type: 'error', timestamp: new Date().toISOString(), data: { message: this.environmentRecord?.status === 'paused' ? 'Environment paused. Use /environment resume before starting an agent turn.' : 'Wait for the environment operation to finish before starting an agent turn.' } });
|
|
2519
|
+
return;
|
|
2520
|
+
}
|
|
2521
|
+
if (this.runtimeMutationDone)
|
|
2522
|
+
await this.runtimeMutationDone;
|
|
2523
|
+
this.turnAdmissionCount++;
|
|
2524
|
+
try {
|
|
2525
|
+
await this.runAgentOnCurrentMessagesAdmitted();
|
|
2526
|
+
}
|
|
2527
|
+
finally {
|
|
2528
|
+
await this.finishTurnAdmission();
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
async runAgentOnCurrentMessagesAdmitted() {
|
|
2085
2532
|
if (!await this.ensureAgentForTurn())
|
|
2086
2533
|
return;
|
|
2087
2534
|
let cleanup;
|
|
@@ -2145,9 +2592,10 @@ export class HeadlessApp {
|
|
|
2145
2592
|
}
|
|
2146
2593
|
if (response.content) {
|
|
2147
2594
|
const assistantMsg = {
|
|
2148
|
-
id: `msg_${
|
|
2595
|
+
id: `msg_${randomUUID()}`,
|
|
2149
2596
|
role: 'assistant',
|
|
2150
2597
|
content: response.content,
|
|
2598
|
+
...(response.nativeContent ? { nativeContent: response.nativeContent, nativeModel: response.nativeModel, nativeContextId: response.nativeContextId } : {}),
|
|
2151
2599
|
timestamp: new Date(),
|
|
2152
2600
|
// Reasoning models expect their trace replayed with the assistant
|
|
2153
2601
|
// message on later turns; dropping it strips the history.
|
|
@@ -2228,6 +2676,7 @@ export class HeadlessApp {
|
|
|
2228
2676
|
* Save the current session
|
|
2229
2677
|
*/
|
|
2230
2678
|
async saveCurrentSession() {
|
|
2679
|
+
this.publishCurrentGoal();
|
|
2231
2680
|
try {
|
|
2232
2681
|
await this.sessionManager.save({ required: !!this.options.sessionFile });
|
|
2233
2682
|
}
|
|
@@ -2347,6 +2796,11 @@ export class HeadlessApp {
|
|
|
2347
2796
|
* Shut down background agents and batch orchestrator gracefully before exiting.
|
|
2348
2797
|
*/
|
|
2349
2798
|
async shutdownBackgroundAgents() {
|
|
2799
|
+
this.startupCatalogController.abort(new Error('Runtime stopped'));
|
|
2800
|
+
if (this.environmentRecord && !this.environmentReleased) {
|
|
2801
|
+
await releaseEnvironment(this.environmentRecord.name, this.sessionId);
|
|
2802
|
+
this.environmentReleased = true;
|
|
2803
|
+
}
|
|
2350
2804
|
await shutdownCommandJobs(this.sessionId);
|
|
2351
2805
|
this.commandJobsUnsubscribe?.();
|
|
2352
2806
|
this.commandJobsUnsubscribe = undefined;
|
|
@@ -2402,11 +2856,15 @@ export class HeadlessApp {
|
|
|
2402
2856
|
}
|
|
2403
2857
|
this.embeddedController = null;
|
|
2404
2858
|
this.benchController = null;
|
|
2859
|
+
// Capture the producing agent before retiring its backend and identity.
|
|
2860
|
+
this.sessionManager.getDiagnostics();
|
|
2405
2861
|
// Reap the live agent's backend (a codex child now outlives each turn).
|
|
2406
2862
|
this.agent?.dispose();
|
|
2407
2863
|
// The worker executor holds a SEPARATE backend instance — reap it too.
|
|
2408
2864
|
clearWorkerExecutor();
|
|
2409
2865
|
this.agent = null;
|
|
2866
|
+
await this.workspaceCoordinator?.close();
|
|
2867
|
+
this.workspaceCoordinator = null;
|
|
2410
2868
|
}
|
|
2411
2869
|
outputHeadlessShellMode() {
|
|
2412
2870
|
this.output({
|
|
@@ -2541,6 +2999,7 @@ export class HeadlessApp {
|
|
|
2541
2999
|
switch (classified.kind) {
|
|
2542
3000
|
case 'prompt':
|
|
2543
3001
|
assertPromptWithinLimit(classified.text);
|
|
3002
|
+
this.dismissPendingQuestion();
|
|
2544
3003
|
await this.runInteractivePrompt(classified.text);
|
|
2545
3004
|
this.outputPromptComplete();
|
|
2546
3005
|
break;
|
|
@@ -2575,8 +3034,24 @@ export class HeadlessApp {
|
|
|
2575
3034
|
this.outputPromptComplete();
|
|
2576
3035
|
break;
|
|
2577
3036
|
case 'cancel':
|
|
3037
|
+
this.dismissPendingQuestion();
|
|
2578
3038
|
this.cancelActiveRun();
|
|
2579
3039
|
break;
|
|
3040
|
+
case 'ask_user_answer':
|
|
3041
|
+
if (this.pendingQuestionId !== classified.questionId) {
|
|
3042
|
+
this.emitPaneChildNotice('Stale question answer ignored. No prompt was submitted.');
|
|
3043
|
+
break;
|
|
3044
|
+
}
|
|
3045
|
+
assertPromptWithinLimit(classified.answer);
|
|
3046
|
+
this.dismissPendingQuestion();
|
|
3047
|
+
if (classified.answer === '__SKIP__') {
|
|
3048
|
+
this.messages.push({ id: randomUUID(), role: 'user', content: '__SKIP__', timestamp: new Date() });
|
|
3049
|
+
}
|
|
3050
|
+
else {
|
|
3051
|
+
await this.runInteractivePrompt(classified.answer);
|
|
3052
|
+
this.outputPromptComplete();
|
|
3053
|
+
}
|
|
3054
|
+
break;
|
|
2580
3055
|
case 'unknown_cmd':
|
|
2581
3056
|
this.emitPaneChildNotice(`Unknown pane command "${classified.cmd}" — ignored.`);
|
|
2582
3057
|
break;
|
|
@@ -2663,7 +3138,7 @@ export class HeadlessApp {
|
|
|
2663
3138
|
async runSingle(prompt) {
|
|
2664
3139
|
this.turnStartGoal = snapshotGoalForTurn();
|
|
2665
3140
|
await this.runPrompt(prompt);
|
|
2666
|
-
this.accountGoalFinalTurnAfterPrompt();
|
|
3141
|
+
await this.accountGoalFinalTurnAfterPrompt();
|
|
2667
3142
|
// If the prompt set/resumed an autonomous /goal, drive it to a terminal
|
|
2668
3143
|
// state before exiting (no-op when there is no armed goal).
|
|
2669
3144
|
await this.runGoalLoopIfArmed();
|
|
@@ -2736,10 +3211,22 @@ export class HeadlessApp {
|
|
|
2736
3211
|
* auto-starts; the user runs /goal resume. Shared by both load branches.
|
|
2737
3212
|
*/
|
|
2738
3213
|
applyResumedSession(session, restoreRuntimeMode = true) {
|
|
3214
|
+
if (!session.hosted_settings)
|
|
3215
|
+
configStore.restoreSessionSelection(session.metadata);
|
|
3216
|
+
this.sessionToolResponseStore = new ToolResponseStore();
|
|
3217
|
+
this.sessionToolResponseBinding = null;
|
|
2739
3218
|
this.sessionId = session.metadata.id;
|
|
2740
3219
|
this.sessionManager.setSessionId(this.sessionId);
|
|
3220
|
+
this.sessionManager.restoreDiagnostics(session.diagnostics);
|
|
3221
|
+
this.sessionManager.restoreUsageSnapshot(session.usage);
|
|
2741
3222
|
this.sessionName = session.metadata.name;
|
|
3223
|
+
this.sessionLabels = { ...session.metadata.labels, manual_title: this.sessionName };
|
|
2742
3224
|
this.messages = session.messages;
|
|
3225
|
+
this.taskHandoff = session.task_handoff ? projectTaskHandoff(session.task_handoff) : null;
|
|
3226
|
+
this.restoredHandoffCorrections = session.task_handoff?.corrections.map(correction => ({
|
|
3227
|
+
...correction, deliveryState: correction.deliveryState === 'pending' ? 'unknown' : correction.deliveryState,
|
|
3228
|
+
})) ?? [];
|
|
3229
|
+
this.publishTaskHandoff();
|
|
2743
3230
|
goalManager.hydrate(session.metadata.goal);
|
|
2744
3231
|
if (!restoreRuntimeMode)
|
|
2745
3232
|
return true;
|
|
@@ -2777,7 +3264,18 @@ export class HeadlessApp {
|
|
|
2777
3264
|
* makes a second call in the same terminal episode a no-op, so this cannot
|
|
2778
3265
|
* double-count with the goal loop's own accounting.
|
|
2779
3266
|
*/
|
|
2780
|
-
accountGoalFinalTurnAfterPrompt() {
|
|
3267
|
+
async accountGoalFinalTurnAfterPrompt() {
|
|
3268
|
+
const initial = goalManager.accountSustainedFirstTurn({ turnTokens: this.lastTurnTokens,
|
|
3269
|
+
...(detectGoalBlocked(this.lastTurnText) ? { blockedReason: goalBlockedReason(this.lastTurnText) } : {}),
|
|
3270
|
+
toolCallCount: this.lastTurnToolCalls, hadTextualOutput: this.lastTurnHadTextualOutput,
|
|
3271
|
+
automaticGoalTurn: false, turnSummary: this.lastTurnText, ...this.lastTurnToolOutcome,
|
|
3272
|
+
evidence: this.agent?.getEvidenceSnapshot() });
|
|
3273
|
+
if (initial) {
|
|
3274
|
+
if (initial.kind !== 'idle')
|
|
3275
|
+
this.emitGoalNote(initial.note);
|
|
3276
|
+
await this.saveCurrentSession();
|
|
3277
|
+
return;
|
|
3278
|
+
}
|
|
2781
3279
|
if (!shouldAccountFinalTurn(this.turnStartGoal, goalManager.get()))
|
|
2782
3280
|
return;
|
|
2783
3281
|
const accounted = goalManager.accountFinalTurn({
|
|
@@ -2785,8 +3283,10 @@ export class HeadlessApp {
|
|
|
2785
3283
|
});
|
|
2786
3284
|
// Only report when this call did the accounting, so the tallies include the
|
|
2787
3285
|
// final turn (the `/goal complete` command message fires before it is known).
|
|
2788
|
-
if (accounted)
|
|
3286
|
+
if (accounted) {
|
|
2789
3287
|
this.emitGoalNote(goalFinalNote(accounted));
|
|
3288
|
+
await this.saveCurrentSession();
|
|
3289
|
+
}
|
|
2790
3290
|
}
|
|
2791
3291
|
/**
|
|
2792
3292
|
* Run an interactive prompt, then drive any /goal it armed to a terminal state
|
|
@@ -2798,7 +3298,7 @@ export class HeadlessApp {
|
|
|
2798
3298
|
async runInteractivePrompt(prompt) {
|
|
2799
3299
|
this.turnStartGoal = snapshotGoalForTurn();
|
|
2800
3300
|
await this.runPrompt(prompt);
|
|
2801
|
-
this.accountGoalFinalTurnAfterPrompt();
|
|
3301
|
+
await this.accountGoalFinalTurnAfterPrompt();
|
|
2802
3302
|
await this.runGoalLoopIfArmed();
|
|
2803
3303
|
}
|
|
2804
3304
|
/**
|
|
@@ -2847,7 +3347,7 @@ export class HeadlessApp {
|
|
|
2847
3347
|
// them in would attribute stale numbers to this turn.
|
|
2848
3348
|
if (this.goalTurnCancelled) {
|
|
2849
3349
|
this.goalTurnCancelled = false;
|
|
2850
|
-
goalManager.pause();
|
|
3350
|
+
goalManager.pause('user_cancelled');
|
|
2851
3351
|
this.emitGoalNote(`⏸ Goal paused (cancelled): "${goal.objective}". /goal resume to continue.`);
|
|
2852
3352
|
break;
|
|
2853
3353
|
}
|
|
@@ -2868,7 +3368,7 @@ export class HeadlessApp {
|
|
|
2868
3368
|
break;
|
|
2869
3369
|
}
|
|
2870
3370
|
// Provider-agnostic completion: the turn ended with the GOAL_COMPLETE sentinel.
|
|
2871
|
-
if (detectGoalCompletion(this.lastTurnText)) {
|
|
3371
|
+
if (!afterTurn.plateau && !afterTurn.sustained && detectGoalCompletion(this.lastTurnText)) {
|
|
2872
3372
|
const done = goalManager.complete({ turnTokens: this.lastTurnTokens });
|
|
2873
3373
|
if (done)
|
|
2874
3374
|
this.emitGoalNote(goalFinalNote(done));
|
|
@@ -2877,19 +3377,21 @@ export class HeadlessApp {
|
|
|
2877
3377
|
// Provider-agnostic blocker: the turn ended with the GOAL_BLOCKED sentinel.
|
|
2878
3378
|
// Terminal like completion — without it the loop keeps buying turns from an
|
|
2879
3379
|
// agent that has already said it cannot get there.
|
|
2880
|
-
if (detectGoalBlocked(this.lastTurnText)) {
|
|
3380
|
+
if (!afterTurn.plateau && !afterTurn.sustained && detectGoalBlocked(this.lastTurnText)) {
|
|
2881
3381
|
const blocked = goalManager.block(goalBlockedReason(this.lastTurnText), { turnTokens: this.lastTurnTokens });
|
|
2882
3382
|
if (blocked)
|
|
2883
3383
|
this.emitGoalNote(goalFinalNote(blocked));
|
|
2884
3384
|
break;
|
|
2885
3385
|
}
|
|
2886
3386
|
const decision = goalManager.onTurnComplete({
|
|
3387
|
+
...(detectGoalBlocked(this.lastTurnText) ? { blockedReason: goalBlockedReason(this.lastTurnText) } : {}),
|
|
2887
3388
|
turnTokens: this.lastTurnTokens,
|
|
2888
3389
|
toolCallCount: this.lastTurnToolCalls,
|
|
2889
3390
|
hadTextualOutput: this.lastTurnHadTextualOutput,
|
|
2890
3391
|
automaticGoalTurn: this.lastTurnAutomaticGoal,
|
|
2891
3392
|
turnSummary: this.lastTurnText,
|
|
2892
3393
|
...this.lastTurnToolOutcome,
|
|
3394
|
+
evidence: this.agent?.getEvidenceSnapshot(),
|
|
2893
3395
|
});
|
|
2894
3396
|
if (decision.kind === 'continue') {
|
|
2895
3397
|
this.emitGoalNote(decision.note);
|
|
@@ -2907,7 +3409,13 @@ export class HeadlessApp {
|
|
|
2907
3409
|
// goal as finished — not stale-'active', which would re-drive a done goal.
|
|
2908
3410
|
await this.saveCurrentSession();
|
|
2909
3411
|
}
|
|
3412
|
+
publishCurrentGoal() {
|
|
3413
|
+
const data = { sessionId: this.sessionId, goal: projectGoal(goalManager.get()) };
|
|
3414
|
+
this.output({ type: 'goal', timestamp: new Date().toISOString(), data });
|
|
3415
|
+
this.autoMirror?.publish({ type: 'goal', data });
|
|
3416
|
+
}
|
|
2910
3417
|
emitGoalNote(content) {
|
|
3418
|
+
this.publishCurrentGoal();
|
|
2911
3419
|
this.output({
|
|
2912
3420
|
type: 'message',
|
|
2913
3421
|
timestamp: new Date().toISOString(),
|
|
@@ -3050,7 +3558,7 @@ export async function runHeadless(options, initialPrompt) {
|
|
|
3050
3558
|
initialized = await app.init();
|
|
3051
3559
|
}
|
|
3052
3560
|
catch (error) {
|
|
3053
|
-
const message = error instanceof RouterConfigurationError ? error.message : 'Headless initialization failed.';
|
|
3561
|
+
const message = error instanceof RouterConfigurationError || error instanceof EnvironmentRecoveryError ? error.message : 'Headless initialization failed.';
|
|
3054
3562
|
if (options.json) {
|
|
3055
3563
|
process.stdout.write(`${JSON.stringify({
|
|
3056
3564
|
type: 'error',
|