@gajae-code/coding-agent 0.13.3 → 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 +184 -2
- 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 +9 -1
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +70 -6
- 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 +1 -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/gajae-pet-widget.d.ts +8 -30
- 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 +11 -25
- 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/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 +40 -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 +9 -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 +20 -1
- package/src/config/model-profiles.ts +29 -19
- package/src/config/model-registry.ts +132 -21
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +76 -6
- 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/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 +40 -32
- package/src/main.ts +32 -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/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/gajae-pet-widget.ts +539 -213
- package/src/modes/components/irc-sidebar.ts +11 -0
- package/src/modes/components/iterm-pet-transport.ts +585 -0
- package/src/modes/components/oauth-selector.ts +277 -86
- package/src/modes/components/pet-capability.ts +39 -40
- package/src/modes/components/settings-selector.ts +9 -0
- package/src/modes/components/status-line/gh.ts +45 -1
- package/src/modes/components/status-line/segments.ts +16 -1
- 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 +177 -72
- 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/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 +2857 -582
- 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 +173 -12
- package/src/session/messages.ts +1 -1
- package/src/session/secure-token-file.ts +80 -0
- package/src/session/session-manager.ts +730 -58
- 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 +98 -16
- 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 +27 -16
- 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/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,10 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type AnimationRegistration,
|
|
3
3
|
buildGajaePixelFrames,
|
|
4
|
+
type CellRect,
|
|
4
5
|
type Component,
|
|
5
6
|
type Container,
|
|
7
|
+
type GajaeGifFrame,
|
|
8
|
+
type GajaeGifTimeline,
|
|
6
9
|
type GajaePixelFrames,
|
|
7
10
|
getCellDimensions,
|
|
11
|
+
getGajaePetGifCached,
|
|
8
12
|
PET_SKINS,
|
|
9
13
|
type PetBurst,
|
|
10
14
|
type PetFrameName,
|
|
@@ -12,12 +16,13 @@ import {
|
|
|
12
16
|
type PetSkinId,
|
|
13
17
|
petBurstDurationMs,
|
|
14
18
|
petBurstFrame,
|
|
19
|
+
type RasterLeaseToken,
|
|
15
20
|
registerAnimationCallback,
|
|
16
|
-
resolvePetMode,
|
|
17
21
|
type TUI,
|
|
22
|
+
wrapITerm2RecordForTmux,
|
|
18
23
|
} from "@gajae-code/tui";
|
|
19
24
|
import type { CustomEditor } from "./custom-editor";
|
|
20
|
-
import { getPetPixelProtocol } from "./pet-capability";
|
|
25
|
+
import { getItermPetUnavailableReason, getPetPixelProtocol, getVerifiedItermPetAvailability } from "./pet-capability";
|
|
21
26
|
|
|
22
27
|
/** Re-exported from the tui skin registry so widget-relative imports stay valid. */
|
|
23
28
|
export type { PetMode, PetSkinId };
|
|
@@ -38,6 +43,8 @@ const KITTY_DROP_FRACTION = 0.45;
|
|
|
38
43
|
const petKittyDropPx = (cellHeightPx: number): number =>
|
|
39
44
|
Math.min(Math.max(0, cellHeightPx - 1), Math.floor(cellHeightPx * KITTY_DROP_FRACTION));
|
|
40
45
|
const PET_RAISE_ROWS = 1;
|
|
46
|
+
const PET_ART_ROWS = 2;
|
|
47
|
+
const ITERM_CANVAS_ROWS = PET_ART_ROWS + 1;
|
|
41
48
|
const allocatedPetKittyImageIds = new Set<number>();
|
|
42
49
|
|
|
43
50
|
function allocatePetKittyImageId(): number {
|
|
@@ -60,17 +67,22 @@ function sameFootprint(left: SixelFootprint, right: SixelFootprint): boolean {
|
|
|
60
67
|
return left.x === right.x && left.y === right.y && left.columns === right.columns && left.rows === right.rows;
|
|
61
68
|
}
|
|
62
69
|
|
|
70
|
+
type PetOverlayEmission = {
|
|
71
|
+
payload: string;
|
|
72
|
+
onWritten?: () => void;
|
|
73
|
+
};
|
|
74
|
+
|
|
63
75
|
/**
|
|
64
76
|
* Which widget currently owns each TUI's single shared post-render emitter
|
|
65
77
|
* slot. A stale or repeated dispose (or off-switch) of a predecessor widget
|
|
66
78
|
* must never clear a successor's overlay authority.
|
|
67
79
|
*/
|
|
68
80
|
const petOverlayEmitterOwners = new WeakMap<TUI, GajaePetWidget>();
|
|
81
|
+
const petOverlayOwnershipEpochs = new WeakMap<TUI, number>();
|
|
69
82
|
|
|
70
|
-
/** Random gap between automatic claw flexes
|
|
83
|
+
/** Random gap between automatic claw flexes while work is active. */
|
|
71
84
|
const AUTO_FLEX_MIN_GAP_MS = 12_000;
|
|
72
85
|
const AUTO_FLEX_MAX_GAP_MS = 40_000;
|
|
73
|
-
|
|
74
86
|
function animationFrameAt(
|
|
75
87
|
steps: ReadonlyArray<readonly [PetFrameName, number]>,
|
|
76
88
|
now: number,
|
|
@@ -102,6 +114,27 @@ function animationDuration(steps: ReadonlyArray<readonly [PetFrameName, number]>
|
|
|
102
114
|
return steps.reduce((sum, [, ms]) => sum + ms, 0);
|
|
103
115
|
}
|
|
104
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
|
+
|
|
105
138
|
interface WorkTransition {
|
|
106
139
|
startedAt: number;
|
|
107
140
|
steps: ReadonlyArray<readonly [PetFrameName, number]>;
|
|
@@ -110,18 +143,10 @@ interface WorkTransition {
|
|
|
110
143
|
const OUROBOROS_WORK_BURST_MIN_GAP_MS = 14_000;
|
|
111
144
|
const OUROBOROS_WORK_BURST_MAX_GAP_MS = 30_000;
|
|
112
145
|
|
|
113
|
-
/**
|
|
114
|
-
* Selector preview: fire the first burst this soon after a skin is previewed, so the
|
|
115
|
-
* pet shows one idle eye-roll (base -> gazeL -> base -> gazeR) and then its signature
|
|
116
|
-
* flex/cry. Live use keeps the random AUTO_FLEX gap; only preview forces this demo.
|
|
117
|
-
*/
|
|
146
|
+
/** Selector preview: fire the first burst this soon after a skin is previewed. */
|
|
118
147
|
const PREVIEW_INTRO_MS = 2300;
|
|
119
148
|
|
|
120
|
-
/**
|
|
121
|
-
* Wraps the composer editor, reserving a right-side area beside it where the
|
|
122
|
-
* real-pixel pet is drawn. The editor just renders narrower; the pet pixels
|
|
123
|
-
* are emitted separately as an absolute-positioned overlay.
|
|
124
|
-
*/
|
|
149
|
+
/** Reserve a right-side area beside the composer where the pixel pet is drawn. */
|
|
125
150
|
export class PetFramedEditor implements Component {
|
|
126
151
|
#editor: CustomEditor;
|
|
127
152
|
#reserve = 0;
|
|
@@ -143,27 +168,12 @@ export class PetFramedEditor implements Component {
|
|
|
143
168
|
}
|
|
144
169
|
|
|
145
170
|
render(width: number): string[] {
|
|
146
|
-
if (!this.canFit(width))
|
|
147
|
-
return this.#editor.render(width);
|
|
148
|
-
}
|
|
171
|
+
if (!this.canFit(width)) return this.#editor.render(width);
|
|
149
172
|
return this.#editor.render(width - this.#reserve);
|
|
150
173
|
}
|
|
151
174
|
}
|
|
152
175
|
|
|
153
|
-
/**
|
|
154
|
-
* The gajae pet: a real-pixel sprite living in a reserved area beside the
|
|
155
|
-
* composer. It is nearest-neighbor scaled to the two terminal rows occupied
|
|
156
|
-
* by an empty one-line composer and lifted one row so its feet meet the input
|
|
157
|
-
* box's bottom edge.
|
|
158
|
-
*
|
|
159
|
-
* Rendering has two paths that share one payload builder:
|
|
160
|
-
* - a post-render emitter re-draws the sprite after every TUI write (line
|
|
161
|
-
* renders clear the pet cells, so the overlay must be re-applied), and
|
|
162
|
-
* - frame advances write the payload directly to the terminal, because the
|
|
163
|
-
* TUI skips writes entirely when no component line changed.
|
|
164
|
-
*
|
|
165
|
-
* Requires a sixel- or kitty-graphics terminal (`pixelProtocol()`).
|
|
166
|
-
*/
|
|
176
|
+
/** The gajae pet pixel sprite and protocol-specific rendering lifecycle. */
|
|
167
177
|
export class GajaePetWidget {
|
|
168
178
|
#ui: TUI;
|
|
169
179
|
#editor: CustomEditor;
|
|
@@ -183,25 +193,28 @@ export class GajaePetWidget {
|
|
|
183
193
|
#workTransition: WorkTransition | undefined;
|
|
184
194
|
#nextWorkBurstAt = 0;
|
|
185
195
|
#workBurstIndex = 0;
|
|
196
|
+
#flexSource: "preview" | "working" | undefined;
|
|
197
|
+
#previewFlexAt = 0;
|
|
186
198
|
#autoFlexGapMs: [number, number] | null;
|
|
187
|
-
#forcedProtocol: "sixel" | "kitty" | "
|
|
188
|
-
/** Cell metrics the current frames were built for; a change triggers a rebuild. */
|
|
199
|
+
#forcedProtocol: "sixel" | "kitty" | "iterm" | undefined;
|
|
189
200
|
#builtCellW = 0;
|
|
190
201
|
#builtCellH = 0;
|
|
191
202
|
#kittyImageId: number | undefined;
|
|
192
|
-
/** True while a kitty placement may exist on screen; cleared only after the delete escape is delivered. */
|
|
193
203
|
#kittyCleanupPending = false;
|
|
194
|
-
|
|
204
|
+
#kittyCleanupGeneration = 0;
|
|
195
205
|
#lastSixelFootprint: SixelFootprint | undefined;
|
|
196
|
-
/** Terminal state: a disposed widget never touches the TUI or shared slots again. */
|
|
197
206
|
#disposed = false;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
#
|
|
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>;
|
|
205
218
|
|
|
206
219
|
constructor(options: {
|
|
207
220
|
ui: TUI;
|
|
@@ -209,10 +222,9 @@ export class GajaePetWidget {
|
|
|
209
222
|
editorContainer: Container;
|
|
210
223
|
floorContainer: Container;
|
|
211
224
|
isWorking: () => boolean;
|
|
212
|
-
/** Rows rendered below the composer box (pet floor + hook widgets). */
|
|
213
225
|
getComposerBottomOffset: () => number;
|
|
214
|
-
|
|
215
|
-
|
|
226
|
+
syncManagedItermCursor: (row: number, column: number) => Promise<boolean>;
|
|
227
|
+
forcePixelProtocol?: "sixel" | "kitty";
|
|
216
228
|
autoFlexGapMs?: [number, number] | null;
|
|
217
229
|
}) {
|
|
218
230
|
this.#ui = options.ui;
|
|
@@ -222,13 +234,13 @@ export class GajaePetWidget {
|
|
|
222
234
|
this.#framedEditor = new PetFramedEditor(options.editor);
|
|
223
235
|
this.#isWorking = options.isWorking;
|
|
224
236
|
this.#getComposerBottomOffset = options.getComposerBottomOffset;
|
|
237
|
+
this.#syncManagedItermCursor = options.syncManagedItermCursor;
|
|
225
238
|
this.#forcedProtocol = options.forcePixelProtocol;
|
|
226
239
|
this.#autoFlexGapMs =
|
|
227
240
|
options.autoFlexGapMs === undefined ? [AUTO_FLEX_MIN_GAP_MS, AUTO_FLEX_MAX_GAP_MS] : options.autoFlexGapMs;
|
|
228
241
|
}
|
|
229
242
|
|
|
230
|
-
|
|
231
|
-
static pixelProtocol(): "sixel" | "kitty" | "iterm2" | null {
|
|
243
|
+
static pixelProtocol(): "sixel" | "kitty" | "iterm" | null {
|
|
232
244
|
return getPetPixelProtocol();
|
|
233
245
|
}
|
|
234
246
|
|
|
@@ -240,19 +252,25 @@ export class GajaePetWidget {
|
|
|
240
252
|
return performance.now() < this.#flexUntil;
|
|
241
253
|
}
|
|
242
254
|
|
|
243
|
-
setMode(mode:
|
|
244
|
-
this.#applyMode(
|
|
255
|
+
setMode(mode: PetMode): void {
|
|
256
|
+
this.#applyMode(mode, true);
|
|
257
|
+
}
|
|
258
|
+
|
|
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);
|
|
245
267
|
}
|
|
246
268
|
|
|
247
|
-
/** Live preview during a selector: change the sprite without re-mounting the
|
|
248
|
-
* composer editor (that would tear down the open overlay). After a short idle
|
|
249
|
-
* eye-roll it fires the signature burst once (RedGajae flex, BlueGajae para-para
|
|
250
|
-
* then sob) so the selector demos the animation instead of waiting the random gap. */
|
|
251
269
|
previewMode(mode: PetMode): void {
|
|
270
|
+
if (this.#disposed) return;
|
|
252
271
|
this.#applyMode(mode, false);
|
|
253
|
-
if (mode
|
|
254
|
-
|
|
255
|
-
}
|
|
272
|
+
if (!this.#isActiveOwner() || mode === "off" || !this.#autoFlexGapMs) return;
|
|
273
|
+
this.#previewFlexAt = performance.now() + PREVIEW_INTRO_MS;
|
|
256
274
|
}
|
|
257
275
|
|
|
258
276
|
commitPreviewMode(mode: PetMode): void {
|
|
@@ -261,18 +279,25 @@ export class GajaePetWidget {
|
|
|
261
279
|
|
|
262
280
|
#applyMode(mode: PetMode, mountComposer: boolean): void {
|
|
263
281
|
if (this.#disposed || mode === this.#mode) return;
|
|
264
|
-
|
|
265
282
|
if (mode === "off") {
|
|
266
|
-
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);
|
|
267
292
|
this.#mode = "off";
|
|
268
293
|
this.#animation?.unregister();
|
|
269
294
|
this.#animation = undefined;
|
|
270
295
|
this.#releaseOverlayEmitter();
|
|
271
296
|
this.#floorContainer.clear();
|
|
272
297
|
this.#pixel = undefined;
|
|
298
|
+
this.#activeBurst = undefined;
|
|
273
299
|
this.#workTransition = undefined;
|
|
274
300
|
this.#nextWorkBurstAt = 0;
|
|
275
|
-
this.#activeBurst = undefined;
|
|
276
301
|
this.#framedEditor.setReserve(0);
|
|
277
302
|
if (mountComposer) this.#mountEditor(false);
|
|
278
303
|
this.#ui.requestRender(true);
|
|
@@ -280,94 +305,136 @@ export class GajaePetWidget {
|
|
|
280
305
|
}
|
|
281
306
|
|
|
282
307
|
const protocol = this.#forcedProtocol ?? GajaePetWidget.pixelProtocol();
|
|
283
|
-
|
|
284
|
-
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
|
+
}
|
|
285
322
|
this.#mode = mode;
|
|
286
323
|
this.#frame = PET_SKINS[mode].baseFrame;
|
|
287
324
|
this.#flexUntil = 0;
|
|
288
325
|
this.#activeBurst = undefined;
|
|
289
|
-
this.#
|
|
326
|
+
this.#flexSource = undefined;
|
|
290
327
|
this.#working = this.#isWorking();
|
|
291
328
|
this.#workTransition = undefined;
|
|
292
329
|
this.#nextWorkBurstAt = 0;
|
|
293
330
|
this.#workBurstIndex = 0;
|
|
331
|
+
this.#previewFlexAt = 0;
|
|
332
|
+
this.#nextAutoFlexAt = 0;
|
|
294
333
|
this.#buildPixel(protocol);
|
|
295
334
|
if (mountComposer) this.#mountEditor(true);
|
|
296
|
-
// The pet overlays the composer's bottom rows; no floor row is reserved, so
|
|
297
|
-
// the composer stays pinned to the terminal bottom.
|
|
298
335
|
this.#floorContainer.clear();
|
|
299
|
-
this.#ui.setPostRenderEmitter(() => this.#
|
|
336
|
+
this.#ui.setPostRenderEmitter(() => this.#overlayEmission());
|
|
337
|
+
this.#ownedOverlayEpoch = ownershipEpoch + 1;
|
|
338
|
+
petOverlayOwnershipEpochs.set(this.#ui, this.#ownedOverlayEpoch);
|
|
300
339
|
petOverlayEmitterOwners.set(this.#ui, this);
|
|
301
340
|
this.#animation ??= registerAnimationCallback(now => this.#tick(now), 80);
|
|
302
341
|
this.#ui.requestRender(true);
|
|
303
342
|
}
|
|
304
343
|
|
|
305
|
-
|
|
306
|
-
|
|
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 {
|
|
307
363
|
const cell = getCellDimensions();
|
|
308
364
|
this.#builtCellW = cell.widthPx;
|
|
309
365
|
this.#builtCellH = cell.heightPx;
|
|
310
366
|
const skin: PetSkinId = this.#mode === "off" ? "red" : this.#mode;
|
|
311
367
|
if (protocol === "kitty") {
|
|
312
368
|
this.#kittyImageId ??= allocatePetKittyImageId();
|
|
369
|
+
this.#kittyCleanupGeneration++;
|
|
313
370
|
this.#kittyCleanupPending = true;
|
|
314
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;
|
|
315
379
|
this.#pixel = buildGajaePixelFrames({
|
|
316
380
|
protocol,
|
|
317
381
|
skin,
|
|
318
382
|
cellWidthPx: cell.widthPx,
|
|
319
383
|
cellHeightPx: cell.heightPx,
|
|
320
|
-
// Encode iTerm2 at the same two-row pixel size as Kitty/Sixel. The
|
|
321
|
-
// iTerm2 protocol receives explicit pixel dimensions below, so it must
|
|
322
|
-
// not be reduced to a fractional cell canvas or it becomes undersized.
|
|
323
384
|
targetRows: 2,
|
|
324
385
|
sixelTopPaddingPx: protocol === "sixel" ? PET_SIXEL_DROP_PX : 0,
|
|
325
386
|
kittyCellYOffsetPx: protocol === "kitty" ? petKittyDropPx(cell.heightPx) : 0,
|
|
326
387
|
kittyImageId: protocol === "kitty" ? this.#kittyImageId : undefined,
|
|
327
|
-
// iTerm2 receives an explicit 1:1 pixel size; keep its raster inside the
|
|
328
|
-
// same two-row footprint reserved for Kitty and Sixel.
|
|
329
|
-
iterm2TopPaddingPx: 0,
|
|
330
|
-
iterm2BottomPaddingPx: 0,
|
|
331
388
|
});
|
|
332
389
|
this.#framedEditor.setReserve(this.#pixel.columns + PET_SIDE_MARGIN);
|
|
333
390
|
}
|
|
334
391
|
|
|
335
392
|
dispose(): void {
|
|
336
393
|
if (this.#disposed) return;
|
|
394
|
+
const canMutateSharedUi = this.#canMutateSharedUi();
|
|
395
|
+
this.#disposeNeedsLifecycle = canMutateSharedUi;
|
|
337
396
|
this.#disposed = true;
|
|
338
|
-
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
this.#pixel = undefined;
|
|
357
|
-
this.#workTransition = undefined;
|
|
358
|
-
this.#nextWorkBurstAt = 0;
|
|
359
|
-
this.#activeBurst = 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) {
|
|
360
415
|
this.#floorContainer.clear();
|
|
361
416
|
this.#framedEditor.setReserve(0);
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
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);
|
|
367
434
|
}
|
|
435
|
+
await this.#disposePromise;
|
|
368
436
|
}
|
|
369
437
|
|
|
370
|
-
/** Clear the shared post-render slot only while this widget still owns it. */
|
|
371
438
|
#releaseOverlayEmitter(): void {
|
|
372
439
|
if (petOverlayEmitterOwners.get(this.#ui) === this) {
|
|
373
440
|
this.#ui.setPostRenderEmitter(undefined);
|
|
@@ -380,15 +447,18 @@ export class GajaePetWidget {
|
|
|
380
447
|
this.#editorContainer.addChild(framed ? this.#framedEditor : this.#editor);
|
|
381
448
|
}
|
|
382
449
|
|
|
383
|
-
/** Re-mount the composer editor (framed when a skin is active) after an overlay. */
|
|
384
450
|
remountComposer(): void {
|
|
385
|
-
|
|
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");
|
|
386
457
|
}
|
|
387
458
|
|
|
388
|
-
#
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
const skin = PET_SKINS[mode];
|
|
459
|
+
#syncWorkingState(now: number): PetSkinId | undefined {
|
|
460
|
+
if (this.#mode === "off") return undefined;
|
|
461
|
+
const skin = PET_SKINS[this.#mode];
|
|
392
462
|
const working = this.#isWorking();
|
|
393
463
|
if (working !== this.#working) {
|
|
394
464
|
this.#working = working;
|
|
@@ -398,26 +468,258 @@ export class GajaePetWidget {
|
|
|
398
468
|
const steps = working ? skin.workEnter : skin.workExit;
|
|
399
469
|
this.#workTransition = steps?.length ? { startedAt: now, steps } : undefined;
|
|
400
470
|
}
|
|
471
|
+
return this.#mode;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
#pickFrame(now: number): PetFrameName {
|
|
475
|
+
const mode = this.#mode;
|
|
476
|
+
if (mode === "off") return "base";
|
|
477
|
+
const skin = PET_SKINS[mode];
|
|
478
|
+
this.#syncWorkingState(now);
|
|
401
479
|
if (this.#workTransition) {
|
|
402
480
|
const elapsed = now - this.#workTransition.startedAt;
|
|
403
481
|
const duration = animationDuration(this.#workTransition.steps);
|
|
404
|
-
if (elapsed < duration)
|
|
405
|
-
return animationFrameAtElapsed(this.#workTransition.steps, elapsed, skin.baseFrame);
|
|
406
|
-
}
|
|
482
|
+
if (elapsed < duration) return animationFrameAtElapsed(this.#workTransition.steps, elapsed, skin.baseFrame);
|
|
407
483
|
this.#workTransition = undefined;
|
|
408
484
|
}
|
|
409
|
-
// Random idle burst → the skin's own animation, driven by its burst descriptor
|
|
410
|
-
// (RedGajae holds a flex; BlueGajae dances the para-para then sobs).
|
|
411
485
|
if (now < this.#flexUntil) {
|
|
412
486
|
const burst = this.#activeBurst ?? skin.burst;
|
|
413
487
|
const elapsed = now - (this.#flexUntil - petBurstDurationMs(burst));
|
|
414
488
|
return petBurstFrame(burst, elapsed, now);
|
|
415
489
|
}
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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" });
|
|
532
|
+
}
|
|
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;
|
|
546
|
+
}
|
|
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;
|
|
419
722
|
}
|
|
420
|
-
return animationFrameAt(skin.idle, now, skin.baseFrame);
|
|
421
723
|
}
|
|
422
724
|
|
|
423
725
|
#scheduleWorkBurst(now: number): void {
|
|
@@ -434,51 +736,92 @@ export class GajaePetWidget {
|
|
|
434
736
|
}
|
|
435
737
|
|
|
436
738
|
#tick(now: number): void {
|
|
437
|
-
if (
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
const
|
|
441
|
-
if (
|
|
442
|
-
|
|
443
|
-
if (
|
|
444
|
-
this.#
|
|
445
|
-
this.#
|
|
446
|
-
this.#ui.requestRender(true);
|
|
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;
|
|
447
748
|
}
|
|
448
749
|
}
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
if (this.#autoFlexGapMs && !usesWorkBursts && now >= this.#flexUntil) {
|
|
454
|
-
if (this.#nextAutoFlexAt === 0) {
|
|
455
|
-
this.#scheduleAutoFlex(now);
|
|
456
|
-
} else if (now >= this.#nextAutoFlexAt) {
|
|
457
|
-
const burstMs = petBurstDurationMs(PET_SKINS[this.#mode].burst);
|
|
750
|
+
if (now >= this.#flexUntil) {
|
|
751
|
+
this.#flexUntil = 0;
|
|
752
|
+
this.#flexSource = undefined;
|
|
753
|
+
if (this.#previewFlexAt !== 0 && now >= this.#previewFlexAt && skin) {
|
|
458
754
|
this.#activeBurst = skin.burst;
|
|
459
|
-
this.#flexUntil = now +
|
|
460
|
-
this.#
|
|
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
|
+
}
|
|
461
767
|
}
|
|
462
768
|
}
|
|
463
|
-
if (
|
|
464
|
-
if (this.#nextWorkBurstAt === 0)
|
|
465
|
-
|
|
466
|
-
} else if (now >= this.#nextWorkBurstAt) {
|
|
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) {
|
|
467
772
|
const burst = skin.workBursts[this.#workBurstIndex % skin.workBursts.length];
|
|
468
773
|
this.#workBurstIndex++;
|
|
469
774
|
this.#activeBurst = burst;
|
|
470
775
|
this.#flexUntil = now + petBurstDurationMs(burst);
|
|
776
|
+
this.#flexSource = "working";
|
|
471
777
|
this.#scheduleWorkBurst(this.#flexUntil);
|
|
472
778
|
}
|
|
473
779
|
}
|
|
780
|
+
if (this.#itermProtocol) {
|
|
781
|
+
this.#tickIterm(now);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
if (this.#mode === "off" || !this.#pixel) return;
|
|
785
|
+
const cell = getCellDimensions();
|
|
786
|
+
if (cell.widthPx !== this.#builtCellW || cell.heightPx !== this.#builtCellH) {
|
|
787
|
+
const protocol = this.#forcedProtocol ?? GajaePetWidget.pixelProtocol();
|
|
788
|
+
if (protocol) {
|
|
789
|
+
this.#buildPixel(protocol);
|
|
790
|
+
this.#mountEditor(true);
|
|
791
|
+
this.#ui.requestRender(true);
|
|
792
|
+
}
|
|
793
|
+
}
|
|
474
794
|
const frame = this.#pickFrame(now);
|
|
475
795
|
if (frame === this.#frame) return;
|
|
476
796
|
this.#frame = frame;
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
const
|
|
480
|
-
|
|
481
|
-
|
|
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
|
+
});
|
|
482
825
|
}
|
|
483
826
|
}
|
|
484
827
|
|
|
@@ -488,19 +831,8 @@ export class GajaePetWidget {
|
|
|
488
831
|
const columns = this.#ui.terminal.columns;
|
|
489
832
|
if (!this.#framedEditor.canFit(columns)) return null;
|
|
490
833
|
const rows = this.#ui.terminal.rows;
|
|
491
|
-
// The sprite is lifted one safety row above the scrolling edge, then dropped
|
|
492
|
-
// back onto the composer's bottom border per protocol (sixel via transparent
|
|
493
|
-
// top padding, kitty via a sub-cell Y offset baked into the frames).
|
|
494
834
|
const composerBottom = rows - this.#getComposerBottomOffset();
|
|
495
|
-
|
|
496
|
-
// sprite inside the composer rows and leave the HUD boundary below it.
|
|
497
|
-
// Keep the full-size iTerm2 sprite aligned with the composer like the
|
|
498
|
-
// cursor-neutral Kitty/Sixel overlays; only the protocol encoding differs.
|
|
499
|
-
// Nudge the iTerm2 image one terminal row upward while preserving its
|
|
500
|
-
// explicit 36px size and aspect ratio. Kitty/Sixel keep their established
|
|
501
|
-
// safety lift.
|
|
502
|
-
const safetyLift = PET_RAISE_ROWS;
|
|
503
|
-
const y = composerBottom - pixel.rows - safetyLift;
|
|
835
|
+
const y = composerBottom - pixel.rows - PET_RAISE_ROWS;
|
|
504
836
|
const x = columns - pixel.columns - PET_SIDE_MARGIN;
|
|
505
837
|
if (y < 0 || x < 0) return null;
|
|
506
838
|
return { x, y };
|
|
@@ -508,21 +840,16 @@ export class GajaePetWidget {
|
|
|
508
840
|
|
|
509
841
|
#clearSixelFootprint(footprint: SixelFootprint): string {
|
|
510
842
|
let out = "\x1b[0m";
|
|
511
|
-
for (let row = 0; row < footprint.rows; row++)
|
|
843
|
+
for (let row = 0; row < footprint.rows; row++)
|
|
512
844
|
out += `\x1b[${footprint.y + row + 1};${footprint.x + 1}H\x1b[${footprint.columns}X`;
|
|
513
|
-
}
|
|
514
845
|
return out;
|
|
515
846
|
}
|
|
516
847
|
|
|
517
|
-
/** Pending on-screen image cleanup. Pure: authority is consumed separately, on delivery. */
|
|
518
848
|
#imageCleanupPayload(): string {
|
|
519
849
|
let out = "";
|
|
520
|
-
if (this.#kittyCleanupPending && this.#kittyImageId !== undefined)
|
|
850
|
+
if (this.#kittyCleanupPending && this.#kittyImageId !== undefined)
|
|
521
851
|
out += `\x1b_Ga=d,d=I,i=${this.#kittyImageId},q=2\x1b\\`;
|
|
522
|
-
|
|
523
|
-
if (this.#lastSixelFootprint) {
|
|
524
|
-
out += this.#clearSixelFootprint(this.#lastSixelFootprint);
|
|
525
|
-
}
|
|
852
|
+
if (this.#lastSixelFootprint) out += this.#clearSixelFootprint(this.#lastSixelFootprint);
|
|
526
853
|
return out;
|
|
527
854
|
}
|
|
528
855
|
|
|
@@ -531,67 +858,66 @@ export class GajaePetWidget {
|
|
|
531
858
|
this.#lastSixelFootprint = undefined;
|
|
532
859
|
}
|
|
533
860
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
if (!this.#ui.terminalAvailable) return;
|
|
542
|
-
const payload = this.#imageCleanupPayload();
|
|
543
|
-
if (!payload) return;
|
|
544
|
-
try {
|
|
545
|
-
this.#ui.terminal.write(`\x1b[?2026h\x1b7${payload}\x1b8\x1b[?2026l`);
|
|
546
|
-
} catch {
|
|
547
|
-
// Keep the footprint/placement authority; the terminal write layer
|
|
548
|
-
// reports availability separately and callers retry on the next
|
|
549
|
-
// lifecycle transition.
|
|
550
|
-
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);
|
|
551
868
|
}
|
|
552
|
-
|
|
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
|
+
});
|
|
553
887
|
}
|
|
554
888
|
|
|
555
|
-
|
|
556
|
-
|
|
889
|
+
#overlayEmission(clearPet = false): PetOverlayEmission | null {
|
|
890
|
+
if (!this.#isActiveOwner()) return null;
|
|
557
891
|
const pixel = this.#pixel;
|
|
558
892
|
if (!pixel) return null;
|
|
559
893
|
const pos = this.#petPosition();
|
|
560
894
|
if (!pos) {
|
|
561
|
-
// Deferred delivery acknowledgement: the TUI writes the frame after
|
|
562
|
-
// this emitter returns, and that write can fail. Consume the cleanup
|
|
563
|
-
// authority only once a later pass observes the terminal survived
|
|
564
|
-
// the frame that carried the payload; otherwise retain it so a later
|
|
565
|
-
// lifecycle cleanup retries the erase/delete.
|
|
566
|
-
if (this.#frameCleanupAwaitingAck && this.#ui.terminalAvailable) {
|
|
567
|
-
this.#consumeCleanupAuthority();
|
|
568
|
-
}
|
|
569
|
-
this.#frameCleanupAwaitingAck = false;
|
|
570
|
-
if (!this.#ui.terminalAvailable) return null;
|
|
571
895
|
const cleanup = this.#imageCleanupPayload();
|
|
572
896
|
if (!cleanup) return null;
|
|
573
|
-
|
|
574
|
-
|
|
897
|
+
return {
|
|
898
|
+
payload: cleanup,
|
|
899
|
+
onWritten: () => {
|
|
900
|
+
if (this.#isActiveOwner()) this.#consumeCleanupAuthority();
|
|
901
|
+
},
|
|
902
|
+
};
|
|
575
903
|
}
|
|
576
|
-
// A full frame supersedes any cleanup-only frame still awaiting ack.
|
|
577
|
-
this.#frameCleanupAwaitingAck = false;
|
|
578
904
|
const { x, y } = pos;
|
|
579
905
|
let out = "";
|
|
580
|
-
|
|
581
|
-
if (pixel.protocol === "sixel"
|
|
906
|
+
let onWritten: (() => void) | undefined;
|
|
907
|
+
if (pixel.protocol === "sixel") {
|
|
582
908
|
const footprint = { x, y, columns: pixel.columns, rows: pixel.rasterRows };
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
}
|
|
909
|
+
const previous = this.#lastSixelFootprint;
|
|
910
|
+
if (previous && !sameFootprint(previous, footprint)) out += this.#clearSixelFootprint(previous);
|
|
586
911
|
if (clearPet) out += this.#clearSixelFootprint(footprint);
|
|
587
|
-
|
|
912
|
+
onWritten = () => {
|
|
913
|
+
if (this.#isActiveOwner()) this.#lastSixelFootprint = footprint;
|
|
914
|
+
};
|
|
588
915
|
} else {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
916
|
+
onWritten = () => {
|
|
917
|
+
if (this.#isActiveOwner()) this.#kittyCleanupPending = true;
|
|
918
|
+
};
|
|
592
919
|
}
|
|
593
|
-
|
|
594
920
|
out += `\x1b[${y + 1};${x + 1}H${pixel.frames[this.#frame]}`;
|
|
595
|
-
return out;
|
|
921
|
+
return { payload: out, onWritten };
|
|
596
922
|
}
|
|
597
923
|
}
|