@deepseek-insight/dsi 0.8.5 → 0.9.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/.agents/skills/{dsi-gb-verifier → glass-dsi}/SKILL.md +57 -5
- package/.agents/skills/glass-dsi/references/cdp-verification.md +132 -0
- package/.agents/skills/glass-dsi/scripts/_connect.mjs +81 -0
- package/.agents/skills/glass-dsi/scripts/glass-url.mjs +48 -0
- package/.agents/skills/glass-dsi/scripts/glass.mjs +84 -0
- package/.agents/skills/glass-url/SKILL.md +117 -0
- package/.agents/skills/glass-url/scripts/_args.mjs +49 -0
- package/.agents/skills/glass-url/scripts/_connect.mjs +99 -0
- package/.agents/skills/glass-url/scripts/glass-url.mjs +114 -0
- package/bin/dsi.mjs +23 -74
- package/bin/lib/zai-patch.mjs +115 -0
- package/build/client/_app/immutable/assets/0.Ch5VtsKp.css +2 -0
- package/build/client/_app/immutable/assets/2.D0QOh44D.css +1 -0
- package/build/client/_app/immutable/chunks/{DwcY-69G.js → 02Wfo2G3.js} +1 -1
- package/build/client/_app/immutable/chunks/0Tfhif1V.js +3 -0
- package/build/client/_app/immutable/chunks/0ruuBBbh.js +2 -0
- package/build/client/_app/immutable/chunks/{DUCaFYlx.js → 4bHE1npv.js} +1 -1
- package/build/client/_app/immutable/chunks/{4cwyag_I.js → B4hDUAJl.js} +1 -1
- package/build/client/_app/immutable/chunks/{Cr2ck_ss.js → BIPXB-2I.js} +1 -1
- package/build/client/_app/immutable/chunks/{CeLBjOd9.js → BIgv-kQR.js} +1 -1
- package/build/client/_app/immutable/chunks/BK6k1nBs.js +1 -0
- package/build/client/_app/immutable/chunks/{SN3Efo-Q.js → BKwmKcDY.js} +1 -1
- package/build/client/_app/immutable/chunks/{CRFuOqJI.js → BORjuqef.js} +1 -1
- package/build/client/_app/immutable/chunks/{CH_bR_0j.js → BPmZB0-N.js} +1 -1
- package/build/client/_app/immutable/chunks/BROtno1Y.js +1 -0
- package/build/client/_app/immutable/chunks/{DEVxi5CK.js → BT5Iel00.js} +1 -1
- package/build/client/_app/immutable/chunks/{DdI16loP.js → BX3y_1Hh.js} +1 -1
- package/build/client/_app/immutable/chunks/{DuiFyTVb.js → Bea1gxLq.js} +1 -1
- package/build/client/_app/immutable/chunks/{D0uxHECr.js → BpkpgvVw.js} +1 -1
- package/build/client/_app/immutable/chunks/{CB55Rp7-.js → BreZS7EW.js} +1 -1
- package/build/client/_app/immutable/chunks/{BmDADyfH.js → BsS_byzk.js} +1 -1
- package/build/client/_app/immutable/chunks/{BWRXzjmQ.js → Bslg-dr5.js} +1 -1
- package/build/client/_app/immutable/chunks/{BkYT72a1.js → C-YczRN1.js} +1 -1
- package/build/client/_app/immutable/chunks/{DBKMIEwD.js → C2aW4lzo.js} +1 -1
- package/build/client/_app/immutable/chunks/{C4gs6zoI.js → C2qFXaz5.js} +1 -1
- package/build/client/_app/immutable/chunks/{BBd0nTHG.js → C5RyRpOh.js} +1 -1
- package/build/client/_app/immutable/chunks/{DJQr4efH.js → C5iHDVU_.js} +1 -1
- package/build/client/_app/immutable/chunks/{B4F5liKq.js → C7opVlLF.js} +1 -1
- package/build/client/_app/immutable/chunks/{DIxy2USu.js → CAuEkmZ4.js} +1 -1
- package/build/client/_app/immutable/chunks/{BO99LSSA.js → CIkiqgtA.js} +1 -1
- package/build/client/_app/immutable/chunks/{Bpd0I3U7.js → CJesWaZn.js} +1 -1
- package/build/client/_app/immutable/chunks/{at6PQqQ4.js → CRsoS5Y9.js} +1 -1
- package/build/client/_app/immutable/chunks/CTWtsoJD.js +6 -0
- package/build/client/_app/immutable/chunks/CWk5gmU2.js +1 -0
- package/build/client/_app/immutable/chunks/{lF8CNVOA.js → CXkrluSK.js} +1 -1
- package/build/client/_app/immutable/chunks/{DmRY6FWm.js → C_8kFZ_X.js} +4 -4
- package/build/client/_app/immutable/chunks/{D6KenyiF.js → Ch7hUoAH.js} +1 -1
- package/build/client/_app/immutable/chunks/{b4-Ro8NH.js → ChmmHPdM.js} +1 -1
- package/build/client/_app/immutable/chunks/{DfUgh5E_.js → CjajmcJs.js} +1 -1
- package/build/client/_app/immutable/chunks/{q5PRaRZk.js → Ck6GS6Vb.js} +1 -1
- package/build/client/_app/immutable/chunks/{eFcFJ9Ld.js → ClGoDr_f.js} +1 -1
- package/build/client/_app/immutable/chunks/{BQC6O_RV.js → ClqGHlec.js} +1 -1
- package/build/client/_app/immutable/chunks/{zypfUZYM.js → CnW6hje6.js} +1 -1
- package/build/client/_app/immutable/chunks/{OW5Q7tGb.js → CpI6VYCH.js} +1 -1
- package/build/client/_app/immutable/chunks/{BXKc4uuX.js → CygwwaiE.js} +1 -1
- package/build/client/_app/immutable/chunks/{Bqwvv7Vf.js → CyhZtsZO.js} +35 -35
- package/build/client/_app/immutable/chunks/{BenkQ_4r.js → D-E2Noqq.js} +1 -1
- package/build/client/_app/immutable/chunks/{DuRZnRVw.js → D4Btzp_A.js} +1 -1
- package/build/client/_app/immutable/chunks/{CdaJvl_A.js → D4C3Jijv.js} +1 -1
- package/build/client/_app/immutable/chunks/D9jhmf3I.js +1 -0
- package/build/client/_app/immutable/chunks/{Cf0aMC4n.js → DCw0gAtv.js} +1 -1
- package/build/client/_app/immutable/chunks/{B6bTO8_7.js → DEW3KpiC.js} +1 -1
- package/build/client/_app/immutable/chunks/{O6xxeEm8.js → DYLFbKJe.js} +1 -1
- package/build/client/_app/immutable/chunks/{BsBBq-Qk.js → DYu7kgVa.js} +1 -1
- package/build/client/_app/immutable/chunks/Dfexc5qV.js +1 -0
- package/build/client/_app/immutable/chunks/{kzciT-3i.js → DhmUE8Ri.js} +1 -1
- package/build/client/_app/immutable/chunks/{DdJNsJBH.js → DjwX3rAC.js} +1 -1
- package/build/client/_app/immutable/chunks/{CajOZJDl.js → DlOfy8Sx.js} +1 -1
- package/build/client/_app/immutable/chunks/{CK5vhXvt.js → Do7Y1_MQ.js} +1 -1
- package/build/client/_app/immutable/chunks/{ap4GAVq-.js → Dq2XIb1m.js} +1 -1
- package/build/client/_app/immutable/chunks/{Czey8tDK.js → DuT_Qr5k.js} +1 -1
- package/build/client/_app/immutable/chunks/{4B6J_kM2.js → DyGggFea.js} +1 -1
- package/build/client/_app/immutable/chunks/{D0ChUnpi.js → Dym4i64U.js} +1 -1
- package/build/client/_app/immutable/chunks/FPsIAiN_.js +1 -0
- package/build/client/_app/immutable/chunks/{CevKuuic.js → GIczpP_D.js} +1 -1
- package/build/client/_app/immutable/chunks/{B2jrDnt8.js → LjOLSmU7.js} +1 -1
- package/build/client/_app/immutable/chunks/VtK73aN-.js +8 -0
- package/build/client/_app/immutable/chunks/{AcmOeh2U.js → ZqoQH_jm.js} +1 -1
- package/build/client/_app/immutable/chunks/{BlwWx85l.js → aXn6rE_7.js} +1 -1
- package/build/client/_app/immutable/chunks/{Czc4_W7v.js → dUOeoGwg.js} +1 -1
- package/build/client/_app/immutable/chunks/f50lp1rr.js +1 -0
- package/build/client/_app/immutable/chunks/{7FnrqGK9.js → lvLrv1cG.js} +1 -1
- package/build/client/_app/immutable/chunks/{CZoElI5B.js → pt3_jHwh.js} +1 -1
- package/build/client/_app/immutable/chunks/{Byu_teLA.js → q8irUX-p.js} +1 -1
- package/build/client/_app/immutable/chunks/{CnxoqrkQ.js → qmOgUo3c.js} +1 -1
- package/build/client/_app/immutable/chunks/vpNeypNM.js +1 -0
- package/build/client/_app/immutable/chunks/{DU8C5thd.js → xvTPLhcB.js} +1 -1
- package/build/client/_app/immutable/chunks/{DFBKiA2Z.js → zp7hrpsC.js} +1 -1
- package/build/client/_app/immutable/entry/app.D4oc_iez.js +2 -0
- package/build/client/_app/immutable/entry/start.Xkr2MCWg.js +1 -0
- package/build/client/_app/immutable/nodes/0.fsrqKU9i.js +1 -0
- package/build/client/_app/immutable/nodes/1.3F37GwcO.js +1 -0
- package/build/client/_app/immutable/nodes/2.DsWNNw0K.js +340 -0
- package/build/client/_app/version.json +1 -1
- package/build/handler.js +6 -6
- package/build/index.js +6 -6
- package/build/server/chunks/chunks/{app-config.svelte.js-DCc9d7A4.js → app-config.svelte.js-BXjvTmJu.js} +4 -3
- package/build/server/chunks/chunks/{config.js-s6iKwHD7.js → config.js-r_jw_bQQ.js} +53 -2
- package/build/server/chunks/chunks/{db.js-CxxWK5sn.js → db.js-f2PmBjyD.js} +2 -2
- package/build/server/chunks/chunks/{db2.js-DwJ9lySe.js → db2.js-DkwY64WO.js} +2 -2
- package/build/server/chunks/chunks/{dsh-connection.js-Chtudg1p.js → dsh-connection.js-BW07Aicl.js} +18 -10
- package/build/server/chunks/chunks/{dsh-events.js-BUdvZQmd.js → dsh-events.js-BHf0lLZ5.js} +11 -1
- package/build/server/chunks/chunks/{git-probe.js-BX9FPnet.js → git-probe.js-CQqTV7XX.js} +3 -3
- package/build/server/chunks/chunks/{index-server.js-DmIEbDVz.js → index-server.js-CPkVoRxB.js} +2 -2
- package/build/server/chunks/chunks/{insight-config.js-Db5fe5Df.js → insight-config.js-C5-Rhh5A.js} +13 -4
- package/build/server/chunks/chunks/{internal2.js-CaZaz-a9.js → internal2.js-DbC8VGqD.js} +4 -4
- package/build/server/chunks/chunks/{registry.js-syaTZ_-A.js → registry.js-CWnRQ4vx.js} +430 -52
- package/build/server/chunks/chunks/{registry2.js-D3Pr1Rv9.js → registry2.js-CFzpvj9c.js} +17 -1
- package/build/server/chunks/chunks/{server.js-B1bDXhHu.js → server.js-Dijo7DtV.js} +2 -2
- package/build/server/chunks/chunks/{settings-document.js-BHESJ7im.js → settings-document.js-DxKURfc_.js} +2 -2
- package/build/server/chunks/chunks/{state.js-oYjf745s.js → state.js-DR4xiIVw.js} +5 -5
- package/build/server/chunks/chunks/{watcher.js-Ci9jsM5l.js → watcher.js-DvlNn8X0.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/a2a/_id_/{_server.ts.js-CHaYhzjy.js → _server.ts.js-DItDXV23.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/a2a/{_server.ts.js-CdyqA85c.js → _server.ts.js-Hor8QZb1.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/a2a/register/{_server.ts.js-DO_FS5b4.js → _server.ts.js-CEvvsa8B.js} +8 -8
- package/build/server/chunks/entries/endpoints/api/browser/_id_/activate/{_server.ts.js-D7Be4JUf.js → _server.ts.js-sXqf-okw.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/close/{_server.ts.js-CGkm2H-U.js → _server.ts.js-Byj9ApJh.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/closetab/{_server.ts.js-D7SLUfOo.js → _server.ts.js-DOIsrzvg.js} +16 -9
- package/build/server/chunks/entries/endpoints/api/browser/_id_/element/{_server.ts.js-C3d_JV-q.js → _server.ts.js-Cq3gmRfE.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/history/_server.ts.js-BGSLIV0t.js +61 -0
- package/build/server/chunks/entries/endpoints/api/browser/_id_/input/{_server.ts.js-DW0hyVML.js → _server.ts.js-8slca75-.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/mcp/{_server.ts.js-Ev-hdBlf.js → _server.ts.js-CpbdTYds.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/navigate/{_server.ts.js-DZ8-wocV.js → _server.ts.js-Bls9LtLY.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/opentab/{_server.ts.js-aapPrIQK.js → _server.ts.js-DqNi_iW_.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/page/{_server.ts.js-DANA_hMd.js → _server.ts.js-DuXWwo7i.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/stream/{_server.ts.js-BqfseXFy.js → _server.ts.js-DXfqBDEw.js} +17 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/tabs/{_server.ts.js-DFFF9qe-.js → _server.ts.js-Bgnl8lYs.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/viewport/{_server.ts.js-ek6-D4Zm.js → _server.ts.js-FHmQVbrv.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/browser/_id_/zoom/_server.ts.js-BV4cBtSA.js +62 -0
- package/build/server/chunks/entries/endpoints/api/browser/{_server.ts.js-CPjKy3ma.js → _server.ts.js-4vgkwh7v.js} +9 -6
- package/build/server/chunks/entries/endpoints/api/config/{_server.ts.js-CWE9NP6g.js → _server.ts.js-C_9kwANR.js} +9 -6
- package/build/server/chunks/entries/endpoints/api/dsh/directory/{_server.ts.js-D-raYQon.js → _server.ts.js-h1OTHcL4.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/jobs/{_server.ts.js-CI4dEHFY.js → _server.ts.js-B6nih9Sd.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/jobs/follow/{_server.ts.js-cnjoSLtY.js → _server.ts.js-Cf17SVmD.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/pick-directory/{_server.ts.js-0UUtapX5.js → _server.ts.js-DjNwMbdS.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/presets/{_server.ts.js-MK5ezU8u.js → _server.ts.js-Cz5aaEhC.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/_server.ts.js-BFBy5O9Y.js +78 -0
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/cancel/{_server.ts.js-wGEl1fuF.js → _server.ts.js-CgEdCo3T.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/catalog/{_server.ts.js-Bz7u2BlD.js → _server.ts.js-Bo_aEnHh.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/changes/{_server.ts.js-yue5aEjr.js → _server.ts.js-Bd2G_GaH.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/command/{_server.ts.js-BFSs5T2m.js → _server.ts.js-DL64FyRw.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/events/{_server.ts.js-C2i85wQy.js → _server.ts.js-MhOGB66D.js} +6 -6
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/fork/{_server.ts.js-_toO4f4W.js → _server.ts.js-MjPgXgGO.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/goal/{_server.ts.js-BGJnDV85.js → _server.ts.js-BUjDae5H.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/history/{_server.ts.js-CQCJg8U8.js → _server.ts.js-dTKd7Hsv.js} +6 -6
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/models/{_server.ts.js-0ADvdE79.js → _server.ts.js-B82rvKoI.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/path/{_server.ts.js-DyO4T1Ro.js → _server.ts.js-Cqijsi-c.js} +4 -4
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/permission/{_server.ts.js-CIY7oimw.js → _server.ts.js-CL_vVv2p.js} +29 -6
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/prompt/{_server.ts.js-B-9faNHX.js → _server.ts.js-WS4W9Ly4.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/rename/{_server.ts.js-E7-0zfiH.js → _server.ts.js-B72KGRGh.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/respond/{_server.ts.js-CODtLQ3Q.js → _server.ts.js-DK5xb2b5.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/select-model/{_server.ts.js-BiSxsU-j.js → _server.ts.js-lhT87EQu.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/sessions/{_server.ts.js-C0WJnv2b.js → _server.ts.js-CMhfhbkN.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/subagents/{_server.ts.js-D5bc4xg4.js → _server.ts.js-BLvcFsg6.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/workspace-file/{_server.ts.js-23ycAyUg.js → _server.ts.js-D_rw2Uq6.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/workspace-tree/{_server.ts.js-B4w5Jh7f.js → _server.ts.js-DfXpMMpw.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/workspaces/{_server.ts.js-VQLxDbFE.js → _server.ts.js-2mJCJVxk.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/delete/{_server.ts.js-vs5N5Cya.js → _server.ts.js-BCx0Lzjf.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/rename/{_server.ts.js-BOWhoBHV.js → _server.ts.js-DECaSjwp.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/prompts/_id_/{_server.ts.js-aDEAGfJe.js → _server.ts.js-i_ciJzlb.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/prompts/{_server.ts.js-BZ-nRrTp.js → _server.ts.js-BO1pScn7.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/prompts/use/{_server.ts.js-CkDY1PQ7.js → _server.ts.js-Buhpf7WE.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/settings/{_server.ts.js-CHvgF47Y.js → _server.ts.js-DngUQzcT.js} +4 -4
- package/build/server/chunks/entries/endpoints/api/terminal/_id_/output/{_server.ts.js-BNBxebgG.js → _server.ts.js-DLETP4yQ.js} +2 -2
- package/build/server/chunks/entries/endpoints/api/terminal/_id_/reattach/{_server.ts.js-DDRJBGIr.js → _server.ts.js-uWl6oxPS.js} +2 -2
- package/build/server/chunks/entries/endpoints/api/terminal/_id_/send/{_server.ts.js-CA0vc_Cm.js → _server.ts.js-DYNmXaAd.js} +9 -2
- package/build/server/chunks/entries/endpoints/api/terminal/_id_/stream/{_server.ts.js-D6L8Gd_f.js → _server.ts.js-C5m3Ktho.js} +2 -2
- package/build/server/chunks/entries/endpoints/api/terminal/{_server.ts.js-CbRT4vBo.js → _server.ts.js-DoTNvcOa.js} +5 -5
- package/build/server/chunks/entries/endpoints/api/workspace/file-write/{_server.ts.js-BwD0KaXy.js → _server.ts.js-BzYOJSkI.js} +7 -7
- package/build/server/chunks/entries/endpoints/api/workspace/git-events/{_server.ts.js-DgbMRh3d.js → _server.ts.js-xcNesei9.js} +7 -7
- package/build/server/chunks/entries/endpoints/api/workspace/git-file-head/{_server.ts.js-DRqZawic.js → _server.ts.js-DsJWYdxt.js} +7 -7
- package/build/server/chunks/entries/endpoints/api/workspace/git-map/{_server.ts.js-CTXwwwB1.js → _server.ts.js-CNCku9BR.js} +7 -7
- package/build/server/chunks/entries/endpoints/api/workspace/git-status/{_server.ts.js-B4aJBY2w.js → _server.ts.js-nLsNjOxj.js} +7 -7
- package/build/server/chunks/entries/endpoints/api/workspace/write-gate/{_server.ts.js-CDJJA18L.js → _server.ts.js-urQk2-ds.js} +7 -7
- package/build/server/chunks/entries/{hooks.server.js-Iel6oE7w.js → hooks.server.js-CU2RE5vs.js} +3 -3
- package/build/server/chunks/entries/pages/{_error.svelte.js-B-wdFjVG.js → _error.svelte.js-e018KpwE.js} +6 -6
- package/build/server/chunks/entries/pages/{_page.server.ts.js-CaoeQzem.js → _page.server.ts.js-BK3Y6eff.js} +3 -3
- package/build/server/chunks/entries/pages/{_page.svelte.js-CY7zcWr4.js → _page.svelte.js-DQWBiRk1.js} +2681 -648
- package/build/server/chunks/{handler-DYk4NJto.js → handler-DsD7I1_u.js} +3 -3
- package/build/server/chunks/{index.js-kL9MZ99b.js → index.js-C_WAkwJs.js} +4 -4
- package/build/server/chunks/{manifest.js-BrMLQqec.js → manifest.js-DUy52VaP.js} +79 -65
- package/build/server/chunks/nodes/{0.js-BembYTTr.js → 0.js-CuV3dXVD.js} +3 -3
- package/build/server/chunks/nodes/1.js-Dc5QC-NJ.js +9 -0
- package/build/server/chunks/nodes/{2.js-BezA2RPm.js → 2.js-PwcF4_kT.js} +10 -10
- package/package.json +2 -2
- package/template/.dsi/prompts.sqlite +0 -0
- package/template/.dsi/prompts.sqlite-shm +0 -0
- package/template/.dsi/prompts.sqlite-wal +0 -0
- package/template/.dsi/settings.yaml +7 -2
- package/build/client/_app/immutable/assets/0.C6AGVUc8.css +0 -2
- package/build/client/_app/immutable/assets/2.gXzZuuwh.css +0 -1
- package/build/client/_app/immutable/chunks/BFOY8uwF.js +0 -1
- package/build/client/_app/immutable/chunks/BHDqH9nE.js +0 -1
- package/build/client/_app/immutable/chunks/CAneZX4t.js +0 -8
- package/build/client/_app/immutable/chunks/CrTRqozz.js +0 -1
- package/build/client/_app/immutable/chunks/DQXo7qdJ.js +0 -1
- package/build/client/_app/immutable/chunks/DxGYLnDH.js +0 -1
- package/build/client/_app/immutable/chunks/HD-mJtOS.js +0 -6
- package/build/client/_app/immutable/chunks/K3xyLTzZ.js +0 -1
- package/build/client/_app/immutable/chunks/cHj8EuyS.js +0 -3
- package/build/client/_app/immutable/chunks/hC0DBYN6.js +0 -2
- package/build/client/_app/immutable/chunks/o7DVZODA.js +0 -1
- package/build/client/_app/immutable/chunks/pdYhlwhf.js +0 -1
- package/build/client/_app/immutable/entry/app.DHewwbUQ.js +0 -2
- package/build/client/_app/immutable/entry/start.C0PcwkeZ.js +0 -1
- package/build/client/_app/immutable/nodes/0.CP10wY64.js +0 -1
- package/build/client/_app/immutable/nodes/1.qWvE0DiU.js +0 -1
- package/build/client/_app/immutable/nodes/2.Nw7iFtoh.js +0 -341
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/_server.ts.js-CEiMgzjC.js +0 -46
- package/build/server/chunks/nodes/1.js-CKJjyWGZ.js +0 -9
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: dsi
|
|
3
|
-
description: Use when asked to test/verify work "live", "on the glass", "headed", or on the real DSI surface — drive the operator's own Glass Browser over its MCP tools (mcp__glass-browser__browser_*), opening a glass panel if none exists or adding a focused tab when one does. Reserved keyword /dsi-
|
|
2
|
+
name: glass-dsi
|
|
3
|
+
description: Use when asked to test/verify work "live", "on the glass", "headed", or on the real DSI surface — drive the operator's own Glass Browser over its MCP tools (mcp__glass-browser__browser_*), opening a glass panel if none exists or adding a focused tab when one does. Reserved keyword /glass-dsi (legacy alias /dsi-glass still matches).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# dsi
|
|
6
|
+
# glass-dsi — verify work on the operator's own Glass Browser
|
|
7
|
+
|
|
8
|
+
**Dispatch rule (2026-10-30, the Tab-Juggling RCA):** before any glass work,
|
|
9
|
+
ask — is the surface I must drive the DSI workspace, or some other URL?
|
|
10
|
+
DSI workspace → this skill (the driver hard-requires the DSI tab on :5175).
|
|
11
|
+
Any other URL → the `glass-url` skill; it opens a NEW tab and NEVER touches
|
|
12
|
+
the DSI tab. Do NOT navigate the DSI tab to an external URL and do NOT
|
|
13
|
+
re-run `open` to "recover" — that dance produced a useless DSI tab, a
|
|
14
|
+
strike from the driver, and three tabs where one was needed.
|
|
7
15
|
|
|
8
16
|
Companion KB: `dev/feature-contract-scenario/glass-browser-verification.md`
|
|
9
17
|
(the why and the wire: CDP, the :9515 in-process brain, the three doors).
|
|
10
|
-
This skill is the DO-path.
|
|
18
|
+
This skill is the DO-path.
|
|
19
|
+
Reference (raw-CDP DO-path when the MCP tools cannot reach the glass —
|
|
20
|
+
orphaned glasses, stack-trace instrumentation, no-nesting rule):
|
|
21
|
+
`references/cdp-verification.md` in this skill folder. The one rule above all:
|
|
11
22
|
|
|
12
23
|
**The hands are the browser.** `mcp__glass-browser__browser_*` tools drive
|
|
13
24
|
the SAME headed Chromium the operator's floor panel mirrors (CDP via the
|
|
@@ -140,4 +151,45 @@ re-litigate them):**
|
|
|
140
151
|
Numbers before/after, the gesture that produced them, and the gates that
|
|
141
152
|
passed. Label anything you seeded as seeded. If a step could not run,
|
|
142
153
|
say so — a partial verification is a claim about what RAN, not about
|
|
143
|
-
the feature.
|
|
154
|
+
the feature.
|
|
155
|
+
## Tab-ID grammar (2026-10-28 — glass-tab-ids wave)
|
|
156
|
+
|
|
157
|
+
Glass prompts and the panel omnibox share ONE parser: src/lib/browser/tab-grammar.ts (`parseTabCommand`, discriminated union) — the both-doors rule; they can never disagree about what a command means. Grammar:
|
|
158
|
+
|
|
159
|
+
| Input | Meaning |
|
|
160
|
+
|---|---|
|
|
161
|
+
| `glass <url>` | open a new tab to url |
|
|
162
|
+
| `glass <text>` | open a new tab to a web search of text |
|
|
163
|
+
| `reuse tab:N [url]` | focus tab N, optionally navigate |
|
|
164
|
+
| `change [to] tab:N` / `tab:N` | focus tab N |
|
|
165
|
+
| `close tab:N` / `close active` | close that tab / the active tab |
|
|
166
|
+
| `active` | report the focused tab (id + URL) |
|
|
167
|
+
| anything else | chrome fallback — navigate or web search on the active tab |
|
|
168
|
+
|
|
169
|
+
`Alt+N` on the panel (not a grammar input) focuses the Nth tab by STRIP POSITION before the CDP relay — Alt+0 is the last tab; empty slot is a no-op and the combo never reaches the glass page.
|
|
170
|
+
|
|
171
|
+
`tab:N` is the registry-owned ordinal rendered on the strip badge (data-testid=browser-tab-ordinal) — the badge IS the prompt ID. Focus polish 2026-10-28: the badge now READS `t{index}:{id}` (the 1-based strip position, the same index Alt+N dispatches on), while PROMPTS still use the `tab:{id}` grammar — the registry is unchanged. Ordinals are never reused after close: a retired/unknown tab:N is an explicit error (404 NO_TARGET), never a silent nearest-match. When verifying live, read the number off the badge and address the tab by it.
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
## Fast path — the driver script (2026-10-29)
|
|
175
|
+
|
|
176
|
+
The whole discovery dance above is codified in ONE script. Run it FIRST;
|
|
177
|
+
fall back to the manual steps only when it fails:
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
# from the DSI repo root (playwright-core resolves there)
|
|
181
|
+
node .agents/skills/dsi-glass/scripts/glass.mjs open # resolve port, connect, reuse-or-create the DSI tab
|
|
182
|
+
node .agents/skills/dsi-glass/scripts/glass.mjs type '?adr' # real keystrokes into the composer
|
|
183
|
+
node .agents/skills/dsi-glass/scripts/glass.mjs strip # rows / activeIdx / ariaSel / tipCount verdict
|
|
184
|
+
node .agents/skills/dsi-glass/scripts/glass.mjs shot tmp/glass.png
|
|
185
|
+
node .agents/skills/dsi-glass/scripts/glass.mjs eval '1+1' # arbitrary page.evaluate
|
|
186
|
+
node .agents/skills/dsi-glass/scripts/glass.mjs pages
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
It caches NOTHING: every run re-resolves the session from
|
|
190
|
+
`GET /api/browser` (rule 3 — a hardcoded port verifies a ghost). On
|
|
191
|
+
failure it prints the manual fallback (operator clicks the Browser chip).
|
|
192
|
+
Complex gestures (mouse drags, multi-step keyboards, instrumentation
|
|
193
|
+
shims) still go through playwright-core by hand per §2–§4 — the script
|
|
194
|
+
covers the connect + common verbs, not every probe.
|
|
195
|
+
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Reference — Driving a Glass Over Raw CDP (the orphaned-glass DO-path)
|
|
2
|
+
|
|
3
|
+
Companion to SKILL.md. Read when the `mcp__glass-browser__browser_*`
|
|
4
|
+
tools cannot reach the glass you need (brain re-homed, preset entry
|
|
5
|
+
stale) or when you need evidence the MCP tools cannot produce (stack
|
|
6
|
+
traces, per-frame scroll curves, wire-call counts). The KB companion
|
|
7
|
+
(`dev/feature-contract-scenario/glass-browser-verification.md`,
|
|
8
|
+
"2026-10-28 additions II") carries the WHY; this file is the HOW, every
|
|
9
|
+
pattern battle-tested 2026-10-28 on the operator's own glass (port 9400,
|
|
10
|
+
three session ids, one investigation — the floor-steal RCA).
|
|
11
|
+
|
|
12
|
+
## 0. The rules that outrank every pattern
|
|
13
|
+
|
|
14
|
+
1. **NO NESTING.** Never open the host DSI inside a glass tab to "drive
|
|
15
|
+
the GUI". The host GUI's gestures belong to the OPERATOR; you verify
|
|
16
|
+
effects through the glass CDP and ask the operator to click. (Operator
|
|
17
|
+
correction 2026-10-28: "do not nest DSI".)
|
|
18
|
+
2. **A re-homed glass is not dead.** `mcpHealth: "down", mcpError:
|
|
19
|
+
"brain re-homed to a newer glass"` means the MCP tools left — the
|
|
20
|
+
chromium and its CDP port are still fully alive and still may be the
|
|
21
|
+
browser the operator's panel mirrors.
|
|
22
|
+
3. **Re-resolve the port every session.** `GET /api/browser` rows carry
|
|
23
|
+
`port`; the registry cycles whenever the operator re-chips. A
|
|
24
|
+
hardcoded port verifies a ghost.
|
|
25
|
+
4. **Instrument BEFORE the gesture.** A counter armed after the click
|
|
26
|
+
proves nothing.
|
|
27
|
+
|
|
28
|
+
## 1. Resolve the target
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
curl -s http://127.0.0.1:5175/api/browser
|
|
32
|
+
# → {"sessions":[{"id":"…","port":9400,"mcpHealth":"…"}]}
|
|
33
|
+
curl -s http://127.0.0.1:<port>/json/list
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Pick the DSI-under-test page: `type === "page"`, URL contains
|
|
37
|
+
`127.0.0.1:5175`. Its `title` is the FOCUSED SESSION's name — DSI sets
|
|
38
|
+
`document.title` to it, so the title flipping IS a focus probe. Ignore
|
|
39
|
+
`browser_ui` rows (Omnibox Popup) and the `data:text/html` placeholder.
|
|
40
|
+
|
|
41
|
+
## 2. Connect (playwright-core over CDP — real input, real pages)
|
|
42
|
+
|
|
43
|
+
```js
|
|
44
|
+
import { chromium } from 'playwright-core';
|
|
45
|
+
const browser = await chromium.connectOverCDP('http://127.0.0.1:' + port);
|
|
46
|
+
const page = browser.contexts()[0].pages().find(p => p.url().includes('5175'));
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This gives real `locator.click()` gestures (pointerdown included — the
|
|
50
|
+
activation verb) and `page.evaluate` into the live page. Raw-CDP
|
|
51
|
+
alternatives for the same doors: `Runtime.evaluate` (+`userGesture:
|
|
52
|
+
true`), `Input.dispatchMouseEvent/KeyEvent`, `Page.captureScreenshot`.
|
|
53
|
+
|
|
54
|
+
## 3. Arm the instrumentation (one `page.evaluate`, before acting)
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
await page.evaluate(() => {
|
|
58
|
+
window.__ev = []; window.__sl = [];
|
|
59
|
+
const vp = document.querySelector('[data-testid=panels-viewport]');
|
|
60
|
+
// (a) rAF scroll sampler — CDP round-trips miss the smooth-scroll curve
|
|
61
|
+
let last = vp.scrollLeft;
|
|
62
|
+
const sample = () => { const s = vp.scrollLeft;
|
|
63
|
+
if (s !== last) { last = s; window.__sl.push({ t: Math.round(performance.now()), sl: Math.round(s * 10) / 10 }); }
|
|
64
|
+
requestAnimationFrame(sample); };
|
|
65
|
+
requestAnimationFrame(sample);
|
|
66
|
+
const proto = Element.prototype;
|
|
67
|
+
// (b) scroll watches with STACKS — the stack frame names the guilty component
|
|
68
|
+
if (!proto.__watched) { proto.__watched = true;
|
|
69
|
+
const siv = proto.scrollIntoView, sto = proto.scrollTo;
|
|
70
|
+
proto.scrollIntoView = function (...a) {
|
|
71
|
+
if (this.closest('[data-testid=panels-viewport]'))
|
|
72
|
+
window.__ev.push({ t: Math.round(performance.now()), kind: 'scrollIntoView',
|
|
73
|
+
d: (this.getAttribute?.('data-testid') ?? this.tagName),
|
|
74
|
+
stack: new Error().stack.split('\n')[2]?.trim() });
|
|
75
|
+
return siv.apply(this, a); };
|
|
76
|
+
proto.scrollTo = function (...a) {
|
|
77
|
+
if (this.matches?.('[data-testid=panels-viewport]'))
|
|
78
|
+
window.__ev.push({ t: Math.round(performance.now()), kind: 'floor.scrollTo', d: JSON.stringify(a[0]) });
|
|
79
|
+
return sto.apply(this, a); }; }
|
|
80
|
+
// (c) fetch shim — negative evidence (zero POSTs) kills hypotheses
|
|
81
|
+
if (!window.__fw) { window.__fw = true; const of_ = window.fetch;
|
|
82
|
+
window.fetch = function (...a) {
|
|
83
|
+
const u = String(a[0]);
|
|
84
|
+
if (u.includes('/viewport') || u.includes('/activate') || u.includes('/tabs'))
|
|
85
|
+
window.__ev.push({ t: Math.round(performance.now()), kind: 'fetch', d: u.split('/').pop() });
|
|
86
|
+
return of_.apply(this, a); }; }
|
|
87
|
+
// (d) selection timestamps
|
|
88
|
+
new MutationObserver(() => window.__ev.push({ t: Math.round(performance.now()), kind: 'selection' }))
|
|
89
|
+
.observe(document.querySelector('[data-testid=panels-row]'), { attributes: true, attributeFilter: ['class'], subtree: true });
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Notes: arm once (the `__watched`/`__fw` guards) — HMR reloads wipe
|
|
94
|
+
everything and the guards re-arm cleanly; the stack slice `[2]` is the
|
|
95
|
+
first APP frame (skip the wrapper).
|
|
96
|
+
|
|
97
|
+
## 4. Gesture, then read the verdict
|
|
98
|
+
|
|
99
|
+
Perform the REAL gesture (`locator.click()` on the panel header), wait
|
|
100
|
+
OUT past at least one poll cadence (the tabs poll is 2000 ms — a 2s wait
|
|
101
|
+
verifies nothing), then:
|
|
102
|
+
|
|
103
|
+
```js
|
|
104
|
+
const out = await page.evaluate(() => ({
|
|
105
|
+
sl: document.querySelector('[data-testid=panels-viewport]').scrollLeft,
|
|
106
|
+
sel: document.querySelector('.panels-row [data-testid=panel-column].selected')
|
|
107
|
+
?.getBoundingClientRect().toJSON(),
|
|
108
|
+
vp: document.querySelector('[data-testid=panels-viewport]').getBoundingClientRect().toJSON(),
|
|
109
|
+
ev: window.__ev, samples: window.__sl }));
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Verdict = NUMBERS: selected rect fully inside viewport rect? scroll trace
|
|
113
|
+
monotonic (reveal settles) or snapped back (a steal)? which stack frames
|
|
114
|
+
appear? Report before/after pairs and the gates passed; adjectives are not
|
|
115
|
+
verification.
|
|
116
|
+
|
|
117
|
+
## 5. Geometry facts that bite
|
|
118
|
+
|
|
119
|
+
- The floor viewport's left edge is NOT page x=0 (the sidebar rail sits
|
|
120
|
+
left of it) — compare column rects against `panels-viewport`'s OWN
|
|
121
|
+
rect, never against the page.
|
|
122
|
+
- `getBoundingClientRect` is transform-true (zoom included); `clientWidth`
|
|
123
|
+
is layout px. At floor zoom ≠ 1 the two disagree — use the rect.
|
|
124
|
+
- A 12px glass resize you did not cause is usually the mirror's
|
|
125
|
+
viewport-sync, not your gesture — check the fetch shim before claiming it.
|
|
126
|
+
|
|
127
|
+
## 6. Worked example
|
|
128
|
+
|
|
129
|
+
The full live trace that convicted the tab-strip floor steal (instrument
|
|
130
|
+
→ gesture → stack frame → fix → re-trace) is in
|
|
131
|
+
`dev/kb/rca/2026-10-28 - RCA — The Tab Chip That Rearranged the Room
|
|
132
|
+
(A Strip's Scroll Walked Into the Floor).md`.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* _connect.mjs — shared glass connection for the glass-url / glass-dsi drivers.
|
|
4
|
+
*
|
|
5
|
+
* EXPORTS (do not guess — this header is the contract, keep it in sync):
|
|
6
|
+
* die(msg) — print a JSON error and exit 1.
|
|
7
|
+
* identityFrom(argv) — caller identity, first-wins: --owner-session
|
|
8
|
+
* flag > GLASS_OWNER_SESSION > DSH_SESSION_ID
|
|
9
|
+
* (the harness built-in is CONDITIONAL —
|
|
10
|
+
* dsh-shell-env index.js:89 injects it only
|
|
11
|
+
* when the execution carries an agent binding,
|
|
12
|
+
* RCA 2026-10-30 "the session id is gone" —
|
|
13
|
+
* so explicit beats inherited).
|
|
14
|
+
* pickSession(sessions, envId)
|
|
15
|
+
* — PURE D7 resolver (unit-tested): match the
|
|
16
|
+
* caller's identity to ownerSessionId. NEVER
|
|
17
|
+
* registry index (ADR-0045 amendment 3).
|
|
18
|
+
* Returns { session } | { session:null, error }.
|
|
19
|
+
* connect() — GET /api/browser (the ONLY source of truth,
|
|
20
|
+
* ADR-0030) → pickSession → CDP connect →
|
|
21
|
+
* { session, browser, ctx }. Dies LOUDLY on
|
|
22
|
+
* ambiguity; degraded single-session runs print
|
|
23
|
+
* a warning on stderr and proceed.
|
|
24
|
+
* pick(ctx, substr) — page whose URL contains substr; NEVER
|
|
25
|
+
* positional "newest" among foreign tabs (D2).
|
|
26
|
+
*/
|
|
27
|
+
import { chromium } from 'playwright-core';
|
|
28
|
+
|
|
29
|
+
const DSI = 'http://127.0.0.1:5175';
|
|
30
|
+
|
|
31
|
+
export function die(msg) {
|
|
32
|
+
console.error(JSON.stringify({ error: msg, fallback: 'SKILL.md Step 1 — ask the OPERATOR to click the Browser chip IN THE RIGHT CONVERSATION, then catch the session via GET /api/browser. If DSH_SESSION_ID is absent from env, pass --owner-session <id> (the session id you already know from context).' }));
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function identityFrom(argv) {
|
|
37
|
+
const flag = argv.indexOf('--owner-session');
|
|
38
|
+
if (flag !== -1 && argv[flag + 1]) return argv[flag + 1];
|
|
39
|
+
if (process.env.GLASS_OWNER_SESSION) return process.env.GLASS_OWNER_SESSION;
|
|
40
|
+
if (process.env.DSH_SESSION_ID) return process.env.DSH_SESSION_ID;
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function pickSession(sessions, envId) {
|
|
45
|
+
const list = sessions ?? [];
|
|
46
|
+
if (envId) {
|
|
47
|
+
const mine = list.filter((s) => (s.ownerSessionId ?? null) === envId);
|
|
48
|
+
if (mine.length === 1) return { session: mine[0], degraded: false };
|
|
49
|
+
if (mine.length > 1) {
|
|
50
|
+
const newest = [...mine].sort((a, b) => String(a.createdAt ?? '').localeCompare(String(b.createdAt ?? ''))).at(-1);
|
|
51
|
+
return { session: newest, degraded: false, note: 'multiple glasses owned by ' + envId + ' — newest wins' };
|
|
52
|
+
}
|
|
53
|
+
if (list.length === 1 && (list[0].ownerSessionId ?? null) === null) {
|
|
54
|
+
return { session: list[0], degraded: true, note: 'legacy session without ownerSessionId — degraded match' };
|
|
55
|
+
}
|
|
56
|
+
return { session: null, error: 'no glass owned by ' + envId + ' — your glass is dead or never summoned (click the Browser chip in THIS conversation); live glasses belong to other conversations and are untouchable (D7)' };
|
|
57
|
+
}
|
|
58
|
+
if (list.length === 1) {
|
|
59
|
+
return { session: list[0], degraded: true, note: 'no explicit identity in env — degraded single-session resolution' };
|
|
60
|
+
}
|
|
61
|
+
return { session: null, error: 'multiple live glasses and no explicit identity — pass --owner-session <id> (or GLASS_OWNER_SESSION) from the session id you already know; refusing to guess (D7)' };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function connect() {
|
|
65
|
+
let reg;
|
|
66
|
+
try {
|
|
67
|
+
reg = await (await fetch(DSI + '/api/browser')).json();
|
|
68
|
+
} catch {
|
|
69
|
+
die('DSI dev server not reachable on 5175 — floor not up (dsi dsh --sync --dev --playwright-mcp)');
|
|
70
|
+
}
|
|
71
|
+
const { session, degraded, note, error } = pickSession(reg.sessions, identityFrom(process.argv));
|
|
72
|
+
if (!session) die(error ?? 'no glass session resolved — operator must click the Browser chip');
|
|
73
|
+
if (degraded || note) console.error(JSON.stringify({ warn: note ?? 'degraded', sessionId: session.id }));
|
|
74
|
+
const browser = await chromium.connectOverCDP('http://127.0.0.1:' + session.port).catch(() => null);
|
|
75
|
+
if (!browser) die('CDP connect failed on port ' + session.port);
|
|
76
|
+
return { session, browser, ctx: browser.contexts()[0] };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function pick(ctx, substr) {
|
|
80
|
+
return ctx.pages().find((p) => p.url().includes(substr));
|
|
81
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* glass-url.mjs — the dsi-glass URL path (2026-10-29).
|
|
4
|
+
*
|
|
5
|
+
* For driving NON-DSI surfaces (YouTube, docs, anything) on the operator's
|
|
6
|
+
* glass. Never touches the DSI tab: open <url> adds a NEW tab last and
|
|
7
|
+
* focuses it (tab-grammar: glass <url>); the other verbs run against the
|
|
8
|
+
* NEWEST tab, whatever it is. The DSI server is still needed — it owns the
|
|
9
|
+
* session registry (see _connect.mjs).
|
|
10
|
+
*
|
|
11
|
+
* Usage (run from the DSI repo root so playwright-core resolves):
|
|
12
|
+
* node .agents/skills/dsi-glass/scripts/glass-url.mjs open <url>
|
|
13
|
+
* node …/glass-url.mjs pages
|
|
14
|
+
* node …/glass-url.mjs eval '<js>' # async page.evaluate on newest tab
|
|
15
|
+
* node …/glass-url.mjs shot <file.png> # screenshot of newest tab
|
|
16
|
+
*/
|
|
17
|
+
import { connect, die } from './_connect.mjs';
|
|
18
|
+
|
|
19
|
+
const [cmd, ...args] = process.argv.slice(2);
|
|
20
|
+
const { session, browser, ctx } = await connect();
|
|
21
|
+
|
|
22
|
+
// newest real tab = last http(s) page; CDP page order is not insertion order
|
|
23
|
+
// and the glass placeholder (data:text/html,<title>Glass Browser…) can sit last
|
|
24
|
+
const newest = () => {
|
|
25
|
+
const pages = ctx.pages().filter((p) => p.url().startsWith('http'));
|
|
26
|
+
return pages[pages.length - 1];
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (cmd === 'open') {
|
|
30
|
+
const url = args[0];
|
|
31
|
+
if (!url) die('open needs a url');
|
|
32
|
+
const page = await ctx.newPage();
|
|
33
|
+
await page.goto(url, { waitUntil: 'domcontentloaded' }).catch((e) => die('goto failed: ' + e.message));
|
|
34
|
+
await page.waitForTimeout(1500); // let the SPA settle
|
|
35
|
+
console.log(JSON.stringify({ ok: true, sessionId: session.id, url: page.url(), title: await page.title() }));
|
|
36
|
+
} else if (cmd === 'pages') {
|
|
37
|
+
console.log(JSON.stringify(await Promise.all(ctx.pages().map(async (p) => ({ url: p.url(), title: await p.title() }))), null, 1));
|
|
38
|
+
} else if (cmd === 'eval') {
|
|
39
|
+
if (!args[0]) die('eval needs a js expression');
|
|
40
|
+
console.log(JSON.stringify(await newest().evaluate(async (src) => await eval(src), args[0]), null, 1));
|
|
41
|
+
} else if (cmd === 'shot') {
|
|
42
|
+
const file = args[0] ?? 'tmp/glass-url-shot.png';
|
|
43
|
+
await newest().screenshot({ path: file });
|
|
44
|
+
console.log(JSON.stringify({ ok: true, file }));
|
|
45
|
+
} else {
|
|
46
|
+
die('unknown command: ' + cmd);
|
|
47
|
+
}
|
|
48
|
+
await browser.close();
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* glass.mjs — the dsi-glass fast path (2026-10-29).
|
|
4
|
+
*
|
|
5
|
+
* ONE command replaces the discovery dance: port resolve (:5175 health →
|
|
6
|
+
* GET /api/browser → session port → /json/list → playwright-core
|
|
7
|
+
* connectOverCDP → reuse-or-create the DSI tab). The browser-session
|
|
8
|
+
* registry stays the ONLY source of truth — this script caches nothing
|
|
9
|
+
* (skill rule 3: a hardcoded port verifies a ghost).
|
|
10
|
+
*
|
|
11
|
+
* Usage (run from the DSI repo root so playwright-core resolves):
|
|
12
|
+
* node .agents/skills/dsi-glass/scripts/glass.mjs open [url]
|
|
13
|
+
* node …/glass.mjs eval '<js>' # async page.evaluate, JSON out
|
|
14
|
+
* node …/glass.mjs type '<text>' # real keystrokes into the composer
|
|
15
|
+
* node …/glass.mjs shot <file.png> # viewport screenshot
|
|
16
|
+
* node …/glass.mjs strip # suggest-strip verdict (rows,
|
|
17
|
+
* # activeIdx, ariaSel, tipCount)
|
|
18
|
+
* node …/glass.mjs pages # list glass pages (url + title)
|
|
19
|
+
*
|
|
20
|
+
* On any failure it prints the manual fallback hint (SKILL.md Step 1 —
|
|
21
|
+
* the operator clicks the Browser chip; agents never open sessions).
|
|
22
|
+
*/
|
|
23
|
+
import { connect, die } from './_connect.mjs';
|
|
24
|
+
|
|
25
|
+
const DSI = 'http://127.0.0.1:5175';
|
|
26
|
+
const [cmd, ...args] = process.argv.slice(2);
|
|
27
|
+
|
|
28
|
+
const { session, browser, ctx } = await connect();
|
|
29
|
+
|
|
30
|
+
let page = ctx.pages().find((p) => p.url().includes('5175'));
|
|
31
|
+
if (cmd === 'open') {
|
|
32
|
+
if (!page) {
|
|
33
|
+
page = await ctx.newPage();
|
|
34
|
+
await page.goto(args[0] ?? DSI, { waitUntil: 'domcontentloaded' }).catch(() => {});
|
|
35
|
+
} else if (args[0] && args[0] !== page.url()) {
|
|
36
|
+
await page.goto(args[0], { waitUntil: 'domcontentloaded' }).catch(() => {});
|
|
37
|
+
}
|
|
38
|
+
await page.waitForSelector('body', { timeout: 15000 });
|
|
39
|
+
} else if (!page) {
|
|
40
|
+
die('no DSI tab in the glass — run: glass.mjs open');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (cmd === 'open') {
|
|
44
|
+
await page.waitForTimeout(1500); // let the SPA settle
|
|
45
|
+
console.log(JSON.stringify({ ok: true, sessionId: session.id, port: session.port, url: page.url(), title: await page.title() }));
|
|
46
|
+
} else if (cmd === 'pages') {
|
|
47
|
+
console.log(JSON.stringify(await Promise.all(ctx.pages().map(async (p) => ({ url: p.url(), title: await p.title() }))), null, 1));
|
|
48
|
+
} else if (cmd === 'eval') {
|
|
49
|
+
if (!args[0]) die('eval needs a js expression');
|
|
50
|
+
console.log(JSON.stringify(await page.evaluate(async (src) => await eval(src), args[0]), null, 1));
|
|
51
|
+
} else if (cmd === 'type') {
|
|
52
|
+
if (!args[0]) die('type needs text');
|
|
53
|
+
const ta = page.locator('textarea').first();
|
|
54
|
+
await ta.click();
|
|
55
|
+
await page.keyboard.press('Meta+a');
|
|
56
|
+
await page.keyboard.press('Backspace');
|
|
57
|
+
await page.keyboard.type(args[0], { delay: 60 });
|
|
58
|
+
await page.waitForTimeout(1000); // debounce (120 ms) + fetch
|
|
59
|
+
console.log(JSON.stringify({ ok: true, typed: args[0] }));
|
|
60
|
+
} else if (cmd === 'shot') {
|
|
61
|
+
const file = args[0] ?? 'tmp/glass-shot.png';
|
|
62
|
+
await page.screenshot({ path: file });
|
|
63
|
+
console.log(JSON.stringify({ ok: true, file }));
|
|
64
|
+
} else if (cmd === 'strip') {
|
|
65
|
+
console.log(JSON.stringify(await page.evaluate(() => {
|
|
66
|
+
const strip = document.querySelector('[data-testid=suggest-strip]');
|
|
67
|
+
if (!strip) return { strip: false };
|
|
68
|
+
const chips = [...strip.querySelectorAll(':scope > .strip-chip')];
|
|
69
|
+
const tips = [...document.body.querySelectorAll(':scope > .strip-tip')];
|
|
70
|
+
return {
|
|
71
|
+
strip: true,
|
|
72
|
+
rows: chips.length,
|
|
73
|
+
labels: chips.map((c) => c.querySelector('.strip-label')?.textContent?.trim()),
|
|
74
|
+
activeIdx: chips.findIndex((c) => c.classList.contains('active')),
|
|
75
|
+
ariaSel: chips.map((c) => c.querySelector('.strip-pick')?.getAttribute('aria-selected')),
|
|
76
|
+
tipCount: tips.length,
|
|
77
|
+
tipText: tips[0]?.querySelector('pre')?.textContent?.slice(0, 80) ?? null,
|
|
78
|
+
taValue: document.querySelector('textarea')?.value
|
|
79
|
+
};
|
|
80
|
+
}), null, 1));
|
|
81
|
+
} else {
|
|
82
|
+
die('unknown command: ' + cmd);
|
|
83
|
+
}
|
|
84
|
+
await browser.close();
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: glass-url
|
|
3
|
+
description: Open and drive an ARBITRARY URL (YouTube, docs, any web page) in a NEW tab on the operator's glass browser via CDP — search, click, screenshot, read the page. NOT for verifying DSI work; that is glass-dsi. Reserved keyword /glass-url.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# glass-url — drive an arbitrary URL on the operator's glass
|
|
7
|
+
|
|
8
|
+
Companion skill: `glass-dsi` (verify DSI work on the glass — the DSI tab,
|
|
9
|
+
the floor mirror, the SSE probe). This skill is the OTHER scenario: the
|
|
10
|
+
target is some web page, and the DSI tab is none of your business.
|
|
11
|
+
|
|
12
|
+
**The dispatch rule (Tab-Juggling RCA, ADR-0045):** before any glass work
|
|
13
|
+
ask ONE question — is the surface I must drive the DSI workspace, or some
|
|
14
|
+
other URL? DSI workspace → `glass-dsi`. Any other URL → THIS skill.
|
|
15
|
+
Never navigate the DSI tab, never re-run `open` to "recover".
|
|
16
|
+
|
|
17
|
+
## Environment contract (read before the first command — RCA 2026-10-30)
|
|
18
|
+
|
|
19
|
+
- **Node lives off the default PATH here** (`~/.local/bin/node` observed
|
|
20
|
+
2026-10-30). If `node` is not found, resolve it first:
|
|
21
|
+
`bash -lc "which node"` or check `~/.local/bin`, `/opt/homebrew/bin`.
|
|
22
|
+
- **Run from the DSI repo root** (`~/agentic-ai/deepseek-insight`) so
|
|
23
|
+
`playwright-core` resolves.
|
|
24
|
+
- **Never hand unquoted JS through a shell** — a stripped quote fails
|
|
25
|
+
after the round-trip was already spent. Use `eval --b64 <base64>`.
|
|
26
|
+
- **Every ad-hoc driver snippet must `process.exit()`** — a driver that
|
|
27
|
+
played media once hung its caller for a full 120s timeout.
|
|
28
|
+
- **Script headers are contracts** — `_connect.mjs` exports
|
|
29
|
+
`die`, `connect`, `pick(ctx, substr)`; do not guess names, read the
|
|
30
|
+
header; re-read the header in the same edit that changes the code.
|
|
31
|
+
|
|
32
|
+
## The fast path — glass-url.mjs (one command per intent)
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
# from the DSI repo root (playwright-core resolves there)
|
|
36
|
+
node .agents/skills/glass-url/scripts/glass-url.mjs yt "Dimas Senopati" --play "What's Up" --shot tmp/proof.png
|
|
37
|
+
# → search + normalized match + open watch tab + unmute/play + double
|
|
38
|
+
# gate + shot, ONE JSON with every stage, then exits. --play consumes
|
|
39
|
+
# EVERY term (artist AND title) — put both in it (ADR-0045 D9).
|
|
40
|
+
|
|
41
|
+
node .agents/skills/glass-url/scripts/glass-url.mjs open <url> # NEW tab, focused
|
|
42
|
+
node .agents/skills/glass-url/scripts/glass-url.mjs pages # list tabs
|
|
43
|
+
node .agents/skills/glass-url/scripts/glass-url.mjs eval '<js>' # newest non-DSI tab
|
|
44
|
+
node .agents/skills/glass-url/scripts/glass-url.mjs eval watch?v= '<js>' # inline: LAST arg is the js
|
|
45
|
+
node .agents/skills/glass-url/scripts/glass-url.mjs eval --b64 <b64-js> <url-substring>
|
|
46
|
+
# quote-proof eval; anything left after the payload IS the url-substring
|
|
47
|
+
# (ADR-0045 D10 — parsed by shape, never positional fallback)
|
|
48
|
+
node .agents/skills/glass-url/scripts/glass-url.mjs shot f.png [url-substring]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
"Newest tab" = last http(s) page that is neither the glass placeholder nor
|
|
52
|
+
the DSI tab (:5175). When SEVERAL foreign tabs exist, position lies —
|
|
53
|
+
pass the URL-substring argument (the `yt` verb does this for you).
|
|
54
|
+
Every run re-resolves the session from `GET /api/browser`.
|
|
55
|
+
|
|
56
|
+
## Recipes
|
|
57
|
+
|
|
58
|
+
- **Search + play a video:** the `yt` verb IS the recipe (match
|
|
59
|
+
normalization included: apostrophes/case folded). Only drop to
|
|
60
|
+
`open` → `eval` when the flow is not search-and-play.
|
|
61
|
+
- **Read a page:** `open` → `eval` extract DOM text/links.
|
|
62
|
+
|
|
63
|
+
## Rules
|
|
64
|
+
|
|
65
|
+
1. Always `open` a NEW tab for your target — never reuse a tab you did
|
|
66
|
+
not create, never close operator tabs.
|
|
67
|
+
2. Never navigate the DSI workspace tab; it belongs to glass-dsi.
|
|
68
|
+
3. Multi-step state (click, type, drag) beyond eval/shot: drop to
|
|
69
|
+
playwright-core by hand over CDP (import `connect`/`pick` from
|
|
70
|
+
`.agents/skills/glass-url/scripts/_connect.mjs` — exports listed in
|
|
71
|
+
its header), same as glass-dsi §2–4.
|
|
72
|
+
4. If `GET /api/browser` has no session: the operator must click the
|
|
73
|
+
Browser chip first (the one gesture you cannot simulate). Say so and wait.
|
|
74
|
+
5. Verify with gates, not adjectives: a playback gate is `paused:false`
|
|
75
|
+
plus rising `currentTime`; a navigation gate is the URL/title you
|
|
76
|
+
expected; finish by asking the operator to confirm they SEE it.
|
|
77
|
+
|
|
78
|
+
## Identity (2026-10-30, RCA "the session id is gone")
|
|
79
|
+
|
|
80
|
+
The driver claims YOUR glass by identity, first-wins:
|
|
81
|
+
1. `--owner-session <id>` flag — pass the session id you already know from
|
|
82
|
+
your context when `DSH_SESSION_ID` is absent (the harness injects it
|
|
83
|
+
only when the execution carries an agent binding — dsh-shell-env
|
|
84
|
+
index.js:89 — so its absence is possible and NOT an error).
|
|
85
|
+
2. `GLASS_OWNER_SESSION` env.
|
|
86
|
+
3. `DSH_SESSION_ID` env.
|
|
87
|
+
No identity + several live glasses = loud refusal, never a guess (D7).
|
|
88
|
+
|
|
89
|
+
## The Stop-Loss Law (2026-10-30, ADR-0045 D11 — a refusal is an answer)
|
|
90
|
+
|
|
91
|
+
- **NO_MATCH is an answer.** When the yt verb exits `stage:"match"` with a
|
|
92
|
+
candidate list, REPORT that list and STOP — do not open ad-hoc search
|
|
93
|
+
tabs, do not re-search with different words, do not drop to open/eval to
|
|
94
|
+
hand-roll what the verb just refused. The operator decides the next move.
|
|
95
|
+
- **Grammar dies are answers.** A `die` ("no tab matching …", "no
|
|
96
|
+
non-DSI tab …") ends the investigation, not triggers a workaround hunt.
|
|
97
|
+
Run `pages` once to re-orient if you must, then report.
|
|
98
|
+
- **Already playing is DONE.** If the media is live on the operator's glass
|
|
99
|
+
(they say so, or a prior gate passed), the goal is met — report and stop.
|
|
100
|
+
No follow-up verification, no "one more tab". Verification serves the
|
|
101
|
+
operator's goal; when the goal is met, the correct next action is WORDS.
|
|
102
|
+
- Every extra tab and round-trip after a refusal is a token burn the
|
|
103
|
+
operator pays for. (RCA: "The Answer That Bought Another Round".)
|
|
104
|
+
|
|
105
|
+
## Failure branches (2026-10-30)
|
|
106
|
+
|
|
107
|
+
- `eval` on a cross-origin page still loading can return empty — wait and
|
|
108
|
+
re-run; do not conclude "no results".
|
|
109
|
+
- String matching needs normalization (case, apostrophes) or exact titles
|
|
110
|
+
will NO_MATCH — `yt` normalizes for you.
|
|
111
|
+
- A vite restart empties the registry and kills the Chrome — re-run from
|
|
112
|
+
the operator's chip click, same as glass-dsi.
|
|
113
|
+
- "Newest non-DSI tab" is positional and CAN pick a sibling foreign tab —
|
|
114
|
+
select by URL substring (the optional eval/shot argument), not position.
|
|
115
|
+
- Node/git missing from PATH, quoting mangling, guessed flags, and
|
|
116
|
+
non-exiting drivers each cost a full round-trip: see the environment
|
|
117
|
+
contract above; they are pre-paid now.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* _args.mjs — pure helpers for glass-url.mjs (ADR-0045 Amendment 5, D9 + D10).
|
|
3
|
+
*
|
|
4
|
+
* Lives beside _connect.mjs so vitest can pin them without touching CDP
|
|
5
|
+
* (the driver connects at import; these never do). Exports are a contract:
|
|
6
|
+
* change them in the same edit that changes glass-url.mjs.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Title normalization: fold apostrophes, case, and punctuation runs.
|
|
11
|
+
* @param {string | undefined | null} s
|
|
12
|
+
* @returns {string}
|
|
13
|
+
*/
|
|
14
|
+
export const norm = (s) => (s || '').toLowerCase().replace(/[\u2019']/g, '').replace(/[^a-z0-9]+/g, ' ').trim();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* D10 — the eval grammar is parsed, not positional.
|
|
18
|
+
* Inline mode: [substr?] src — the LAST arg is always the JS source.
|
|
19
|
+
* b64 mode: [b64payload, substr?] — the payload is consumed by the caller
|
|
20
|
+
* (it already stripped --b64), so anything LEFT is the substring.
|
|
21
|
+
* Returns an object with src and substr, undefined where absent.
|
|
22
|
+
* @param {string[]} rest
|
|
23
|
+
* @param {{ b64?: boolean } | undefined} [opts]
|
|
24
|
+
* @returns {{ src: string | undefined, substr: string | undefined }}
|
|
25
|
+
*/
|
|
26
|
+
export function parseEvalArgs(rest, opts) {
|
|
27
|
+
const b64 = !!(opts && opts.b64);
|
|
28
|
+
if (b64) {
|
|
29
|
+
return { src: rest[0], substr: rest.length > 1 ? rest[1] : undefined };
|
|
30
|
+
}
|
|
31
|
+
if (rest.length > 1) return { substr: rest[0], src: rest[1] };
|
|
32
|
+
return { src: rest[0], substr: undefined };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* D9 — the play match consumes EVERY play term.
|
|
37
|
+
* True only when every whitespace-split term of play appears in the
|
|
38
|
+
* normalized title. An empty or absent play value means no filter (true) —
|
|
39
|
+
* the yt verb then takes the first result, unchanged behavior.
|
|
40
|
+
* @param {string} title
|
|
41
|
+
* @param {string | undefined | null} play
|
|
42
|
+
* @returns {boolean}
|
|
43
|
+
*/
|
|
44
|
+
export function matchAllTerms(title, play) {
|
|
45
|
+
const terms = (play || '').split(/\s+/).filter(Boolean);
|
|
46
|
+
if (!terms.length) return true;
|
|
47
|
+
const t = norm(title);
|
|
48
|
+
return terms.every((term) => t.includes(norm(term)));
|
|
49
|
+
}
|