aicodeman 1.43.0 → 1.45.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/README.md +9 -4
- package/dist/case-rename.d.ts +65 -0
- package/dist/case-rename.d.ts.map +1 -0
- package/dist/case-rename.js +198 -0
- package/dist/case-rename.js.map +1 -0
- package/dist/cli-agent.d.ts +63 -4
- package/dist/cli-agent.d.ts.map +1 -1
- package/dist/cli-agent.js +233 -19
- package/dist/cli-agent.js.map +1 -1
- package/dist/config/auth-config.d.ts +16 -1
- package/dist/config/auth-config.d.ts.map +1 -1
- package/dist/config/auth-config.js +16 -1
- package/dist/config/auth-config.js.map +1 -1
- package/dist/config/cli-registry/stock.d.ts.map +1 -1
- package/dist/config/cli-registry/stock.js +8 -3
- package/dist/config/cli-registry/stock.js.map +1 -1
- package/dist/config/cli-registry/types.d.ts +2 -2
- package/dist/config/map-limits.d.ts +13 -1
- package/dist/config/map-limits.d.ts.map +1 -1
- package/dist/config/map-limits.js +28 -1
- package/dist/config/map-limits.js.map +1 -1
- package/dist/config-backup.d.ts +279 -0
- package/dist/config-backup.d.ts.map +1 -0
- package/dist/config-backup.js +794 -0
- package/dist/config-backup.js.map +1 -0
- package/dist/cron/cron-service.d.ts +5 -5
- package/dist/cron/cron-service.js +6 -6
- package/dist/cron/cron-service.js.map +1 -1
- package/dist/custom-model-hosts.d.ts +16 -0
- package/dist/custom-model-hosts.d.ts.map +1 -1
- package/dist/custom-model-hosts.js.map +1 -1
- package/dist/hooks-config.d.ts +15 -0
- package/dist/hooks-config.d.ts.map +1 -1
- package/dist/hooks-config.js +35 -0
- package/dist/hooks-config.js.map +1 -1
- package/dist/host-sensors.d.ts +115 -0
- package/dist/host-sensors.d.ts.map +1 -0
- package/dist/host-sensors.js +457 -0
- package/dist/host-sensors.js.map +1 -0
- package/dist/intent-store.d.ts +2 -0
- package/dist/intent-store.d.ts.map +1 -1
- package/dist/intent-store.js +9 -0
- package/dist/intent-store.js.map +1 -1
- package/dist/mux-interface.d.ts +21 -4
- package/dist/mux-interface.d.ts.map +1 -1
- package/dist/prompt-cache-keepwarm.d.ts +193 -0
- package/dist/prompt-cache-keepwarm.d.ts.map +1 -0
- package/dist/prompt-cache-keepwarm.js +359 -0
- package/dist/prompt-cache-keepwarm.js.map +1 -0
- package/dist/remote-hosts.d.ts +7 -0
- package/dist/remote-hosts.d.ts.map +1 -1
- package/dist/remote-hosts.js +17 -3
- package/dist/remote-hosts.js.map +1 -1
- package/dist/remote-pane-history.d.ts.map +1 -1
- package/dist/remote-pane-history.js +2 -2
- package/dist/remote-pane-history.js.map +1 -1
- package/dist/respawn-controller.d.ts.map +1 -1
- package/dist/respawn-controller.js +6 -5
- package/dist/respawn-controller.js.map +1 -1
- package/dist/session-auto-ops.d.ts.map +1 -1
- package/dist/session-auto-ops.js +6 -1
- package/dist/session-auto-ops.js.map +1 -1
- package/dist/session-cli-registry-bridge.d.ts +13 -0
- package/dist/session-cli-registry-bridge.d.ts.map +1 -1
- package/dist/session-cli-registry-bridge.js +20 -3
- package/dist/session-cli-registry-bridge.js.map +1 -1
- package/dist/session-submit-verifier.d.ts +19 -0
- package/dist/session-submit-verifier.d.ts.map +1 -1
- package/dist/session-submit-verifier.js +88 -0
- package/dist/session-submit-verifier.js.map +1 -1
- package/dist/session.d.ts +61 -5
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +125 -7
- package/dist/session.js.map +1 -1
- package/dist/state-store.d.ts +10 -0
- package/dist/state-store.d.ts.map +1 -1
- package/dist/state-store.js +35 -0
- package/dist/state-store.js.map +1 -1
- package/dist/tab-layout-service.d.ts +33 -0
- package/dist/tab-layout-service.d.ts.map +1 -1
- package/dist/tab-layout-service.js +75 -3
- package/dist/tab-layout-service.js.map +1 -1
- package/dist/tmux-manager.d.ts +57 -11
- package/dist/tmux-manager.d.ts.map +1 -1
- package/dist/tmux-manager.js +190 -42
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-prefix-table.d.ts +86 -0
- package/dist/tmux-prefix-table.d.ts.map +1 -0
- package/dist/tmux-prefix-table.js +172 -0
- package/dist/tmux-prefix-table.js.map +1 -0
- package/dist/tui/tui-app.d.ts +17 -2
- package/dist/tui/tui-app.d.ts.map +1 -1
- package/dist/tui/tui-app.js +70 -20
- package/dist/tui/tui-app.js.map +1 -1
- package/dist/tui/tui-client.d.ts +93 -5
- package/dist/tui/tui-client.d.ts.map +1 -1
- package/dist/tui/tui-client.js +198 -28
- package/dist/tui/tui-client.js.map +1 -1
- package/dist/types/app-state.d.ts +6 -0
- package/dist/types/app-state.d.ts.map +1 -1
- package/dist/types/app-state.js.map +1 -1
- package/dist/types/session.d.ts +40 -1
- package/dist/types/session.d.ts.map +1 -1
- package/dist/types/session.js.map +1 -1
- package/dist/usage-telemetry.d.ts +15 -0
- package/dist/usage-telemetry.d.ts.map +1 -1
- package/dist/usage-telemetry.js +45 -2
- package/dist/usage-telemetry.js.map +1 -1
- package/dist/utils/copilot-plan-usage.d.ts +46 -0
- package/dist/utils/copilot-plan-usage.d.ts.map +1 -0
- package/dist/utils/copilot-plan-usage.js +95 -0
- package/dist/utils/copilot-plan-usage.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/single-line.d.ts +22 -0
- package/dist/utils/single-line.d.ts.map +1 -0
- package/dist/utils/single-line.js +30 -0
- package/dist/utils/single-line.js.map +1 -0
- package/dist/web/agent-inbox-persistence.d.ts +52 -0
- package/dist/web/agent-inbox-persistence.d.ts.map +1 -0
- package/dist/web/agent-inbox-persistence.js +139 -0
- package/dist/web/agent-inbox-persistence.js.map +1 -0
- package/dist/web/agent-inbox.d.ts +140 -0
- package/dist/web/agent-inbox.d.ts.map +1 -0
- package/dist/web/agent-inbox.js +258 -0
- package/dist/web/agent-inbox.js.map +1 -0
- package/dist/web/approval-inbox.d.ts +6 -0
- package/dist/web/approval-inbox.d.ts.map +1 -1
- package/dist/web/approval-inbox.js +2 -2
- package/dist/web/approval-inbox.js.map +1 -1
- package/dist/web/middleware/auth.d.ts +2 -0
- package/dist/web/middleware/auth.d.ts.map +1 -1
- package/dist/web/middleware/auth.js +145 -52
- package/dist/web/middleware/auth.js.map +1 -1
- package/dist/web/plan-usage-latest.d.ts +2 -1
- package/dist/web/plan-usage-latest.d.ts.map +1 -1
- package/dist/web/plan-usage-latest.js +12 -2
- package/dist/web/plan-usage-latest.js.map +1 -1
- package/dist/web/ports/index.d.ts +1 -0
- package/dist/web/ports/index.d.ts.map +1 -1
- package/dist/web/ports/keep-warm-port.d.ts +9 -0
- package/dist/web/ports/keep-warm-port.d.ts.map +1 -0
- package/dist/web/ports/keep-warm-port.js +6 -0
- package/dist/web/ports/keep-warm-port.js.map +1 -0
- package/dist/web/ports/session-port.d.ts +3 -1
- package/dist/web/ports/session-port.d.ts.map +1 -1
- package/dist/web/public/admin-ui.js.gz +0 -0
- package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
- package/dist/web/public/app.42d0abae.js +43 -0
- package/dist/web/public/app.42d0abae.js.br +0 -0
- package/dist/web/public/app.42d0abae.js.gz +0 -0
- package/dist/web/public/approvals-ui.js.gz +0 -0
- package/dist/web/public/{constants.e5e588db.js → constants.0b3cdde9.js} +60 -1
- package/dist/web/public/constants.0b3cdde9.js.br +0 -0
- package/dist/web/public/constants.0b3cdde9.js.gz +0 -0
- package/dist/web/public/cron-ui.js.gz +0 -0
- package/dist/web/public/entrance-animations.js.gz +0 -0
- package/dist/web/public/git-status-ui.js.gz +0 -0
- package/dist/web/public/header-divider.eb2d2463.js +1 -0
- package/dist/web/public/header-divider.eb2d2463.js.br +0 -0
- package/dist/web/public/header-divider.eb2d2463.js.gz +0 -0
- package/dist/web/public/home-sessions.js.gz +0 -0
- package/dist/web/public/host-wake-ui.js.gz +0 -0
- package/dist/web/public/i18n.1e68220d.js +2 -0
- package/dist/web/public/i18n.1e68220d.js.br +0 -0
- package/dist/web/public/i18n.1e68220d.js.gz +0 -0
- package/dist/web/public/image-input.941386e7.js.gz +0 -0
- package/dist/web/public/index.html +162 -14
- package/dist/web/public/index.html.br +0 -0
- package/dist/web/public/index.html.gz +0 -0
- package/dist/web/public/input-cjk.8bc46081.js.gz +0 -0
- package/dist/web/public/{keyboard-accessory.c283e827.js → keyboard-accessory.4e8b20ac.js} +23 -5
- package/dist/web/public/keyboard-accessory.4e8b20ac.js.br +0 -0
- package/dist/web/public/keyboard-accessory.4e8b20ac.js.gz +0 -0
- package/dist/web/public/{mobile-handlers.0ef9c311.js → mobile-handlers.1c0cbcd8.js} +50 -16
- package/dist/web/public/mobile-handlers.1c0cbcd8.js.br +0 -0
- package/dist/web/public/mobile-handlers.1c0cbcd8.js.gz +0 -0
- package/dist/web/public/mobile-ime-preview.2dbaf262.js.gz +0 -0
- package/dist/web/public/mobile-overview.js.gz +0 -0
- package/dist/web/public/mobile.12fb18de.css +1 -0
- package/dist/web/public/mobile.12fb18de.css.br +0 -0
- package/dist/web/public/mobile.12fb18de.css.gz +0 -0
- package/dist/web/public/notification-manager.feb82c04.js.gz +0 -0
- package/dist/web/public/orchestrator-panel.js.gz +0 -0
- package/dist/web/public/{panels-ui.b7bfb9da.js → panels-ui.78c3defb.js} +19 -13
- package/dist/web/public/panels-ui.78c3defb.js.br +0 -0
- package/dist/web/public/panels-ui.78c3defb.js.gz +0 -0
- package/dist/web/public/ralph-panel.b350e2ef.js.gz +0 -0
- package/dist/web/public/ralph-wizard.b6c0dd19.js.gz +0 -0
- package/dist/web/public/readmymind-ui.js.gz +0 -0
- package/dist/web/public/reboot-restore-ui.js.gz +0 -0
- package/dist/web/public/respawn-ui.d7adcf6a.js.gz +0 -0
- package/dist/web/public/sanitize-html.e7147e76.js.gz +0 -0
- package/dist/web/public/session-lineage.js.gz +0 -0
- package/dist/web/public/{session-ui.be076c88.js → session-ui.ea6b1994.js} +33 -27
- package/dist/web/public/session-ui.ea6b1994.js.br +0 -0
- package/dist/web/public/session-ui.ea6b1994.js.gz +0 -0
- package/dist/web/public/settings-ui.085dd202.js +106 -0
- package/dist/web/public/settings-ui.085dd202.js.br +0 -0
- package/dist/web/public/settings-ui.085dd202.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview-worker.js.gz +0 -0
- package/dist/web/public/spreadsheet-preview.75c751de.js.gz +0 -0
- package/dist/web/public/spreadsheet-xlsx-core.js.gz +0 -0
- package/dist/web/public/styles.3b59b41d.css +1 -0
- package/dist/web/public/styles.3b59b41d.css.br +0 -0
- package/dist/web/public/styles.3b59b41d.css.gz +0 -0
- package/dist/web/public/subagent-windows.07277a58.js.gz +0 -0
- package/dist/web/public/sw.js +2 -2
- package/dist/web/public/sw.js.br +0 -0
- package/dist/web/public/sw.js.gz +0 -0
- package/dist/web/public/tab-layout-browser.2d6189f7.js.gz +0 -0
- package/dist/web/public/tab-rail-resize.7157e0bd.js.gz +0 -0
- package/dist/web/public/terminal-keycode229-recovery.af09f99a.js.gz +0 -0
- package/dist/web/public/terminal-split.js.gz +0 -0
- package/dist/web/public/terminal-tile.js +49 -23
- package/dist/web/public/terminal-tile.js.br +0 -0
- package/dist/web/public/terminal-tile.js.gz +0 -0
- package/dist/web/public/terminal-ui.fb2a27f5.js +2 -0
- package/dist/web/public/terminal-ui.fb2a27f5.js.br +0 -0
- package/dist/web/public/terminal-ui.fb2a27f5.js.gz +0 -0
- package/dist/web/public/tile-grid.js.gz +0 -0
- package/dist/web/public/ultracode-panel.js.gz +0 -0
- package/dist/web/public/ultracode-windows.js.gz +0 -0
- package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
- package/dist/web/public/vendor/exceljs.min.js.gz +0 -0
- package/dist/web/public/vendor/fflate.min.js.gz +0 -0
- package/dist/web/public/vendor/marked.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
- package/dist/web/public/vendor/xterm-predictive-echo.ae5e3d5d.js.gz +0 -0
- package/dist/web/public/vendor/xterm-zerolag-input.0b69623c.js.gz +0 -0
- package/dist/web/public/vendor/xterm.css.gz +0 -0
- package/dist/web/public/vendor/xterm.min.js.gz +0 -0
- package/dist/web/public/voice-input.2342c37b.js.gz +0 -0
- package/dist/web/public/voice-pcm-worklet.js.gz +0 -0
- package/dist/web/public/webview-tabs.js.gz +0 -0
- package/dist/web/public/whats-new.json +9 -9
- package/dist/web/route-helpers.d.ts +57 -6
- package/dist/web/route-helpers.d.ts.map +1 -1
- package/dist/web/route-helpers.js +72 -4
- package/dist/web/route-helpers.js.map +1 -1
- package/dist/web/routes/admin-routes.d.ts +2 -1
- package/dist/web/routes/admin-routes.d.ts.map +1 -1
- package/dist/web/routes/admin-routes.js +3 -0
- package/dist/web/routes/admin-routes.js.map +1 -1
- package/dist/web/routes/case-routes.d.ts +2 -2
- package/dist/web/routes/case-routes.d.ts.map +1 -1
- package/dist/web/routes/case-routes.js +263 -4
- package/dist/web/routes/case-routes.js.map +1 -1
- package/dist/web/routes/config-backup-routes.d.ts +54 -0
- package/dist/web/routes/config-backup-routes.d.ts.map +1 -0
- package/dist/web/routes/config-backup-routes.js +268 -0
- package/dist/web/routes/config-backup-routes.js.map +1 -0
- package/dist/web/routes/custom-model-routes.d.ts +17 -1
- package/dist/web/routes/custom-model-routes.d.ts.map +1 -1
- package/dist/web/routes/custom-model-routes.js +118 -13
- package/dist/web/routes/custom-model-routes.js.map +1 -1
- package/dist/web/routes/hook-event-routes.d.ts.map +1 -1
- package/dist/web/routes/hook-event-routes.js +26 -5
- package/dist/web/routes/hook-event-routes.js.map +1 -1
- package/dist/web/routes/inbox-routes.d.ts +43 -0
- package/dist/web/routes/inbox-routes.d.ts.map +1 -0
- package/dist/web/routes/inbox-routes.js +148 -0
- package/dist/web/routes/inbox-routes.js.map +1 -0
- package/dist/web/routes/index.d.ts +2 -0
- package/dist/web/routes/index.d.ts.map +1 -1
- package/dist/web/routes/index.js +2 -0
- package/dist/web/routes/index.js.map +1 -1
- package/dist/web/routes/ralph-routes.js +2 -2
- package/dist/web/routes/ralph-routes.js.map +1 -1
- package/dist/web/routes/reboot-restore-routes.d.ts.map +1 -1
- package/dist/web/routes/reboot-restore-routes.js +2 -0
- package/dist/web/routes/reboot-restore-routes.js.map +1 -1
- package/dist/web/routes/session-routes.d.ts +2 -2
- package/dist/web/routes/session-routes.d.ts.map +1 -1
- package/dist/web/routes/session-routes.js +110 -61
- package/dist/web/routes/session-routes.js.map +1 -1
- package/dist/web/routes/status-telemetry-routes.d.ts +2 -2
- package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -1
- package/dist/web/routes/status-telemetry-routes.js +8 -4
- package/dist/web/routes/status-telemetry-routes.js.map +1 -1
- package/dist/web/routes/system-routes.d.ts +2 -2
- package/dist/web/routes/system-routes.d.ts.map +1 -1
- package/dist/web/routes/system-routes.js +30 -2
- package/dist/web/routes/system-routes.js.map +1 -1
- package/dist/web/routes/webview-routes.d.ts.map +1 -1
- package/dist/web/routes/webview-routes.js +1 -0
- package/dist/web/routes/webview-routes.js.map +1 -1
- package/dist/web/schemas.d.ts +45 -0
- package/dist/web/schemas.d.ts.map +1 -1
- package/dist/web/schemas.js +79 -2
- package/dist/web/schemas.js.map +1 -1
- package/dist/web/sensitive-path.d.ts.map +1 -1
- package/dist/web/sensitive-path.js +2 -0
- package/dist/web/sensitive-path.js.map +1 -1
- package/dist/web/server.d.ts +14 -2
- package/dist/web/server.d.ts.map +1 -1
- package/dist/web/server.js +176 -7
- package/dist/web/server.js.map +1 -1
- package/dist/web/session-listener-wiring.d.ts +6 -0
- package/dist/web/session-listener-wiring.d.ts.map +1 -1
- package/dist/web/session-listener-wiring.js +10 -3
- package/dist/web/session-listener-wiring.js.map +1 -1
- package/dist/web/session-wait-registry.d.ts +48 -4
- package/dist/web/session-wait-registry.d.ts.map +1 -1
- package/dist/web/session-wait-registry.js +144 -6
- package/dist/web/session-wait-registry.js.map +1 -1
- package/dist/web/sse-events.d.ts +9 -3
- package/dist/web/sse-events.d.ts.map +1 -1
- package/dist/web/sse-events.js +9 -3
- package/dist/web/sse-events.js.map +1 -1
- package/dist/web/webview-proxy.d.ts +8 -3
- package/dist/web/webview-proxy.d.ts.map +1 -1
- package/dist/web/webview-proxy.js +23 -5
- package/dist/web/webview-proxy.js.map +1 -1
- package/package.json +1 -1
- package/skills/codeman/SKILL.md +27 -13
- package/skills/codeman/preamble.sh +15 -5
- package/skills/codeman/reference/endpoints.md +32 -10
- package/skills/codeman/reference/recipes.md +1 -1
- package/skills/codeman/reference/verbs.md +68 -13
- package/dist/web/public/app.ae50029a.js +0 -43
- package/dist/web/public/app.ae50029a.js.br +0 -0
- package/dist/web/public/app.ae50029a.js.gz +0 -0
- package/dist/web/public/constants.e5e588db.js.br +0 -0
- package/dist/web/public/constants.e5e588db.js.gz +0 -0
- package/dist/web/public/i18n.8f291f06.js +0 -2
- package/dist/web/public/i18n.8f291f06.js.br +0 -0
- package/dist/web/public/i18n.8f291f06.js.gz +0 -0
- package/dist/web/public/keyboard-accessory.c283e827.js.br +0 -0
- package/dist/web/public/keyboard-accessory.c283e827.js.gz +0 -0
- package/dist/web/public/mobile-handlers.0ef9c311.js.br +0 -0
- package/dist/web/public/mobile-handlers.0ef9c311.js.gz +0 -0
- package/dist/web/public/mobile.13514863.css +0 -1
- package/dist/web/public/mobile.13514863.css.br +0 -0
- package/dist/web/public/mobile.13514863.css.gz +0 -0
- package/dist/web/public/panels-ui.b7bfb9da.js.br +0 -0
- package/dist/web/public/panels-ui.b7bfb9da.js.gz +0 -0
- package/dist/web/public/session-ui.be076c88.js.br +0 -0
- package/dist/web/public/session-ui.be076c88.js.gz +0 -0
- package/dist/web/public/settings-ui.fc4cc50a.js +0 -97
- package/dist/web/public/settings-ui.fc4cc50a.js.br +0 -0
- package/dist/web/public/settings-ui.fc4cc50a.js.gz +0 -0
- package/dist/web/public/styles.dcfa907f.css +0 -1
- package/dist/web/public/styles.dcfa907f.css.br +0 -0
- package/dist/web/public/styles.dcfa907f.css.gz +0 -0
- package/dist/web/public/terminal-ui.ae01a7d1.js +0 -2
- package/dist/web/public/terminal-ui.ae01a7d1.js.br +0 -0
- package/dist/web/public/terminal-ui.ae01a7d1.js.gz +0 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Keep tmux's prefix table on Codeman's socket down to `send-prefix`.
|
|
3
|
+
*
|
|
4
|
+
* Codeman drives tmux through commands, never through key bindings, but every
|
|
5
|
+
* keystroke typed into a browser terminal reaches the `tmux attach-session`
|
|
6
|
+
* client behind it. With tmux's stock prefix table that client obeys the whole
|
|
7
|
+
* menu: Ctrl+B then `(`, `)`, `L`, `s` or `w` runs `switch-client` /
|
|
8
|
+
* `choose-tree` and re-attaches the tab's client to a DIFFERENT session, so the
|
|
9
|
+
* tab shows, and types into, another session's agent while Codeman still labels
|
|
10
|
+
* it as the original. Ctrl+B `d` detaches the client, `$` renames the session
|
|
11
|
+
* under Codeman's feet, `:` opens tmux's command prompt. Ctrl+B is not a rare
|
|
12
|
+
* key in a terminal (readline backward-char, Claude Code's background chord),
|
|
13
|
+
* and whatever is typed next lands in that menu.
|
|
14
|
+
*
|
|
15
|
+
* The prefix itself stays: Claude Code running inside tmux asks for
|
|
16
|
+
* "ctrl+b ctrl+b" to background a command, which only works through
|
|
17
|
+
* `send-prefix`. So the table keeps exactly that one binding, on whatever key
|
|
18
|
+
* the socket's prefix is (the socket reads the user's `~/.tmux.conf`).
|
|
19
|
+
*
|
|
20
|
+
* `codeman tui` shares the socket (src/tui/tui-app.ts, beginAttachHandoff). For
|
|
21
|
+
* the length of an attach it claims a held-Ctrl detach alias (`C-d`) in the
|
|
22
|
+
* prefix table, and its one-key way out (F1) and Alt+1..9 in the `root` table.
|
|
23
|
+
* `root` is never touched here, and a `C-<letter> detach-client` binding is left
|
|
24
|
+
* alone (and put back when a reset clears the rest of the table around it), so
|
|
25
|
+
* creating a session while a TUI attach is open does not take the attach's way
|
|
26
|
+
* out away. The reset only runs while the table holds anything else, i.e. once
|
|
27
|
+
* per tmux server in practice.
|
|
28
|
+
*
|
|
29
|
+
* That tolerance is server-wide like every key table: while such an alias is
|
|
30
|
+
* bound, a browser tab's client can detach itself with it too. F1 in `root`
|
|
31
|
+
* is the same kind of way out. Alt+1..9 are not: `codeman tui` binds those
|
|
32
|
+
* through `if-shell -F` so `switch-client` runs only for the TUI's own client
|
|
33
|
+
* (see `bindSwitchKey` in src/tui/tui-client.ts). This file still does not
|
|
34
|
+
* touch `root`.
|
|
35
|
+
*
|
|
36
|
+
* Docker cases and owned remote sessions run a second tmux (`-L codeman-docker`,
|
|
37
|
+
* `-L codeman-remote`) with `prefix C-q`. That server is not this socket, so
|
|
38
|
+
* the reset above never sees it, and its stock prefix table still switches
|
|
39
|
+
* the inner client. `nestedPrefixTableResetCommands` is the same reduction,
|
|
40
|
+
* appended to those create chains. A non-owned remote attach joins another
|
|
41
|
+
* Codeman's `-L codeman` and must not run it.
|
|
42
|
+
*
|
|
43
|
+
* @module tmux-prefix-table
|
|
44
|
+
*/
|
|
45
|
+
import { execSync } from 'node:child_process';
|
|
46
|
+
import { EXEC_TIMEOUT_MS } from './config/exec-timeout.js';
|
|
47
|
+
import { shellescape } from './remote-hosts.js';
|
|
48
|
+
/** tmux's stock prefix, used when `show-options` cannot be read. */
|
|
49
|
+
const DEFAULT_PREFIX = 'C-b';
|
|
50
|
+
/**
|
|
51
|
+
* Prefix on the dedicated tmux inside a Docker case and an owned remote
|
|
52
|
+
* session. Codeman's own socket keeps the user's prefix; these nested servers
|
|
53
|
+
* always use C-q so it does not collide with the outer prefix.
|
|
54
|
+
*/
|
|
55
|
+
export const NESTED_TMUX_PREFIX = 'C-q';
|
|
56
|
+
/**
|
|
57
|
+
* Commands that reduce a nested tmux's prefix table to `C-q send-prefix`.
|
|
58
|
+
*
|
|
59
|
+
* Joined with `\;` onto the `new-session` that creates the server
|
|
60
|
+
* (`buildRemoteLaunchCommand`, `buildDockerLaunchCommand`). No `tmux` binary
|
|
61
|
+
* and no `-g`: the table is server-global, which is what we want on these
|
|
62
|
+
* dedicated sockets and nowhere else.
|
|
63
|
+
*
|
|
64
|
+
* Those servers load the user's tmux config (no `-f /dev/null`). A config that
|
|
65
|
+
* leaves the prefix table empty makes `unbind-key -a -T prefix` fail with
|
|
66
|
+
* "table prefix doesn't exist", and tmux then drops every later command in the
|
|
67
|
+
* `\;` chain, including the bind and `remain-on-exit failed` (#210). The same
|
|
68
|
+
* empty table is what #669 handled on the local socket. Binding `send-prefix`
|
|
69
|
+
* first creates the table so the unbind can run; the unbind clears stock
|
|
70
|
+
* bindings (and that first bind); the second bind puts `send-prefix` back.
|
|
71
|
+
* Put them BEFORE `remain-on-exit failed` so a remote tmux that rejects
|
|
72
|
+
* `failed` does not drop the reduction.
|
|
73
|
+
*/
|
|
74
|
+
export function nestedPrefixTableResetCommands() {
|
|
75
|
+
const sendPrefix = `bind-key -T prefix ${NESTED_TMUX_PREFIX} send-prefix`;
|
|
76
|
+
return [sendPrefix, 'unbind-key -a -T prefix', sendPrefix];
|
|
77
|
+
}
|
|
78
|
+
/** One `list-keys -T prefix` line: key and command. */
|
|
79
|
+
const PREFIX_LINE = /^bind-key\s+(?:-\S+\s+)*?-T\s+prefix\s+(\S+)\s+(.+)$/;
|
|
80
|
+
/** The held-Ctrl detach alias `codeman tui` claims during an attach (heldCtrlAlias). */
|
|
81
|
+
const TUI_DETACH_ALIAS = /^C-[a-z]$/;
|
|
82
|
+
/**
|
|
83
|
+
* A key as `list-keys` prints it, without tmux's backslash escaping: `show-options`
|
|
84
|
+
* prints the prefix `C-\` as is, while the listing shows `C-\\` (and `\#`, `\$`, `\"`).
|
|
85
|
+
*/
|
|
86
|
+
function unescapeListedKey(key) {
|
|
87
|
+
return key.replace(/\\(.)/g, '$1');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Whether the prefix table (as printed by `tmux list-keys -T prefix`) still holds
|
|
91
|
+
* a binding other than `<prefix> send-prefix` or a TUI detach alias, or lacks
|
|
92
|
+
* `<prefix> send-prefix`. Unparseable output counts as "needs a reset":
|
|
93
|
+
* resetting is idempotent, skipping one leaves `switch-client` reachable from
|
|
94
|
+
* the browser. A prefix of `None` expects no `send-prefix` binding at all.
|
|
95
|
+
*/
|
|
96
|
+
export function prefixTableNeedsReset(listKeysOutput, prefix = DEFAULT_PREFIX) {
|
|
97
|
+
let hasSendPrefix = false;
|
|
98
|
+
for (const raw of listKeysOutput.split('\n')) {
|
|
99
|
+
const line = raw.trim();
|
|
100
|
+
if (!line)
|
|
101
|
+
continue;
|
|
102
|
+
const match = PREFIX_LINE.exec(line);
|
|
103
|
+
if (!match)
|
|
104
|
+
return true;
|
|
105
|
+
const key = unescapeListedKey(match[1]);
|
|
106
|
+
const command = match[2].trim();
|
|
107
|
+
if (command === 'send-prefix' && key === prefix) {
|
|
108
|
+
hasSendPrefix = true;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
if (command === 'detach-client' && TUI_DETACH_ALIAS.test(key) && key !== prefix)
|
|
112
|
+
continue;
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
return prefix === 'None' ? false : !hasSendPrefix;
|
|
116
|
+
}
|
|
117
|
+
/** The `C-<letter> detach-client` bindings in a `list-keys -T prefix` listing (see prefixTableNeedsReset). */
|
|
118
|
+
function tuiDetachAliases(listKeysOutput, prefix) {
|
|
119
|
+
const keys = [];
|
|
120
|
+
for (const raw of listKeysOutput.split('\n')) {
|
|
121
|
+
const match = PREFIX_LINE.exec(raw.trim());
|
|
122
|
+
if (!match)
|
|
123
|
+
continue;
|
|
124
|
+
const key = unescapeListedKey(match[1]);
|
|
125
|
+
if (match[2].trim() === 'detach-client' && TUI_DETACH_ALIAS.test(key) && key !== prefix)
|
|
126
|
+
keys.push(key);
|
|
127
|
+
}
|
|
128
|
+
return keys;
|
|
129
|
+
}
|
|
130
|
+
const defaultRunner = (command) => execSync(command, { encoding: 'utf8', timeout: EXEC_TIMEOUT_MS, stdio: ['ignore', 'pipe', 'ignore'] });
|
|
131
|
+
/**
|
|
132
|
+
* Reduce the prefix table of the tmux server behind `tmux` (e.g. `tmux -L 'codeman'`)
|
|
133
|
+
* to `<prefix> send-prefix`, when it holds anything more. Never throws: a failure
|
|
134
|
+
* only leaves tmux's stock bindings in place. Returns whether a reset ran.
|
|
135
|
+
*/
|
|
136
|
+
export function restrictTmuxPrefixTable(tmux, run = defaultRunner) {
|
|
137
|
+
let prefix = DEFAULT_PREFIX;
|
|
138
|
+
try {
|
|
139
|
+
prefix = run(`${tmux} show-options -gv prefix`).trim() || DEFAULT_PREFIX;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
/* keep tmux's stock prefix */
|
|
143
|
+
}
|
|
144
|
+
let listing;
|
|
145
|
+
try {
|
|
146
|
+
listing = run(`${tmux} list-keys -T prefix`);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
listing = null; // an empty table makes list-keys fail on some tmux builds
|
|
150
|
+
}
|
|
151
|
+
if (listing !== null && !prefixTableNeedsReset(listing, prefix))
|
|
152
|
+
return false;
|
|
153
|
+
try {
|
|
154
|
+
run(`${tmux} unbind-key -a -T prefix`);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
/* an empty table makes unbind-key -a fail too ("table prefix doesn't exist"); nothing to clear */
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
if (prefix !== 'None')
|
|
161
|
+
run(`${tmux} bind-key -T prefix ${shellescape(prefix)} send-prefix`);
|
|
162
|
+
// `unbind-key -a` also took a running TUI attach's held-Ctrl way out; give it back.
|
|
163
|
+
for (const key of tuiDetachAliases(listing ?? '', prefix)) {
|
|
164
|
+
run(`${tmux} bind-key -T prefix ${shellescape(key)} detach-client`);
|
|
165
|
+
}
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=tmux-prefix-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tmux-prefix-table.js","sourceRoot":"","sources":["../src/tmux-prefix-table.ts"],"names":[],"mappings":"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"}
|
package/dist/tui/tui-app.d.ts
CHANGED
|
@@ -135,6 +135,14 @@ export declare function heldCtrlAlias(key: string): string | null;
|
|
|
135
135
|
* through `formatPrefixKey`, which uppercases.
|
|
136
136
|
*/
|
|
137
137
|
export declare function detachChord(prefix?: string, key?: string): string;
|
|
138
|
+
/**
|
|
139
|
+
* The chord an attach advertises when it could not claim the one-key way out.
|
|
140
|
+
*
|
|
141
|
+
* With no key bound to `detach-client` in the prefix table there is no stock
|
|
142
|
+
* `d` to name: Codeman keeps only `send-prefix` there (src/tmux-prefix-table.ts),
|
|
143
|
+
* so the held-Ctrl alias the attach claimed is the chord that works.
|
|
144
|
+
*/
|
|
145
|
+
export declare function fallbackDetachChord(prefix?: string, detachKey?: string, heldAlias?: string): string;
|
|
138
146
|
/**
|
|
139
147
|
* The status line an attached session wears, as tmux option → value.
|
|
140
148
|
*
|
|
@@ -231,7 +239,14 @@ export interface TuiAttachHandoff {
|
|
|
231
239
|
* `window-size manual` with no status bar (what Codeman creates) is exactly
|
|
232
240
|
* that again after the detach.
|
|
233
241
|
*/
|
|
234
|
-
export declare function beginAttachHandoff(client: TuiClient, muxName: string, label: string, tabs?: readonly TuiAttachTab[], cols?: number, rows?: number
|
|
242
|
+
export declare function beginAttachHandoff(client: TuiClient, muxName: string, label: string, tabs?: readonly TuiAttachTab[], cols?: number, rows?: number,
|
|
243
|
+
/**
|
|
244
|
+
* Tty the attach client will inherit. Omit to read this process's terminal.
|
|
245
|
+
* `null` means there is no usable tty: switch keys are not bound (an unscoped
|
|
246
|
+
* `switch-client` would move every client on the socket, including a browser
|
|
247
|
+
* tab). Tests pass a tty so they do not depend on stdin.
|
|
248
|
+
*/
|
|
249
|
+
clientTty?: string | null): Promise<TuiAttachHandoff>;
|
|
235
250
|
/**
|
|
236
251
|
* Is this the session the TUI itself runs in? Codeman exports
|
|
237
252
|
* `CODEMAN_SESSION_ID` into every managed pane, and killing that one would take
|
|
@@ -273,7 +288,7 @@ export interface TuiKeymapContext {
|
|
|
273
288
|
/** False in degraded mode, where the only verb that works is attach. */
|
|
274
289
|
server: boolean;
|
|
275
290
|
approval?: TuiApprovalKeys;
|
|
276
|
-
/**
|
|
291
|
+
/** How the last attach said to leave it. Defaults to F1, the key an attach claims. */
|
|
277
292
|
detach?: string;
|
|
278
293
|
/** A dead-row card is offering `r` to resume, so the footer has to say so. */
|
|
279
294
|
resumeOffer?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tui-app.d.ts","sourceRoot":"","sources":["../../src/tui/tui-app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAYH,OAAO,
|
|
1
|
+
{"version":3,"file":"tui-app.d.ts","sourceRoot":"","sources":["../../src/tui/tui-app.ts"],"names":[],"mappings":"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"}
|
package/dist/tui/tui-app.js
CHANGED
|
@@ -53,7 +53,7 @@ import { dropSeveredEscape, foldPreviewGlyphs, toDisplayLines } from './tui-ansi
|
|
|
53
53
|
import { approvalAnswerForKey, newApprovalIds } from './tui-approvals.js';
|
|
54
54
|
import { composerScroll, composerStep, composerText, createComposer } from './tui-composer.js';
|
|
55
55
|
import { formatAwayDigest } from './tui-digest.js';
|
|
56
|
-
import { ATTACH_BANNER_MARKER, TuiClient, } from './tui-client.js';
|
|
56
|
+
import { ATTACH_BANNER_MARKER, isTuiClientTty, readControllingTty, TuiClient, } from './tui-client.js';
|
|
57
57
|
import { createKeyParser } from './tui-keys.js';
|
|
58
58
|
import { computeLayout, needsBanner } from './tui-layout.js';
|
|
59
59
|
import { buildSearchEntries, createTuiModel, firstSearchIndex, moveSearchIndex, } from './tui-model.js';
|
|
@@ -249,6 +249,18 @@ export function heldCtrlAlias(key) {
|
|
|
249
249
|
export function detachChord(prefix, key) {
|
|
250
250
|
return `${formatPrefixKey(prefix)} then ${key || DEFAULT_DETACH_KEY}`;
|
|
251
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* The chord an attach advertises when it could not claim the one-key way out.
|
|
254
|
+
*
|
|
255
|
+
* With no key bound to `detach-client` in the prefix table there is no stock
|
|
256
|
+
* `d` to name: Codeman keeps only `send-prefix` there (src/tmux-prefix-table.ts),
|
|
257
|
+
* so the held-Ctrl alias the attach claimed is the chord that works.
|
|
258
|
+
*/
|
|
259
|
+
export function fallbackDetachChord(prefix, detachKey, heldAlias) {
|
|
260
|
+
if (!detachKey && heldAlias)
|
|
261
|
+
return detachChord(prefix, formatPrefixKey(heldAlias));
|
|
262
|
+
return detachChord(prefix, detachKey);
|
|
263
|
+
}
|
|
252
264
|
/** `#` opens `#[…]`/`#{…}` in a tmux format, so a name carrying one must double it. */
|
|
253
265
|
function escapeTmuxFormat(value) {
|
|
254
266
|
return value.replace(/#/g, '##');
|
|
@@ -272,10 +284,10 @@ function escapeTmuxFormat(value) {
|
|
|
272
284
|
* and the chord alone carries emphasis.
|
|
273
285
|
*/
|
|
274
286
|
export function buildAttachBanner(options) {
|
|
275
|
-
const chord = escapeTmuxFormat(
|
|
287
|
+
const chord = escapeTmuxFormat(fallbackDetachChord(options.prefix, options.detachKey, options.heldAlias));
|
|
276
288
|
// Named on the bar because it is what people actually type: keeping Ctrl held
|
|
277
289
|
// is the common way to press this, and the bar has to say that it works.
|
|
278
|
-
const held = options.heldAlias ? escapeTmuxFormat(formatPrefixKey(options.heldAlias)) : '';
|
|
290
|
+
const held = options.heldAlias && options.detachKey ? escapeTmuxFormat(formatPrefixKey(options.heldAlias)) : '';
|
|
279
291
|
const alias = held ? ` (or ${held})` : '';
|
|
280
292
|
const label = escapeTmuxFormat(truncateLabel((options.label ?? '').trim(), ATTACH_BANNER_LABEL_MAX));
|
|
281
293
|
// ONE option, not `status-left`/`status-right`/`status-style`: `status-format[0]`
|
|
@@ -411,7 +423,14 @@ export function planResume(session) {
|
|
|
411
423
|
* `window-size manual` with no status bar (what Codeman creates) is exactly
|
|
412
424
|
* that again after the detach.
|
|
413
425
|
*/
|
|
414
|
-
export async function beginAttachHandoff(client, muxName, label, tabs = [], cols, rows
|
|
426
|
+
export async function beginAttachHandoff(client, muxName, label, tabs = [], cols, rows,
|
|
427
|
+
/**
|
|
428
|
+
* Tty the attach client will inherit. Omit to read this process's terminal.
|
|
429
|
+
* `null` means there is no usable tty: switch keys are not bound (an unscoped
|
|
430
|
+
* `switch-client` would move every client on the socket, including a browser
|
|
431
|
+
* tab). Tests pass a tty so they do not depend on stdin.
|
|
432
|
+
*/
|
|
433
|
+
clientTty) {
|
|
415
434
|
const prefix = (await client.readPrefixKey(muxName)) ?? undefined;
|
|
416
435
|
// Read, not assumed: see detachChord() for the `d` vs `D` mix-up this closes.
|
|
417
436
|
const detachKey = (await client.readDetachKey()) ?? undefined;
|
|
@@ -443,16 +462,34 @@ export async function beginAttachHandoff(client, muxName, label, tabs = [], cols
|
|
|
443
462
|
// usable rather than decorative. Only the first nine, only sessions that
|
|
444
463
|
// really have a pane, and only keys tmux reports as free — the same rule the
|
|
445
464
|
// way-out key follows, so a binding of the user's own is never shadowed.
|
|
465
|
+
//
|
|
466
|
+
// The key table is server-global. The command is guarded to this terminal's
|
|
467
|
+
// client (see bindSwitchKey): without a tty we bind nothing, and a leaked
|
|
468
|
+
// unscoped `switch-client` from an older TUI is removed so it cannot keep
|
|
469
|
+
// moving browser tabs. When we do claim the keys, drop whatever previous
|
|
470
|
+
// attach left on M-1..M-9 first — including keys this strip will not reuse.
|
|
446
471
|
const switchKeys = [];
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
472
|
+
const tty = clientTty === undefined ? readControllingTty() : clientTty || null;
|
|
473
|
+
const switchTabs = tabs.slice(0, 9).filter((tab) => tab.index >= 1 && tab.index <= 9 && tab.muxName);
|
|
474
|
+
const guarded = Boolean(tty && isTuiClientTty(tty));
|
|
475
|
+
// The keys are bound here but stay inert until the attach hook records this
|
|
476
|
+
// client's pid, and that hook is armed at the very end (see below).
|
|
477
|
+
if (guarded && switchTabs.length > 0) {
|
|
478
|
+
for (let index = 1; index <= 9; index++)
|
|
479
|
+
await client.unbindSwitchKey(`M-${index}`);
|
|
480
|
+
for (const tab of switchTabs) {
|
|
481
|
+
const key = `M-${tab.index}`;
|
|
482
|
+
const bound = await client.readPrefixBinding(key, 'root');
|
|
483
|
+
// Takeover just cleared ours. Anything still here belongs to the user.
|
|
484
|
+
if (bound !== null)
|
|
485
|
+
continue;
|
|
486
|
+
if (await client.bindSwitchKey(key, tab.muxName, tty))
|
|
487
|
+
switchKeys.push(key);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
for (let index = 1; index <= 9; index++)
|
|
492
|
+
await client.unbindSwitchKey(`M-${index}`, '');
|
|
456
493
|
}
|
|
457
494
|
const bannerFor = (activeMux, ownLabel) => buildAttachBanner({
|
|
458
495
|
...(prefix ? { prefix } : {}),
|
|
@@ -500,11 +537,23 @@ export async function beginAttachHandoff(client, muxName, label, tabs = [], cols
|
|
|
500
537
|
if (target === muxName)
|
|
501
538
|
await client.followAttachingClient(target);
|
|
502
539
|
}
|
|
540
|
+
// ⚠️ Armed LAST, as the final tmux call before the caller's `spawnSync`. The
|
|
541
|
+
// hook is one-shot for this tty, so a TUI killed between arming and attaching
|
|
542
|
+
// leaves it armed, and Linux hands the lowest free pty to the next opener: a
|
|
543
|
+
// browser tab's attach client could land on this tty and have its pid
|
|
544
|
+
// recorded, which would make these keys move that tab. Arming after the
|
|
545
|
+
// dressing loop above shrinks that window to the attach's own startup. A
|
|
546
|
+
// failed arm leaves the keys inert (the closed direction), and `restore()`
|
|
547
|
+
// still unbinds them.
|
|
548
|
+
if (switchKeys.length > 0)
|
|
549
|
+
await client.armTuiSwitchGuard(tty);
|
|
503
550
|
return {
|
|
504
|
-
chord: oneKey ? ONE_KEY_DETACH :
|
|
551
|
+
chord: oneKey ? ONE_KEY_DETACH : fallbackDetachChord(prefix, detachKey, claimed && alias ? alias : undefined),
|
|
505
552
|
async restore() {
|
|
506
553
|
for (const key of switchKeys)
|
|
507
|
-
await client.unbindSwitchKey(key);
|
|
554
|
+
await client.unbindSwitchKey(key, tty ?? '');
|
|
555
|
+
if (tty && isTuiClientTty(tty))
|
|
556
|
+
await client.disarmTuiSwitchGuard(tty);
|
|
508
557
|
if (oneKey)
|
|
509
558
|
await client.unbindDetachKey(ONE_KEY_DETACH, 'root');
|
|
510
559
|
if (claimed && alias)
|
|
@@ -616,7 +665,7 @@ export function helpKeysFor(glyphs, context) {
|
|
|
616
665
|
['tab', 'next session'],
|
|
617
666
|
// The one key that is not the TUI's: an attach hands the terminal to tmux,
|
|
618
667
|
// and leaving it is the question every first attach asks.
|
|
619
|
-
[context.detach ??
|
|
668
|
+
[context.detach ?? ONE_KEY_DETACH, 'detach from an attached session, back to here'],
|
|
620
669
|
];
|
|
621
670
|
if (context.server) {
|
|
622
671
|
keys.push(['y / n', 'approve or deny the selected dialog'], ['1-9', 'answer with that option, when a dialog is on screen'], ['p', 'send one line to the selected session'], ['/', 'search sessions, events and files'], ['g', 'away digest'], ['n', 'new session'], ['x', 'kill (y to confirm)']);
|
|
@@ -858,11 +907,12 @@ class TuiApp {
|
|
|
858
907
|
glyphs;
|
|
859
908
|
socket = resolveTmuxSocketName();
|
|
860
909
|
/**
|
|
861
|
-
* How to leave an attach
|
|
862
|
-
*
|
|
863
|
-
* names
|
|
910
|
+
* How to leave an attach. Read per attach (F1 may be the user's, a session
|
|
911
|
+
* can override the prefix) and remembered for the help overlay; until the
|
|
912
|
+
* first attach it names F1, what an attach claims unless the user's config
|
|
913
|
+
* already holds it.
|
|
864
914
|
*/
|
|
865
|
-
detachChordLabel =
|
|
915
|
+
detachChordLabel = ONE_KEY_DETACH;
|
|
866
916
|
/** True for the length of one resume. The only thing standing between a resume and a loop. */
|
|
867
917
|
resuming = false;
|
|
868
918
|
stream = null;
|