@gajae-code/coding-agent 0.13.2 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +215 -8
- package/README.md +2 -0
- package/bin/gajaessi.js +4 -0
- package/dist/types/async/job-manager.d.ts +55 -2
- package/dist/types/async/support.d.ts +14 -0
- package/dist/types/capability/mcp.d.ts +6 -0
- package/dist/types/capability/types.d.ts +6 -0
- package/dist/types/cli/accounts-cli.d.ts +19 -0
- package/dist/types/cli/args.d.ts +3 -0
- package/dist/types/cli/config-cli.d.ts +6 -0
- package/dist/types/cli/crash-cli.d.ts +10 -0
- package/dist/types/cli/customize-doctor.d.ts +145 -0
- package/dist/types/cli/daemon-cli.d.ts +3 -1
- package/dist/types/cli/mcp-cli.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +1 -1
- package/dist/types/cli/root-flags.d.ts +12 -0
- package/dist/types/cli/setup-cli.d.ts +3 -1
- package/dist/types/cli/skills-cli.d.ts +2 -1
- package/dist/types/cli/update-cli.d.ts +19 -1
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/commands/accounts.d.ts +40 -0
- package/dist/types/commands/crash.d.ts +24 -0
- package/dist/types/commands/customize.d.ts +22 -0
- package/dist/types/commands/daemon.d.ts +1 -1
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/commands/setup.d.ts +6 -0
- package/dist/types/commands/skills.d.ts +6 -1
- package/dist/types/commands/update.d.ts +7 -0
- package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
- package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
- package/dist/types/config/config-schema-version.d.ts +10 -0
- package/dist/types/config/file-lock.d.ts +18 -0
- package/dist/types/config/model-profile-activation.d.ts +3 -1
- package/dist/types/config/model-registry.d.ts +10 -1
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +73 -9
- package/dist/types/config/settings.d.ts +63 -0
- package/dist/types/config/skill-settings-defaults.d.ts +26 -0
- package/dist/types/config/task-delegation.d.ts +39 -0
- package/dist/types/config/update-channel.d.ts +10 -0
- package/dist/types/coordinator-mcp/server.d.ts +5 -1
- package/dist/types/crash/index-store.d.ts +87 -0
- package/dist/types/crash/nudge.d.ts +50 -0
- package/dist/types/crash/record-loader.d.ts +17 -0
- package/dist/types/crash/report.d.ts +134 -0
- package/dist/types/crash/sanitize.d.ts +25 -0
- package/dist/types/cursor.d.ts +13 -2
- package/dist/types/customization/import.d.ts +37 -0
- package/dist/types/customization/index.d.ts +4 -0
- package/dist/types/customization/inventory.d.ts +25 -0
- package/dist/types/customization/mutations.d.ts +32 -0
- package/dist/types/customization/types.d.ts +115 -0
- package/dist/types/daemon/control-types.d.ts +8 -1
- package/dist/types/daemon/operator-contract.d.ts +4 -4
- package/dist/types/discovery/claude.d.ts +39 -1
- package/dist/types/discovery/codex.d.ts +39 -1
- package/dist/types/discovery/index.d.ts +2 -0
- package/dist/types/discovery/mcp-compat.d.ts +30 -0
- package/dist/types/edit/renderer.d.ts +23 -0
- package/dist/types/extensibility/extensions/runner.d.ts +3 -0
- package/dist/types/extensibility/extensions/types.d.ts +21 -4
- package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
- package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
- package/dist/types/extensibility/hooks/loader.d.ts +19 -5
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
- package/dist/types/extensibility/skill-management.d.ts +107 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
- package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
- package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
- package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
- package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
- package/dist/types/hooks/events.d.ts +60 -0
- package/dist/types/hooks/normalize.d.ts +83 -0
- package/dist/types/hooks/skill-state.d.ts +9 -2
- package/dist/types/main.d.ts +2 -1
- package/dist/types/modes/acp/abort-scope.d.ts +13 -0
- package/dist/types/modes/acp/acp-agent.d.ts +7 -4
- package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
- package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
- package/dist/types/modes/components/customization/index.d.ts +1 -0
- package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
- package/dist/types/modes/components/gajae-pet-widget.d.ts +6 -28
- package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
- package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
- package/dist/types/modes/components/oauth-selector.d.ts +10 -4
- package/dist/types/modes/components/pet-capability.d.ts +7 -21
- package/dist/types/modes/components/settings-selector.d.ts +5 -0
- package/dist/types/modes/components/status-line/gh.d.ts +6 -2
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
- package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/theme/defaults/index.d.ts +118 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
- package/dist/types/runtime-mcp/config.d.ts +9 -0
- package/dist/types/runtime-mcp/manager.d.ts +26 -1
- package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
- package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
- package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
- package/dist/types/runtime-mcp/protocol.d.ts +278 -0
- package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
- package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
- package/dist/types/runtime-mcp/types.d.ts +102 -10
- package/dist/types/sdk/acp/adapter.d.ts +26 -5
- package/dist/types/sdk/broker/broker.d.ts +3 -55
- package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
- package/dist/types/sdk/broker/session-index.d.ts +14 -5
- package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
- package/dist/types/sdk/bus/config.d.ts +11 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
- package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
- package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
- package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
- package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
- package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
- package/dist/types/sdk/bus/index.d.ts +85 -99
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
- package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
- package/dist/types/sdk/bus/notification-service.d.ts +52 -0
- package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
- package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
- package/dist/types/sdk/bus/session-control.d.ts +25 -1
- package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
- package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
- package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
- package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
- package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
- package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
- package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
- package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
- package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
- package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
- package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
- package/dist/types/sdk/cli/rows.d.ts +2 -11
- package/dist/types/sdk/cli/session-cli.d.ts +15 -25
- package/dist/types/sdk/client/client.d.ts +97 -1
- package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
- package/dist/types/sdk/host/control/index.d.ts +1 -1
- package/dist/types/sdk/host/control/operations.d.ts +18 -5
- package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
- package/dist/types/sdk/host/host.d.ts +15 -1
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/host/session-runtime.d.ts +127 -7
- package/dist/types/sdk/host/types.d.ts +1 -1
- package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
- package/dist/types/sdk/index.d.ts +2 -1
- package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
- package/dist/types/sdk/lifecycle/client.d.ts +59 -0
- package/dist/types/sdk/lifecycle/index.d.ts +3 -0
- package/dist/types/sdk/lifecycle/service.d.ts +232 -0
- package/dist/types/sdk/mcp/server.d.ts +9 -6
- package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
- package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
- package/dist/types/sdk/prompt-status.d.ts +10 -3
- package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
- package/dist/types/sdk/receipt-state.d.ts +17 -0
- package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
- package/dist/types/sdk/router/index.d.ts +1 -0
- package/dist/types/sdk/router/session-router.d.ts +152 -0
- package/dist/types/sdk/session-list.d.ts +22 -0
- package/dist/types/sdk/session-reconnect.d.ts +43 -1
- package/dist/types/sdk/session.d.ts +34 -1
- package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
- package/dist/types/session/account-inventory.d.ts +86 -0
- package/dist/types/session/agent-session.d.ts +145 -6
- package/dist/types/session/agent-storage.d.ts +10 -0
- package/dist/types/session/coordinator-tool-label.d.ts +28 -0
- package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
- package/dist/types/session/messages.d.ts +1 -1
- package/dist/types/session/secure-token-file.d.ts +3 -0
- package/dist/types/session/session-manager.d.ts +47 -1
- package/dist/types/session/startup-auth-config.d.ts +44 -0
- package/dist/types/session/terminal-abort.d.ts +378 -0
- package/dist/types/session/yield-queue.d.ts +7 -0
- package/dist/types/session-import/claude.d.ts +26 -0
- package/dist/types/session-import/codex.d.ts +88 -0
- package/dist/types/session-import/command.d.ts +35 -0
- package/dist/types/session-import/detect.d.ts +22 -0
- package/dist/types/session-import/index.d.ts +7 -0
- package/dist/types/session-import/provider-codex.d.ts +22 -0
- package/dist/types/session-import/provider-service.d.ts +38 -0
- package/dist/types/session-import/redact.d.ts +23 -0
- package/dist/types/session-import/service.d.ts +47 -0
- package/dist/types/session-import/types.d.ts +120 -0
- package/dist/types/setup/paseo/check.d.ts +16 -0
- package/dist/types/setup/paseo/install-saga.d.ts +115 -0
- package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
- package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
- package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
- package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
- package/dist/types/setup/paseo/provider-config.d.ts +35 -0
- package/dist/types/setup/paseo/remove.d.ts +14 -0
- package/dist/types/setup/paseo/result-types.d.ts +59 -0
- package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
- package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
- package/dist/types/skill-state/active-state.d.ts +5 -1
- package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
- package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
- package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
- package/dist/types/slash-commands/types.d.ts +7 -1
- package/dist/types/task/executor.d.ts +10 -0
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/tools/ask-answer-registry.d.ts +6 -3
- package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
- package/dist/types/tools/bash.d.ts +2 -6
- package/dist/types/tools/browser/attach.d.ts +11 -0
- package/dist/types/tools/browser/launch.d.ts +20 -0
- package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -1
- package/dist/types/tools/image-gen.d.ts +10 -2
- package/dist/types/tools/index.d.ts +8 -0
- package/dist/types/tools/monitor.d.ts +1 -1
- package/dist/types/tools/skill-discovery.d.ts +8 -1
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
- package/dist/types/utils/herdr-pane.d.ts +76 -0
- package/package.json +19 -9
- package/scripts/build-binary.ts +2 -1
- package/scripts/build-sdk-package-smoke.ts +2 -13
- package/scripts/capture-sticky-viewport-showcase.ts +0 -1
- package/scripts/compile-args.ts +2 -0
- package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
- package/scripts/generate-sdk-operation-inventory.ts +28 -0
- package/scripts/generate-telegram-baseline-manifest.ts +1 -0
- package/scripts/generate-tool-catalog.ts +6 -4
- package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
- package/src/async/job-manager.ts +352 -17
- package/src/async/support.ts +25 -0
- package/src/autoresearch/dashboard.ts +28 -13
- package/src/capability/index.ts +3 -1
- package/src/capability/mcp.ts +6 -0
- package/src/capability/types.ts +6 -0
- package/src/cli/accounts-cli.ts +395 -0
- package/src/cli/args.ts +23 -0
- package/src/cli/auth-broker-cli.ts +136 -66
- package/src/cli/auth-gateway-cli.ts +94 -70
- package/src/cli/config-cli.ts +27 -2
- package/src/cli/crash-cli.ts +78 -0
- package/src/cli/customize-doctor.ts +1605 -0
- package/src/cli/daemon-cli.ts +12 -3
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/mcp-cli.ts +128 -60
- package/src/cli/notify-cli.ts +8 -14
- package/src/cli/root-flags.ts +8 -0
- package/src/cli/setup-cli.ts +145 -0
- package/src/cli/skills-cli.ts +38 -2
- package/src/cli/update-cli.ts +167 -12
- package/src/cli.ts +4 -0
- package/src/commands/accounts.ts +71 -0
- package/src/commands/crash.ts +35 -0
- package/src/commands/customize.ts +84 -0
- package/src/commands/daemon.ts +2 -2
- package/src/commands/deep-interview.ts +2 -0
- package/src/commands/launch.ts +1 -0
- package/src/commands/mcp.ts +12 -7
- package/src/commands/ralplan.ts +2 -0
- package/src/commands/sdk.ts +65 -32
- package/src/commands/setup.ts +5 -0
- package/src/commands/skills.ts +14 -4
- package/src/commands/ultragoal.ts +10 -1
- package/src/commands/update.ts +26 -15
- package/src/config/atomic-yaml-patch-worker.ts +57 -0
- package/src/config/atomic-yaml-patch.ts +769 -29
- package/src/config/config-schema-version.ts +10 -0
- package/src/config/file-lock.ts +70 -1
- package/src/config/mcp-schema.json +52 -14
- package/src/config/model-profile-activation.ts +23 -2
- package/src/config/model-profiles.ts +88 -21
- package/src/config/model-registry.ts +147 -21
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +77 -7
- package/src/config/settings.ts +4038 -199
- package/src/config/skill-settings-defaults.ts +41 -3
- package/src/config/task-delegation.ts +87 -0
- package/src/config/update-channel.ts +23 -0
- package/src/coordinator-mcp/server.ts +377 -308
- package/src/crash/index-store.ts +723 -0
- package/src/crash/nudge.ts +89 -0
- package/src/crash/record-loader.ts +149 -0
- package/src/crash/report.ts +551 -0
- package/src/crash/sanitize.ts +129 -0
- package/src/cursor.ts +36 -10
- package/src/customization/import.ts +946 -0
- package/src/customization/index.ts +4 -0
- package/src/customization/inventory.ts +335 -0
- package/src/customization/mutations.ts +141 -0
- package/src/customization/types.ts +223 -0
- package/src/daemon/control-types.ts +8 -1
- package/src/daemon/operator-contract.ts +6 -6
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
- package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
- package/src/discovery/claude-hooks.ts +38 -0
- package/src/discovery/claude.ts +142 -209
- package/src/discovery/codex-hooks.ts +38 -0
- package/src/discovery/codex.ts +132 -198
- package/src/discovery/helpers.ts +8 -1
- package/src/discovery/index.ts +2 -0
- package/src/discovery/mcp-compat.ts +234 -0
- package/src/discovery/mcp-json.ts +6 -0
- package/src/edit/renderer.ts +40 -0
- package/src/edit/streaming.ts +4 -2
- package/src/exec/bash-executor.ts +24 -20
- package/src/export/html/index.ts +51 -2
- package/src/extensibility/extensions/loader.ts +9 -1
- package/src/extensibility/extensions/runner.ts +17 -4
- package/src/extensibility/extensions/types.ts +31 -6
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
- package/src/extensibility/gjc-plugins/installer.ts +9 -5
- package/src/extensibility/gjc-plugins/observability.ts +8 -2
- package/src/extensibility/gjc-plugins/registry.ts +13 -2
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
- package/src/extensibility/gjc-plugins/schema.ts +222 -39
- package/src/extensibility/hooks/loader.ts +154 -10
- package/src/extensibility/runtime-skill-discovery.ts +257 -60
- package/src/extensibility/skill-management.ts +368 -0
- package/src/extensibility/skills.ts +52 -16
- package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
- package/src/gjc-runtime/launch-worktree.ts +56 -2
- package/src/gjc-runtime/linux-proc.ts +7 -1
- package/src/gjc-runtime/ralplan-runtime.ts +100 -164
- package/src/gjc-runtime/session-state-lock.ts +992 -0
- package/src/gjc-runtime/session-state-sidecar.ts +644 -142
- package/src/gjc-runtime/state-writer.ts +39 -14
- package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
- package/src/gjc-runtime/ultragoal-guard.ts +11 -4
- package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
- package/src/gjc-runtime/workflow-settings.ts +596 -0
- package/src/goals/tools/goal-tool.ts +6 -1
- package/src/hooks/events.ts +291 -0
- package/src/hooks/native-skill-hook.ts +4 -0
- package/src/hooks/normalize.ts +369 -0
- package/src/hooks/skill-state.ts +165 -46
- package/src/internal-urls/docs-index.generated.ts +41 -32
- package/src/main.ts +36 -5
- package/src/migrate/mcp-mapper.ts +25 -2
- package/src/modes/acp/abort-scope.ts +29 -0
- package/src/modes/acp/acp-agent.ts +423 -98
- package/src/modes/components/assistant-message.ts +6 -1
- package/src/modes/components/chrome.ts +4 -3
- package/src/modes/components/customization/customization-dashboard.ts +443 -0
- package/src/modes/components/customization/import-wizard.ts +372 -0
- package/src/modes/components/customization/index.ts +1 -0
- package/src/modes/components/dynamic-theme-text.ts +22 -0
- package/src/modes/components/gajae-pet-widget.ts +607 -193
- package/src/modes/components/irc-sidebar.ts +11 -0
- package/src/modes/components/iterm-pet-transport.ts +585 -0
- package/src/modes/components/model-selector.ts +1 -6
- package/src/modes/components/oauth-selector.ts +277 -86
- package/src/modes/components/pet-capability.ts +35 -31
- package/src/modes/components/settings-selector.ts +29 -5
- package/src/modes/components/status-line/gh.ts +45 -1
- package/src/modes/components/status-line/segments.ts +19 -4
- package/src/modes/components/tool-status-header.ts +13 -3
- package/src/modes/controllers/command-controller.ts +20 -8
- package/src/modes/controllers/extension-ui-controller.ts +56 -257
- package/src/modes/controllers/input-controller.ts +10 -0
- package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
- package/src/modes/controllers/selector-controller.ts +238 -77
- package/src/modes/controllers/stt-controller.ts +3 -3
- package/src/modes/interactive-mode.ts +88 -16
- package/src/modes/print-mode.ts +35 -6
- package/src/modes/runtime-init.ts +21 -68
- package/src/modes/theme/defaults/index.ts +2 -0
- package/src/modes/theme/defaults/ouroboros.json +118 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/injected-user-submission.ts +25 -0
- package/src/modes/utils/terminal-bell.ts +15 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
- package/src/prompts/agent-fragments/restricted-bash.md +1 -1
- package/src/prompts/agents/critic.md +1 -1
- package/src/prompts/system/rlm-research.md +1 -1
- package/src/prompts/system/system-prompt.md +0 -2
- package/src/prompts/tools/bash.md +7 -1
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/cron.md +6 -6
- package/src/prompts/tools/read.md +0 -2
- package/src/prompts/tools/skill-discovery.md +4 -2
- package/src/runtime-mcp/client.ts +427 -23
- package/src/runtime-mcp/config.ts +37 -5
- package/src/runtime-mcp/manager-pool.test.ts +56 -0
- package/src/runtime-mcp/manager.ts +52 -2
- package/src/runtime-mcp/oauth-discovery.ts +13 -0
- package/src/runtime-mcp/oauth-flow.ts +46 -1
- package/src/runtime-mcp/pool-key.ts +5 -1
- package/src/runtime-mcp/pool.test.ts +9 -0
- package/src/runtime-mcp/protocol.test.ts +353 -0
- package/src/runtime-mcp/protocol.ts +624 -0
- package/src/runtime-mcp/scope-config.ts +78 -0
- package/src/runtime-mcp/tool-bridge.ts +44 -10
- package/src/runtime-mcp/transports/http.ts +84 -13
- package/src/runtime-mcp/types.ts +123 -12
- package/src/sdk/acp/adapter.ts +328 -97
- package/src/sdk/broker/broker.ts +160 -741
- package/src/sdk/broker/ensure.ts +9 -1
- package/src/sdk/broker/lifecycle.ts +510 -116
- package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
- package/src/sdk/broker/process-incarnation.ts +19 -0
- package/src/sdk/broker/session-index.ts +516 -117
- package/src/sdk/broker/startup-failure.ts +28 -5
- package/src/sdk/broker/transport.ts +1 -13
- package/src/sdk/bus/chat-daemon-cli.ts +4 -2
- package/src/sdk/bus/chat-daemon-control.ts +67 -6
- package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
- package/src/sdk/bus/config.ts +13 -0
- package/src/sdk/bus/conversation-store.ts +59 -171
- package/src/sdk/bus/daemon-paths.ts +20 -0
- package/src/sdk/bus/discord-conversation.ts +2 -0
- package/src/sdk/bus/discord-daemon.ts +524 -126
- package/src/sdk/bus/discord-live-provider.ts +206 -79
- package/src/sdk/bus/existing-thread-readiness.ts +4 -97
- package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
- package/src/sdk/bus/index.ts +2480 -456
- package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
- package/src/sdk/bus/lifecycle-commands.ts +2 -2
- package/src/sdk/bus/managed-daemon.ts +2 -145
- package/src/sdk/bus/notification-service.ts +196 -0
- package/src/sdk/bus/operator-runtime.ts +1 -1
- package/src/sdk/bus/prompt-reconciliation.ts +24 -15
- package/src/sdk/bus/reconciliation-store.ts +553 -24
- package/src/sdk/bus/session-control.ts +49 -3
- package/src/sdk/bus/slack-conversation.ts +4 -0
- package/src/sdk/bus/slack-daemon.ts +733 -134
- package/src/sdk/bus/slack-live-provider.ts +65 -15
- package/src/sdk/bus/slack-provider.ts +4 -0
- package/src/sdk/bus/slack-thread-binding.ts +9 -104
- package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
- package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
- package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
- package/src/sdk/bus/telegram-daemon-control.ts +3 -13
- package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
- package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
- package/src/sdk/bus/telegram-daemon.ts +2552 -2280
- package/src/sdk/bus/telegram-reference.ts +1 -226
- package/src/sdk/bus/telegram-setup.ts +2 -2
- package/src/sdk/bus/threaded-render.ts +1 -0
- package/src/sdk/bus/topic-registry.ts +279 -146
- package/src/sdk/cli/rows.ts +2 -35
- package/src/sdk/cli/session-cli.ts +776 -700
- package/src/sdk/client/client.ts +892 -1
- package/src/sdk/host/control/dispatch.ts +93 -58
- package/src/sdk/host/control/index.ts +1 -1
- package/src/sdk/host/control/operations.ts +18 -10
- package/src/sdk/host/control/runtime-gate.ts +40 -0
- package/src/sdk/host/host.ts +63 -12
- package/src/sdk/host/query/handlers.ts +66 -7
- package/src/sdk/host/reverse-leases.ts +2 -2
- package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
- package/src/sdk/host/session-runtime.test.ts +2787 -34
- package/src/sdk/host/session-runtime.ts +1489 -101
- package/src/sdk/host/surface-policy.ts +12 -8
- package/src/sdk/host/types.ts +1 -1
- package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
- package/src/sdk/host/websocket-transport.ts +85 -50
- package/src/sdk/index.ts +2 -1
- package/src/sdk/lifecycle/broker-client.ts +53 -0
- package/src/sdk/lifecycle/client.ts +234 -0
- package/src/sdk/lifecycle/index.ts +3 -0
- package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
- package/src/sdk/lifecycle/service.ts +720 -0
- package/src/sdk/mcp/server.ts +226 -188
- package/src/sdk/prompt-deadline-lease.ts +55 -0
- package/src/sdk/prompt-deadline-manager.ts +148 -0
- package/src/sdk/prompt-status.ts +11 -3
- package/src/sdk/protocol/operation-inventory.generated.json +272 -129
- package/src/sdk/protocol/operation-registry.ts +71 -8
- package/src/sdk/receipt-state.ts +43 -0
- package/src/sdk/reconciliation-extensions.ts +14 -0
- package/src/sdk/router/index.ts +1 -0
- package/src/sdk/router/session-router.ts +1658 -0
- package/src/sdk/session-list.ts +93 -0
- package/src/sdk/session-reconnect.ts +45 -1
- package/src/sdk/session.ts +716 -120
- package/src/sdk/transport/serve-cli.ts +18 -34
- package/src/session/account-inventory.ts +603 -0
- package/src/session/agent-session.ts +2873 -559
- package/src/session/agent-storage.ts +35 -0
- package/src/session/blob-store.ts +32 -1
- package/src/session/coordinator-tool-label.ts +40 -0
- package/src/session/internal/managed-session-scope.ts +4 -0
- package/src/session/internal/managed-session-storage.ts +199 -31
- package/src/session/messages.ts +1 -1
- package/src/session/secure-token-file.ts +80 -0
- package/src/session/session-manager.ts +757 -57
- package/src/session/session-storage.ts +25 -16
- package/src/session/startup-auth-config.ts +297 -0
- package/src/session/terminal-abort.ts +1253 -0
- package/src/session/yield-queue.ts +57 -15
- package/src/session-import/claude.ts +334 -0
- package/src/session-import/codex.ts +1033 -0
- package/src/session-import/command.ts +77 -0
- package/src/session-import/detect.ts +133 -0
- package/src/session-import/index.ts +7 -0
- package/src/session-import/provider-codex.ts +327 -0
- package/src/session-import/provider-service.ts +457 -0
- package/src/session-import/redact.ts +128 -0
- package/src/session-import/service.ts +1264 -0
- package/src/session-import/types.ts +148 -0
- package/src/setup/paseo/check.ts +213 -0
- package/src/setup/paseo/install-saga.ts +293 -0
- package/src/setup/paseo/json-publisher.ts +263 -0
- package/src/setup/paseo/orchestration-preferences.ts +86 -0
- package/src/setup/paseo/paseo-ownership.ts +224 -0
- package/src/setup/paseo/paseo-setup.ts +253 -0
- package/src/setup/paseo/provider-config.ts +139 -0
- package/src/setup/paseo/remove.ts +183 -0
- package/src/setup/paseo/result-types.ts +79 -0
- package/src/setup/paseo/setup-deps.ts +175 -0
- package/src/setup/paseo/skills-bridge.ts +260 -0
- package/src/skill-state/active-state.ts +21 -11
- package/src/slash-commands/acp-builtins.ts +9 -1
- package/src/slash-commands/builtin-registry.ts +117 -19
- package/src/slash-commands/helpers/credential-switch.ts +143 -0
- package/src/slash-commands/helpers/mcp.ts +9 -3
- package/src/slash-commands/helpers/usage-report.ts +61 -56
- package/src/slash-commands/types.ts +7 -2
- package/src/task/executor.ts +30 -11
- package/src/task/index.ts +66 -7
- package/src/task/render.ts +23 -9
- package/src/tools/ask-answer-registry.ts +23 -7
- package/src/tools/ask.ts +8 -4
- package/src/tools/bash-sleep-advisory.ts +115 -0
- package/src/tools/bash.ts +98 -18
- package/src/tools/browser/attach.ts +71 -3
- package/src/tools/browser/launch.ts +86 -13
- package/src/tools/browser/profile-discovery.ts +57 -7
- package/src/tools/browser/render.ts +8 -1
- package/src/tools/browser.ts +130 -21
- package/src/tools/computer.enforcement.test.ts +1 -1
- package/src/tools/computer.ts +3 -2
- package/src/tools/cron.ts +12 -1
- package/src/tools/image-gen.ts +349 -142
- package/src/tools/index.ts +8 -0
- package/src/tools/job.ts +33 -6
- package/src/tools/monitor.ts +41 -2
- package/src/tools/skill-discovery.ts +21 -29
- package/src/tools/subagent.ts +142 -24
- package/src/tools/todo-contract.ts +55 -3
- package/src/tools/todo-write.ts +4 -3
- package/src/tools/tool-catalog.generated.ts +6 -6
- package/src/tools/ultragoal-ask-guard.ts +10 -3
- package/src/utils/herdr-pane.ts +345 -0
- package/src/utils/title-generator.ts +2 -0
- package/src/web/scrapers/index.ts +6 -4
- package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
- package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
- package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
- package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
- package/dist/types/runtime/lazy-service.test.d.ts +0 -1
- package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
- package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
- package/dist/types/runtime-mcp/config.test.d.ts +0 -1
- package/dist/types/runtime-mcp/http.test.d.ts +0 -1
- package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
- package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
- package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
- package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
- package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
- package/dist/types/sdk/elevation/audit.d.ts +0 -93
- package/dist/types/sdk/elevation/capability.d.ts +0 -3
- package/dist/types/sdk/elevation/digest.d.ts +0 -72
- package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
- package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
- package/dist/types/sdk/elevation/owner.d.ts +0 -48
- package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
- package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
- package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
- package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
- package/dist/types/session/auth-broker-config.d.ts +0 -13
- package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
- package/dist/types/skills/skills.test.d.ts +0 -1
- package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
- package/dist/types/task/token-log.test.d.ts +0 -1
- package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
- package/dist/types/tools/descriptors.test.d.ts +0 -1
- package/scripts/g005-daemon-smoke.ts +0 -180
- package/scripts/g011-daemon-path-smoke.ts +0 -153
- package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
- package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
- package/src/sdk/bus/telegram-cli.ts +0 -212
- package/src/sdk/elevation/allowlist.ts +0 -54
- package/src/sdk/elevation/audit.ts +0 -208
- package/src/sdk/elevation/capability.ts +0 -41
- package/src/sdk/elevation/digest.ts +0 -129
- package/src/sdk/elevation/dispatch-receipt.ts +0 -184
- package/src/sdk/elevation/grant-ledger.ts +0 -1142
- package/src/sdk/elevation/owner.ts +0 -109
- package/src/session/auth-broker-config.ts +0 -109
- /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
- /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
- /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AnimationRegistration,
|
|
3
3
|
buildGajaePixelFrames,
|
|
4
|
+
type CellRect,
|
|
4
5
|
type Component,
|
|
5
6
|
type Container,
|
|
6
|
-
type
|
|
7
|
+
type GajaeGifFrame,
|
|
8
|
+
type GajaeGifTimeline,
|
|
7
9
|
type GajaePixelFrames,
|
|
8
10
|
getCellDimensions,
|
|
9
|
-
|
|
11
|
+
getGajaePetGifCached,
|
|
10
12
|
PET_SKINS,
|
|
13
|
+
type PetBurst,
|
|
14
|
+
type PetFrameName,
|
|
11
15
|
type PetMode,
|
|
12
16
|
type PetSkinId,
|
|
13
17
|
petBurstDurationMs,
|
|
14
18
|
petBurstFrame,
|
|
19
|
+
type RasterLeaseToken,
|
|
15
20
|
registerAnimationCallback,
|
|
16
21
|
type TUI,
|
|
22
|
+
wrapITerm2RecordForTmux,
|
|
17
23
|
} from "@gajae-code/tui";
|
|
18
24
|
import type { CustomEditor } from "./custom-editor";
|
|
19
|
-
import { getPetPixelProtocol } from "./pet-capability";
|
|
25
|
+
import { getItermPetUnavailableReason, getPetPixelProtocol, getVerifiedItermPetAvailability } from "./pet-capability";
|
|
20
26
|
|
|
21
27
|
/** Re-exported from the tui skin registry so widget-relative imports stay valid. */
|
|
22
28
|
export type { PetMode, PetSkinId };
|
|
@@ -37,6 +43,8 @@ const KITTY_DROP_FRACTION = 0.45;
|
|
|
37
43
|
const petKittyDropPx = (cellHeightPx: number): number =>
|
|
38
44
|
Math.min(Math.max(0, cellHeightPx - 1), Math.floor(cellHeightPx * KITTY_DROP_FRACTION));
|
|
39
45
|
const PET_RAISE_ROWS = 1;
|
|
46
|
+
const PET_ART_ROWS = 2;
|
|
47
|
+
const ITERM_CANVAS_ROWS = PET_ART_ROWS + 1;
|
|
40
48
|
const allocatedPetKittyImageIds = new Set<number>();
|
|
41
49
|
|
|
42
50
|
function allocatePetKittyImageId(): number {
|
|
@@ -59,41 +67,86 @@ function sameFootprint(left: SixelFootprint, right: SixelFootprint): boolean {
|
|
|
59
67
|
return left.x === right.x && left.y === right.y && left.columns === right.columns && left.rows === right.rows;
|
|
60
68
|
}
|
|
61
69
|
|
|
70
|
+
type PetOverlayEmission = {
|
|
71
|
+
payload: string;
|
|
72
|
+
onWritten?: () => void;
|
|
73
|
+
};
|
|
74
|
+
|
|
62
75
|
/**
|
|
63
76
|
* Which widget currently owns each TUI's single shared post-render emitter
|
|
64
77
|
* slot. A stale or repeated dispose (or off-switch) of a predecessor widget
|
|
65
78
|
* must never clear a successor's overlay authority.
|
|
66
79
|
*/
|
|
67
80
|
const petOverlayEmitterOwners = new WeakMap<TUI, GajaePetWidget>();
|
|
81
|
+
const petOverlayOwnershipEpochs = new WeakMap<TUI, number>();
|
|
68
82
|
|
|
69
|
-
/**
|
|
70
|
-
const WORK_LOOP_TOTAL = PARA_PARA_STEPS.reduce((sum, [, ms]) => sum + ms, 0);
|
|
71
|
-
/** Random gap between automatic claw flexes (fires while idle AND working). */
|
|
83
|
+
/** Random gap between automatic claw flexes while work is active. */
|
|
72
84
|
const AUTO_FLEX_MIN_GAP_MS = 12_000;
|
|
73
85
|
const AUTO_FLEX_MAX_GAP_MS = 40_000;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
[
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
]
|
|
83
|
-
|
|
86
|
+
function animationFrameAt(
|
|
87
|
+
steps: ReadonlyArray<readonly [PetFrameName, number]>,
|
|
88
|
+
now: number,
|
|
89
|
+
fallback: PetFrameName,
|
|
90
|
+
): PetFrameName {
|
|
91
|
+
const total = steps.reduce((sum, [, ms]) => sum + ms, 0);
|
|
92
|
+
if (total <= 0) return fallback;
|
|
93
|
+
let elapsed = now % total;
|
|
94
|
+
for (const [frame, ms] of steps) {
|
|
95
|
+
if (elapsed < ms) return frame;
|
|
96
|
+
elapsed -= ms;
|
|
97
|
+
}
|
|
98
|
+
return fallback;
|
|
99
|
+
}
|
|
84
100
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
101
|
+
function animationFrameAtElapsed(
|
|
102
|
+
steps: ReadonlyArray<readonly [PetFrameName, number]>,
|
|
103
|
+
elapsed: number,
|
|
104
|
+
fallback: PetFrameName,
|
|
105
|
+
): PetFrameName {
|
|
106
|
+
for (const [frame, ms] of steps) {
|
|
107
|
+
if (elapsed < ms) return frame;
|
|
108
|
+
elapsed -= ms;
|
|
109
|
+
}
|
|
110
|
+
return fallback;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function animationDuration(steps: ReadonlyArray<readonly [PetFrameName, number]>): number {
|
|
114
|
+
return steps.reduce((sum, [, ms]) => sum + ms, 0);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function gifTimeline(steps: ReadonlyArray<readonly [PetFrameName, number]>): GajaeGifFrame[] {
|
|
118
|
+
return steps.map(([name, delayMs]) => ({ name, delayMs }));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function burstGifTimeline(burst: PetBurst): GajaeGifTimeline {
|
|
122
|
+
const frames = gifTimeline(burst.intro);
|
|
123
|
+
const tail = burst.tail;
|
|
124
|
+
if (!tail || tail.frames.length === 0) return frames;
|
|
125
|
+
for (let elapsed = 0; elapsed < tail.ms; elapsed += tail.stepMs) {
|
|
126
|
+
frames.push({
|
|
127
|
+
name: tail.frames[Math.floor(elapsed / tail.stepMs) % tail.frames.length]!,
|
|
128
|
+
delayMs: Math.min(tail.stepMs, tail.ms - elapsed),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return frames;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function timelineSignature(frames: GajaeGifTimeline): string {
|
|
135
|
+
return frames.map(({ name, delayMs }) => `${name}:${delayMs}`).join(",");
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
interface WorkTransition {
|
|
139
|
+
startedAt: number;
|
|
140
|
+
steps: ReadonlyArray<readonly [PetFrameName, number]>;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const OUROBOROS_WORK_BURST_MIN_GAP_MS = 14_000;
|
|
144
|
+
const OUROBOROS_WORK_BURST_MAX_GAP_MS = 30_000;
|
|
145
|
+
|
|
146
|
+
/** Selector preview: fire the first burst this soon after a skin is previewed. */
|
|
90
147
|
const PREVIEW_INTRO_MS = 2300;
|
|
91
148
|
|
|
92
|
-
/**
|
|
93
|
-
* Wraps the composer editor, reserving a right-side area beside it where the
|
|
94
|
-
* real-pixel pet is drawn. The editor just renders narrower; the pet pixels
|
|
95
|
-
* are emitted separately as an absolute-positioned overlay.
|
|
96
|
-
*/
|
|
149
|
+
/** Reserve a right-side area beside the composer where the pixel pet is drawn. */
|
|
97
150
|
export class PetFramedEditor implements Component {
|
|
98
151
|
#editor: CustomEditor;
|
|
99
152
|
#reserve = 0;
|
|
@@ -115,27 +168,12 @@ export class PetFramedEditor implements Component {
|
|
|
115
168
|
}
|
|
116
169
|
|
|
117
170
|
render(width: number): string[] {
|
|
118
|
-
if (!this.canFit(width))
|
|
119
|
-
return this.#editor.render(width);
|
|
120
|
-
}
|
|
171
|
+
if (!this.canFit(width)) return this.#editor.render(width);
|
|
121
172
|
return this.#editor.render(width - this.#reserve);
|
|
122
173
|
}
|
|
123
174
|
}
|
|
124
175
|
|
|
125
|
-
/**
|
|
126
|
-
* The gajae pet: a 16x16 real-pixel sprite living in a reserved area beside
|
|
127
|
-
* the composer. It is nearest-neighbor scaled to the two terminal rows occupied
|
|
128
|
-
* by an empty one-line composer and lifted one row so its feet meet the input
|
|
129
|
-
* box's bottom edge.
|
|
130
|
-
*
|
|
131
|
-
* Rendering has two paths that share one payload builder:
|
|
132
|
-
* - a post-render emitter re-draws the sprite after every TUI write (line
|
|
133
|
-
* renders clear the pet cells, so the overlay must be re-applied), and
|
|
134
|
-
* - frame advances write the payload directly to the terminal, because the
|
|
135
|
-
* TUI skips writes entirely when no component line changed.
|
|
136
|
-
*
|
|
137
|
-
* Requires a sixel- or kitty-graphics terminal (`pixelProtocol()`).
|
|
138
|
-
*/
|
|
176
|
+
/** The gajae pet pixel sprite and protocol-specific rendering lifecycle. */
|
|
139
177
|
export class GajaePetWidget {
|
|
140
178
|
#ui: TUI;
|
|
141
179
|
#editor: CustomEditor;
|
|
@@ -146,29 +184,37 @@ export class GajaePetWidget {
|
|
|
146
184
|
#getComposerBottomOffset: () => number;
|
|
147
185
|
#mode: PetMode = "off";
|
|
148
186
|
#pixel: GajaePixelFrames | undefined;
|
|
149
|
-
#frame:
|
|
187
|
+
#frame: PetFrameName = "base";
|
|
150
188
|
#animation: AnimationRegistration | undefined;
|
|
151
189
|
#flexUntil = 0;
|
|
190
|
+
#activeBurst: PetBurst | undefined;
|
|
152
191
|
#nextAutoFlexAt = 0;
|
|
192
|
+
#working = false;
|
|
193
|
+
#workTransition: WorkTransition | undefined;
|
|
194
|
+
#nextWorkBurstAt = 0;
|
|
195
|
+
#workBurstIndex = 0;
|
|
196
|
+
#flexSource: "preview" | "working" | undefined;
|
|
197
|
+
#previewFlexAt = 0;
|
|
153
198
|
#autoFlexGapMs: [number, number] | null;
|
|
154
|
-
#forcedProtocol: "sixel" | "kitty" | undefined;
|
|
155
|
-
/** Cell metrics the current frames were built for; a change triggers a rebuild. */
|
|
199
|
+
#forcedProtocol: "sixel" | "kitty" | "iterm" | undefined;
|
|
156
200
|
#builtCellW = 0;
|
|
157
201
|
#builtCellH = 0;
|
|
158
202
|
#kittyImageId: number | undefined;
|
|
159
|
-
/** True while a kitty placement may exist on screen; cleared only after the delete escape is delivered. */
|
|
160
203
|
#kittyCleanupPending = false;
|
|
161
|
-
|
|
204
|
+
#kittyCleanupGeneration = 0;
|
|
162
205
|
#lastSixelFootprint: SixelFootprint | undefined;
|
|
163
|
-
/** Terminal state: a disposed widget never touches the TUI or shared slots again. */
|
|
164
206
|
#disposed = false;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
#
|
|
207
|
+
#ownedOverlayEpoch = 0;
|
|
208
|
+
#itermLease: RasterLeaseToken | undefined;
|
|
209
|
+
#disposePromise: Promise<void> | undefined;
|
|
210
|
+
#disposeRasterBarrier: Promise<void> = Promise.resolve();
|
|
211
|
+
#disposeNeedsLifecycle = false;
|
|
212
|
+
#itermProtocol = false;
|
|
213
|
+
#itermLastSemantic = "";
|
|
214
|
+
#itermOwner = `gajae-pet-${Math.random().toString(36).slice(2)}`;
|
|
215
|
+
#itermGeneration = 0;
|
|
216
|
+
#itermSubmitPending = false;
|
|
217
|
+
#syncManagedItermCursor: (row: number, column: number) => Promise<boolean>;
|
|
172
218
|
|
|
173
219
|
constructor(options: {
|
|
174
220
|
ui: TUI;
|
|
@@ -176,10 +222,9 @@ export class GajaePetWidget {
|
|
|
176
222
|
editorContainer: Container;
|
|
177
223
|
floorContainer: Container;
|
|
178
224
|
isWorking: () => boolean;
|
|
179
|
-
/** Rows rendered below the composer box (pet floor + hook widgets). */
|
|
180
225
|
getComposerBottomOffset: () => number;
|
|
226
|
+
syncManagedItermCursor: (row: number, column: number) => Promise<boolean>;
|
|
181
227
|
forcePixelProtocol?: "sixel" | "kitty";
|
|
182
|
-
/** Random [min, max] ms between auto-flexes; null disables. */
|
|
183
228
|
autoFlexGapMs?: [number, number] | null;
|
|
184
229
|
}) {
|
|
185
230
|
this.#ui = options.ui;
|
|
@@ -189,13 +234,13 @@ export class GajaePetWidget {
|
|
|
189
234
|
this.#framedEditor = new PetFramedEditor(options.editor);
|
|
190
235
|
this.#isWorking = options.isWorking;
|
|
191
236
|
this.#getComposerBottomOffset = options.getComposerBottomOffset;
|
|
237
|
+
this.#syncManagedItermCursor = options.syncManagedItermCursor;
|
|
192
238
|
this.#forcedProtocol = options.forcePixelProtocol;
|
|
193
239
|
this.#autoFlexGapMs =
|
|
194
240
|
options.autoFlexGapMs === undefined ? [AUTO_FLEX_MIN_GAP_MS, AUTO_FLEX_MAX_GAP_MS] : options.autoFlexGapMs;
|
|
195
241
|
}
|
|
196
242
|
|
|
197
|
-
|
|
198
|
-
static pixelProtocol(): "sixel" | "kitty" | null {
|
|
243
|
+
static pixelProtocol(): "sixel" | "kitty" | "iterm" | null {
|
|
199
244
|
return getPetPixelProtocol();
|
|
200
245
|
}
|
|
201
246
|
|
|
@@ -211,15 +256,21 @@ export class GajaePetWidget {
|
|
|
211
256
|
this.#applyMode(mode, true);
|
|
212
257
|
}
|
|
213
258
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
259
|
+
async suspendItermCapability(): Promise<void> {
|
|
260
|
+
if (!this.#isActiveOwner()) return;
|
|
261
|
+
this.#itermGeneration++;
|
|
262
|
+
const lease = this.#itermLease;
|
|
263
|
+
this.#itermLease = undefined;
|
|
264
|
+
this.#itermLastSemantic = "";
|
|
265
|
+
if (lease) await this.#ui.invalidateRasterLease({ token: lease, cause: "capability-loss" });
|
|
266
|
+
this.#ui.requestRender(true);
|
|
267
|
+
}
|
|
268
|
+
|
|
218
269
|
previewMode(mode: PetMode): void {
|
|
270
|
+
if (this.#disposed) return;
|
|
219
271
|
this.#applyMode(mode, false);
|
|
220
|
-
if (mode
|
|
221
|
-
|
|
222
|
-
}
|
|
272
|
+
if (!this.#isActiveOwner() || mode === "off" || !this.#autoFlexGapMs) return;
|
|
273
|
+
this.#previewFlexAt = performance.now() + PREVIEW_INTRO_MS;
|
|
223
274
|
}
|
|
224
275
|
|
|
225
276
|
commitPreviewMode(mode: PetMode): void {
|
|
@@ -228,15 +279,25 @@ export class GajaePetWidget {
|
|
|
228
279
|
|
|
229
280
|
#applyMode(mode: PetMode, mountComposer: boolean): void {
|
|
230
281
|
if (this.#disposed || mode === this.#mode) return;
|
|
231
|
-
|
|
232
282
|
if (mode === "off") {
|
|
233
|
-
this.#
|
|
283
|
+
if (!this.#canMutateSharedUi()) return;
|
|
284
|
+
this.#itermGeneration++;
|
|
285
|
+
if (this.#itermLease) {
|
|
286
|
+
void this.#ui.invalidateRasterLease({ token: this.#itermLease, cause: "mode-off" });
|
|
287
|
+
this.#itermLease = undefined;
|
|
288
|
+
}
|
|
289
|
+
this.#itermLastSemantic = "";
|
|
290
|
+
this.#itermProtocol = false;
|
|
291
|
+
this.#queueImageCleanup(true);
|
|
234
292
|
this.#mode = "off";
|
|
235
293
|
this.#animation?.unregister();
|
|
236
294
|
this.#animation = undefined;
|
|
237
295
|
this.#releaseOverlayEmitter();
|
|
238
296
|
this.#floorContainer.clear();
|
|
239
297
|
this.#pixel = undefined;
|
|
298
|
+
this.#activeBurst = undefined;
|
|
299
|
+
this.#workTransition = undefined;
|
|
300
|
+
this.#nextWorkBurstAt = 0;
|
|
240
301
|
this.#framedEditor.setReserve(0);
|
|
241
302
|
if (mountComposer) this.#mountEditor(false);
|
|
242
303
|
this.#ui.requestRender(true);
|
|
@@ -244,33 +305,77 @@ export class GajaePetWidget {
|
|
|
244
305
|
}
|
|
245
306
|
|
|
246
307
|
const protocol = this.#forcedProtocol ?? GajaePetWidget.pixelProtocol();
|
|
247
|
-
|
|
248
|
-
if (this.#
|
|
308
|
+
const ownershipEpoch = petOverlayOwnershipEpochs.get(this.#ui) ?? 0;
|
|
309
|
+
if (!protocol || (this.#ownedOverlayEpoch !== 0 && this.#ownedOverlayEpoch < ownershipEpoch)) return;
|
|
310
|
+
const predecessor = petOverlayEmitterOwners.get(this.#ui);
|
|
311
|
+
if (predecessor && predecessor !== this) predecessor.#retireForSuccessor();
|
|
312
|
+
this.#itermGeneration++;
|
|
313
|
+
if (this.#itermLease) {
|
|
314
|
+
void this.#ui.invalidateRasterLease({ token: this.#itermLease, cause: "explicit" });
|
|
315
|
+
this.#itermLease = undefined;
|
|
316
|
+
}
|
|
317
|
+
this.#itermLastSemantic = "";
|
|
318
|
+
if (this.#mode !== "off") {
|
|
319
|
+
const releasesKittyImage = this.#pixel?.protocol === "kitty" && protocol !== "kitty";
|
|
320
|
+
this.#queueImageCleanup(releasesKittyImage);
|
|
321
|
+
}
|
|
249
322
|
this.#mode = mode;
|
|
250
|
-
this.#frame =
|
|
323
|
+
this.#frame = PET_SKINS[mode].baseFrame;
|
|
251
324
|
this.#flexUntil = 0;
|
|
325
|
+
this.#activeBurst = undefined;
|
|
326
|
+
this.#flexSource = undefined;
|
|
327
|
+
this.#working = this.#isWorking();
|
|
328
|
+
this.#workTransition = undefined;
|
|
329
|
+
this.#nextWorkBurstAt = 0;
|
|
330
|
+
this.#workBurstIndex = 0;
|
|
331
|
+
this.#previewFlexAt = 0;
|
|
252
332
|
this.#nextAutoFlexAt = 0;
|
|
253
333
|
this.#buildPixel(protocol);
|
|
254
334
|
if (mountComposer) this.#mountEditor(true);
|
|
255
|
-
// The pet overlays the composer's bottom rows; no floor row is reserved, so
|
|
256
|
-
// the composer stays pinned to the terminal bottom.
|
|
257
335
|
this.#floorContainer.clear();
|
|
258
|
-
this.#ui.setPostRenderEmitter(() => this.#
|
|
336
|
+
this.#ui.setPostRenderEmitter(() => this.#overlayEmission());
|
|
337
|
+
this.#ownedOverlayEpoch = ownershipEpoch + 1;
|
|
338
|
+
petOverlayOwnershipEpochs.set(this.#ui, this.#ownedOverlayEpoch);
|
|
259
339
|
petOverlayEmitterOwners.set(this.#ui, this);
|
|
260
340
|
this.#animation ??= registerAnimationCallback(now => this.#tick(now), 80);
|
|
261
341
|
this.#ui.requestRender(true);
|
|
262
342
|
}
|
|
263
343
|
|
|
264
|
-
|
|
265
|
-
|
|
344
|
+
#isActiveOwner(): boolean {
|
|
345
|
+
return !this.#disposed && petOverlayEmitterOwners.get(this.#ui) === this;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
#canMutateSharedUi(): boolean {
|
|
349
|
+
const owner = petOverlayEmitterOwners.get(this.#ui);
|
|
350
|
+
return (
|
|
351
|
+
owner === this ||
|
|
352
|
+
(owner === undefined &&
|
|
353
|
+
this.#ownedOverlayEpoch !== 0 &&
|
|
354
|
+
this.#ownedOverlayEpoch === (petOverlayOwnershipEpochs.get(this.#ui) ?? 0))
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
#retireForSuccessor(): void {
|
|
359
|
+
this.dispose();
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
#buildPixel(protocol: "sixel" | "kitty" | "iterm"): void {
|
|
266
363
|
const cell = getCellDimensions();
|
|
267
364
|
this.#builtCellW = cell.widthPx;
|
|
268
365
|
this.#builtCellH = cell.heightPx;
|
|
269
366
|
const skin: PetSkinId = this.#mode === "off" ? "red" : this.#mode;
|
|
270
367
|
if (protocol === "kitty") {
|
|
271
368
|
this.#kittyImageId ??= allocatePetKittyImageId();
|
|
369
|
+
this.#kittyCleanupGeneration++;
|
|
272
370
|
this.#kittyCleanupPending = true;
|
|
273
371
|
}
|
|
372
|
+
if (protocol === "iterm") {
|
|
373
|
+
this.#itermProtocol = true;
|
|
374
|
+
this.#pixel = undefined;
|
|
375
|
+
this.#framedEditor.setReserve(Math.max(1, Math.ceil((2 * cell.heightPx) / cell.widthPx)) + PET_SIDE_MARGIN);
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
this.#itermProtocol = false;
|
|
274
379
|
this.#pixel = buildGajaePixelFrames({
|
|
275
380
|
protocol,
|
|
276
381
|
skin,
|
|
@@ -286,37 +391,50 @@ export class GajaePetWidget {
|
|
|
286
391
|
|
|
287
392
|
dispose(): void {
|
|
288
393
|
if (this.#disposed) return;
|
|
394
|
+
const canMutateSharedUi = this.#canMutateSharedUi();
|
|
395
|
+
this.#disposeNeedsLifecycle = canMutateSharedUi;
|
|
289
396
|
this.#disposed = true;
|
|
290
|
-
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
this.#pixel = undefined;
|
|
397
|
+
this.#itermGeneration++;
|
|
398
|
+
const lease = this.#itermLease;
|
|
399
|
+
this.#itermLease = undefined;
|
|
400
|
+
if (lease)
|
|
401
|
+
this.#disposeRasterBarrier = this.#ui
|
|
402
|
+
.invalidateRasterLease({ token: lease, cause: "dispose" })
|
|
403
|
+
.then(() => undefined);
|
|
404
|
+
const cleanupBarrier = canMutateSharedUi ? this.#queueImageCleanup(true) : this.#queueImageCleanup(true, false);
|
|
405
|
+
this.#disposeRasterBarrier = Promise.all([this.#disposeRasterBarrier, cleanupBarrier]).then(() => undefined);
|
|
406
|
+
this.#animation?.unregister();
|
|
407
|
+
this.#animation = undefined;
|
|
408
|
+
this.#releaseOverlayEmitter();
|
|
409
|
+
this.#mode = "off";
|
|
410
|
+
this.#pixel = undefined;
|
|
411
|
+
this.#activeBurst = undefined;
|
|
412
|
+
this.#workTransition = undefined;
|
|
413
|
+
this.#nextWorkBurstAt = 0;
|
|
414
|
+
if (canMutateSharedUi) {
|
|
309
415
|
this.#floorContainer.clear();
|
|
310
416
|
this.#framedEditor.setReserve(0);
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
417
|
+
if (this.#editorContainer.children.includes(this.#framedEditor)) this.#mountEditor(false);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
async disposeAsync(): Promise<void> {
|
|
422
|
+
if (!this.#disposePromise) {
|
|
423
|
+
this.dispose();
|
|
424
|
+
if (!this.#disposeNeedsLifecycle) return;
|
|
425
|
+
this.#disposePromise = this.#disposeRasterBarrier
|
|
426
|
+
.then(() =>
|
|
427
|
+
this.#ui.notifyTerminalLifecycle({
|
|
428
|
+
kind: "explicit-cleanup",
|
|
429
|
+
source: "interactive-mode",
|
|
430
|
+
terminalGeneration: this.#ui.terminalGeneration,
|
|
431
|
+
}),
|
|
432
|
+
)
|
|
433
|
+
.then(() => undefined);
|
|
316
434
|
}
|
|
435
|
+
await this.#disposePromise;
|
|
317
436
|
}
|
|
318
437
|
|
|
319
|
-
/** Clear the shared post-render slot only while this widget still owns it. */
|
|
320
438
|
#releaseOverlayEmitter(): void {
|
|
321
439
|
if (petOverlayEmitterOwners.get(this.#ui) === this) {
|
|
322
440
|
this.#ui.setPostRenderEmitter(undefined);
|
|
@@ -329,36 +447,286 @@ export class GajaePetWidget {
|
|
|
329
447
|
this.#editorContainer.addChild(framed ? this.#framedEditor : this.#editor);
|
|
330
448
|
}
|
|
331
449
|
|
|
332
|
-
/** Re-mount the composer editor (framed when a skin is active) after an overlay. */
|
|
333
450
|
remountComposer(): void {
|
|
334
|
-
|
|
451
|
+
// The composer container is shared with overlays (palette, selectors). A
|
|
452
|
+
// registered overlay owner or this widget may remount it; when no owner is
|
|
453
|
+
// registered the pet was never mounted, and remounting the plain editor is
|
|
454
|
+
// the same no-overlay restore the host would perform itself.
|
|
455
|
+
const owner = petOverlayEmitterOwners.get(this.#ui);
|
|
456
|
+
if (owner === undefined || owner === this) this.#mountEditor(this.#mode !== "off");
|
|
335
457
|
}
|
|
336
458
|
|
|
337
|
-
#
|
|
459
|
+
#syncWorkingState(now: number): PetSkinId | undefined {
|
|
460
|
+
if (this.#mode === "off") return undefined;
|
|
461
|
+
const skin = PET_SKINS[this.#mode];
|
|
462
|
+
const working = this.#isWorking();
|
|
463
|
+
if (working !== this.#working) {
|
|
464
|
+
this.#working = working;
|
|
465
|
+
this.#flexUntil = 0;
|
|
466
|
+
this.#activeBurst = undefined;
|
|
467
|
+
this.#nextWorkBurstAt = 0;
|
|
468
|
+
const steps = working ? skin.workEnter : skin.workExit;
|
|
469
|
+
this.#workTransition = steps?.length ? { startedAt: now, steps } : undefined;
|
|
470
|
+
}
|
|
471
|
+
return this.#mode;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
#pickFrame(now: number): PetFrameName {
|
|
338
475
|
const mode = this.#mode;
|
|
339
476
|
if (mode === "off") return "base";
|
|
340
|
-
|
|
341
|
-
|
|
477
|
+
const skin = PET_SKINS[mode];
|
|
478
|
+
this.#syncWorkingState(now);
|
|
479
|
+
if (this.#workTransition) {
|
|
480
|
+
const elapsed = now - this.#workTransition.startedAt;
|
|
481
|
+
const duration = animationDuration(this.#workTransition.steps);
|
|
482
|
+
if (elapsed < duration) return animationFrameAtElapsed(this.#workTransition.steps, elapsed, skin.baseFrame);
|
|
483
|
+
this.#workTransition = undefined;
|
|
484
|
+
}
|
|
342
485
|
if (now < this.#flexUntil) {
|
|
343
|
-
const burst =
|
|
486
|
+
const burst = this.#activeBurst ?? skin.burst;
|
|
344
487
|
const elapsed = now - (this.#flexUntil - petBurstDurationMs(burst));
|
|
345
488
|
return petBurstFrame(burst, elapsed, now);
|
|
346
489
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
490
|
+
return this.#isWorking()
|
|
491
|
+
? animationFrameAt(skin.work, now, skin.baseFrame)
|
|
492
|
+
: animationFrameAt(skin.idle, now, skin.baseFrame);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
#itermTimeline(now: number, working: boolean, flexing: boolean): GajaeGifTimeline {
|
|
496
|
+
if (this.#mode === "off") return gifTimeline([]);
|
|
497
|
+
this.#syncWorkingState(now);
|
|
498
|
+
const skin = PET_SKINS[this.#mode];
|
|
499
|
+
if (flexing) return burstGifTimeline(this.#activeBurst ?? skin.burst);
|
|
500
|
+
if (this.#workTransition) {
|
|
501
|
+
const elapsed = now - this.#workTransition.startedAt;
|
|
502
|
+
if (elapsed < animationDuration(this.#workTransition.steps)) return gifTimeline(this.#workTransition.steps);
|
|
503
|
+
this.#workTransition = undefined;
|
|
504
|
+
}
|
|
505
|
+
return gifTimeline(working ? skin.work : skin.idle);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
#tickIterm(now: number): void {
|
|
509
|
+
if (!this.#ui.isRunning || !this.#isActiveOwner() || this.#ui.manualViewportActive) return;
|
|
510
|
+
const cell = getCellDimensions();
|
|
511
|
+
const pixelColumns = Math.max(1, Math.ceil((PET_ART_ROWS * cell.heightPx) / cell.widthPx));
|
|
512
|
+
const pixelRows = ITERM_CANVAS_ROWS;
|
|
513
|
+
let metricsChanged = false;
|
|
514
|
+
if (cell.widthPx !== this.#builtCellW || cell.heightPx !== this.#builtCellH) {
|
|
515
|
+
metricsChanged = true;
|
|
516
|
+
this.#itermGeneration++;
|
|
517
|
+
const lease = this.#itermLease;
|
|
518
|
+
this.#itermLease = undefined;
|
|
519
|
+
if (lease) void this.#ui.invalidateRasterLease({ token: lease, cause: "resize" });
|
|
520
|
+
this.#itermLastSemantic = "";
|
|
521
|
+
this.#builtCellW = cell.widthPx;
|
|
522
|
+
this.#builtCellH = cell.heightPx;
|
|
523
|
+
this.#framedEditor.setReserve(pixelColumns + PET_SIDE_MARGIN);
|
|
524
|
+
this.#ui.requestRender(true);
|
|
525
|
+
}
|
|
526
|
+
if (!this.#framedEditor.canFit(this.#ui.terminal.columns)) {
|
|
527
|
+
if (!metricsChanged) {
|
|
528
|
+
this.#itermGeneration++;
|
|
529
|
+
const lease = this.#itermLease;
|
|
530
|
+
this.#itermLease = undefined;
|
|
531
|
+
if (lease) void this.#ui.invalidateRasterLease({ token: lease, cause: "resize" });
|
|
353
532
|
}
|
|
354
|
-
|
|
533
|
+
this.#itermLastSemantic = "";
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
const terminalRows = this.#ui.terminal.rows;
|
|
537
|
+
if (terminalRows < ITERM_CANVAS_ROWS + PET_RAISE_ROWS) {
|
|
538
|
+
if (!metricsChanged) {
|
|
539
|
+
this.#itermGeneration++;
|
|
540
|
+
const lease = this.#itermLease;
|
|
541
|
+
this.#itermLease = undefined;
|
|
542
|
+
if (lease) void this.#ui.invalidateRasterLease({ token: lease, cause: "resize" });
|
|
543
|
+
}
|
|
544
|
+
this.#itermLastSemantic = "";
|
|
545
|
+
return;
|
|
355
546
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
547
|
+
const composerBottom = terminalRows - this.#getComposerBottomOffset();
|
|
548
|
+
const desiredRow = composerBottom - pixelRows;
|
|
549
|
+
const maxSafeRow =
|
|
550
|
+
terminalRows === ITERM_CANVAS_ROWS + PET_RAISE_ROWS
|
|
551
|
+
? terminalRows - pixelRows - PET_RAISE_ROWS
|
|
552
|
+
: terminalRows - pixelRows;
|
|
553
|
+
const rect: CellRect = {
|
|
554
|
+
column: Math.max(0, this.#ui.terminal.columns - pixelColumns - PET_SIDE_MARGIN),
|
|
555
|
+
row: Math.max(0, Math.min(desiredRow, maxSafeRow)),
|
|
556
|
+
width: pixelColumns,
|
|
557
|
+
height: pixelRows,
|
|
558
|
+
};
|
|
559
|
+
const availability = getVerifiedItermPetAvailability();
|
|
560
|
+
if (!availability?.available || getItermPetUnavailableReason() || !this.#ui.terminalAvailable) return;
|
|
561
|
+
this.#syncWorkingState(now);
|
|
562
|
+
const working = this.#isWorking();
|
|
563
|
+
const flexing = this.#flexUntil > now;
|
|
564
|
+
const frames = this.#itermTimeline(now, working, flexing);
|
|
565
|
+
const semantic = `${this.#mode}:${availability.mode}:${availability.epoch}:${working}:${flexing}:${timelineSignature(frames)}:${rect.column},${rect.row}:${cell.widthPx},${cell.heightPx}:${this.#ui.terminal.columns},${this.#ui.terminal.rows}`;
|
|
566
|
+
if (this.#itermSubmitPending || (semantic === this.#itermLastSemantic && this.#itermLease)) return;
|
|
567
|
+
this.#itermLastSemantic = semantic;
|
|
568
|
+
this.#itermSubmitPending = true;
|
|
569
|
+
const generation = this.#itermGeneration;
|
|
570
|
+
void this.#submitIterm(
|
|
571
|
+
rect,
|
|
572
|
+
generation,
|
|
573
|
+
availability.epoch,
|
|
574
|
+
availability.mode,
|
|
575
|
+
semantic,
|
|
576
|
+
working,
|
|
577
|
+
flexing,
|
|
578
|
+
frames,
|
|
579
|
+
{
|
|
580
|
+
columns: this.#ui.terminal.columns,
|
|
581
|
+
rows: terminalRows,
|
|
582
|
+
cellWidthPx: cell.widthPx,
|
|
583
|
+
cellHeightPx: cell.heightPx,
|
|
584
|
+
},
|
|
585
|
+
this.#getComposerBottomOffset(),
|
|
586
|
+
).finally(() => {
|
|
587
|
+
this.#itermSubmitPending = false;
|
|
588
|
+
if (!this.#itermLease) this.#itermLastSemantic = "";
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
async #submitIterm(
|
|
593
|
+
rect: CellRect,
|
|
594
|
+
generation: number,
|
|
595
|
+
epoch: number,
|
|
596
|
+
mode: "direct" | "managed",
|
|
597
|
+
semantic: string,
|
|
598
|
+
working: boolean,
|
|
599
|
+
flexing: boolean,
|
|
600
|
+
frames: GajaeGifTimeline,
|
|
601
|
+
geometry: Readonly<{ columns: number; rows: number; cellWidthPx: number; cellHeightPx: number }>,
|
|
602
|
+
composerBottomOffset: number,
|
|
603
|
+
): Promise<void> {
|
|
604
|
+
const current = () => {
|
|
605
|
+
const availability = getVerifiedItermPetAvailability();
|
|
606
|
+
const flexingNow = this.#flexUntil > performance.now();
|
|
607
|
+
const terminal = this.#ui.terminal;
|
|
608
|
+
const cell = getCellDimensions();
|
|
609
|
+
const liveComposerBottomOffset = this.#getComposerBottomOffset();
|
|
610
|
+
const liveComposerBottom = terminal.rows - liveComposerBottomOffset;
|
|
611
|
+
const liveMaxSafeRow =
|
|
612
|
+
terminal.rows === ITERM_CANVAS_ROWS + PET_RAISE_ROWS
|
|
613
|
+
? terminal.rows - rect.height - PET_RAISE_ROWS
|
|
614
|
+
: terminal.rows - rect.height;
|
|
615
|
+
const expectedColumn = Math.max(0, terminal.columns - rect.width - PET_SIDE_MARGIN);
|
|
616
|
+
const expectedRow = Math.max(0, Math.min(liveComposerBottom - rect.height, liveMaxSafeRow));
|
|
617
|
+
return (
|
|
618
|
+
this.#ui.isRunning &&
|
|
619
|
+
this.#isActiveOwner() &&
|
|
620
|
+
generation === this.#itermGeneration &&
|
|
621
|
+
availability?.available === true &&
|
|
622
|
+
availability.epoch === epoch &&
|
|
623
|
+
availability.mode === mode &&
|
|
624
|
+
!this.#ui.manualViewportActive &&
|
|
625
|
+
this.#isWorking() === working &&
|
|
626
|
+
flexingNow === flexing &&
|
|
627
|
+
timelineSignature(this.#itermTimeline(performance.now(), this.#isWorking(), flexingNow)) ===
|
|
628
|
+
timelineSignature(frames) &&
|
|
629
|
+
this.#framedEditor.canFit(terminal.columns) &&
|
|
630
|
+
terminal.columns === geometry.columns &&
|
|
631
|
+
terminal.rows === geometry.rows &&
|
|
632
|
+
cell.widthPx === geometry.cellWidthPx &&
|
|
633
|
+
cell.heightPx === geometry.cellHeightPx &&
|
|
634
|
+
liveComposerBottomOffset === composerBottomOffset &&
|
|
635
|
+
rect.column === expectedColumn &&
|
|
636
|
+
rect.row === expectedRow &&
|
|
637
|
+
rect.column + rect.width <= terminal.columns &&
|
|
638
|
+
rect.row + rect.height <= terminal.rows
|
|
639
|
+
);
|
|
640
|
+
};
|
|
641
|
+
let token = this.#itermLease;
|
|
642
|
+
if (
|
|
643
|
+
token &&
|
|
644
|
+
(token.rect.column !== rect.column ||
|
|
645
|
+
token.rect.row !== rect.row ||
|
|
646
|
+
token.rect.width !== rect.width ||
|
|
647
|
+
token.rect.height !== rect.height)
|
|
648
|
+
) {
|
|
649
|
+
await this.#ui.invalidateRasterLease({ token, cause: "resize" });
|
|
650
|
+
if (this.#itermLease === token) this.#itermLease = undefined;
|
|
651
|
+
token = undefined;
|
|
652
|
+
}
|
|
653
|
+
if (!current()) return;
|
|
654
|
+
if (!token) {
|
|
655
|
+
const acquired = await this.#ui.acquireRasterLease({
|
|
656
|
+
ownerId: this.#itermOwner,
|
|
657
|
+
rect,
|
|
658
|
+
erase: {
|
|
659
|
+
type: "raster-erase",
|
|
660
|
+
bytes: new TextEncoder().encode(
|
|
661
|
+
`\x1b[0m${Array.from({ length: rect.height }, (_, row) => `\x1b[${rect.row + row + 1};${rect.column + 1}H\x1b[${rect.width}X`).join("")}`,
|
|
662
|
+
),
|
|
663
|
+
},
|
|
664
|
+
onInvalidated: notice => {
|
|
665
|
+
if (this.#itermLease === notice.token) {
|
|
666
|
+
this.#itermLease = undefined;
|
|
667
|
+
this.#itermLastSemantic = "";
|
|
668
|
+
}
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
if (!current() || acquired.status !== "acquired") {
|
|
672
|
+
if (acquired.status === "acquired")
|
|
673
|
+
await this.#ui.invalidateRasterLease({
|
|
674
|
+
token: acquired.token,
|
|
675
|
+
cause: this.#ui.manualViewportActive ? "manual-viewport" : "capability-loss",
|
|
676
|
+
});
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
token = acquired.token;
|
|
680
|
+
this.#itermLease = token;
|
|
681
|
+
}
|
|
682
|
+
this.#itermLastSemantic = semantic;
|
|
683
|
+
const cell = getCellDimensions();
|
|
684
|
+
const gif = getGajaePetGifCached({
|
|
685
|
+
skin: this.#mode === "off" ? "red" : this.#mode,
|
|
686
|
+
timeline: frames,
|
|
687
|
+
targetRows: PET_ART_ROWS,
|
|
688
|
+
rectangle: { width: rect.width * cell.widthPx, height: rect.height * cell.heightPx },
|
|
689
|
+
contentInset: { topPx: Math.floor(cell.heightPx / 2), bottomPx: Math.ceil(cell.heightPx / 2) },
|
|
690
|
+
displaySize: { width: rect.width, height: rect.height },
|
|
691
|
+
});
|
|
692
|
+
const cursorPosition = `\x1b[${rect.row + 1};${rect.column + 1}H`;
|
|
693
|
+
const cursorRestore =
|
|
694
|
+
mode === "managed" ? `${wrapITerm2RecordForTmux("\x1b8\x1b[?2026l")}\x1b8` : "\x1b8\x1b[?2026l";
|
|
695
|
+
const encodedRecords = (mode === "managed" ? gif.tmuxDcs : gif.multipart).map(record =>
|
|
696
|
+
new TextEncoder().encode(record),
|
|
697
|
+
);
|
|
698
|
+
const submit = await this.#ui.submitTerminalOutput({
|
|
699
|
+
token,
|
|
700
|
+
operation: {
|
|
701
|
+
type: "raster-multipart-batch",
|
|
702
|
+
prefix: new TextEncoder().encode(
|
|
703
|
+
mode === "managed"
|
|
704
|
+
? `${wrapITerm2RecordForTmux("\x1b[?2026h\x1b7\x1b[?25l")}\x1b7${cursorPosition}`
|
|
705
|
+
: `\x1b[?2026h\x1b7\x1b[?25l${cursorPosition}`,
|
|
706
|
+
),
|
|
707
|
+
afterPrefix:
|
|
708
|
+
mode === "managed"
|
|
709
|
+
? async () => (current() ? await this.#syncManagedItermCursor(rect.row, rect.column) : false)
|
|
710
|
+
: undefined,
|
|
711
|
+
replayPrefix: mode === "managed" ? new TextEncoder().encode(cursorPosition) : undefined,
|
|
712
|
+
records: encodedRecords,
|
|
713
|
+
suffix: new TextEncoder().encode(cursorRestore),
|
|
714
|
+
abortSuffix: mode === "managed" ? new TextEncoder().encode(cursorRestore) : undefined,
|
|
715
|
+
restoreCursorVisibility: true,
|
|
716
|
+
shouldWrite: current,
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
if (!current() || submit.status !== "written") {
|
|
720
|
+
await this.#ui.invalidateRasterLease({ token, cause: "capability-loss" });
|
|
721
|
+
if (this.#itermLease === token) this.#itermLease = undefined;
|
|
360
722
|
}
|
|
361
|
-
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
#scheduleWorkBurst(now: number): void {
|
|
726
|
+
this.#nextWorkBurstAt =
|
|
727
|
+
now +
|
|
728
|
+
OUROBOROS_WORK_BURST_MIN_GAP_MS +
|
|
729
|
+
Math.random() * (OUROBOROS_WORK_BURST_MAX_GAP_MS - OUROBOROS_WORK_BURST_MIN_GAP_MS);
|
|
362
730
|
}
|
|
363
731
|
|
|
364
732
|
#scheduleAutoFlex(now: number): void {
|
|
@@ -368,9 +736,52 @@ export class GajaePetWidget {
|
|
|
368
736
|
}
|
|
369
737
|
|
|
370
738
|
#tick(now: number): void {
|
|
739
|
+
if (!this.#isActiveOwner()) return;
|
|
740
|
+
const skin = this.#mode === "off" ? undefined : PET_SKINS[this.#mode];
|
|
741
|
+
this.#syncWorkingState(now);
|
|
742
|
+
const working = this.#isWorking();
|
|
743
|
+
if (!working) {
|
|
744
|
+
this.#nextAutoFlexAt = 0;
|
|
745
|
+
if (this.#flexSource === "working") {
|
|
746
|
+
this.#flexUntil = 0;
|
|
747
|
+
this.#flexSource = undefined;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if (now >= this.#flexUntil) {
|
|
751
|
+
this.#flexUntil = 0;
|
|
752
|
+
this.#flexSource = undefined;
|
|
753
|
+
if (this.#previewFlexAt !== 0 && now >= this.#previewFlexAt && skin) {
|
|
754
|
+
this.#activeBurst = skin.burst;
|
|
755
|
+
this.#flexUntil = now + petBurstDurationMs(skin.burst);
|
|
756
|
+
this.#flexSource = "preview";
|
|
757
|
+
this.#previewFlexAt = 0;
|
|
758
|
+
} else if (this.#autoFlexGapMs && working && skin && !skin.workBursts?.length) {
|
|
759
|
+
if (this.#nextAutoFlexAt === 0) this.#scheduleAutoFlex(now);
|
|
760
|
+
else if (now >= this.#nextAutoFlexAt) {
|
|
761
|
+
this.#activeBurst = skin.burst;
|
|
762
|
+
const burstMs = petBurstDurationMs(skin.burst);
|
|
763
|
+
this.#flexUntil = now + burstMs;
|
|
764
|
+
this.#flexSource = "working";
|
|
765
|
+
this.#scheduleAutoFlex(now + burstMs);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
if (working && skin?.workBursts?.length && !this.#workTransition && now >= this.#flexUntil) {
|
|
770
|
+
if (this.#nextWorkBurstAt === 0) this.#scheduleWorkBurst(now);
|
|
771
|
+
else if (now >= this.#nextWorkBurstAt) {
|
|
772
|
+
const burst = skin.workBursts[this.#workBurstIndex % skin.workBursts.length];
|
|
773
|
+
this.#workBurstIndex++;
|
|
774
|
+
this.#activeBurst = burst;
|
|
775
|
+
this.#flexUntil = now + petBurstDurationMs(burst);
|
|
776
|
+
this.#flexSource = "working";
|
|
777
|
+
this.#scheduleWorkBurst(this.#flexUntil);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
if (this.#itermProtocol) {
|
|
781
|
+
this.#tickIterm(now);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
371
784
|
if (this.#mode === "off" || !this.#pixel) return;
|
|
372
|
-
// A font/zoom change resizes the terminal cells; rebuild the frames so the
|
|
373
|
-
// kitty image and its sub-cell drop match the new cell metrics.
|
|
374
785
|
const cell = getCellDimensions();
|
|
375
786
|
if (cell.widthPx !== this.#builtCellW || cell.heightPx !== this.#builtCellH) {
|
|
376
787
|
const protocol = this.#forcedProtocol ?? GajaePetWidget.pixelProtocol();
|
|
@@ -380,25 +791,37 @@ export class GajaePetWidget {
|
|
|
380
791
|
this.#ui.requestRender(true);
|
|
381
792
|
}
|
|
382
793
|
}
|
|
383
|
-
// Random show-off, both while idle and while working. Each skin's burst runs for
|
|
384
|
-
// its own length (RedGajae a brief flex; BlueGajae a para-para cycle plus sob).
|
|
385
|
-
if (this.#autoFlexGapMs && now >= this.#flexUntil) {
|
|
386
|
-
if (this.#nextAutoFlexAt === 0) {
|
|
387
|
-
this.#scheduleAutoFlex(now);
|
|
388
|
-
} else if (now >= this.#nextAutoFlexAt) {
|
|
389
|
-
const burstMs = petBurstDurationMs(PET_SKINS[this.#mode].burst);
|
|
390
|
-
this.#flexUntil = now + burstMs;
|
|
391
|
-
this.#scheduleAutoFlex(now + burstMs);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
794
|
const frame = this.#pickFrame(now);
|
|
395
795
|
if (frame === this.#frame) return;
|
|
396
796
|
this.#frame = frame;
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
const
|
|
400
|
-
|
|
401
|
-
|
|
797
|
+
const pixel = this.#pixel;
|
|
798
|
+
const mode = this.#mode;
|
|
799
|
+
const position = this.#petPosition();
|
|
800
|
+
const terminalColumns = this.#ui.terminal.columns;
|
|
801
|
+
const terminalRows = this.#ui.terminal.rows;
|
|
802
|
+
const queuedCell = getCellDimensions();
|
|
803
|
+
const emission = this.#overlayEmission(true);
|
|
804
|
+
if (emission && pixel && this.#ui.terminalAvailable) {
|
|
805
|
+
void this.#ui.queueTerminalOutput(`\x1b[?2026h\x1b7${emission.payload}\x1b8\x1b[?2026l`, {
|
|
806
|
+
shouldWrite: () => {
|
|
807
|
+
const currentPosition = this.#petPosition();
|
|
808
|
+
const currentCell = getCellDimensions();
|
|
809
|
+
return (
|
|
810
|
+
this.#isActiveOwner() &&
|
|
811
|
+
this.#mode === mode &&
|
|
812
|
+
this.#pixel === pixel &&
|
|
813
|
+
this.#frame === frame &&
|
|
814
|
+
this.#ui.terminal.columns === terminalColumns &&
|
|
815
|
+
this.#ui.terminal.rows === terminalRows &&
|
|
816
|
+
currentCell.widthPx === queuedCell.widthPx &&
|
|
817
|
+
currentCell.heightPx === queuedCell.heightPx &&
|
|
818
|
+
(position === null
|
|
819
|
+
? currentPosition === null
|
|
820
|
+
: currentPosition?.x === position.x && currentPosition.y === position.y)
|
|
821
|
+
);
|
|
822
|
+
},
|
|
823
|
+
onWritten: emission.onWritten,
|
|
824
|
+
});
|
|
402
825
|
}
|
|
403
826
|
}
|
|
404
827
|
|
|
@@ -408,9 +831,6 @@ export class GajaePetWidget {
|
|
|
408
831
|
const columns = this.#ui.terminal.columns;
|
|
409
832
|
if (!this.#framedEditor.canFit(columns)) return null;
|
|
410
833
|
const rows = this.#ui.terminal.rows;
|
|
411
|
-
// The sprite is lifted one safety row above the scrolling edge, then dropped
|
|
412
|
-
// back onto the composer's bottom border per protocol (sixel via transparent
|
|
413
|
-
// top padding, kitty via a sub-cell Y offset baked into the frames).
|
|
414
834
|
const composerBottom = rows - this.#getComposerBottomOffset();
|
|
415
835
|
const y = composerBottom - pixel.rows - PET_RAISE_ROWS;
|
|
416
836
|
const x = columns - pixel.columns - PET_SIDE_MARGIN;
|
|
@@ -420,21 +840,16 @@ export class GajaePetWidget {
|
|
|
420
840
|
|
|
421
841
|
#clearSixelFootprint(footprint: SixelFootprint): string {
|
|
422
842
|
let out = "\x1b[0m";
|
|
423
|
-
for (let row = 0; row < footprint.rows; row++)
|
|
843
|
+
for (let row = 0; row < footprint.rows; row++)
|
|
424
844
|
out += `\x1b[${footprint.y + row + 1};${footprint.x + 1}H\x1b[${footprint.columns}X`;
|
|
425
|
-
}
|
|
426
845
|
return out;
|
|
427
846
|
}
|
|
428
847
|
|
|
429
|
-
/** Pending on-screen image cleanup. Pure: authority is consumed separately, on delivery. */
|
|
430
848
|
#imageCleanupPayload(): string {
|
|
431
849
|
let out = "";
|
|
432
|
-
if (this.#kittyCleanupPending && this.#kittyImageId !== undefined)
|
|
850
|
+
if (this.#kittyCleanupPending && this.#kittyImageId !== undefined)
|
|
433
851
|
out += `\x1b_Ga=d,d=I,i=${this.#kittyImageId},q=2\x1b\\`;
|
|
434
|
-
|
|
435
|
-
if (this.#lastSixelFootprint) {
|
|
436
|
-
out += this.#clearSixelFootprint(this.#lastSixelFootprint);
|
|
437
|
-
}
|
|
852
|
+
if (this.#lastSixelFootprint) out += this.#clearSixelFootprint(this.#lastSixelFootprint);
|
|
438
853
|
return out;
|
|
439
854
|
}
|
|
440
855
|
|
|
@@ -443,67 +858,66 @@ export class GajaePetWidget {
|
|
|
443
858
|
this.#lastSixelFootprint = undefined;
|
|
444
859
|
}
|
|
445
860
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
if (!this.#ui.terminalAvailable) return;
|
|
454
|
-
const payload = this.#imageCleanupPayload();
|
|
455
|
-
if (!payload) return;
|
|
456
|
-
try {
|
|
457
|
-
this.#ui.terminal.write(`\x1b[?2026h\x1b7${payload}\x1b8\x1b[?2026l`);
|
|
458
|
-
} catch {
|
|
459
|
-
// Keep the footprint/placement authority; the terminal write layer
|
|
460
|
-
// reports availability separately and callers retry on the next
|
|
461
|
-
// lifecycle transition.
|
|
462
|
-
return;
|
|
861
|
+
#queueImageCleanup(releaseKittyImage = false, includeSixel = true): Promise<void> {
|
|
862
|
+
const sixelFootprint = includeSixel ? this.#lastSixelFootprint : undefined;
|
|
863
|
+
const kittyImageId = this.#kittyCleanupPending ? this.#kittyImageId : undefined;
|
|
864
|
+
const deliveredKittyImageId = releaseKittyImage && kittyImageId === undefined ? this.#kittyImageId : undefined;
|
|
865
|
+
if (deliveredKittyImageId !== undefined) {
|
|
866
|
+
this.#kittyImageId = undefined;
|
|
867
|
+
allocatedPetKittyImageIds.delete(deliveredKittyImageId);
|
|
463
868
|
}
|
|
464
|
-
|
|
869
|
+
let payload = "";
|
|
870
|
+
if (kittyImageId !== undefined) payload += `\x1b_Ga=d,d=I,i=${kittyImageId},q=2\x1b\\`;
|
|
871
|
+
if (sixelFootprint) payload += this.#clearSixelFootprint(sixelFootprint);
|
|
872
|
+
if (!payload) return Promise.resolve();
|
|
873
|
+
const kittyCleanupGeneration = kittyImageId === undefined ? undefined : ++this.#kittyCleanupGeneration;
|
|
874
|
+
if (releaseKittyImage && kittyImageId !== undefined && this.#kittyImageId === kittyImageId)
|
|
875
|
+
this.#kittyImageId = undefined;
|
|
876
|
+
return this.#ui.queueTerminalCleanup(`\x1b[?2026h\x1b7${payload}\x1b8\x1b[?2026l`, () => {
|
|
877
|
+
if (sixelFootprint && this.#lastSixelFootprint && sameFootprint(this.#lastSixelFootprint, sixelFootprint))
|
|
878
|
+
this.#lastSixelFootprint = undefined;
|
|
879
|
+
if (
|
|
880
|
+
kittyImageId !== undefined &&
|
|
881
|
+
kittyCleanupGeneration === this.#kittyCleanupGeneration &&
|
|
882
|
+
(this.#kittyImageId === kittyImageId || this.#kittyImageId === undefined)
|
|
883
|
+
)
|
|
884
|
+
this.#kittyCleanupPending = false;
|
|
885
|
+
if (kittyImageId !== undefined && releaseKittyImage) allocatedPetKittyImageIds.delete(kittyImageId);
|
|
886
|
+
});
|
|
465
887
|
}
|
|
466
888
|
|
|
467
|
-
|
|
468
|
-
|
|
889
|
+
#overlayEmission(clearPet = false): PetOverlayEmission | null {
|
|
890
|
+
if (!this.#isActiveOwner()) return null;
|
|
469
891
|
const pixel = this.#pixel;
|
|
470
892
|
if (!pixel) return null;
|
|
471
893
|
const pos = this.#petPosition();
|
|
472
894
|
if (!pos) {
|
|
473
|
-
// Deferred delivery acknowledgement: the TUI writes the frame after
|
|
474
|
-
// this emitter returns, and that write can fail. Consume the cleanup
|
|
475
|
-
// authority only once a later pass observes the terminal survived
|
|
476
|
-
// the frame that carried the payload; otherwise retain it so a later
|
|
477
|
-
// lifecycle cleanup retries the erase/delete.
|
|
478
|
-
if (this.#frameCleanupAwaitingAck && this.#ui.terminalAvailable) {
|
|
479
|
-
this.#consumeCleanupAuthority();
|
|
480
|
-
}
|
|
481
|
-
this.#frameCleanupAwaitingAck = false;
|
|
482
|
-
if (!this.#ui.terminalAvailable) return null;
|
|
483
895
|
const cleanup = this.#imageCleanupPayload();
|
|
484
896
|
if (!cleanup) return null;
|
|
485
|
-
|
|
486
|
-
|
|
897
|
+
return {
|
|
898
|
+
payload: cleanup,
|
|
899
|
+
onWritten: () => {
|
|
900
|
+
if (this.#isActiveOwner()) this.#consumeCleanupAuthority();
|
|
901
|
+
},
|
|
902
|
+
};
|
|
487
903
|
}
|
|
488
|
-
// A full frame supersedes any cleanup-only frame still awaiting ack.
|
|
489
|
-
this.#frameCleanupAwaitingAck = false;
|
|
490
904
|
const { x, y } = pos;
|
|
491
905
|
let out = "";
|
|
492
|
-
|
|
906
|
+
let onWritten: (() => void) | undefined;
|
|
493
907
|
if (pixel.protocol === "sixel") {
|
|
494
908
|
const footprint = { x, y, columns: pixel.columns, rows: pixel.rasterRows };
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
}
|
|
909
|
+
const previous = this.#lastSixelFootprint;
|
|
910
|
+
if (previous && !sameFootprint(previous, footprint)) out += this.#clearSixelFootprint(previous);
|
|
498
911
|
if (clearPet) out += this.#clearSixelFootprint(footprint);
|
|
499
|
-
|
|
912
|
+
onWritten = () => {
|
|
913
|
+
if (this.#isActiveOwner()) this.#lastSixelFootprint = footprint;
|
|
914
|
+
};
|
|
500
915
|
} else {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
916
|
+
onWritten = () => {
|
|
917
|
+
if (this.#isActiveOwner()) this.#kittyCleanupPending = true;
|
|
918
|
+
};
|
|
504
919
|
}
|
|
505
|
-
|
|
506
920
|
out += `\x1b[${y + 1};${x + 1}H${pixel.frames[this.#frame]}`;
|
|
507
|
-
return out;
|
|
921
|
+
return { payload: out, onWritten };
|
|
508
922
|
}
|
|
509
923
|
}
|