@juspay/shooter 1.0.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/.claude/hooks/notifier.cjs +1431 -0
- package/.claude/settings.json +162 -0
- package/README.md +515 -0
- package/bin/shooter.cjs +141 -0
- package/build/client/_app/immutable/assets/0.CM9Hl6d-.css +1 -0
- package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.br +0 -0
- package/build/client/_app/immutable/assets/0.CM9Hl6d-.css.gz +0 -0
- package/build/client/_app/immutable/assets/2.CAShZ7lQ.css +1 -0
- package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.br +1 -0
- package/build/client/_app/immutable/assets/2.CAShZ7lQ.css.gz +0 -0
- package/build/client/_app/immutable/assets/3.C0uFg0IS.css +1 -0
- package/build/client/_app/immutable/assets/3.C0uFg0IS.css.br +0 -0
- package/build/client/_app/immutable/assets/3.C0uFg0IS.css.gz +0 -0
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css +1 -0
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.br +0 -0
- package/build/client/_app/immutable/assets/4.cJuCkJKZ.css.gz +0 -0
- package/build/client/_app/immutable/assets/5.DRjApZQW.css +1 -0
- package/build/client/_app/immutable/assets/5.DRjApZQW.css.br +0 -0
- package/build/client/_app/immutable/assets/5.DRjApZQW.css.gz +0 -0
- package/build/client/_app/immutable/assets/6.AraZrY8I.css +1 -0
- package/build/client/_app/immutable/assets/6.AraZrY8I.css.br +0 -0
- package/build/client/_app/immutable/assets/6.AraZrY8I.css.gz +0 -0
- package/build/client/_app/immutable/assets/7.BCJ1IuMx.css +1 -0
- package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.br +0 -0
- package/build/client/_app/immutable/assets/7.BCJ1IuMx.css.gz +0 -0
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css +1 -0
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.br +0 -0
- package/build/client/_app/immutable/assets/ChatView.CsdBAOKx.css.gz +0 -0
- package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css +1 -0
- package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.br +0 -0
- package/build/client/_app/immutable/assets/markdown.B0b5w2tq.css.gz +0 -0
- package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css +1 -0
- package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.br +0 -0
- package/build/client/_app/immutable/assets/xterm.DFuMZ0ql.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BNJphC1q.js +56 -0
- package/build/client/_app/immutable/chunks/BNJphC1q.js.br +0 -0
- package/build/client/_app/immutable/chunks/BNJphC1q.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BTGVxaYV.js +9 -0
- package/build/client/_app/immutable/chunks/BTGVxaYV.js.br +0 -0
- package/build/client/_app/immutable/chunks/BTGVxaYV.js.gz +0 -0
- package/build/client/_app/immutable/chunks/BlxrFPDK.js +1 -0
- package/build/client/_app/immutable/chunks/BlxrFPDK.js.br +0 -0
- package/build/client/_app/immutable/chunks/BlxrFPDK.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Bvk7mfPM.js +1 -0
- package/build/client/_app/immutable/chunks/Bvk7mfPM.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bvk7mfPM.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CAokzuPQ.js +1 -0
- package/build/client/_app/immutable/chunks/CAokzuPQ.js.br +0 -0
- package/build/client/_app/immutable/chunks/CAokzuPQ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CGLrx-H5.js +1 -0
- package/build/client/_app/immutable/chunks/CGLrx-H5.js.br +0 -0
- package/build/client/_app/immutable/chunks/CGLrx-H5.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CgCpWzEA.js +1 -0
- package/build/client/_app/immutable/chunks/CgCpWzEA.js.br +0 -0
- package/build/client/_app/immutable/chunks/CgCpWzEA.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Cjwk_cGO.js +6 -0
- package/build/client/_app/immutable/chunks/Cjwk_cGO.js.br +0 -0
- package/build/client/_app/immutable/chunks/Cjwk_cGO.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CtQ8EED1.js +11 -0
- package/build/client/_app/immutable/chunks/CtQ8EED1.js.br +0 -0
- package/build/client/_app/immutable/chunks/CtQ8EED1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DERQCisl.js +1 -0
- package/build/client/_app/immutable/chunks/DERQCisl.js.br +0 -0
- package/build/client/_app/immutable/chunks/DERQCisl.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DKrg8TQs.js +1 -0
- package/build/client/_app/immutable/chunks/DKrg8TQs.js.br +0 -0
- package/build/client/_app/immutable/chunks/DKrg8TQs.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DLu6yJIZ.js +1 -0
- package/build/client/_app/immutable/chunks/DLu6yJIZ.js.br +0 -0
- package/build/client/_app/immutable/chunks/DLu6yJIZ.js.gz +0 -0
- package/build/client/_app/immutable/chunks/Dkkpz_4D.js +126 -0
- package/build/client/_app/immutable/chunks/Dkkpz_4D.js.br +0 -0
- package/build/client/_app/immutable/chunks/Dkkpz_4D.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DoczjQhA.js +1 -0
- package/build/client/_app/immutable/chunks/DoczjQhA.js.br +0 -0
- package/build/client/_app/immutable/chunks/DoczjQhA.js.gz +0 -0
- package/build/client/_app/immutable/chunks/PPVm8Dsz.js +1 -0
- package/build/client/_app/immutable/chunks/PPVm8Dsz.js.br +0 -0
- package/build/client/_app/immutable/chunks/PPVm8Dsz.js.gz +0 -0
- package/build/client/_app/immutable/chunks/RpcNruLP.js +2 -0
- package/build/client/_app/immutable/chunks/RpcNruLP.js.br +0 -0
- package/build/client/_app/immutable/chunks/RpcNruLP.js.gz +0 -0
- package/build/client/_app/immutable/chunks/a-St0Zwo.js +1 -0
- package/build/client/_app/immutable/chunks/a-St0Zwo.js.br +0 -0
- package/build/client/_app/immutable/chunks/a-St0Zwo.js.gz +0 -0
- package/build/client/_app/immutable/chunks/bo70OQUZ.js +1 -0
- package/build/client/_app/immutable/chunks/bo70OQUZ.js.br +0 -0
- package/build/client/_app/immutable/chunks/bo70OQUZ.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.QvGgdvTI.js +2 -0
- package/build/client/_app/immutable/entry/app.QvGgdvTI.js.br +0 -0
- package/build/client/_app/immutable/entry/app.QvGgdvTI.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BntDNRMC.js +1 -0
- package/build/client/_app/immutable/entry/start.BntDNRMC.js.br +0 -0
- package/build/client/_app/immutable/entry/start.BntDNRMC.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js +1 -0
- package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.CzkdvJ7j.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.MG1QhfrI.js +1 -0
- package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.MG1QhfrI.js.gz +0 -0
- package/build/client/_app/immutable/nodes/2.B4MlOSh6.js +1 -0
- package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.B4MlOSh6.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.DIwYkjDn.js +3 -0
- package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.DIwYkjDn.js.gz +0 -0
- package/build/client/_app/immutable/nodes/4.D-cIe70D.js +1 -0
- package/build/client/_app/immutable/nodes/4.D-cIe70D.js.br +0 -0
- package/build/client/_app/immutable/nodes/4.D-cIe70D.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.D7zPRe3L.js +1 -0
- package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.D7zPRe3L.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.BB7QE48r.js +2 -0
- package/build/client/_app/immutable/nodes/6.BB7QE48r.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.BB7QE48r.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.D8mqsrZG.js +2 -0
- package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.D8mqsrZG.js.gz +0 -0
- package/build/client/_app/version.json +1 -0
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/client/app-icon.png +0 -0
- package/build/client/apple-touch-icon.png +0 -0
- package/build/client/favicon.png +0 -0
- package/build/client/favicon.svg +10 -0
- package/build/client/favicon.svg.br +0 -0
- package/build/client/favicon.svg.gz +0 -0
- package/build/client/manifest.webmanifest +1 -0
- package/build/client/pwa-192x192.png +0 -0
- package/build/client/pwa-512x512.png +0 -0
- package/build/client/registerSW.js +1 -0
- package/build/client/registerSW.js.br +0 -0
- package/build/client/registerSW.js.gz +0 -0
- package/build/client/sw.js +222 -0
- package/build/client/sw.js.br +0 -0
- package/build/client/sw.js.gz +0 -0
- package/build/client/workbox-5119daf5.js +3395 -0
- package/build/client/workbox-5119daf5.js.br +0 -0
- package/build/client/workbox-5119daf5.js.gz +0 -0
- package/build/env.js +94 -0
- package/build/handler.js +1494 -0
- package/build/index.js +345 -0
- package/build/pty-holder.cjs +510 -0
- package/build/server/chunks/0-q2IUp76Y.js +9 -0
- package/build/server/chunks/0-q2IUp76Y.js.map +1 -0
- package/build/server/chunks/1-CU50G5wZ.js +9 -0
- package/build/server/chunks/1-CU50G5wZ.js.map +1 -0
- package/build/server/chunks/2-D01t9s8T.js +9 -0
- package/build/server/chunks/2-D01t9s8T.js.map +1 -0
- package/build/server/chunks/3-5PUQ04wC.js +9 -0
- package/build/server/chunks/3-5PUQ04wC.js.map +1 -0
- package/build/server/chunks/4-e7gywnSG.js +9 -0
- package/build/server/chunks/4-e7gywnSG.js.map +1 -0
- package/build/server/chunks/5-CA1SA6KZ.js +9 -0
- package/build/server/chunks/5-CA1SA6KZ.js.map +1 -0
- package/build/server/chunks/6-71H221sV.js +9 -0
- package/build/server/chunks/6-71H221sV.js.map +1 -0
- package/build/server/chunks/7-Bo-vmdyz.js +9 -0
- package/build/server/chunks/7-Bo-vmdyz.js.map +1 -0
- package/build/server/chunks/_layout.svelte-SFHOxs74.js +132 -0
- package/build/server/chunks/_layout.svelte-SFHOxs74.js.map +1 -0
- package/build/server/chunks/_page.svelte-B4w-2wD-.js +120 -0
- package/build/server/chunks/_page.svelte-B4w-2wD-.js.map +1 -0
- package/build/server/chunks/_page.svelte-B_qAXjkh.js +213 -0
- package/build/server/chunks/_page.svelte-B_qAXjkh.js.map +1 -0
- package/build/server/chunks/_page.svelte-CsF1_TRG.js +50 -0
- package/build/server/chunks/_page.svelte-CsF1_TRG.js.map +1 -0
- package/build/server/chunks/_page.svelte-DJC6U-P0.js +68 -0
- package/build/server/chunks/_page.svelte-DJC6U-P0.js.map +1 -0
- package/build/server/chunks/_page.svelte-DQ6HBtsz.js +407 -0
- package/build/server/chunks/_page.svelte-DQ6HBtsz.js.map +1 -0
- package/build/server/chunks/_page.svelte-LbhhjP21.js +148 -0
- package/build/server/chunks/_page.svelte-LbhhjP21.js.map +1 -0
- package/build/server/chunks/_server.ts-BL2FGb5Z.js +387 -0
- package/build/server/chunks/_server.ts-BL2FGb5Z.js.map +1 -0
- package/build/server/chunks/_server.ts-BgdjBZco.js +47 -0
- package/build/server/chunks/_server.ts-BgdjBZco.js.map +1 -0
- package/build/server/chunks/_server.ts-BihKSdj_.js +59 -0
- package/build/server/chunks/_server.ts-BihKSdj_.js.map +1 -0
- package/build/server/chunks/_server.ts-BjOJsoy4.js +63 -0
- package/build/server/chunks/_server.ts-BjOJsoy4.js.map +1 -0
- package/build/server/chunks/_server.ts-C29xzfaw.js +77 -0
- package/build/server/chunks/_server.ts-C29xzfaw.js.map +1 -0
- package/build/server/chunks/_server.ts-CPa6DgIt.js +71 -0
- package/build/server/chunks/_server.ts-CPa6DgIt.js.map +1 -0
- package/build/server/chunks/_server.ts-CbDRDIoP.js +36 -0
- package/build/server/chunks/_server.ts-CbDRDIoP.js.map +1 -0
- package/build/server/chunks/_server.ts-Cl1OEWL4.js +54 -0
- package/build/server/chunks/_server.ts-Cl1OEWL4.js.map +1 -0
- package/build/server/chunks/_server.ts-ColfDHW8.js +60 -0
- package/build/server/chunks/_server.ts-ColfDHW8.js.map +1 -0
- package/build/server/chunks/_server.ts-Cv_OrRuL.js +494 -0
- package/build/server/chunks/_server.ts-Cv_OrRuL.js.map +1 -0
- package/build/server/chunks/_server.ts-D4MNi4cD.js +25 -0
- package/build/server/chunks/_server.ts-D4MNi4cD.js.map +1 -0
- package/build/server/chunks/_server.ts-DRVbgm6k.js +125 -0
- package/build/server/chunks/_server.ts-DRVbgm6k.js.map +1 -0
- package/build/server/chunks/_server.ts-DfajWaqh.js +39 -0
- package/build/server/chunks/_server.ts-DfajWaqh.js.map +1 -0
- package/build/server/chunks/_server.ts-y9-WYDMa.js +35 -0
- package/build/server/chunks/_server.ts-y9-WYDMa.js.map +1 -0
- package/build/server/chunks/auth-CEgFis71.js +32 -0
- package/build/server/chunks/auth-CEgFis71.js.map +1 -0
- package/build/server/chunks/client-CxCatAKr.js +255 -0
- package/build/server/chunks/client-CxCatAKr.js.map +1 -0
- package/build/server/chunks/error.svelte-BqdwMWdK.js +26 -0
- package/build/server/chunks/error.svelte-BqdwMWdK.js.map +1 -0
- package/build/server/chunks/exports-CJ0Q5XmL.js +4081 -0
- package/build/server/chunks/exports-CJ0Q5XmL.js.map +1 -0
- package/build/server/chunks/index2-DAxIoAO-.js +36 -0
- package/build/server/chunks/index2-DAxIoAO-.js.map +1 -0
- package/build/server/chunks/jsonl-parser-dmZU_Hyu.js +137 -0
- package/build/server/chunks/jsonl-parser-dmZU_Hyu.js.map +1 -0
- package/build/server/chunks/library-apns-BHxLmuIx.js +104 -0
- package/build/server/chunks/library-apns-BHxLmuIx.js.map +1 -0
- package/build/server/chunks/markdown-Bxrl3cCF.js +1241 -0
- package/build/server/chunks/markdown-Bxrl3cCF.js.map +1 -0
- package/build/server/chunks/pending-requests-D8UiTw7L.js +44 -0
- package/build/server/chunks/pending-requests-D8UiTw7L.js.map +1 -0
- package/build/server/chunks/pty-manager-C0FhBiVq.js +1697 -0
- package/build/server/chunks/pty-manager-C0FhBiVq.js.map +1 -0
- package/build/server/chunks/shared-server-BDY8jh20.js +200 -0
- package/build/server/chunks/shared-server-BDY8jh20.js.map +1 -0
- package/build/server/chunks/stores-D0HorpgL.js +36 -0
- package/build/server/chunks/stores-D0HorpgL.js.map +1 -0
- package/build/server/index.js +6466 -0
- package/build/server/index.js.map +1 -0
- package/build/server/manifest.js +184 -0
- package/build/server/manifest.js.map +1 -0
- package/build/shims.js +32 -0
- package/package.json +94 -0
- package/scripts/clipboard-shims/wl-paste +48 -0
- package/scripts/clipboard-shims/xclip +31 -0
- package/scripts/install.sh +477 -0
- package/scripts/setup-node-pty.sh +63 -0
- package/scripts/setup.cjs +571 -0
- package/scripts/test-runner.ts +243 -0
- package/scripts/vercel-env-commands.sh +60 -0
- package/server.ts +139 -0
- package/src/app.css +1835 -0
- package/src/app.d.ts +31 -0
- package/src/app.html +24 -0
- package/src/generated/types/APN.ts +305 -0
- package/src/generated/types/CLI.ts +52 -0
- package/src/generated/types/JWT.ts +92 -0
- package/src/generated/types/Terminal.ts +2736 -0
- package/src/generated/types/index.ts +6 -0
- package/src/lib/assets/icons/alert-triangle.svg +5 -0
- package/src/lib/assets/icons/bell.svg +4 -0
- package/src/lib/assets/icons/check-circle.svg +4 -0
- package/src/lib/assets/icons/file.svg +4 -0
- package/src/lib/assets/icons/folder.svg +3 -0
- package/src/lib/assets/icons/play.svg +3 -0
- package/src/lib/assets/icons/refresh.svg +4 -0
- package/src/lib/assets/icons/settings.svg +4 -0
- package/src/lib/assets/icons/terminal.svg +1 -0
- package/src/lib/assets/icons/tool.svg +3 -0
- package/src/lib/assets/icons/x-circle.svg +5 -0
- package/src/lib/modules/client/common/Card.svelte +26 -0
- package/src/lib/modules/client/common/EmptyState.svelte +36 -0
- package/src/lib/modules/client/common/Icon.svelte +61 -0
- package/src/lib/modules/client/common/StatusBadge.svelte +38 -0
- package/src/lib/modules/client/common/cache.ts +31 -0
- package/src/lib/modules/client/common/config-guard.ts +18 -0
- package/src/lib/modules/client/common/index.ts +12 -0
- package/src/lib/modules/client/common/markdown.ts +23 -0
- package/src/lib/modules/client/common/native-bridge.ts +50 -0
- package/src/lib/modules/client/common/time.ts +22 -0
- package/src/lib/modules/client/common/tool-title.ts +28 -0
- package/src/lib/modules/client/terminal/ChatView.svelte +400 -0
- package/src/lib/modules/client/terminal/CommandPalette.svelte +60 -0
- package/src/lib/modules/client/terminal/ConnectionStatus.svelte +99 -0
- package/src/lib/modules/client/terminal/LaunchSheet.svelte +294 -0
- package/src/lib/modules/client/terminal/QuickKeys.svelte +71 -0
- package/src/lib/modules/client/terminal/ShortcutsHelp.svelte +79 -0
- package/src/lib/modules/client/terminal/keyboard-shortcuts.ts +70 -0
- package/src/lib/modules/client/terminal/xterm-wrapper.ts +243 -0
- package/src/lib/modules/server/apn/library-apns.ts +137 -0
- package/src/lib/modules/server/apn/notification-history.ts +35 -0
- package/src/lib/modules/server/apn/notification-sessions.ts +117 -0
- package/src/lib/modules/server/apn/pending-requests.ts +65 -0
- package/src/lib/modules/server/apn/types.ts +51 -0
- package/src/lib/modules/server/auth.ts +34 -0
- package/src/lib/modules/server/cli/index.ts +79 -0
- package/src/lib/modules/server/cli/runner.ts +162 -0
- package/src/lib/modules/server/fcm/fcm-service.ts +72 -0
- package/src/lib/modules/server/sessions/jsonl-parser.ts +197 -0
- package/src/lib/modules/server/sessions/jsonl-reader.ts +301 -0
- package/src/lib/modules/server/sessions/opencode-reader.ts +264 -0
- package/src/lib/modules/server/sessions/types.ts +53 -0
- package/src/lib/modules/server/terminal/holder-client.ts +273 -0
- package/src/lib/modules/server/terminal/opencode-watcher.ts +661 -0
- package/src/lib/modules/server/terminal/pty-holder.cjs +510 -0
- package/src/lib/modules/server/terminal/pty-manager.ts +1012 -0
- package/src/lib/modules/server/terminal/session-watcher.ts +320 -0
- package/src/lib/modules/server/terminal/terminal-store.ts +198 -0
- package/src/lib/modules/server/ws/events-handler.ts +73 -0
- package/src/lib/modules/server/ws/keepalive.ts +108 -0
- package/src/lib/modules/server/ws/server.ts +93 -0
- package/src/lib/modules/server/ws/session-handler.ts +462 -0
- package/src/lib/modules/server/ws/terminal-handler.ts +197 -0
- package/src/lib/modules/server/ws/ticket-store.ts +58 -0
- package/src/lib/theme.css +529 -0
- package/src/lib/types/config.ts +6 -0
- package/src/routes/+layout.svelte +218 -0
- package/src/routes/+page.svelte +261 -0
- package/src/routes/api/debug/+server.ts +33 -0
- package/src/routes/api/device-token/+server.ts +85 -0
- package/src/routes/api/health/+server.ts +100 -0
- package/src/routes/api/notify/+server.ts +418 -0
- package/src/routes/api/qr-config/+server.ts +45 -0
- package/src/routes/api/response/+server.ts +73 -0
- package/src/routes/api/sessions/+server.ts +120 -0
- package/src/routes/api/terminals/+server.ts +141 -0
- package/src/routes/api/terminals/[id]/+server.ts +75 -0
- package/src/routes/api/terminals/[id]/paste-image/+server.ts +61 -0
- package/src/routes/api/terminals/[id]/resize/+server.ts +60 -0
- package/src/routes/api/webhook/+server.ts +42 -0
- package/src/routes/api/ws-status/+server.ts +23 -0
- package/src/routes/api/ws-ticket/+server.ts +86 -0
- package/src/routes/config/+page.svelte +600 -0
- package/src/routes/project/+page.svelte +274 -0
- package/src/routes/session/[id]/+page.svelte +434 -0
- package/src/routes/terminals/+page.svelte +618 -0
- package/src/routes/terminals/[id]/+page.svelte +968 -0
- package/svelte.config.js +18 -0
- package/tsconfig.json +14 -0
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// pty-holder.cjs — Standalone detached process that owns a single PTY.
|
|
5
|
+
// Spawned by PtyManager via child_process.fork(). Communicates with the
|
|
6
|
+
// server over a Unix domain socket using ndjson (newline-delimited JSON).
|
|
7
|
+
//
|
|
8
|
+
// argv: id socketPath cwd cols rows command [args...]
|
|
9
|
+
|
|
10
|
+
const net = require('net');
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const pty = require('node-pty');
|
|
13
|
+
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// Parse arguments
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
|
|
18
|
+
const [,, id, socketPath, cwd, colsStr, rowsStr, command, ...args] = process.argv;
|
|
19
|
+
|
|
20
|
+
if (!id || !socketPath || !cwd || !colsStr || !rowsStr || !command) {
|
|
21
|
+
process.stderr.write('pty-holder: missing required arguments\n');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const cols = parseInt(colsStr, 10);
|
|
26
|
+
const rows = parseInt(rowsStr, 10);
|
|
27
|
+
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Constants
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
const MAX_SCROLLBACK_LINES = 5000;
|
|
33
|
+
const MAX_INPUT_BYTES = 65_536; // 64 KB — cap per-write to prevent memory abuse
|
|
34
|
+
const GRACE_PERIOD_MS = 60_000; // 60 seconds after PTY exit before self-terminating
|
|
35
|
+
const ACTIVITY_IDLE_MS = 5_000; // 5 seconds of no output → idle
|
|
36
|
+
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
// Scrollback ring buffer
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
const scrollbackChunks = [];
|
|
42
|
+
let scrollbackLineCount = 0;
|
|
43
|
+
|
|
44
|
+
function pushScrollback(data) {
|
|
45
|
+
const newLines = data.split('\n').length - 1;
|
|
46
|
+
scrollbackChunks.push(data);
|
|
47
|
+
scrollbackLineCount += newLines;
|
|
48
|
+
|
|
49
|
+
while (scrollbackLineCount > MAX_SCROLLBACK_LINES && scrollbackChunks.length > 1) {
|
|
50
|
+
const removed = scrollbackChunks.shift();
|
|
51
|
+
if (removed) {
|
|
52
|
+
scrollbackLineCount -= (removed.split('\n').length - 1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function getScrollback() {
|
|
58
|
+
return scrollbackChunks.join('');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
// Clean up stale socket file
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
if (fs.existsSync(socketPath)) {
|
|
67
|
+
fs.unlinkSync(socketPath);
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
// Ignore — may not exist or may be cleaned up already
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Shell hook injection for OSC 7
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
const os = require('os');
|
|
78
|
+
const path = require('path');
|
|
79
|
+
|
|
80
|
+
const OSC7_HOOK = `__shooter_osc7() { printf '\\033]7;file://%s%s\\033\\\\' "$(hostname)" "$PWD"; }`;
|
|
81
|
+
|
|
82
|
+
const SHELL_COMMANDS = ['zsh', 'bash', 'sh', 'fish'];
|
|
83
|
+
const commandBase = command.split('/').pop() || command;
|
|
84
|
+
const ptyEnv = { ...process.env };
|
|
85
|
+
|
|
86
|
+
// Clipboard image paste support: per-terminal clipboard directory
|
|
87
|
+
const clipboardDir = path.join(os.tmpdir(), `shooter-clipboard-${id}`);
|
|
88
|
+
try { fs.mkdirSync(clipboardDir, { recursive: true }); } catch { /* best effort */ }
|
|
89
|
+
ptyEnv.SHOOTER_CLIPBOARD_DIR = clipboardDir;
|
|
90
|
+
|
|
91
|
+
// Prepend clipboard shim scripts to PATH so tools find our xclip/wl-paste
|
|
92
|
+
const shimsDir = path.resolve(__dirname, '..', 'scripts', 'clipboard-shims');
|
|
93
|
+
// Also check relative to cwd for dev mode
|
|
94
|
+
const shimsDir2 = path.resolve(process.cwd(), 'scripts', 'clipboard-shims');
|
|
95
|
+
if (fs.existsSync(shimsDir)) {
|
|
96
|
+
ptyEnv.PATH = `${shimsDir}:${ptyEnv.PATH || ''}`;
|
|
97
|
+
} else if (fs.existsSync(shimsDir2)) {
|
|
98
|
+
ptyEnv.PATH = `${shimsDir2}:${ptyEnv.PATH || ''}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let spawnCommand;
|
|
102
|
+
let spawnArgs;
|
|
103
|
+
|
|
104
|
+
if (SHELL_COMMANDS.includes(commandBase)) {
|
|
105
|
+
if (commandBase === 'zsh' || (commandBase === 'sh' && (process.env.SHELL || '').includes('zsh'))) {
|
|
106
|
+
// zsh: use ZDOTDIR with custom .zshrc
|
|
107
|
+
const zdotdir = path.join(os.tmpdir(), `shooter-zd-${id}`);
|
|
108
|
+
try {
|
|
109
|
+
fs.mkdirSync(zdotdir, { recursive: true });
|
|
110
|
+
const realRc = path.join(process.env.HOME || '', '.zshrc');
|
|
111
|
+
const rcContent = [
|
|
112
|
+
`[ -f "${realRc}" ] && source "${realRc}"`,
|
|
113
|
+
OSC7_HOOK,
|
|
114
|
+
`precmd_functions+=(__shooter_osc7)`,
|
|
115
|
+
'',
|
|
116
|
+
].join('\n');
|
|
117
|
+
fs.writeFileSync(path.join(zdotdir, '.zshrc'), rcContent, 'utf8');
|
|
118
|
+
ptyEnv.ZDOTDIR = zdotdir;
|
|
119
|
+
} catch {
|
|
120
|
+
// Best effort — shell will work without the hook
|
|
121
|
+
}
|
|
122
|
+
spawnCommand = command;
|
|
123
|
+
spawnArgs = args;
|
|
124
|
+
} else if (commandBase === 'bash') {
|
|
125
|
+
// bash: use --rcfile
|
|
126
|
+
const rcPath = path.join(os.tmpdir(), `shooter-rc-${id}.sh`);
|
|
127
|
+
try {
|
|
128
|
+
const realRc = path.join(process.env.HOME || '', '.bashrc');
|
|
129
|
+
const rcContent = [
|
|
130
|
+
`[ -f "${realRc}" ] && source "${realRc}"`,
|
|
131
|
+
OSC7_HOOK,
|
|
132
|
+
`PROMPT_COMMAND="__shooter_osc7\${PROMPT_COMMAND:+;\$PROMPT_COMMAND}"`,
|
|
133
|
+
'',
|
|
134
|
+
].join('\n');
|
|
135
|
+
fs.writeFileSync(rcPath, rcContent, 'utf8');
|
|
136
|
+
} catch {
|
|
137
|
+
// Best effort
|
|
138
|
+
}
|
|
139
|
+
spawnCommand = command;
|
|
140
|
+
spawnArgs = ['--rcfile', rcPath, ...args];
|
|
141
|
+
} else {
|
|
142
|
+
// sh/fish: no hook injection
|
|
143
|
+
spawnCommand = command;
|
|
144
|
+
spawnArgs = args;
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
// Non-shell commands: wrap in login shell
|
|
148
|
+
spawnCommand = null;
|
|
149
|
+
spawnArgs = null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Spawn PTY
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
let ptyProcess;
|
|
157
|
+
|
|
158
|
+
if (spawnCommand) {
|
|
159
|
+
// Interactive shell: spawn directly for proper rc injection
|
|
160
|
+
ptyProcess = pty.spawn(spawnCommand, spawnArgs, {
|
|
161
|
+
cols,
|
|
162
|
+
rows,
|
|
163
|
+
cwd,
|
|
164
|
+
env: ptyEnv,
|
|
165
|
+
name: 'xterm-color',
|
|
166
|
+
});
|
|
167
|
+
} else {
|
|
168
|
+
// Non-shell command: wrap in login shell as before
|
|
169
|
+
const shell = process.env.SHELL || '/bin/zsh';
|
|
170
|
+
const shellEscape = (arg) => `'${arg.replace(/'/g, "'\\''")}'`;
|
|
171
|
+
const fullCommand = [command, ...args].map(shellEscape).join(' ');
|
|
172
|
+
ptyProcess = pty.spawn(shell, ['-l', '-c', fullCommand], {
|
|
173
|
+
cols,
|
|
174
|
+
rows,
|
|
175
|
+
cwd,
|
|
176
|
+
env: ptyEnv,
|
|
177
|
+
name: 'xterm-color',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let exited = false;
|
|
182
|
+
let exitCode = null;
|
|
183
|
+
let exitSignal = null;
|
|
184
|
+
let gracePeriodTimer = null;
|
|
185
|
+
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
// Connected clients (multiple concurrent sockets)
|
|
188
|
+
// ---------------------------------------------------------------------------
|
|
189
|
+
|
|
190
|
+
const clients = new Set();
|
|
191
|
+
|
|
192
|
+
function send(socket, msg) {
|
|
193
|
+
try {
|
|
194
|
+
socket.write(JSON.stringify(msg) + '\n');
|
|
195
|
+
} catch {
|
|
196
|
+
// Socket may have been destroyed
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function broadcast(msg) {
|
|
201
|
+
for (const socket of clients) {
|
|
202
|
+
send(socket, msg);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
// OSC 7 CWD parsing
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
|
|
210
|
+
// Matches: \x1b]7;file://hostname/path\x1b\\ or \x1b]7;file://hostname/path\x07
|
|
211
|
+
const OSC7_RE = /\x1b\]7;file:\/\/[^/]*([^\x07\x1b]*)\x07|\x1b\]7;file:\/\/[^/]*([^\x07\x1b]*)\x1b\\/g;
|
|
212
|
+
|
|
213
|
+
// Buffer for incomplete OSC 7 sequences split across data chunks
|
|
214
|
+
let osc7PartialBuf = '';
|
|
215
|
+
|
|
216
|
+
let currentCwd = cwd; // Initialize with launch cwd
|
|
217
|
+
|
|
218
|
+
function parseOsc7(data) {
|
|
219
|
+
// Prepend any partial OSC 7 sequence from the previous chunk
|
|
220
|
+
const combined = osc7PartialBuf + data;
|
|
221
|
+
osc7PartialBuf = '';
|
|
222
|
+
|
|
223
|
+
// Check for an incomplete trailing OSC 7 sequence (starts with \x1b]7; but
|
|
224
|
+
// no terminator \x07 or \x1b\\ before end of data)
|
|
225
|
+
const lastEsc = combined.lastIndexOf('\x1b]7;');
|
|
226
|
+
if (lastEsc !== -1) {
|
|
227
|
+
const afterEsc = combined.slice(lastEsc);
|
|
228
|
+
if (!afterEsc.includes('\x07') && !afterEsc.includes('\x1b\\')) {
|
|
229
|
+
// Incomplete sequence — buffer it for the next chunk
|
|
230
|
+
osc7PartialBuf = afterEsc;
|
|
231
|
+
// Only parse the portion before the incomplete sequence
|
|
232
|
+
if (lastEsc === 0) return;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const toParse = osc7PartialBuf.length > 0 ? combined.slice(0, -osc7PartialBuf.length) : combined;
|
|
237
|
+
|
|
238
|
+
let match;
|
|
239
|
+
let lastPath = null;
|
|
240
|
+
OSC7_RE.lastIndex = 0;
|
|
241
|
+
while ((match = OSC7_RE.exec(toParse)) !== null) {
|
|
242
|
+
const rawPath = match[1] || match[2] || '';
|
|
243
|
+
let decoded;
|
|
244
|
+
try {
|
|
245
|
+
decoded = decodeURIComponent(rawPath);
|
|
246
|
+
} catch {
|
|
247
|
+
// Malformed percent-encoding — use the raw path as fallback
|
|
248
|
+
decoded = rawPath;
|
|
249
|
+
}
|
|
250
|
+
if (decoded) lastPath = decoded;
|
|
251
|
+
}
|
|
252
|
+
if (lastPath && lastPath !== currentCwd) {
|
|
253
|
+
currentCwd = lastPath;
|
|
254
|
+
broadcast({ type: 'cwd', path: currentCwd });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
// Activity tracking
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
|
|
262
|
+
let isActive = false;
|
|
263
|
+
let activityTimer = null;
|
|
264
|
+
|
|
265
|
+
function touchActivity() {
|
|
266
|
+
if (!isActive) {
|
|
267
|
+
isActive = true;
|
|
268
|
+
broadcast({ type: 'activity', active: true });
|
|
269
|
+
}
|
|
270
|
+
if (activityTimer) clearTimeout(activityTimer);
|
|
271
|
+
activityTimer = setTimeout(() => {
|
|
272
|
+
isActive = false;
|
|
273
|
+
activityTimer = null;
|
|
274
|
+
broadcast({ type: 'activity', active: false });
|
|
275
|
+
}, ACTIVITY_IDLE_MS);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ---------------------------------------------------------------------------
|
|
279
|
+
// PTY event handlers
|
|
280
|
+
// ---------------------------------------------------------------------------
|
|
281
|
+
|
|
282
|
+
ptyProcess.onData((data) => {
|
|
283
|
+
pushScrollback(data);
|
|
284
|
+
touchActivity();
|
|
285
|
+
parseOsc7(data);
|
|
286
|
+
broadcast({ type: 'output', data });
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
ptyProcess.onExit(({ exitCode: code, signal }) => {
|
|
290
|
+
exited = true;
|
|
291
|
+
exitCode = code ?? null;
|
|
292
|
+
exitSignal = signal != null ? String(signal) : null;
|
|
293
|
+
|
|
294
|
+
broadcast({ type: 'exit', code: exitCode, signal: exitSignal });
|
|
295
|
+
|
|
296
|
+
// Write sidecar exit file so the server can detect exits that happened
|
|
297
|
+
// while it was disconnected.
|
|
298
|
+
try {
|
|
299
|
+
const exitData = JSON.stringify({ code: exitCode, timestamp: Date.now() });
|
|
300
|
+
fs.writeFileSync(socketPath + '.exit', exitData, 'utf8');
|
|
301
|
+
} catch {
|
|
302
|
+
// Best effort
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Grace period: stay alive so the server can reconnect and read exit info
|
|
306
|
+
gracePeriodTimer = setTimeout(() => {
|
|
307
|
+
cleanupAndExit();
|
|
308
|
+
}, GRACE_PERIOD_MS);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// ---------------------------------------------------------------------------
|
|
312
|
+
// Unix domain socket server
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
314
|
+
|
|
315
|
+
const server = net.createServer((socket) => {
|
|
316
|
+
clients.add(socket);
|
|
317
|
+
|
|
318
|
+
// On connect: send current state, activity, cwd, and scrollback
|
|
319
|
+
send(socket, { type: 'info', pid: ptyProcess.pid, exited, exitCode });
|
|
320
|
+
send(socket, { type: 'activity', active: isActive });
|
|
321
|
+
if (currentCwd) {
|
|
322
|
+
send(socket, { type: 'cwd', path: currentCwd });
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
const sb = getScrollback();
|
|
326
|
+
if (sb.length > 0) {
|
|
327
|
+
send(socket, { type: 'scrollback', data: sb });
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// If PTY already exited, send exit message and cancel grace timer
|
|
331
|
+
if (exited) {
|
|
332
|
+
send(socket, { type: 'exit', code: exitCode, signal: exitSignal });
|
|
333
|
+
|
|
334
|
+
// Cancel grace period — server has reconnected and received exit info
|
|
335
|
+
if (gracePeriodTimer) {
|
|
336
|
+
clearTimeout(gracePeriodTimer);
|
|
337
|
+
gracePeriodTimer = null;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// Server connected during grace period — it gets exit info via protocol,
|
|
341
|
+
// so delete the sidecar file.
|
|
342
|
+
try {
|
|
343
|
+
const exitFilePath = socketPath + '.exit';
|
|
344
|
+
if (fs.existsSync(exitFilePath)) {
|
|
345
|
+
fs.unlinkSync(exitFilePath);
|
|
346
|
+
}
|
|
347
|
+
} catch {
|
|
348
|
+
// Best effort
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// ndjson line buffer for incoming messages
|
|
353
|
+
let buffer = '';
|
|
354
|
+
|
|
355
|
+
socket.on('data', (chunk) => {
|
|
356
|
+
buffer += chunk.toString();
|
|
357
|
+
let newlineIdx;
|
|
358
|
+
while ((newlineIdx = buffer.indexOf('\n')) !== -1) {
|
|
359
|
+
const line = buffer.slice(0, newlineIdx);
|
|
360
|
+
buffer = buffer.slice(newlineIdx + 1);
|
|
361
|
+
if (line.length === 0) continue;
|
|
362
|
+
|
|
363
|
+
let msg;
|
|
364
|
+
try {
|
|
365
|
+
msg = JSON.parse(line);
|
|
366
|
+
} catch {
|
|
367
|
+
continue; // Skip malformed messages
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
handleMessage(msg);
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
socket.on('error', () => {
|
|
375
|
+
clients.delete(socket);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
socket.on('close', () => {
|
|
379
|
+
clients.delete(socket);
|
|
380
|
+
});
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
function handleMessage(msg) {
|
|
384
|
+
if (!msg || !msg.type) return;
|
|
385
|
+
|
|
386
|
+
switch (msg.type) {
|
|
387
|
+
case 'input':
|
|
388
|
+
// Security note: writing user-provided data to PTY stdin IS the intended
|
|
389
|
+
// behaviour — this is a remote terminal, so input by definition comes from
|
|
390
|
+
// the user. We validate type (must be string) and cap size to satisfy
|
|
391
|
+
// static-analysis scanners and prevent memory abuse.
|
|
392
|
+
if (!exited && typeof msg.data === 'string' && msg.data.length > 0) {
|
|
393
|
+
try {
|
|
394
|
+
const input = msg.data.length > MAX_INPUT_BYTES
|
|
395
|
+
? msg.data.slice(0, MAX_INPUT_BYTES)
|
|
396
|
+
: msg.data;
|
|
397
|
+
ptyProcess.write(input); // CodeQL[js/code-injection] — intentional PTY stdin
|
|
398
|
+
} catch {
|
|
399
|
+
// PTY may have closed between check and write
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
break;
|
|
403
|
+
|
|
404
|
+
case 'resize':
|
|
405
|
+
if (!exited && typeof msg.cols === 'number' && typeof msg.rows === 'number') {
|
|
406
|
+
try {
|
|
407
|
+
ptyProcess.resize(msg.cols, msg.rows);
|
|
408
|
+
} catch {
|
|
409
|
+
// PTY may have closed
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
|
|
414
|
+
case 'kill': {
|
|
415
|
+
if (!exited) {
|
|
416
|
+
const sig = msg.signal || 'SIGTERM';
|
|
417
|
+
try {
|
|
418
|
+
process.kill(ptyProcess.pid, sig);
|
|
419
|
+
} catch {
|
|
420
|
+
// Process may already be gone
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
server.on('error', (err) => {
|
|
429
|
+
process.stderr.write(`pty-holder: socket server error: ${err.message}\n`);
|
|
430
|
+
cleanupAndExit();
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
server.listen(socketPath, () => {
|
|
434
|
+
// Signal parent that the holder is ready
|
|
435
|
+
if (typeof process.send === 'function') {
|
|
436
|
+
process.send({ type: 'ready' });
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// ---------------------------------------------------------------------------
|
|
441
|
+
// Cleanup
|
|
442
|
+
// ---------------------------------------------------------------------------
|
|
443
|
+
|
|
444
|
+
function cleanupAndExit() {
|
|
445
|
+
// Close all client sockets
|
|
446
|
+
for (const socket of clients) {
|
|
447
|
+
try {
|
|
448
|
+
socket.destroy();
|
|
449
|
+
} catch {
|
|
450
|
+
// Best effort
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
clients.clear();
|
|
454
|
+
|
|
455
|
+
// Close the socket server
|
|
456
|
+
try {
|
|
457
|
+
server.close();
|
|
458
|
+
} catch {
|
|
459
|
+
// Best effort
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
// Delete the socket file
|
|
463
|
+
try {
|
|
464
|
+
if (fs.existsSync(socketPath)) {
|
|
465
|
+
fs.unlinkSync(socketPath);
|
|
466
|
+
}
|
|
467
|
+
} catch {
|
|
468
|
+
// Best effort
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Clean up shell hook temp files
|
|
472
|
+
try {
|
|
473
|
+
const zdotdir = path.join(os.tmpdir(), `shooter-zd-${id}`);
|
|
474
|
+
const rcPath = path.join(os.tmpdir(), `shooter-rc-${id}.sh`);
|
|
475
|
+
if (fs.existsSync(path.join(zdotdir, '.zshrc'))) {
|
|
476
|
+
fs.unlinkSync(path.join(zdotdir, '.zshrc'));
|
|
477
|
+
fs.rmdirSync(zdotdir);
|
|
478
|
+
}
|
|
479
|
+
if (fs.existsSync(rcPath)) {
|
|
480
|
+
fs.unlinkSync(rcPath);
|
|
481
|
+
}
|
|
482
|
+
} catch {
|
|
483
|
+
// Best effort
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Clean up clipboard directory
|
|
487
|
+
try {
|
|
488
|
+
const clipImg = path.join(clipboardDir, 'image.png');
|
|
489
|
+
if (fs.existsSync(clipImg)) fs.unlinkSync(clipImg);
|
|
490
|
+
if (fs.existsSync(clipboardDir)) fs.rmdirSync(clipboardDir);
|
|
491
|
+
} catch {
|
|
492
|
+
// Best effort
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
process.exit(0);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Handle signals for clean shutdown
|
|
499
|
+
process.on('SIGTERM', cleanupAndExit);
|
|
500
|
+
process.on('SIGINT', cleanupAndExit);
|
|
501
|
+
|
|
502
|
+
// Prevent unhandled exceptions from crashing silently
|
|
503
|
+
process.on('uncaughtException', (err) => {
|
|
504
|
+
process.stderr.write(`pty-holder[${id}]: uncaught exception: ${err.message}\n`);
|
|
505
|
+
cleanupAndExit();
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
process.on('unhandledRejection', (err) => {
|
|
509
|
+
process.stderr.write(`pty-holder[${id}]: unhandled rejection: ${err}\n`);
|
|
510
|
+
});
|