@deepseek-insight/dsi 0.8.5 → 0.9.1

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.
Files changed (210) hide show
  1. package/.agents/skills/{dsi-gb-verifier → glass-dsi}/SKILL.md +57 -5
  2. package/.agents/skills/glass-dsi/references/cdp-verification.md +132 -0
  3. package/.agents/skills/glass-dsi/scripts/_connect.mjs +81 -0
  4. package/.agents/skills/glass-dsi/scripts/glass-url.mjs +48 -0
  5. package/.agents/skills/glass-dsi/scripts/glass.mjs +84 -0
  6. package/.agents/skills/glass-url/SKILL.md +117 -0
  7. package/.agents/skills/glass-url/scripts/_args.mjs +49 -0
  8. package/.agents/skills/glass-url/scripts/_connect.mjs +99 -0
  9. package/.agents/skills/glass-url/scripts/glass-url.mjs +114 -0
  10. package/bin/dsi.mjs +48 -74
  11. package/bin/lib/zai-patch.mjs +115 -0
  12. package/build/client/_app/immutable/assets/0.Ch5VtsKp.css +2 -0
  13. package/build/client/_app/immutable/assets/2.D0QOh44D.css +1 -0
  14. package/build/client/_app/immutable/chunks/{DwcY-69G.js → 02Wfo2G3.js} +1 -1
  15. package/build/client/_app/immutable/chunks/0Tfhif1V.js +3 -0
  16. package/build/client/_app/immutable/chunks/{DUCaFYlx.js → 4bHE1npv.js} +1 -1
  17. package/build/client/_app/immutable/chunks/{4cwyag_I.js → B4hDUAJl.js} +1 -1
  18. package/build/client/_app/immutable/chunks/{hC0DBYN6.js → BFNQKoqg.js} +2 -2
  19. package/build/client/_app/immutable/chunks/{Cr2ck_ss.js → BIPXB-2I.js} +1 -1
  20. package/build/client/_app/immutable/chunks/{CeLBjOd9.js → BIgv-kQR.js} +1 -1
  21. package/build/client/_app/immutable/chunks/BK6k1nBs.js +1 -0
  22. package/build/client/_app/immutable/chunks/{SN3Efo-Q.js → BKwmKcDY.js} +1 -1
  23. package/build/client/_app/immutable/chunks/{CRFuOqJI.js → BORjuqef.js} +1 -1
  24. package/build/client/_app/immutable/chunks/{CH_bR_0j.js → BPmZB0-N.js} +1 -1
  25. package/build/client/_app/immutable/chunks/BROtno1Y.js +1 -0
  26. package/build/client/_app/immutable/chunks/{DEVxi5CK.js → BT5Iel00.js} +1 -1
  27. package/build/client/_app/immutable/chunks/{DdI16loP.js → BX3y_1Hh.js} +1 -1
  28. package/build/client/_app/immutable/chunks/Be-_M64M.js +1 -0
  29. package/build/client/_app/immutable/chunks/{DuiFyTVb.js → Bea1gxLq.js} +1 -1
  30. package/build/client/_app/immutable/chunks/{D0uxHECr.js → BpkpgvVw.js} +1 -1
  31. package/build/client/_app/immutable/chunks/{CB55Rp7-.js → BreZS7EW.js} +1 -1
  32. package/build/client/_app/immutable/chunks/{BmDADyfH.js → BsS_byzk.js} +1 -1
  33. package/build/client/_app/immutable/chunks/{BWRXzjmQ.js → Bslg-dr5.js} +1 -1
  34. package/build/client/_app/immutable/chunks/{BkYT72a1.js → C-YczRN1.js} +1 -1
  35. package/build/client/_app/immutable/chunks/{DBKMIEwD.js → C2aW4lzo.js} +1 -1
  36. package/build/client/_app/immutable/chunks/{C4gs6zoI.js → C2qFXaz5.js} +1 -1
  37. package/build/client/_app/immutable/chunks/{BBd0nTHG.js → C5RyRpOh.js} +1 -1
  38. package/build/client/_app/immutable/chunks/{DJQr4efH.js → C5iHDVU_.js} +1 -1
  39. package/build/client/_app/immutable/chunks/{B4F5liKq.js → C7opVlLF.js} +1 -1
  40. package/build/client/_app/immutable/chunks/{DIxy2USu.js → CAuEkmZ4.js} +1 -1
  41. package/build/client/_app/immutable/chunks/{BO99LSSA.js → CIkiqgtA.js} +1 -1
  42. package/build/client/_app/immutable/chunks/{Bpd0I3U7.js → CJesWaZn.js} +1 -1
  43. package/build/client/_app/immutable/chunks/{at6PQqQ4.js → CRsoS5Y9.js} +1 -1
  44. package/build/client/_app/immutable/chunks/CTWtsoJD.js +6 -0
  45. package/build/client/_app/immutable/chunks/{lF8CNVOA.js → CXkrluSK.js} +1 -1
  46. package/build/client/_app/immutable/chunks/{DmRY6FWm.js → C_8kFZ_X.js} +4 -4
  47. package/build/client/_app/immutable/chunks/{D6KenyiF.js → Ch7hUoAH.js} +1 -1
  48. package/build/client/_app/immutable/chunks/{DfUgh5E_.js → CjajmcJs.js} +1 -1
  49. package/build/client/_app/immutable/chunks/{q5PRaRZk.js → Ck6GS6Vb.js} +1 -1
  50. package/build/client/_app/immutable/chunks/{eFcFJ9Ld.js → ClGoDr_f.js} +1 -1
  51. package/build/client/_app/immutable/chunks/{BQC6O_RV.js → ClqGHlec.js} +1 -1
  52. package/build/client/_app/immutable/chunks/{zypfUZYM.js → CnW6hje6.js} +1 -1
  53. package/build/client/_app/immutable/chunks/{OW5Q7tGb.js → CpI6VYCH.js} +1 -1
  54. package/build/client/_app/immutable/chunks/{BXKc4uuX.js → CygwwaiE.js} +1 -1
  55. package/build/client/_app/immutable/chunks/{Bqwvv7Vf.js → CyhZtsZO.js} +35 -35
  56. package/build/client/_app/immutable/chunks/{BenkQ_4r.js → D-E2Noqq.js} +1 -1
  57. package/build/client/_app/immutable/chunks/{DuRZnRVw.js → D4Btzp_A.js} +1 -1
  58. package/build/client/_app/immutable/chunks/{CdaJvl_A.js → D4C3Jijv.js} +1 -1
  59. package/build/client/_app/immutable/chunks/D9jhmf3I.js +1 -0
  60. package/build/client/_app/immutable/chunks/{Cf0aMC4n.js → DCw0gAtv.js} +1 -1
  61. package/build/client/_app/immutable/chunks/{B6bTO8_7.js → DEW3KpiC.js} +1 -1
  62. package/build/client/_app/immutable/chunks/{b4-Ro8NH.js → DXD_Wzp9.js} +1 -1
  63. package/build/client/_app/immutable/chunks/{O6xxeEm8.js → DYLFbKJe.js} +1 -1
  64. package/build/client/_app/immutable/chunks/{BsBBq-Qk.js → DYu7kgVa.js} +1 -1
  65. package/build/client/_app/immutable/chunks/Dfexc5qV.js +1 -0
  66. package/build/client/_app/immutable/chunks/{kzciT-3i.js → DhmUE8Ri.js} +1 -1
  67. package/build/client/_app/immutable/chunks/{DdJNsJBH.js → DjwX3rAC.js} +1 -1
  68. package/build/client/_app/immutable/chunks/{CajOZJDl.js → DlOfy8Sx.js} +1 -1
  69. package/build/client/_app/immutable/chunks/{CK5vhXvt.js → Do7Y1_MQ.js} +1 -1
  70. package/build/client/_app/immutable/chunks/{ap4GAVq-.js → Dq2XIb1m.js} +1 -1
  71. package/build/client/_app/immutable/chunks/Ds3NY1WI.js +1 -0
  72. package/build/client/_app/immutable/chunks/{Czey8tDK.js → DuT_Qr5k.js} +1 -1
  73. package/build/client/_app/immutable/chunks/{4B6J_kM2.js → DyGggFea.js} +1 -1
  74. package/build/client/_app/immutable/chunks/{D0ChUnpi.js → Dym4i64U.js} +1 -1
  75. package/build/client/_app/immutable/chunks/FPsIAiN_.js +1 -0
  76. package/build/client/_app/immutable/chunks/{CevKuuic.js → GIczpP_D.js} +1 -1
  77. package/build/client/_app/immutable/chunks/{B2jrDnt8.js → LjOLSmU7.js} +1 -1
  78. package/build/client/_app/immutable/chunks/VtK73aN-.js +8 -0
  79. package/build/client/_app/immutable/chunks/{AcmOeh2U.js → ZqoQH_jm.js} +1 -1
  80. package/build/client/_app/immutable/chunks/{BlwWx85l.js → aXn6rE_7.js} +1 -1
  81. package/build/client/_app/immutable/chunks/{Czc4_W7v.js → dUOeoGwg.js} +1 -1
  82. package/build/client/_app/immutable/chunks/f50lp1rr.js +1 -0
  83. package/build/client/_app/immutable/chunks/{7FnrqGK9.js → lvLrv1cG.js} +1 -1
  84. package/build/client/_app/immutable/chunks/{CZoElI5B.js → pt3_jHwh.js} +1 -1
  85. package/build/client/_app/immutable/chunks/{Byu_teLA.js → q8irUX-p.js} +1 -1
  86. package/build/client/_app/immutable/chunks/{CnxoqrkQ.js → qmOgUo3c.js} +1 -1
  87. package/build/client/_app/immutable/chunks/{DU8C5thd.js → xvTPLhcB.js} +1 -1
  88. package/build/client/_app/immutable/chunks/{DFBKiA2Z.js → zp7hrpsC.js} +1 -1
  89. package/build/client/_app/immutable/entry/app.C_yn4m6w.js +2 -0
  90. package/build/client/_app/immutable/entry/start.Cvx_lhm5.js +1 -0
  91. package/build/client/_app/immutable/nodes/0.fsrqKU9i.js +1 -0
  92. package/build/client/_app/immutable/nodes/1.DZxzqrcK.js +1 -0
  93. package/build/client/_app/immutable/nodes/2.ckwEPlsL.js +340 -0
  94. package/build/client/_app/version.json +1 -1
  95. package/build/handler.js +6 -6
  96. package/build/index.js +6 -6
  97. package/build/server/chunks/chunks/{app-config.svelte.js-DCc9d7A4.js → app-config.svelte.js-BXjvTmJu.js} +4 -3
  98. package/build/server/chunks/chunks/{config.js-s6iKwHD7.js → config.js-r_jw_bQQ.js} +53 -2
  99. package/build/server/chunks/chunks/{db.js-CxxWK5sn.js → db.js-f2PmBjyD.js} +2 -2
  100. package/build/server/chunks/chunks/{db2.js-DwJ9lySe.js → db2.js-DkwY64WO.js} +2 -2
  101. package/build/server/chunks/chunks/{dsh-connection.js-Chtudg1p.js → dsh-connection.js-BW07Aicl.js} +18 -10
  102. package/build/server/chunks/chunks/{dsh-events.js-BUdvZQmd.js → dsh-events.js-BHf0lLZ5.js} +11 -1
  103. package/build/server/chunks/chunks/{git-probe.js-BX9FPnet.js → git-probe.js-CQqTV7XX.js} +3 -3
  104. package/build/server/chunks/chunks/{index-server.js-DmIEbDVz.js → index-server.js-CPkVoRxB.js} +2 -2
  105. package/build/server/chunks/chunks/{insight-config.js-Db5fe5Df.js → insight-config.js-C5-Rhh5A.js} +13 -4
  106. package/build/server/chunks/chunks/{internal2.js-CaZaz-a9.js → internal2.js-zTmbne6n.js} +4 -4
  107. package/build/server/chunks/chunks/{registry.js-syaTZ_-A.js → registry.js-CWnRQ4vx.js} +430 -52
  108. package/build/server/chunks/chunks/{registry2.js-D3Pr1Rv9.js → registry2.js-CFzpvj9c.js} +17 -1
  109. package/build/server/chunks/chunks/{server.js-B1bDXhHu.js → server.js-Dijo7DtV.js} +2 -2
  110. package/build/server/chunks/chunks/{settings-document.js-BHESJ7im.js → settings-document.js-DxKURfc_.js} +2 -2
  111. package/build/server/chunks/chunks/{state.js-oYjf745s.js → state.js-CPIukTkD.js} +5 -5
  112. package/build/server/chunks/chunks/{watcher.js-Ci9jsM5l.js → watcher.js-DvlNn8X0.js} +5 -5
  113. package/build/server/chunks/entries/endpoints/api/a2a/_id_/{_server.ts.js-CHaYhzjy.js → _server.ts.js-DItDXV23.js} +5 -5
  114. package/build/server/chunks/entries/endpoints/api/a2a/{_server.ts.js-CdyqA85c.js → _server.ts.js-Hor8QZb1.js} +8 -8
  115. package/build/server/chunks/entries/endpoints/api/a2a/register/{_server.ts.js-DO_FS5b4.js → _server.ts.js-CEvvsa8B.js} +8 -8
  116. package/build/server/chunks/entries/endpoints/api/browser/_id_/activate/{_server.ts.js-D7Be4JUf.js → _server.ts.js-sXqf-okw.js} +5 -5
  117. package/build/server/chunks/entries/endpoints/api/browser/_id_/close/{_server.ts.js-CGkm2H-U.js → _server.ts.js-Byj9ApJh.js} +5 -5
  118. package/build/server/chunks/entries/endpoints/api/browser/_id_/closetab/{_server.ts.js-D7SLUfOo.js → _server.ts.js-DOIsrzvg.js} +16 -9
  119. package/build/server/chunks/entries/endpoints/api/browser/_id_/element/{_server.ts.js-C3d_JV-q.js → _server.ts.js-Cq3gmRfE.js} +5 -5
  120. package/build/server/chunks/entries/endpoints/api/browser/_id_/history/_server.ts.js-BGSLIV0t.js +61 -0
  121. package/build/server/chunks/entries/endpoints/api/browser/_id_/input/{_server.ts.js-DW0hyVML.js → _server.ts.js-8slca75-.js} +5 -5
  122. package/build/server/chunks/entries/endpoints/api/browser/_id_/mcp/{_server.ts.js-Ev-hdBlf.js → _server.ts.js-CpbdTYds.js} +5 -5
  123. package/build/server/chunks/entries/endpoints/api/browser/_id_/navigate/{_server.ts.js-DZ8-wocV.js → _server.ts.js-Bls9LtLY.js} +5 -5
  124. package/build/server/chunks/entries/endpoints/api/browser/_id_/opentab/{_server.ts.js-aapPrIQK.js → _server.ts.js-DqNi_iW_.js} +5 -5
  125. package/build/server/chunks/entries/endpoints/api/browser/_id_/page/{_server.ts.js-DANA_hMd.js → _server.ts.js-DuXWwo7i.js} +5 -5
  126. package/build/server/chunks/entries/endpoints/api/browser/_id_/stream/{_server.ts.js-BqfseXFy.js → _server.ts.js-DXfqBDEw.js} +17 -5
  127. package/build/server/chunks/entries/endpoints/api/browser/_id_/tabs/{_server.ts.js-DFFF9qe-.js → _server.ts.js-Bgnl8lYs.js} +5 -5
  128. package/build/server/chunks/entries/endpoints/api/browser/_id_/viewport/{_server.ts.js-ek6-D4Zm.js → _server.ts.js-FHmQVbrv.js} +5 -5
  129. package/build/server/chunks/entries/endpoints/api/browser/_id_/zoom/_server.ts.js-BV4cBtSA.js +62 -0
  130. package/build/server/chunks/entries/endpoints/api/browser/{_server.ts.js-CPjKy3ma.js → _server.ts.js-4vgkwh7v.js} +9 -6
  131. package/build/server/chunks/entries/endpoints/api/config/{_server.ts.js-CWE9NP6g.js → _server.ts.js-C_9kwANR.js} +9 -6
  132. package/build/server/chunks/entries/endpoints/api/dsh/directory/{_server.ts.js-D-raYQon.js → _server.ts.js-h1OTHcL4.js} +5 -5
  133. package/build/server/chunks/entries/endpoints/api/dsh/jobs/{_server.ts.js-CI4dEHFY.js → _server.ts.js-B6nih9Sd.js} +5 -5
  134. package/build/server/chunks/entries/endpoints/api/dsh/jobs/follow/{_server.ts.js-cnjoSLtY.js → _server.ts.js-Cf17SVmD.js} +5 -5
  135. package/build/server/chunks/entries/endpoints/api/dsh/pick-directory/{_server.ts.js-0UUtapX5.js → _server.ts.js-DjNwMbdS.js} +5 -5
  136. package/build/server/chunks/entries/endpoints/api/dsh/presets/{_server.ts.js-MK5ezU8u.js → _server.ts.js-Cz5aaEhC.js} +5 -5
  137. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/_server.ts.js-BFBy5O9Y.js +78 -0
  138. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/cancel/{_server.ts.js-wGEl1fuF.js → _server.ts.js-CgEdCo3T.js} +5 -5
  139. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/catalog/{_server.ts.js-Bz7u2BlD.js → _server.ts.js-Bo_aEnHh.js} +5 -5
  140. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/changes/{_server.ts.js-yue5aEjr.js → _server.ts.js-Bd2G_GaH.js} +5 -5
  141. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/command/{_server.ts.js-BFSs5T2m.js → _server.ts.js-DL64FyRw.js} +5 -5
  142. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/events/{_server.ts.js-C2i85wQy.js → _server.ts.js-MhOGB66D.js} +6 -6
  143. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/fork/{_server.ts.js-_toO4f4W.js → _server.ts.js-MjPgXgGO.js} +5 -5
  144. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/goal/{_server.ts.js-BGJnDV85.js → _server.ts.js-BUjDae5H.js} +5 -5
  145. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/history/{_server.ts.js-CQCJg8U8.js → _server.ts.js-dTKd7Hsv.js} +6 -6
  146. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/models/{_server.ts.js-0ADvdE79.js → _server.ts.js-B82rvKoI.js} +5 -5
  147. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/path/{_server.ts.js-DyO4T1Ro.js → _server.ts.js-Cqijsi-c.js} +4 -4
  148. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/permission/{_server.ts.js-CIY7oimw.js → _server.ts.js-CL_vVv2p.js} +29 -6
  149. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/prompt/{_server.ts.js-B-9faNHX.js → _server.ts.js-WS4W9Ly4.js} +5 -5
  150. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/rename/{_server.ts.js-E7-0zfiH.js → _server.ts.js-B72KGRGh.js} +5 -5
  151. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/respond/{_server.ts.js-CODtLQ3Q.js → _server.ts.js-DK5xb2b5.js} +5 -5
  152. 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
  153. package/build/server/chunks/entries/endpoints/api/dsh/sessions/{_server.ts.js-C0WJnv2b.js → _server.ts.js-CMhfhbkN.js} +5 -5
  154. package/build/server/chunks/entries/endpoints/api/dsh/subagents/{_server.ts.js-D5bc4xg4.js → _server.ts.js-BLvcFsg6.js} +5 -5
  155. package/build/server/chunks/entries/endpoints/api/dsh/workspace-file/{_server.ts.js-23ycAyUg.js → _server.ts.js-D_rw2Uq6.js} +5 -5
  156. package/build/server/chunks/entries/endpoints/api/dsh/workspace-tree/{_server.ts.js-B4w5Jh7f.js → _server.ts.js-DfXpMMpw.js} +5 -5
  157. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/{_server.ts.js-VQLxDbFE.js → _server.ts.js-2mJCJVxk.js} +5 -5
  158. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/delete/{_server.ts.js-vs5N5Cya.js → _server.ts.js-BCx0Lzjf.js} +5 -5
  159. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/rename/{_server.ts.js-BOWhoBHV.js → _server.ts.js-DECaSjwp.js} +5 -5
  160. package/build/server/chunks/entries/endpoints/api/prompts/_id_/{_server.ts.js-aDEAGfJe.js → _server.ts.js-i_ciJzlb.js} +5 -5
  161. package/build/server/chunks/entries/endpoints/api/prompts/{_server.ts.js-BZ-nRrTp.js → _server.ts.js-BO1pScn7.js} +5 -5
  162. package/build/server/chunks/entries/endpoints/api/prompts/use/{_server.ts.js-CkDY1PQ7.js → _server.ts.js-Buhpf7WE.js} +5 -5
  163. package/build/server/chunks/entries/endpoints/api/settings/{_server.ts.js-CHvgF47Y.js → _server.ts.js-DngUQzcT.js} +4 -4
  164. package/build/server/chunks/entries/endpoints/api/terminal/_id_/output/{_server.ts.js-BNBxebgG.js → _server.ts.js-DLETP4yQ.js} +2 -2
  165. package/build/server/chunks/entries/endpoints/api/terminal/_id_/reattach/{_server.ts.js-DDRJBGIr.js → _server.ts.js-uWl6oxPS.js} +2 -2
  166. package/build/server/chunks/entries/endpoints/api/terminal/_id_/send/{_server.ts.js-CA0vc_Cm.js → _server.ts.js-DYNmXaAd.js} +9 -2
  167. package/build/server/chunks/entries/endpoints/api/terminal/_id_/stream/{_server.ts.js-D6L8Gd_f.js → _server.ts.js-C5m3Ktho.js} +2 -2
  168. package/build/server/chunks/entries/endpoints/api/terminal/{_server.ts.js-CbRT4vBo.js → _server.ts.js-DoTNvcOa.js} +5 -5
  169. package/build/server/chunks/entries/endpoints/api/workspace/file-write/{_server.ts.js-BwD0KaXy.js → _server.ts.js-BzYOJSkI.js} +7 -7
  170. package/build/server/chunks/entries/endpoints/api/workspace/git-events/{_server.ts.js-DgbMRh3d.js → _server.ts.js-xcNesei9.js} +7 -7
  171. package/build/server/chunks/entries/endpoints/api/workspace/git-file-head/{_server.ts.js-DRqZawic.js → _server.ts.js-DsJWYdxt.js} +7 -7
  172. package/build/server/chunks/entries/endpoints/api/workspace/git-map/{_server.ts.js-CTXwwwB1.js → _server.ts.js-CNCku9BR.js} +7 -7
  173. package/build/server/chunks/entries/endpoints/api/workspace/git-status/{_server.ts.js-B4aJBY2w.js → _server.ts.js-nLsNjOxj.js} +7 -7
  174. package/build/server/chunks/entries/endpoints/api/workspace/write-gate/{_server.ts.js-CDJJA18L.js → _server.ts.js-urQk2-ds.js} +7 -7
  175. package/build/server/chunks/entries/{hooks.server.js-Iel6oE7w.js → hooks.server.js-CU2RE5vs.js} +3 -3
  176. package/build/server/chunks/entries/pages/{_error.svelte.js-B-wdFjVG.js → _error.svelte.js-Dss5_PtG.js} +6 -6
  177. package/build/server/chunks/entries/pages/{_page.server.ts.js-CaoeQzem.js → _page.server.ts.js-BK3Y6eff.js} +3 -3
  178. package/build/server/chunks/entries/pages/{_page.svelte.js-CY7zcWr4.js → _page.svelte.js-CJboFEGf.js} +2681 -648
  179. package/build/server/chunks/{handler-DYk4NJto.js → handler-Bn-Z9bWE.js} +3 -3
  180. package/build/server/chunks/{index.js-kL9MZ99b.js → index.js-NQAT8Awn.js} +4 -4
  181. package/build/server/chunks/{manifest.js-BrMLQqec.js → manifest.js-hlUhRW1X.js} +79 -65
  182. package/build/server/chunks/nodes/{0.js-BembYTTr.js → 0.js-CuV3dXVD.js} +3 -3
  183. package/build/server/chunks/nodes/1.js-CxcLyijV.js +9 -0
  184. package/build/server/chunks/nodes/{2.js-BezA2RPm.js → 2.js-_lM-D6Dt.js} +10 -10
  185. package/package.json +2 -2
  186. package/scripts/dsh-web-synced.sh +21 -5
  187. package/template/.dsi/prompts.sqlite +0 -0
  188. package/template/.dsi/prompts.sqlite-shm +0 -0
  189. package/template/.dsi/prompts.sqlite-wal +0 -0
  190. package/template/.dsi/settings.yaml +7 -2
  191. package/build/client/_app/immutable/assets/0.C6AGVUc8.css +0 -2
  192. package/build/client/_app/immutable/assets/2.gXzZuuwh.css +0 -1
  193. package/build/client/_app/immutable/chunks/BFOY8uwF.js +0 -1
  194. package/build/client/_app/immutable/chunks/BHDqH9nE.js +0 -1
  195. package/build/client/_app/immutable/chunks/CAneZX4t.js +0 -8
  196. package/build/client/_app/immutable/chunks/CrTRqozz.js +0 -1
  197. package/build/client/_app/immutable/chunks/DQXo7qdJ.js +0 -1
  198. package/build/client/_app/immutable/chunks/DxGYLnDH.js +0 -1
  199. package/build/client/_app/immutable/chunks/HD-mJtOS.js +0 -6
  200. package/build/client/_app/immutable/chunks/K3xyLTzZ.js +0 -1
  201. package/build/client/_app/immutable/chunks/cHj8EuyS.js +0 -3
  202. package/build/client/_app/immutable/chunks/o7DVZODA.js +0 -1
  203. package/build/client/_app/immutable/chunks/pdYhlwhf.js +0 -1
  204. package/build/client/_app/immutable/entry/app.DHewwbUQ.js +0 -2
  205. package/build/client/_app/immutable/entry/start.C0PcwkeZ.js +0 -1
  206. package/build/client/_app/immutable/nodes/0.CP10wY64.js +0 -1
  207. package/build/client/_app/immutable/nodes/1.qWvE0DiU.js +0 -1
  208. package/build/client/_app/immutable/nodes/2.Nw7iFtoh.js +0 -341
  209. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/_server.ts.js-CEiMgzjC.js +0 -46
  210. package/build/server/chunks/nodes/1.js-CKJjyWGZ.js +0 -9
@@ -1,13 +1,24 @@
1
1
  ---
2
- name: dsi-gb-verifier
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-gb-verifier.
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-gb-verifier — verify work on the operator's own Glass Browser
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. The one rule above all:
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
+ }