@juspay/shooter 1.21.0 → 1.23.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 +94 -1
- package/build/client/_app/immutable/assets/2.JWRrnR-w.css +1 -0
- package/build/client/_app/immutable/assets/2.JWRrnR-w.css.br +0 -0
- package/build/client/_app/immutable/assets/2.JWRrnR-w.css.gz +0 -0
- package/build/client/_app/immutable/chunks/{DOEXXmsh.js → Bj5wFimK.js} +2 -2
- package/build/client/_app/immutable/chunks/Bj5wFimK.js.br +0 -0
- package/build/client/_app/immutable/chunks/Bj5wFimK.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{EqMAkEha.js → BjYr_-Ss.js} +1 -1
- package/build/client/_app/immutable/chunks/BjYr_-Ss.js.br +0 -0
- package/build/client/_app/immutable/chunks/BjYr_-Ss.js.gz +0 -0
- package/build/client/_app/immutable/chunks/C4Hns_Wl.js +1 -0
- package/build/client/_app/immutable/chunks/C4Hns_Wl.js.br +0 -0
- package/build/client/_app/immutable/chunks/C4Hns_Wl.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DULfdsh6.js +6 -0
- package/build/client/_app/immutable/chunks/DULfdsh6.js.br +0 -0
- package/build/client/_app/immutable/chunks/DULfdsh6.js.gz +0 -0
- package/build/client/_app/immutable/chunks/{BmfLecb1.js → fcNfTA-E.js} +1 -1
- package/build/client/_app/immutable/chunks/fcNfTA-E.js.br +0 -0
- package/build/client/_app/immutable/chunks/fcNfTA-E.js.gz +0 -0
- package/build/client/_app/immutable/entry/{app.CeSxgGat.js → app.Bvoqymnp.js} +2 -2
- package/build/client/_app/immutable/entry/app.Bvoqymnp.js.br +0 -0
- package/build/client/_app/immutable/entry/app.Bvoqymnp.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.BqXCPPZJ.js +1 -0
- package/build/client/_app/immutable/entry/start.BqXCPPZJ.js.br +2 -0
- package/build/client/_app/immutable/entry/start.BqXCPPZJ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{0.oaPwxh1O.js → 0.Bv_TwEnq.js} +1 -1
- package/build/client/_app/immutable/nodes/0.Bv_TwEnq.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.Bv_TwEnq.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{1.DMPyoM-M.js → 1.7lffTIeb.js} +1 -1
- package/build/client/_app/immutable/nodes/1.7lffTIeb.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.7lffTIeb.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{10.Cbm7nQKK.js → 10.ChiIrIDl.js} +1 -1
- package/build/client/_app/immutable/nodes/10.ChiIrIDl.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.ChiIrIDl.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{11.CKmZjP_a.js → 11.DO3vyXEv.js} +2 -2
- package/build/client/_app/immutable/nodes/11.DO3vyXEv.js.br +0 -0
- package/build/client/_app/immutable/nodes/{11.CKmZjP_a.js.gz → 11.DO3vyXEv.js.gz} +0 -0
- package/build/client/_app/immutable/nodes/2.iMIqsE7n.js +23 -0
- package/build/client/_app/immutable/nodes/2.iMIqsE7n.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.iMIqsE7n.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{3.BgLpGnzb.js → 3.CArnSHOO.js} +1 -1
- package/build/client/_app/immutable/nodes/3.CArnSHOO.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.CArnSHOO.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{5.Avc1-gVb.js → 5.DziEu9rx.js} +1 -1
- package/build/client/_app/immutable/nodes/5.DziEu9rx.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.DziEu9rx.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{6.Dw2wEssJ.js → 6.B8l1RwkB.js} +1 -1
- package/build/client/_app/immutable/nodes/6.B8l1RwkB.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.B8l1RwkB.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{7.DwKZjoBg.js → 7.BPyfhDis.js} +1 -1
- package/build/client/_app/immutable/nodes/7.BPyfhDis.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.BPyfhDis.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{8.ZUAI6g5E.js → 8.D_vszZ9E.js} +1 -1
- package/build/client/_app/immutable/nodes/8.D_vszZ9E.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.D_vszZ9E.js.gz +0 -0
- package/build/client/_app/immutable/nodes/{9.I_KGXPwB.js → 9.Drah-do-.js} +1 -1
- package/build/client/_app/immutable/nodes/9.Drah-do-.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.Drah-do-.js.gz +0 -0
- package/build/client/_app/version.json +1 -1
- package/build/client/_app/version.json.br +0 -0
- package/build/client/_app/version.json.gz +0 -0
- package/build/pty-holder.cjs +6 -0
- package/build/server/chunks/{0-vrTNAfZB.js → 0-DAB_6Vm1.js} +2 -2
- package/build/server/chunks/{0-vrTNAfZB.js.map → 0-DAB_6Vm1.js.map} +1 -1
- package/build/server/chunks/{1-nbr-bOoF.js → 1-D-qMYaCx.js} +2 -2
- package/build/server/chunks/{1-nbr-bOoF.js.map → 1-D-qMYaCx.js.map} +1 -1
- package/build/server/chunks/{10-ChyvvJ6w.js → 10-CeFFGo-X.js} +2 -2
- package/build/server/chunks/{10-ChyvvJ6w.js.map → 10-CeFFGo-X.js.map} +1 -1
- package/build/server/chunks/{11-6ZAjL3uU.js → 11-DRMu_ATU.js} +2 -2
- package/build/server/chunks/{11-6ZAjL3uU.js.map → 11-DRMu_ATU.js.map} +1 -1
- package/build/server/chunks/{2-DWFRVDWJ.js → 2-B7OLBMNH.js} +4 -4
- package/build/server/chunks/{2-DWFRVDWJ.js.map → 2-B7OLBMNH.js.map} +1 -1
- package/build/server/chunks/{3-CKANM_WM.js → 3-B38ZarLw.js} +2 -2
- package/build/server/chunks/{3-CKANM_WM.js.map → 3-B38ZarLw.js.map} +1 -1
- package/build/server/chunks/{5-BxVjs2qi.js → 5-D-Uv1voC.js} +2 -2
- package/build/server/chunks/{5-BxVjs2qi.js.map → 5-D-Uv1voC.js.map} +1 -1
- package/build/server/chunks/{6-Cbf1AAMQ.js → 6-DP46cUej.js} +2 -2
- package/build/server/chunks/{6-Cbf1AAMQ.js.map → 6-DP46cUej.js.map} +1 -1
- package/build/server/chunks/{7-CMK2quEf.js → 7-B29_3ar6.js} +2 -2
- package/build/server/chunks/{7-CMK2quEf.js.map → 7-B29_3ar6.js.map} +1 -1
- package/build/server/chunks/{8-DhdfkfDM.js → 8-DCnSDVrX.js} +2 -2
- package/build/server/chunks/{8-DhdfkfDM.js.map → 8-DCnSDVrX.js.map} +1 -1
- package/build/server/chunks/{9-CPpxtRM5.js → 9-BwqDc8wC.js} +2 -2
- package/build/server/chunks/{9-CPpxtRM5.js.map → 9-BwqDc8wC.js.map} +1 -1
- package/build/server/chunks/_page.svelte-8OFzwdNA.js +758 -0
- package/build/server/chunks/_page.svelte-8OFzwdNA.js.map +1 -0
- package/build/server/chunks/{_server.ts-BWVlO8iV.js → _server.ts-05JJOdcX.js} +15 -12
- package/build/server/chunks/_server.ts-05JJOdcX.js.map +1 -0
- package/build/server/chunks/{_server.ts-BevnuePu.js → _server.ts-BCljU9Sg.js} +7 -3
- package/build/server/chunks/_server.ts-BCljU9Sg.js.map +1 -0
- package/build/server/chunks/{_server.ts-D-vgx5UZ.js → _server.ts-BTmknWpO.js} +2 -2
- package/build/server/chunks/{_server.ts-D-vgx5UZ.js.map → _server.ts-BTmknWpO.js.map} +1 -1
- package/build/server/chunks/{_server.ts-tChyh9FX.js → _server.ts-BXhmLZwN.js} +4 -2
- package/build/server/chunks/{_server.ts-tChyh9FX.js.map → _server.ts-BXhmLZwN.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CvJKTS3Z.js → _server.ts-BbRSpB74.js} +4 -2
- package/build/server/chunks/{_server.ts-CvJKTS3Z.js.map → _server.ts-BbRSpB74.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CC2K8-L2.js → _server.ts-Blx6TuRU.js} +4 -2
- package/build/server/chunks/_server.ts-Blx6TuRU.js.map +1 -0
- package/build/server/chunks/_server.ts-C6NRpe7e.js +33 -0
- package/build/server/chunks/_server.ts-C6NRpe7e.js.map +1 -0
- package/build/server/chunks/_server.ts-CGqCOCdK.js +53 -0
- package/build/server/chunks/_server.ts-CGqCOCdK.js.map +1 -0
- package/build/server/chunks/{_server.ts-X1R7L_QI.js → _server.ts-CYWXjihn.js} +4 -2
- package/build/server/chunks/{_server.ts-X1R7L_QI.js.map → _server.ts-CYWXjihn.js.map} +1 -1
- package/build/server/chunks/{_server.ts-CD7JP3fz.js → _server.ts-D0___krA.js} +4 -2
- package/build/server/chunks/_server.ts-D0___krA.js.map +1 -0
- package/build/server/chunks/{_server.ts-VzDcFFgy.js → _server.ts-DPHRUFYS.js} +4 -2
- package/build/server/chunks/_server.ts-DPHRUFYS.js.map +1 -0
- package/build/server/chunks/{_server.ts-D0zRDSx0.js → _server.ts-D_WRex0k.js} +4 -2
- package/build/server/chunks/_server.ts-D_WRex0k.js.map +1 -0
- package/build/server/chunks/{_server.ts-CA5KUENM.js → _server.ts-Da1kSClZ.js} +4 -2
- package/build/server/chunks/_server.ts-Da1kSClZ.js.map +1 -0
- package/build/server/chunks/{_server.ts-Dp-hXW_I.js → _server.ts-l3cd4Cto.js} +4 -2
- package/build/server/chunks/_server.ts-l3cd4Cto.js.map +1 -0
- package/build/server/chunks/{library-apns-Dl3iRE2h.js → library-apns-D8RPINlv.js} +62 -7
- package/build/server/chunks/library-apns-D8RPINlv.js.map +1 -0
- package/build/server/chunks/{pending-requests-C9p57WoU.js → pending-requests-8rWjrF6d.js} +3 -2
- package/build/server/chunks/pending-requests-8rWjrF6d.js.map +1 -0
- package/build/server/chunks/presence-store-Bx_g0-Gd.js +23 -0
- package/build/server/chunks/presence-store-Bx_g0-Gd.js.map +1 -0
- package/build/server/chunks/{pty-manager-ZqXqa-6A.js → pty-manager-DDjG7DlH.js} +297 -31
- package/build/server/chunks/pty-manager-DDjG7DlH.js.map +1 -0
- package/build/server/chunks/shooter-home-4f_HkdGI.js +10 -0
- package/build/server/chunks/shooter-home-4f_HkdGI.js.map +1 -0
- package/build/server/index.js +1 -1
- package/build/server/index.js.map +1 -1
- package/build/server/manifest.js +38 -24
- package/build/server/manifest.js.map +1 -1
- package/package.json +4 -2
- package/server.ts +2 -2
- package/src/lib/modules/client/common/index.ts +1 -0
- package/src/lib/modules/client/common/presence.ts +47 -0
- package/src/lib/modules/client/dashboard/AutopilotPanel.svelte +188 -4
- package/src/lib/modules/client/dashboard/autopilot-driver.svelte.ts +681 -0
- package/src/lib/modules/client/dashboard/decide-injection.ts +127 -0
- package/src/lib/modules/client/dashboard/store.svelte.ts +65 -24
- package/src/lib/modules/client/neurolink/fetch-proxy.ts +38 -1
- package/src/lib/modules/client/terminal/xterm-wrapper.ts +52 -12
- package/src/lib/modules/server/apn/apns-payload.ts +50 -0
- package/src/lib/modules/server/apn/library-apns.ts +50 -8
- package/src/lib/modules/server/apn/pending-requests.ts +3 -1
- package/src/lib/modules/server/sessions/autopilot-context.ts +57 -0
- package/src/lib/modules/server/sessions/autopilot-engine.ts +148 -43
- package/src/lib/modules/server/sessions/litellm-client.ts +90 -34
- package/src/lib/modules/server/sessions/next-step-consensus.ts +27 -2
- package/src/lib/modules/server/sessions/summary-store.ts +3 -1
- package/src/lib/modules/server/terminal/agent-launch.ts +26 -0
- package/src/lib/modules/server/terminal/pty-holder.cjs +6 -0
- package/src/lib/modules/server/terminal/pty-manager.ts +292 -38
- package/src/lib/modules/server/terminal/session-watcher.ts +12 -2
- package/src/lib/modules/server/terminal/terminal-emulator.ts +102 -0
- package/src/lib/modules/server/terminal/terminal-store.ts +3 -1
- package/src/lib/modules/server/utils/shooter-home.ts +16 -0
- package/src/lib/modules/server/ws/presence-store.ts +50 -0
- package/src/lib/modules/server/ws/server.ts +18 -2
- package/src/lib/modules/server/ws/terminal-handler.ts +11 -6
- package/src/lib/types/autopilot.ts +65 -0
- package/src/lib/types/generated/WsProtocol.ts +10 -1
- package/src/lib/types/server.ts +27 -1
- package/src/lib/types/terminal-client.ts +3 -0
- package/src/lib/types/ws.ts +3 -2
- package/src/routes/api/autopilot/goal/+server.ts +72 -0
- package/src/routes/api/neurolink-proxy/+server.ts +8 -2
- package/src/routes/api/notify/+server.ts +22 -15
- package/src/routes/api/presence/+server.ts +39 -0
- package/src/routes/api/ws-status/+server.ts +8 -5
- package/build/client/_app/immutable/assets/2.BHi6pjT2.css +0 -1
- package/build/client/_app/immutable/assets/2.BHi6pjT2.css.br +0 -0
- package/build/client/_app/immutable/assets/2.BHi6pjT2.css.gz +0 -0
- package/build/client/_app/immutable/chunks/BmfLecb1.js.br +0 -0
- package/build/client/_app/immutable/chunks/BmfLecb1.js.gz +0 -0
- package/build/client/_app/immutable/chunks/CRkG7oE4.js +0 -1
- package/build/client/_app/immutable/chunks/CRkG7oE4.js.br +0 -0
- package/build/client/_app/immutable/chunks/CRkG7oE4.js.gz +0 -0
- package/build/client/_app/immutable/chunks/DOEXXmsh.js.br +0 -0
- package/build/client/_app/immutable/chunks/DOEXXmsh.js.gz +0 -0
- package/build/client/_app/immutable/chunks/EqMAkEha.js.br +0 -0
- package/build/client/_app/immutable/chunks/EqMAkEha.js.gz +0 -0
- package/build/client/_app/immutable/chunks/J5-Cr5oR.js +0 -6
- package/build/client/_app/immutable/chunks/J5-Cr5oR.js.br +0 -0
- package/build/client/_app/immutable/chunks/J5-Cr5oR.js.gz +0 -0
- package/build/client/_app/immutable/entry/app.CeSxgGat.js.br +0 -0
- package/build/client/_app/immutable/entry/app.CeSxgGat.js.gz +0 -0
- package/build/client/_app/immutable/entry/start.DrnJFwxA.js +0 -1
- package/build/client/_app/immutable/entry/start.DrnJFwxA.js.br +0 -2
- package/build/client/_app/immutable/entry/start.DrnJFwxA.js.gz +0 -0
- package/build/client/_app/immutable/nodes/0.oaPwxh1O.js.br +0 -0
- package/build/client/_app/immutable/nodes/0.oaPwxh1O.js.gz +0 -0
- package/build/client/_app/immutable/nodes/1.DMPyoM-M.js.br +0 -0
- package/build/client/_app/immutable/nodes/1.DMPyoM-M.js.gz +0 -0
- package/build/client/_app/immutable/nodes/10.Cbm7nQKK.js.br +0 -0
- package/build/client/_app/immutable/nodes/10.Cbm7nQKK.js.gz +0 -0
- package/build/client/_app/immutable/nodes/11.CKmZjP_a.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.zlrdNFtH.js +0 -13
- package/build/client/_app/immutable/nodes/2.zlrdNFtH.js.br +0 -0
- package/build/client/_app/immutable/nodes/2.zlrdNFtH.js.gz +0 -0
- package/build/client/_app/immutable/nodes/3.BgLpGnzb.js.br +0 -0
- package/build/client/_app/immutable/nodes/3.BgLpGnzb.js.gz +0 -0
- package/build/client/_app/immutable/nodes/5.Avc1-gVb.js.br +0 -0
- package/build/client/_app/immutable/nodes/5.Avc1-gVb.js.gz +0 -0
- package/build/client/_app/immutable/nodes/6.Dw2wEssJ.js.br +0 -0
- package/build/client/_app/immutable/nodes/6.Dw2wEssJ.js.gz +0 -0
- package/build/client/_app/immutable/nodes/7.DwKZjoBg.js.br +0 -0
- package/build/client/_app/immutable/nodes/7.DwKZjoBg.js.gz +0 -0
- package/build/client/_app/immutable/nodes/8.ZUAI6g5E.js.br +0 -0
- package/build/client/_app/immutable/nodes/8.ZUAI6g5E.js.gz +0 -0
- package/build/client/_app/immutable/nodes/9.I_KGXPwB.js.br +0 -0
- package/build/client/_app/immutable/nodes/9.I_KGXPwB.js.gz +0 -0
- package/build/server/chunks/_page.svelte-tBuIq8Pg.js +0 -159
- package/build/server/chunks/_page.svelte-tBuIq8Pg.js.map +0 -1
- package/build/server/chunks/_server.ts-BWVlO8iV.js.map +0 -1
- package/build/server/chunks/_server.ts-BevnuePu.js.map +0 -1
- package/build/server/chunks/_server.ts-CA5KUENM.js.map +0 -1
- package/build/server/chunks/_server.ts-CC2K8-L2.js.map +0 -1
- package/build/server/chunks/_server.ts-CD7JP3fz.js.map +0 -1
- package/build/server/chunks/_server.ts-D0zRDSx0.js.map +0 -1
- package/build/server/chunks/_server.ts-Dp-hXW_I.js.map +0 -1
- package/build/server/chunks/_server.ts-VzDcFFgy.js.map +0 -1
- package/build/server/chunks/library-apns-Dl3iRE2h.js.map +0 -1
- package/build/server/chunks/pending-requests-C9p57WoU.js.map +0 -1
- package/build/server/chunks/pty-manager-ZqXqa-6A.js.map +0 -1
|
@@ -0,0 +1,758 @@
|
|
|
1
|
+
import { aw as head, au as escape_html, a6 as derived, ax as ensure_array_like } from './index-CoYB03g7.js';
|
|
2
|
+
import { g as goto } from './client-Ds1brw-8.js';
|
|
3
|
+
import { E as EmptyState, R as RefreshSvg, c as clearCache } from './cache-BlMaDsHi.js';
|
|
4
|
+
import { S as SettingsSvg } from './settings-Dv3Esboo.js';
|
|
5
|
+
import './markdown-W_mTBct0.js';
|
|
6
|
+
import { o as onDestroy } from './index-server-Bq3cnK69.js';
|
|
7
|
+
import { B as Button } from './Button-D0hZ7JYt.js';
|
|
8
|
+
import { I as Icon } from './Icon-D0GBnDcs.js';
|
|
9
|
+
import { S as Shimmer } from './Shimmer-Dw2uvTC1.js';
|
|
10
|
+
import { S as SvelteMap, a as SvelteSet } from './index-server2-BJrT0wnA.js';
|
|
11
|
+
import './root-D4IoFC8F.js';
|
|
12
|
+
import './index2-dSGQ9Eaa.js';
|
|
13
|
+
import './state.svelte-CmHqngc_.js';
|
|
14
|
+
import 'dompurify';
|
|
15
|
+
import 'marked';
|
|
16
|
+
|
|
17
|
+
const DEFAULT_INJECTION_POLICY = {
|
|
18
|
+
humanGraceMs: 5e3,
|
|
19
|
+
injectConfidence: 0.7,
|
|
20
|
+
maxAutoActions: 8,
|
|
21
|
+
minIntervalMs: 3e4
|
|
22
|
+
};
|
|
23
|
+
const MAX_COMMAND_LENGTH = 400;
|
|
24
|
+
const DANGEROUS_PATTERNS = [
|
|
25
|
+
/\brm\s+-[a-z]*r[a-z]*f?\s+(\/|~|\/\*|\$home)/i,
|
|
26
|
+
// rm -rf /, rm -rf ~, rm -rf /*
|
|
27
|
+
/\brm\s+-[a-z]*f[a-z]*r?\s+(\/|~|\/\*|\$home)/i,
|
|
28
|
+
// rm -fr variants
|
|
29
|
+
/:\(\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;\s*:/,
|
|
30
|
+
// classic fork bomb :(){ :|:& };:
|
|
31
|
+
/\bdd\b[^\n]*\bof=\/dev\//i,
|
|
32
|
+
// dd of=/dev/...
|
|
33
|
+
/>\s*\/dev\/(sd|nvme|disk|hd)/i,
|
|
34
|
+
// redirect onto a raw disk
|
|
35
|
+
/\bmkfs(\.[a-z0-9]+)?\b/i,
|
|
36
|
+
// mkfs, mkfs.ext4, ...
|
|
37
|
+
/\b(shutdown|reboot|halt|poweroff)\b/i
|
|
38
|
+
// power state
|
|
39
|
+
];
|
|
40
|
+
function decideInjection(state, consensus, now, policy = DEFAULT_INJECTION_POLICY, opts = {}) {
|
|
41
|
+
const top = consensus.steps[0];
|
|
42
|
+
if (!top) {
|
|
43
|
+
return { act: false, reason: "no consensus step" };
|
|
44
|
+
}
|
|
45
|
+
if (top.tentative && !opts.allowTentative) {
|
|
46
|
+
return { act: false, reason: "consensus is tentative (no quorum)" };
|
|
47
|
+
}
|
|
48
|
+
if (!state.isManaged) {
|
|
49
|
+
return { act: false, reason: "terminal is external / read-only (cannot inject)" };
|
|
50
|
+
}
|
|
51
|
+
if (state.lastEventType !== "agent-idle") {
|
|
52
|
+
return { act: false, reason: `agent not idle (last event: ${state.lastEventType})` };
|
|
53
|
+
}
|
|
54
|
+
if (now - state.lastActivityAt < policy.humanGraceMs) {
|
|
55
|
+
return { act: false, reason: "recent activity — within human grace window" };
|
|
56
|
+
}
|
|
57
|
+
if (now - state.lastInjectedAt < policy.minIntervalMs) {
|
|
58
|
+
return { act: false, reason: "rate-limited (min inject interval)" };
|
|
59
|
+
}
|
|
60
|
+
if (state.autoActionCount >= policy.maxAutoActions) {
|
|
61
|
+
return { act: false, reason: "circuit breaker — max consecutive auto-actions reached" };
|
|
62
|
+
}
|
|
63
|
+
if (top.confidence < policy.injectConfidence) {
|
|
64
|
+
return { act: false, reason: `confidence ${top.confidence.toFixed(2)} below floor` };
|
|
65
|
+
}
|
|
66
|
+
if (state.lastActedStep !== null && normalizeStep(top.text) === state.lastActedStep) {
|
|
67
|
+
return { act: false, reason: "already acted on this step" };
|
|
68
|
+
}
|
|
69
|
+
return { act: true, reason: "idle + high-confidence consensus", step: top };
|
|
70
|
+
}
|
|
71
|
+
function guardCommand(command, lastInjectedCommand) {
|
|
72
|
+
const trimmed = command.trim();
|
|
73
|
+
if (trimmed.length === 0) {
|
|
74
|
+
return { command: trimmed, reason: "empty command", safe: false };
|
|
75
|
+
}
|
|
76
|
+
if (/[\r\n]/.test(command)) {
|
|
77
|
+
return {
|
|
78
|
+
command: trimmed,
|
|
79
|
+
reason: "multi-line command rejected (single command only)",
|
|
80
|
+
safe: false
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
if (trimmed.length > MAX_COMMAND_LENGTH) {
|
|
84
|
+
return { command: trimmed, reason: `command too long (> ${MAX_COMMAND_LENGTH})`, safe: false };
|
|
85
|
+
}
|
|
86
|
+
for (const pattern of DANGEROUS_PATTERNS) {
|
|
87
|
+
if (pattern.test(trimmed)) {
|
|
88
|
+
return { command: trimmed, reason: "matches a dangerous-command pattern", safe: false };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (lastInjectedCommand !== null && trimmed === lastInjectedCommand.trim()) {
|
|
92
|
+
return { command: trimmed, reason: "duplicate of last injected command", safe: false };
|
|
93
|
+
}
|
|
94
|
+
return { command: trimmed, reason: "ok", safe: true };
|
|
95
|
+
}
|
|
96
|
+
function normalizeStep(text) {
|
|
97
|
+
return text.toLowerCase().trim().replace(/\s+/g, " ").replace(/[.,;:!?]+$/, "");
|
|
98
|
+
}
|
|
99
|
+
const AUTONOMY_KEY = "shooter_autonomy";
|
|
100
|
+
const POLL_INTERVAL_MS = 6e3;
|
|
101
|
+
const RECONNECT_MS = 3e3;
|
|
102
|
+
const OPEN_TIMEOUT_MS = 5e3;
|
|
103
|
+
const MAX_ACTIONS = 40;
|
|
104
|
+
const IDLE_RESUME_WINDOW_MS = 12e4;
|
|
105
|
+
const AGENT_SUBMIT_DELAY_MS = 120;
|
|
106
|
+
const SAFE_ID = /^[A-Za-z0-9_-]+$/;
|
|
107
|
+
const SAFE_COMMAND_HEADS = /* @__PURE__ */ new Set([
|
|
108
|
+
"bun",
|
|
109
|
+
"cargo",
|
|
110
|
+
"cat",
|
|
111
|
+
"deno",
|
|
112
|
+
"echo",
|
|
113
|
+
"eslint",
|
|
114
|
+
"git",
|
|
115
|
+
"go",
|
|
116
|
+
"jest",
|
|
117
|
+
"ls",
|
|
118
|
+
"make",
|
|
119
|
+
"node",
|
|
120
|
+
"npm",
|
|
121
|
+
"npx",
|
|
122
|
+
"pnpm",
|
|
123
|
+
"prettier",
|
|
124
|
+
"pwd",
|
|
125
|
+
"python",
|
|
126
|
+
"python3",
|
|
127
|
+
"tsc",
|
|
128
|
+
"vitest",
|
|
129
|
+
"yarn"
|
|
130
|
+
]);
|
|
131
|
+
const AGENT_COMMANDS = /* @__PURE__ */ new Set(["claude", "opencode"]);
|
|
132
|
+
class AutopilotDriver {
|
|
133
|
+
actions = [];
|
|
134
|
+
enabled = false;
|
|
135
|
+
apiKey = "";
|
|
136
|
+
deps;
|
|
137
|
+
eventsWs = null;
|
|
138
|
+
pollTimer = null;
|
|
139
|
+
reconnectTimer = null;
|
|
140
|
+
started = false;
|
|
141
|
+
// eslint-disable-next-line svelte/prefer-svelte-reactivity -- internal, non-reactive bookkeeping
|
|
142
|
+
terminals = /* @__PURE__ */ new Map();
|
|
143
|
+
constructor(deps) {
|
|
144
|
+
this.deps = {
|
|
145
|
+
now: deps?.now ?? (() => Date.now()),
|
|
146
|
+
produceCommand: deps?.produceCommand ?? defaultProduceCommand
|
|
147
|
+
};
|
|
148
|
+
this.enabled = readPersistedAutonomy();
|
|
149
|
+
}
|
|
150
|
+
setEnabled(value) {
|
|
151
|
+
this.enabled = value;
|
|
152
|
+
try {
|
|
153
|
+
localStorage.setItem(AUTONOMY_KEY, JSON.stringify({ enabled: value }));
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
start(apiKey) {
|
|
158
|
+
this.apiKey = apiKey;
|
|
159
|
+
if (this.started) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this.started = true;
|
|
163
|
+
if (typeof window !== "undefined") {
|
|
164
|
+
window.addEventListener("shooter:wake", this.onWake);
|
|
165
|
+
}
|
|
166
|
+
void this.connectEvents();
|
|
167
|
+
void this.refresh();
|
|
168
|
+
this.pollTimer = setInterval(() => void this.refresh(), POLL_INTERVAL_MS);
|
|
169
|
+
}
|
|
170
|
+
stop() {
|
|
171
|
+
this.started = false;
|
|
172
|
+
if (typeof window !== "undefined") {
|
|
173
|
+
window.removeEventListener("shooter:wake", this.onWake);
|
|
174
|
+
}
|
|
175
|
+
if (this.pollTimer) {
|
|
176
|
+
clearInterval(this.pollTimer);
|
|
177
|
+
this.pollTimer = null;
|
|
178
|
+
}
|
|
179
|
+
if (this.reconnectTimer) {
|
|
180
|
+
clearTimeout(this.reconnectTimer);
|
|
181
|
+
this.reconnectTimer = null;
|
|
182
|
+
}
|
|
183
|
+
if (this.eventsWs) {
|
|
184
|
+
this.eventsWs.onclose = null;
|
|
185
|
+
this.eventsWs.close();
|
|
186
|
+
this.eventsWs = null;
|
|
187
|
+
}
|
|
188
|
+
for (const rt of this.terminals.values()) {
|
|
189
|
+
rt.injectSocket?.close();
|
|
190
|
+
rt.injectSocket = null;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async connectEvents() {
|
|
194
|
+
const ticket = await this.getTicket();
|
|
195
|
+
if (!ticket || !this.started) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const wsBase = window.location.origin.replace(/^http/, "ws");
|
|
199
|
+
const ws = new WebSocket(`${wsBase}/ws/events?ticket=${ticket}`);
|
|
200
|
+
this.eventsWs = ws;
|
|
201
|
+
ws.onmessage = (msg) => {
|
|
202
|
+
try {
|
|
203
|
+
const raw = JSON.parse(msg.data);
|
|
204
|
+
if (raw && typeof raw === "object") {
|
|
205
|
+
this.handleEvent(raw);
|
|
206
|
+
}
|
|
207
|
+
} catch {
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
ws.onclose = () => {
|
|
211
|
+
this.eventsWs = null;
|
|
212
|
+
if (this.started) {
|
|
213
|
+
this.scheduleReconnect();
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
ws.onerror = () => {
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
createRuntime(terminalId) {
|
|
220
|
+
const rt = {
|
|
221
|
+
autoActionCount: 0,
|
|
222
|
+
busy: false,
|
|
223
|
+
command: "",
|
|
224
|
+
consensus: null,
|
|
225
|
+
injectSocket: null,
|
|
226
|
+
isManaged: false,
|
|
227
|
+
lastActedStep: null,
|
|
228
|
+
lastActivityAt: 0,
|
|
229
|
+
lastCommand: null,
|
|
230
|
+
lastEventAt: 0,
|
|
231
|
+
lastEventType: "",
|
|
232
|
+
lastInjectedAt: 0,
|
|
233
|
+
recentOutput: ""
|
|
234
|
+
};
|
|
235
|
+
this.terminals.set(terminalId, rt);
|
|
236
|
+
return rt;
|
|
237
|
+
}
|
|
238
|
+
async evaluate(terminalId) {
|
|
239
|
+
if (!this.enabled) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const rt = this.terminals.get(terminalId);
|
|
243
|
+
if (!rt || rt.busy || !rt.consensus) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const state = {
|
|
247
|
+
autoActionCount: rt.autoActionCount,
|
|
248
|
+
isManaged: rt.isManaged,
|
|
249
|
+
lastActedStep: rt.lastActedStep,
|
|
250
|
+
lastActivityAt: rt.lastActivityAt,
|
|
251
|
+
lastEventType: rt.lastEventType,
|
|
252
|
+
lastInjectedAt: rt.lastInjectedAt
|
|
253
|
+
};
|
|
254
|
+
const decision = decideInjection(state, rt.consensus, this.deps.now(), void 0, { allowTentative: isAgentCommand(rt.command) });
|
|
255
|
+
if (!decision.act || !decision.step) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
rt.busy = true;
|
|
259
|
+
try {
|
|
260
|
+
const isAgent = isAgentCommand(rt.command);
|
|
261
|
+
let command;
|
|
262
|
+
try {
|
|
263
|
+
command = await this.deps.produceCommand({
|
|
264
|
+
apiKey: this.apiKey,
|
|
265
|
+
isAgentTerminal: isAgent,
|
|
266
|
+
recentOutput: rt.recentOutput,
|
|
267
|
+
step: decision.step,
|
|
268
|
+
terminalId
|
|
269
|
+
});
|
|
270
|
+
} catch {
|
|
271
|
+
command = null;
|
|
272
|
+
}
|
|
273
|
+
if (!command) {
|
|
274
|
+
this.log(terminalId, "skipped", `no command for: ${decision.step.text.slice(0, 60)}`);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const candidate = isAgent ? command.replace(/\s*[\r\n]+\s*/g, " ").trim() : command;
|
|
278
|
+
const verdict = guardCommand(candidate, rt.lastCommand);
|
|
279
|
+
if (!verdict.safe) {
|
|
280
|
+
rt.lastActedStep = normalizeStep(decision.step.text);
|
|
281
|
+
this.log(terminalId, "skipped", `guard: ${verdict.reason}`);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
const ok = await this.inject(terminalId, verdict.command);
|
|
285
|
+
if (ok) {
|
|
286
|
+
rt.lastInjectedAt = this.deps.now();
|
|
287
|
+
rt.lastCommand = verdict.command;
|
|
288
|
+
rt.lastActedStep = normalizeStep(decision.step.text);
|
|
289
|
+
rt.autoActionCount += 1;
|
|
290
|
+
this.log(terminalId, "injected", verdict.command);
|
|
291
|
+
} else {
|
|
292
|
+
this.log(terminalId, "error", `inject failed: ${verdict.command}`);
|
|
293
|
+
}
|
|
294
|
+
} finally {
|
|
295
|
+
rt.busy = false;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
async fetchSummaries() {
|
|
299
|
+
try {
|
|
300
|
+
const res = await fetch("/api/summaries?limit=30", { headers: { Authorization: `Bearer ${this.apiKey}` } });
|
|
301
|
+
if (!res.ok) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const body = await res.json();
|
|
305
|
+
const latest = /* @__PURE__ */ new Set();
|
|
306
|
+
for (const rec of body.summaries ?? []) {
|
|
307
|
+
const tid = rec.terminalId;
|
|
308
|
+
if (!tid || latest.has(tid)) {
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
const rt = this.terminals.get(tid);
|
|
312
|
+
if (!rt) {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
latest.add(tid);
|
|
316
|
+
rt.consensus = { agentCount: 5, quorum: 3, steps: parseSteps(rec.nextSteps) };
|
|
317
|
+
const createdMs = Date.parse(rec.createdAt);
|
|
318
|
+
if (rec.trigger === "agent-idle" && Number.isFinite(createdMs) && createdMs >= rt.lastEventAt && this.deps.now() - createdMs < IDLE_RESUME_WINDOW_MS) {
|
|
319
|
+
rt.lastEventType = "agent-idle";
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
} catch {
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
async fetchTerminals() {
|
|
326
|
+
try {
|
|
327
|
+
const res = await fetch("/api/terminals", { headers: { Authorization: `Bearer ${this.apiKey}` } });
|
|
328
|
+
if (!res.ok) {
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const body = await res.json();
|
|
332
|
+
const seen = /* @__PURE__ */ new Set();
|
|
333
|
+
for (const t of body.terminals ?? []) {
|
|
334
|
+
if (t.exitedAt !== null || t.status === "exited") {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
seen.add(t.id);
|
|
338
|
+
const rt = this.terminals.get(t.id) ?? this.createRuntime(t.id);
|
|
339
|
+
rt.isManaged = true;
|
|
340
|
+
rt.command = t.command ?? "";
|
|
341
|
+
}
|
|
342
|
+
for (const id of [...this.terminals.keys()]) {
|
|
343
|
+
if (!seen.has(id)) {
|
|
344
|
+
this.terminals.get(id)?.injectSocket?.close();
|
|
345
|
+
this.terminals.delete(id);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
} catch {
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
async getTicket() {
|
|
352
|
+
try {
|
|
353
|
+
const res = await fetch("/api/ws-ticket", {
|
|
354
|
+
headers: { Authorization: `Bearer ${this.apiKey}` },
|
|
355
|
+
method: "POST"
|
|
356
|
+
});
|
|
357
|
+
if (!res.ok) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
const { ticket } = await res.json();
|
|
361
|
+
return ticket;
|
|
362
|
+
} catch {
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
handleEvent(raw) {
|
|
367
|
+
const type = typeof raw.type === "string" ? raw.type : "";
|
|
368
|
+
const terminalId = typeof raw.terminalId === "string" ? raw.terminalId : "";
|
|
369
|
+
if (!type || type === "welcome" || !terminalId) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const rt = this.terminals.get(terminalId);
|
|
373
|
+
if (!rt) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
rt.lastEventType = type;
|
|
377
|
+
rt.lastEventAt = this.deps.now();
|
|
378
|
+
if (type !== "agent-idle" && type !== "agent-question") {
|
|
379
|
+
rt.lastActivityAt = this.deps.now();
|
|
380
|
+
}
|
|
381
|
+
if (type === "tool-completed" && raw.success === true) {
|
|
382
|
+
rt.autoActionCount = 0;
|
|
383
|
+
}
|
|
384
|
+
if (type === "agent-idle" && this.enabled) {
|
|
385
|
+
void this.evaluate(terminalId);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
async inject(terminalId, command) {
|
|
389
|
+
const rt = this.terminals.get(terminalId);
|
|
390
|
+
if (!rt) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
if (!SAFE_ID.test(terminalId)) {
|
|
394
|
+
return false;
|
|
395
|
+
}
|
|
396
|
+
let ws = rt.injectSocket;
|
|
397
|
+
if (!ws || ws.readyState > WebSocket.OPEN) {
|
|
398
|
+
const ticket = await this.getTicket();
|
|
399
|
+
if (!ticket) {
|
|
400
|
+
return false;
|
|
401
|
+
}
|
|
402
|
+
const wsBase = window.location.origin.replace(/^http/, "ws");
|
|
403
|
+
ws = new WebSocket(`${wsBase}/ws/terminal/${encodeURIComponent(terminalId)}?ticket=${encodeURIComponent(ticket)}`);
|
|
404
|
+
rt.injectSocket = ws;
|
|
405
|
+
const opened = await waitForOpen(ws);
|
|
406
|
+
if (!opened) {
|
|
407
|
+
rt.injectSocket = null;
|
|
408
|
+
return false;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
if (isAgentCommand(rt.command)) {
|
|
415
|
+
const prompt = command.replace(/\s*[\r\n]+\s*/g, " ").trim();
|
|
416
|
+
if (!prompt) {
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
ws.send(JSON.stringify({ data: prompt, type: "input" }));
|
|
420
|
+
await delay(AGENT_SUBMIT_DELAY_MS);
|
|
421
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
ws.send(JSON.stringify({ data: "\r", type: "input" }));
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
ws.send(JSON.stringify({ data: `${command}\r`, type: "input" }));
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
log(terminalId, kind, detail) {
|
|
431
|
+
this.actions = [
|
|
432
|
+
{ at: this.deps.now(), detail, kind, terminalId },
|
|
433
|
+
...this.actions
|
|
434
|
+
].slice(0, MAX_ACTIONS);
|
|
435
|
+
}
|
|
436
|
+
onWake = () => {
|
|
437
|
+
void this.refresh();
|
|
438
|
+
};
|
|
439
|
+
async refresh() {
|
|
440
|
+
if (!this.apiKey) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
await Promise.allSettled([this.fetchTerminals(), this.fetchSummaries()]);
|
|
444
|
+
if (this.enabled) {
|
|
445
|
+
for (const id of this.terminals.keys()) {
|
|
446
|
+
void this.evaluate(id);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
scheduleReconnect() {
|
|
451
|
+
if (this.reconnectTimer) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
this.reconnectTimer = setTimeout(
|
|
455
|
+
() => {
|
|
456
|
+
this.reconnectTimer = null;
|
|
457
|
+
void this.connectEvents();
|
|
458
|
+
},
|
|
459
|
+
RECONNECT_MS
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
async function defaultProduceCommand(input) {
|
|
464
|
+
if (input.isAgentTerminal) {
|
|
465
|
+
const prompt = input.step.text.trim();
|
|
466
|
+
return prompt.length > 0 ? prompt : null;
|
|
467
|
+
}
|
|
468
|
+
const native = await tryNativeDecide(input);
|
|
469
|
+
if (native) {
|
|
470
|
+
return native;
|
|
471
|
+
}
|
|
472
|
+
const litellm = await litellmProduceCommand(input);
|
|
473
|
+
if (litellm) {
|
|
474
|
+
return litellm;
|
|
475
|
+
}
|
|
476
|
+
const text = input.step.text.trim();
|
|
477
|
+
const backticked = /`([^`]+)`/.exec(text);
|
|
478
|
+
if (backticked) {
|
|
479
|
+
return backticked[1].trim();
|
|
480
|
+
}
|
|
481
|
+
const head2 = text.split(/\s+/)[0]?.toLowerCase();
|
|
482
|
+
if (head2 && SAFE_COMMAND_HEADS.has(head2) && !/[\r\n]/.test(text) && text.length < 80) {
|
|
483
|
+
return text;
|
|
484
|
+
}
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
function delay(ms) {
|
|
488
|
+
return new Promise((resolve) => {
|
|
489
|
+
setTimeout(resolve, ms);
|
|
490
|
+
});
|
|
491
|
+
}
|
|
492
|
+
function isAgentCommand(command) {
|
|
493
|
+
const firstToken = command.trim().split(/\s+/)[0] ?? "";
|
|
494
|
+
const base = firstToken.split("/").pop() ?? "";
|
|
495
|
+
return AGENT_COMMANDS.has(base);
|
|
496
|
+
}
|
|
497
|
+
async function litellmProduceCommand(input) {
|
|
498
|
+
const base = readProcessEnv("LITELLM_BASE_URL");
|
|
499
|
+
if (!base || !input.apiKey) {
|
|
500
|
+
return null;
|
|
501
|
+
}
|
|
502
|
+
const model = readProcessEnv("LITELLM_MODEL") || "open-large";
|
|
503
|
+
const userPrompt = `Recent terminal output:
|
|
504
|
+
${input.recentOutput.slice(-2e3)}
|
|
505
|
+
|
|
506
|
+
Suggested next step: ${input.step.text}
|
|
507
|
+
|
|
508
|
+
Reply with ONLY the single shell command to run next — no prose, no backticks, no explanation.`;
|
|
509
|
+
try {
|
|
510
|
+
const res = await fetch("/api/neurolink-proxy", {
|
|
511
|
+
body: JSON.stringify({
|
|
512
|
+
body: {
|
|
513
|
+
max_tokens: 60,
|
|
514
|
+
messages: [
|
|
515
|
+
{
|
|
516
|
+
content: "You are a coding-session copilot. Output ONLY the next shell command.",
|
|
517
|
+
role: "system"
|
|
518
|
+
},
|
|
519
|
+
{ content: userPrompt, role: "user" }
|
|
520
|
+
],
|
|
521
|
+
model,
|
|
522
|
+
temperature: 0
|
|
523
|
+
},
|
|
524
|
+
headers: {},
|
|
525
|
+
provider: "litellm",
|
|
526
|
+
url: `${base}/chat/completions`
|
|
527
|
+
}),
|
|
528
|
+
headers: {
|
|
529
|
+
Authorization: `Bearer ${input.apiKey}`,
|
|
530
|
+
"Content-Type": "application/json"
|
|
531
|
+
},
|
|
532
|
+
method: "POST"
|
|
533
|
+
});
|
|
534
|
+
if (!res.ok) {
|
|
535
|
+
return null;
|
|
536
|
+
}
|
|
537
|
+
const data = await res.json();
|
|
538
|
+
const content = data.choices?.[0]?.message?.content;
|
|
539
|
+
if (typeof content !== "string") {
|
|
540
|
+
return null;
|
|
541
|
+
}
|
|
542
|
+
const cmd = content.trim().replace(/^`+|`+$/g, "").trim();
|
|
543
|
+
return cmd.length > 0 ? cmd : null;
|
|
544
|
+
} catch {
|
|
545
|
+
return null;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
function parseSteps(json) {
|
|
549
|
+
try {
|
|
550
|
+
const parsed = JSON.parse(json);
|
|
551
|
+
if (!Array.isArray(parsed)) {
|
|
552
|
+
return [];
|
|
553
|
+
}
|
|
554
|
+
return parsed.filter((el) => typeof el === "object" && el !== null && typeof el.text === "string" && typeof el.confidence === "number");
|
|
555
|
+
} catch {
|
|
556
|
+
return [];
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
function readPersistedAutonomy() {
|
|
560
|
+
if (typeof localStorage === "undefined") {
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
try {
|
|
564
|
+
const raw = localStorage.getItem(AUTONOMY_KEY);
|
|
565
|
+
if (!raw) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
const parsed = JSON.parse(raw);
|
|
569
|
+
return Boolean(parsed?.enabled);
|
|
570
|
+
} catch {
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
function readProcessEnv(key) {
|
|
575
|
+
const proc = window["process"];
|
|
576
|
+
const value = proc?.env?.[key];
|
|
577
|
+
return typeof value === "string" ? value : "";
|
|
578
|
+
}
|
|
579
|
+
function tryNativeDecide(input) {
|
|
580
|
+
const bridge = window.ShooterBridge;
|
|
581
|
+
if (typeof bridge?.agentDecide !== "function") {
|
|
582
|
+
return Promise.resolve(null);
|
|
583
|
+
}
|
|
584
|
+
const ctx = `Recent terminal output:
|
|
585
|
+
${input.recentOutput.slice(-2e3)}
|
|
586
|
+
|
|
587
|
+
Suggested next step: ${input.step.text}
|
|
588
|
+
|
|
589
|
+
Reply with the single shell command to run next.`;
|
|
590
|
+
return bridge.agentDecide(ctx).then((c) => typeof c === "string" && c.trim().length > 0 ? c.trim() : null).catch(() => null);
|
|
591
|
+
}
|
|
592
|
+
function waitForOpen(ws) {
|
|
593
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
594
|
+
return Promise.resolve(true);
|
|
595
|
+
}
|
|
596
|
+
return new Promise((resolve) => {
|
|
597
|
+
const timer = setTimeout(
|
|
598
|
+
() => {
|
|
599
|
+
ws.close();
|
|
600
|
+
resolve(false);
|
|
601
|
+
},
|
|
602
|
+
OPEN_TIMEOUT_MS
|
|
603
|
+
);
|
|
604
|
+
ws.addEventListener("open", () => {
|
|
605
|
+
clearTimeout(timer);
|
|
606
|
+
resolve(true);
|
|
607
|
+
});
|
|
608
|
+
ws.addEventListener("error", () => {
|
|
609
|
+
clearTimeout(timer);
|
|
610
|
+
ws.close();
|
|
611
|
+
resolve(false);
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
new AutopilotDriver();
|
|
616
|
+
const ACTIVE_THRESHOLD_MS = 3e4;
|
|
617
|
+
let sessions = [];
|
|
618
|
+
const summarizers = new SvelteMap();
|
|
619
|
+
const sessionSockets = new SvelteMap();
|
|
620
|
+
const pendingSessionSockets = new SvelteSet();
|
|
621
|
+
function disconnect() {
|
|
622
|
+
for (const [, sock] of sessionSockets) {
|
|
623
|
+
sock.onclose = null;
|
|
624
|
+
sock.close();
|
|
625
|
+
}
|
|
626
|
+
sessionSockets.clear();
|
|
627
|
+
pendingSessionSockets.clear();
|
|
628
|
+
summarizers.clear();
|
|
629
|
+
}
|
|
630
|
+
function getCards() {
|
|
631
|
+
const now = Date.now();
|
|
632
|
+
return sortSessions(sessions).map((s) => {
|
|
633
|
+
const createdMs = Date.parse(s.createdAt);
|
|
634
|
+
const lastEventTs = s.events.length > 0 ? Date.parse(s.events[s.events.length - 1].timestamp) : 0;
|
|
635
|
+
return {
|
|
636
|
+
...s,
|
|
637
|
+
duration: now - createdMs,
|
|
638
|
+
goal: s.goal,
|
|
639
|
+
// Ensure goal is mapped
|
|
640
|
+
isActive: lastEventTs > 0 && now - lastEventTs < ACTIVE_THRESHOLD_MS,
|
|
641
|
+
isSummarizing: s.isSummarizing,
|
|
642
|
+
// Ensure isSummarizing is mapped
|
|
643
|
+
summary: s.summary
|
|
644
|
+
// Ensure summary is mapped
|
|
645
|
+
};
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
function sortSessions(list) {
|
|
649
|
+
return [...list].sort((a, b) => {
|
|
650
|
+
const order = { error: 2, exited: 3, idle: 1, running: 0 };
|
|
651
|
+
const rankA = order[a.status];
|
|
652
|
+
const rankB = order[b.status];
|
|
653
|
+
if (rankA !== rankB) {
|
|
654
|
+
return rankA - rankB;
|
|
655
|
+
}
|
|
656
|
+
if (a.status !== "exited" && b.status !== "exited") {
|
|
657
|
+
return b.createdAt.localeCompare(a.createdAt);
|
|
658
|
+
}
|
|
659
|
+
const exitA = a.exitedAt ?? a.createdAt;
|
|
660
|
+
const exitB = b.exitedAt ?? b.createdAt;
|
|
661
|
+
return exitB.localeCompare(exitA);
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
function _page($$renderer, $$props) {
|
|
665
|
+
$$renderer.component(($$renderer2) => {
|
|
666
|
+
let projects = [];
|
|
667
|
+
let loading = false;
|
|
668
|
+
const cards = derived(getCards);
|
|
669
|
+
onDestroy(() => {
|
|
670
|
+
disconnect();
|
|
671
|
+
});
|
|
672
|
+
async function fetchSessions(append = false, bustCache = false) {
|
|
673
|
+
{
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
async function forceRefresh() {
|
|
678
|
+
loading = true;
|
|
679
|
+
clearCache("shooter_projects");
|
|
680
|
+
await fetchSessions(false, true);
|
|
681
|
+
}
|
|
682
|
+
function navigateToConfig() {
|
|
683
|
+
void goto();
|
|
684
|
+
}
|
|
685
|
+
function totalSessionCount() {
|
|
686
|
+
return projects.reduce((sum, p) => sum + p.sessionCount, 0);
|
|
687
|
+
}
|
|
688
|
+
head("1uha8ag", $$renderer2, ($$renderer3) => {
|
|
689
|
+
$$renderer3.title(($$renderer4) => {
|
|
690
|
+
$$renderer4.push(`<title>Dashboard - Shooter</title>`);
|
|
691
|
+
});
|
|
692
|
+
$$renderer3.push(`<meta name="description" content="Active terminals and Claude Code sessions"/>`);
|
|
693
|
+
});
|
|
694
|
+
$$renderer2.push(`<main class="main"><div class="page-header"><div class="page-header-content"><div><h1 class="page-title">Dashboard</h1> <p class="page-description">Active terminals and Claude Code sessions</p></div> <div class="page-actions">`);
|
|
695
|
+
Button($$renderer2, {
|
|
696
|
+
classes: "btn-secondary",
|
|
697
|
+
onclick: forceRefresh,
|
|
698
|
+
disabled: loading,
|
|
699
|
+
children: ($$renderer3) => {
|
|
700
|
+
Icon($$renderer3, { svg: RefreshSvg, classes: "icon-14" });
|
|
701
|
+
$$renderer3.push(`<!----> Refresh`);
|
|
702
|
+
},
|
|
703
|
+
$$slots: { default: true }
|
|
704
|
+
});
|
|
705
|
+
$$renderer2.push(`<!----></div></div> `);
|
|
706
|
+
if (projects.length > 0) {
|
|
707
|
+
$$renderer2.push("<!--[0-->");
|
|
708
|
+
$$renderer2.push(`<div class="stats-bar svelte-1uha8ag"><div class="stat-chip svelte-1uha8ag"><span class="stat-value svelte-1uha8ag">${escape_html(projects.length)}</span> <span class="stat-label svelte-1uha8ag">${escape_html(projects.length === 1 ? "project" : "projects")}</span></div> <div class="stat-chip svelte-1uha8ag"><span class="stat-value svelte-1uha8ag">${escape_html(totalSessionCount())}</span> <span class="stat-label svelte-1uha8ag">${escape_html(totalSessionCount() === 1 ? "session" : "sessions")}</span></div> `);
|
|
709
|
+
if (cards().length > 0) {
|
|
710
|
+
$$renderer2.push("<!--[0-->");
|
|
711
|
+
$$renderer2.push(`<div class="stat-chip stat-chip-active svelte-1uha8ag"><span class="stat-value svelte-1uha8ag">${escape_html(cards().length)}</span> <span class="stat-label svelte-1uha8ag">active</span></div>`);
|
|
712
|
+
} else {
|
|
713
|
+
$$renderer2.push("<!--[-1-->");
|
|
714
|
+
}
|
|
715
|
+
$$renderer2.push(`<!--]--></div>`);
|
|
716
|
+
} else {
|
|
717
|
+
$$renderer2.push("<!--[-1-->");
|
|
718
|
+
}
|
|
719
|
+
$$renderer2.push(`<!--]--></div> `);
|
|
720
|
+
{
|
|
721
|
+
$$renderer2.push("<!--[-1-->");
|
|
722
|
+
}
|
|
723
|
+
$$renderer2.push(`<!--]--> `);
|
|
724
|
+
if (loading && projects.length === 0 && cards().length === 0) {
|
|
725
|
+
$$renderer2.push("<!--[0-->");
|
|
726
|
+
$$renderer2.push(`<div class="loading-container"><!--[-->`);
|
|
727
|
+
const each_array = ensure_array_like(Array(3));
|
|
728
|
+
for (let i = 0, $$length = each_array.length; i < $$length; i++) {
|
|
729
|
+
each_array[i];
|
|
730
|
+
Shimmer($$renderer2, { classes: "shimmer-card" });
|
|
731
|
+
}
|
|
732
|
+
$$renderer2.push(`<!--]--></div>`);
|
|
733
|
+
} else {
|
|
734
|
+
$$renderer2.push("<!--[1-->");
|
|
735
|
+
{
|
|
736
|
+
let icon = function($$renderer3) {
|
|
737
|
+
Icon($$renderer3, { svg: SettingsSvg, classes: "icon-24" });
|
|
738
|
+
};
|
|
739
|
+
EmptyState($$renderer2, {
|
|
740
|
+
title: "Configuration Required",
|
|
741
|
+
description: "Set up your API credentials to start tracking sessions",
|
|
742
|
+
icon,
|
|
743
|
+
children: ($$renderer3) => {
|
|
744
|
+
Button($$renderer3, {
|
|
745
|
+
classes: "btn-primary",
|
|
746
|
+
onclick: navigateToConfig,
|
|
747
|
+
text: "Configure Settings"
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
$$renderer2.push(`<!--]--></main>`);
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
export { _page as default };
|
|
758
|
+
//# sourceMappingURL=_page.svelte-8OFzwdNA.js.map
|