@deepseek-insight/dsi 0.8.4 → 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.
Files changed (211) hide show
  1. package/.agents/skills/glass-dsi/SKILL.md +195 -0
  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 +23 -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/{GKkjunMm.js → 0ruuBBbh.js} +2 -2
  17. package/build/client/_app/immutable/chunks/{DUCaFYlx.js → 4bHE1npv.js} +1 -1
  18. package/build/client/_app/immutable/chunks/{4cwyag_I.js → B4hDUAJl.js} +1 -1
  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/{DuiFyTVb.js → Bea1gxLq.js} +1 -1
  29. package/build/client/_app/immutable/chunks/{D0uxHECr.js → BpkpgvVw.js} +1 -1
  30. package/build/client/_app/immutable/chunks/{CB55Rp7-.js → BreZS7EW.js} +1 -1
  31. package/build/client/_app/immutable/chunks/{BmDADyfH.js → BsS_byzk.js} +1 -1
  32. package/build/client/_app/immutable/chunks/{BWRXzjmQ.js → Bslg-dr5.js} +1 -1
  33. package/build/client/_app/immutable/chunks/{BkYT72a1.js → C-YczRN1.js} +1 -1
  34. package/build/client/_app/immutable/chunks/{DBKMIEwD.js → C2aW4lzo.js} +1 -1
  35. package/build/client/_app/immutable/chunks/{C4gs6zoI.js → C2qFXaz5.js} +1 -1
  36. package/build/client/_app/immutable/chunks/{BBd0nTHG.js → C5RyRpOh.js} +1 -1
  37. package/build/client/_app/immutable/chunks/{DJQr4efH.js → C5iHDVU_.js} +1 -1
  38. package/build/client/_app/immutable/chunks/{B4F5liKq.js → C7opVlLF.js} +1 -1
  39. package/build/client/_app/immutable/chunks/{DIxy2USu.js → CAuEkmZ4.js} +1 -1
  40. package/build/client/_app/immutable/chunks/{BO99LSSA.js → CIkiqgtA.js} +1 -1
  41. package/build/client/_app/immutable/chunks/{Bpd0I3U7.js → CJesWaZn.js} +1 -1
  42. package/build/client/_app/immutable/chunks/{at6PQqQ4.js → CRsoS5Y9.js} +1 -1
  43. package/build/client/_app/immutable/chunks/CTWtsoJD.js +6 -0
  44. package/build/client/_app/immutable/chunks/CWk5gmU2.js +1 -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/{CnzmIbjr.js → ChmmHPdM.js} +1 -1
  49. package/build/client/_app/immutable/chunks/{DfUgh5E_.js → CjajmcJs.js} +1 -1
  50. package/build/client/_app/immutable/chunks/{q5PRaRZk.js → Ck6GS6Vb.js} +1 -1
  51. package/build/client/_app/immutable/chunks/{eFcFJ9Ld.js → ClGoDr_f.js} +1 -1
  52. package/build/client/_app/immutable/chunks/{BQC6O_RV.js → ClqGHlec.js} +1 -1
  53. package/build/client/_app/immutable/chunks/{zypfUZYM.js → CnW6hje6.js} +1 -1
  54. package/build/client/_app/immutable/chunks/{OW5Q7tGb.js → CpI6VYCH.js} +1 -1
  55. package/build/client/_app/immutable/chunks/{BXKc4uuX.js → CygwwaiE.js} +1 -1
  56. package/build/client/_app/immutable/chunks/{Bqwvv7Vf.js → CyhZtsZO.js} +35 -35
  57. package/build/client/_app/immutable/chunks/{BenkQ_4r.js → D-E2Noqq.js} +1 -1
  58. package/build/client/_app/immutable/chunks/{DuRZnRVw.js → D4Btzp_A.js} +1 -1
  59. package/build/client/_app/immutable/chunks/{CdaJvl_A.js → D4C3Jijv.js} +1 -1
  60. package/build/client/_app/immutable/chunks/D9jhmf3I.js +1 -0
  61. package/build/client/_app/immutable/chunks/{Cf0aMC4n.js → DCw0gAtv.js} +1 -1
  62. package/build/client/_app/immutable/chunks/{B6bTO8_7.js → DEW3KpiC.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/{Czey8tDK.js → DuT_Qr5k.js} +1 -1
  72. package/build/client/_app/immutable/chunks/{4B6J_kM2.js → DyGggFea.js} +1 -1
  73. package/build/client/_app/immutable/chunks/{D0ChUnpi.js → Dym4i64U.js} +1 -1
  74. package/build/client/_app/immutable/chunks/FPsIAiN_.js +1 -0
  75. package/build/client/_app/immutable/chunks/{CevKuuic.js → GIczpP_D.js} +1 -1
  76. package/build/client/_app/immutable/chunks/{B2jrDnt8.js → LjOLSmU7.js} +1 -1
  77. package/build/client/_app/immutable/chunks/VtK73aN-.js +8 -0
  78. package/build/client/_app/immutable/chunks/{AcmOeh2U.js → ZqoQH_jm.js} +1 -1
  79. package/build/client/_app/immutable/chunks/{BlwWx85l.js → aXn6rE_7.js} +1 -1
  80. package/build/client/_app/immutable/chunks/{Czc4_W7v.js → dUOeoGwg.js} +1 -1
  81. package/build/client/_app/immutable/chunks/f50lp1rr.js +1 -0
  82. package/build/client/_app/immutable/chunks/{7FnrqGK9.js → lvLrv1cG.js} +1 -1
  83. package/build/client/_app/immutable/chunks/{CZoElI5B.js → pt3_jHwh.js} +1 -1
  84. package/build/client/_app/immutable/chunks/{Byu_teLA.js → q8irUX-p.js} +1 -1
  85. package/build/client/_app/immutable/chunks/{CnxoqrkQ.js → qmOgUo3c.js} +1 -1
  86. package/build/client/_app/immutable/chunks/vpNeypNM.js +1 -0
  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.D4oc_iez.js +2 -0
  90. package/build/client/_app/immutable/entry/start.Xkr2MCWg.js +1 -0
  91. package/build/client/_app/immutable/nodes/0.fsrqKU9i.js +1 -0
  92. package/build/client/_app/immutable/nodes/1.3F37GwcO.js +1 -0
  93. package/build/client/_app/immutable/nodes/2.DsWNNw0K.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-BM4WbMFB.js → app-config.svelte.js-BXjvTmJu.js} +8 -3
  98. package/build/server/chunks/chunks/{config.js-vThvQeMn.js → config.js-r_jw_bQQ.js} +54 -2
  99. package/build/server/chunks/chunks/{db.js-DQm6CZ_r.js → db.js-f2PmBjyD.js} +2 -2
  100. package/build/server/chunks/chunks/{db2.js-DUhFxA3a.js → db2.js-DkwY64WO.js} +2 -2
  101. package/build/server/chunks/chunks/{dsh-connection.js-BgeraFA2.js → dsh-connection.js-BW07Aicl.js} +18 -10
  102. package/build/server/chunks/chunks/{dsh-events.js-BUkLR6ZV.js → dsh-events.js-BHf0lLZ5.js} +16 -3
  103. package/build/server/chunks/chunks/{git-probe.js-CLF37SRh.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-Dp_2gB5J.js → insight-config.js-C5-Rhh5A.js} +19 -6
  106. package/build/server/chunks/chunks/{internal2.js-J3h-US64.js → internal2.js-DbC8VGqD.js} +4 -4
  107. package/build/server/chunks/chunks/ledger-stats.js-BWACyDPg.js +72 -0
  108. package/build/server/chunks/chunks/{registry.js-CZNJZ0C-.js → registry.js-CWnRQ4vx.js} +751 -53
  109. package/build/server/chunks/chunks/{registry2.js-D3Pr1Rv9.js → registry2.js-CFzpvj9c.js} +17 -1
  110. package/build/server/chunks/chunks/{server.js-B1bDXhHu.js → server.js-Dijo7DtV.js} +2 -2
  111. package/build/server/chunks/chunks/{settings-document.js-Gw1puaik.js → settings-document.js-DxKURfc_.js} +2 -2
  112. package/build/server/chunks/chunks/{state.js-8RBD56dL.js → state.js-DR4xiIVw.js} +5 -5
  113. package/build/server/chunks/chunks/{watcher.js-BVKnoQUw.js → watcher.js-DvlNn8X0.js} +5 -5
  114. package/build/server/chunks/entries/endpoints/api/a2a/_id_/{_server.ts.js-BjzdVwdY.js → _server.ts.js-DItDXV23.js} +5 -5
  115. package/build/server/chunks/entries/endpoints/api/a2a/{_server.ts.js-3kQCQuHT.js → _server.ts.js-Hor8QZb1.js} +8 -8
  116. package/build/server/chunks/entries/endpoints/api/a2a/register/{_server.ts.js-BUBTCLFn.js → _server.ts.js-CEvvsa8B.js} +8 -8
  117. package/build/server/chunks/entries/endpoints/api/browser/_id_/activate/{_server.ts.js-BdMJzENm.js → _server.ts.js-sXqf-okw.js} +5 -5
  118. package/build/server/chunks/entries/endpoints/api/browser/_id_/close/{_server.ts.js-B5z9-N8Y.js → _server.ts.js-Byj9ApJh.js} +5 -5
  119. package/build/server/chunks/entries/endpoints/api/browser/_id_/closetab/{_server.ts.js-CnZHun5r.js → _server.ts.js-DOIsrzvg.js} +16 -9
  120. package/build/server/chunks/entries/endpoints/api/browser/_id_/element/{_server.ts.js-C1oM2Ihf.js → _server.ts.js-Cq3gmRfE.js} +5 -5
  121. package/build/server/chunks/entries/endpoints/api/browser/_id_/history/_server.ts.js-BGSLIV0t.js +61 -0
  122. package/build/server/chunks/entries/endpoints/api/browser/_id_/input/{_server.ts.js-DmbqGRMg.js → _server.ts.js-8slca75-.js} +5 -5
  123. package/build/server/chunks/entries/endpoints/api/browser/_id_/mcp/{_server.ts.js-Cj80T1yH.js → _server.ts.js-CpbdTYds.js} +5 -5
  124. package/build/server/chunks/entries/endpoints/api/browser/_id_/navigate/{_server.ts.js-6gi1UYTJ.js → _server.ts.js-Bls9LtLY.js} +5 -5
  125. package/build/server/chunks/entries/endpoints/api/browser/_id_/opentab/{_server.ts.js-Bhx_J7ot.js → _server.ts.js-DqNi_iW_.js} +5 -5
  126. package/build/server/chunks/entries/endpoints/api/browser/_id_/page/{_server.ts.js-DvQXNnX9.js → _server.ts.js-DuXWwo7i.js} +5 -5
  127. package/build/server/chunks/entries/endpoints/api/browser/_id_/stream/{_server.ts.js-MflkVWUn.js → _server.ts.js-DXfqBDEw.js} +38 -9
  128. package/build/server/chunks/entries/endpoints/api/browser/_id_/tabs/{_server.ts.js-CoUSlLcP.js → _server.ts.js-Bgnl8lYs.js} +5 -5
  129. package/build/server/chunks/entries/endpoints/api/browser/_id_/viewport/{_server.ts.js-DNk4EgjJ.js → _server.ts.js-FHmQVbrv.js} +5 -5
  130. package/build/server/chunks/entries/endpoints/api/browser/_id_/zoom/_server.ts.js-BV4cBtSA.js +62 -0
  131. package/build/server/chunks/entries/endpoints/api/browser/{_server.ts.js-CECKap7O.js → _server.ts.js-4vgkwh7v.js} +9 -6
  132. package/build/server/chunks/entries/endpoints/api/config/{_server.ts.js-C8XDnDwe.js → _server.ts.js-C_9kwANR.js} +16 -6
  133. package/build/server/chunks/entries/endpoints/api/dsh/directory/{_server.ts.js-BFmWshpv.js → _server.ts.js-h1OTHcL4.js} +5 -5
  134. package/build/server/chunks/entries/endpoints/api/dsh/jobs/{_server.ts.js-DATWy5mQ.js → _server.ts.js-B6nih9Sd.js} +5 -5
  135. package/build/server/chunks/entries/endpoints/api/dsh/jobs/follow/{_server.ts.js-CugOD1Zd.js → _server.ts.js-Cf17SVmD.js} +5 -5
  136. package/build/server/chunks/entries/endpoints/api/dsh/pick-directory/{_server.ts.js-DCupM4da.js → _server.ts.js-DjNwMbdS.js} +5 -5
  137. package/build/server/chunks/entries/endpoints/api/dsh/presets/{_server.ts.js-Bh1btvr9.js → _server.ts.js-Cz5aaEhC.js} +5 -5
  138. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/_server.ts.js-BFBy5O9Y.js +78 -0
  139. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/cancel/{_server.ts.js-WI9yH2iG.js → _server.ts.js-CgEdCo3T.js} +5 -5
  140. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/catalog/{_server.ts.js-bN9adUqz.js → _server.ts.js-Bo_aEnHh.js} +5 -5
  141. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/changes/{_server.ts.js-Bxlm966G.js → _server.ts.js-Bd2G_GaH.js} +5 -5
  142. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/command/{_server.ts.js-CM-raN_Q.js → _server.ts.js-DL64FyRw.js} +5 -5
  143. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/events/{_server.ts.js-BzP30TXW.js → _server.ts.js-MhOGB66D.js} +7 -70
  144. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/fork/{_server.ts.js-DvNkrTaY.js → _server.ts.js-MjPgXgGO.js} +5 -5
  145. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/goal/{_server.ts.js-DXbCrefw.js → _server.ts.js-BUjDae5H.js} +5 -5
  146. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/history/{_server.ts.js-B7YRQhuJ.js → _server.ts.js-dTKd7Hsv.js} +6 -6
  147. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/models/{_server.ts.js-C_AEaLLJ.js → _server.ts.js-B82rvKoI.js} +5 -5
  148. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/path/{_server.ts.js-Dj-pF5ik.js → _server.ts.js-Cqijsi-c.js} +4 -4
  149. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/permission/{_server.ts.js-BX9FWJ6g.js → _server.ts.js-CL_vVv2p.js} +29 -6
  150. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/prompt/{_server.ts.js-CQ2Bmtu4.js → _server.ts.js-WS4W9Ly4.js} +5 -5
  151. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/rename/{_server.ts.js-Ha7xjnKW.js → _server.ts.js-B72KGRGh.js} +5 -5
  152. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/respond/{_server.ts.js-BOg6llHk.js → _server.ts.js-DK5xb2b5.js} +5 -5
  153. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/select-model/{_server.ts.js-DBqGALzZ.js → _server.ts.js-lhT87EQu.js} +5 -5
  154. package/build/server/chunks/entries/endpoints/api/dsh/sessions/{_server.ts.js-CvA8WDDb.js → _server.ts.js-CMhfhbkN.js} +5 -5
  155. package/build/server/chunks/entries/endpoints/api/dsh/subagents/_server.ts.js-BLvcFsg6.js +72 -0
  156. package/build/server/chunks/entries/endpoints/api/dsh/workspace-file/{_server.ts.js-BfjNH40j.js → _server.ts.js-D_rw2Uq6.js} +5 -5
  157. package/build/server/chunks/entries/endpoints/api/dsh/workspace-tree/{_server.ts.js-De_qumyr.js → _server.ts.js-DfXpMMpw.js} +5 -5
  158. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/{_server.ts.js-tFpJJHCb.js → _server.ts.js-2mJCJVxk.js} +5 -5
  159. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/delete/{_server.ts.js-DVx5GGA_.js → _server.ts.js-BCx0Lzjf.js} +5 -5
  160. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/rename/{_server.ts.js-DuKT-aZp.js → _server.ts.js-DECaSjwp.js} +5 -5
  161. package/build/server/chunks/entries/endpoints/api/prompts/_id_/{_server.ts.js-DsWFidFY.js → _server.ts.js-i_ciJzlb.js} +5 -5
  162. package/build/server/chunks/entries/endpoints/api/prompts/{_server.ts.js-C6j0adQs.js → _server.ts.js-BO1pScn7.js} +5 -5
  163. package/build/server/chunks/entries/endpoints/api/prompts/use/{_server.ts.js-BChAg4hm.js → _server.ts.js-Buhpf7WE.js} +5 -5
  164. package/build/server/chunks/entries/endpoints/api/settings/{_server.ts.js-BPSHqbZN.js → _server.ts.js-DngUQzcT.js} +4 -4
  165. package/build/server/chunks/entries/endpoints/api/terminal/_id_/output/{_server.ts.js-BNBxebgG.js → _server.ts.js-DLETP4yQ.js} +2 -2
  166. package/build/server/chunks/entries/endpoints/api/terminal/_id_/reattach/{_server.ts.js-DDRJBGIr.js → _server.ts.js-uWl6oxPS.js} +2 -2
  167. package/build/server/chunks/entries/endpoints/api/terminal/_id_/send/{_server.ts.js-CA0vc_Cm.js → _server.ts.js-DYNmXaAd.js} +9 -2
  168. package/build/server/chunks/entries/endpoints/api/terminal/_id_/stream/{_server.ts.js-D6L8Gd_f.js → _server.ts.js-C5m3Ktho.js} +2 -2
  169. package/build/server/chunks/entries/endpoints/api/terminal/{_server.ts.js-D5CbUe5k.js → _server.ts.js-DoTNvcOa.js} +5 -5
  170. package/build/server/chunks/entries/endpoints/api/workspace/file-write/{_server.ts.js-B-5YihUA.js → _server.ts.js-BzYOJSkI.js} +7 -7
  171. package/build/server/chunks/entries/endpoints/api/workspace/git-events/{_server.ts.js-DT5jRZFE.js → _server.ts.js-xcNesei9.js} +7 -7
  172. package/build/server/chunks/entries/endpoints/api/workspace/git-file-head/{_server.ts.js-DtW-utrd.js → _server.ts.js-DsJWYdxt.js} +7 -7
  173. package/build/server/chunks/entries/endpoints/api/workspace/git-map/{_server.ts.js-8AIAo9jX.js → _server.ts.js-CNCku9BR.js} +7 -7
  174. package/build/server/chunks/entries/endpoints/api/workspace/git-status/{_server.ts.js-CMw96vjY.js → _server.ts.js-nLsNjOxj.js} +7 -7
  175. package/build/server/chunks/entries/endpoints/api/workspace/write-gate/{_server.ts.js-DKufa14_.js → _server.ts.js-urQk2-ds.js} +7 -7
  176. package/build/server/chunks/entries/{hooks.server.js-B-e4_ekh.js → hooks.server.js-CU2RE5vs.js} +3 -3
  177. package/build/server/chunks/entries/pages/{_error.svelte.js-DRPduJdP.js → _error.svelte.js-e018KpwE.js} +6 -6
  178. package/build/server/chunks/entries/pages/{_page.server.ts.js-7x6ZfGoB.js → _page.server.ts.js-BK3Y6eff.js} +3 -3
  179. package/build/server/chunks/entries/pages/{_page.svelte.js-Dek8Q1_v.js → _page.svelte.js-DQWBiRk1.js} +4185 -1734
  180. package/build/server/chunks/{handler-DUyvzXsb.js → handler-DsD7I1_u.js} +3 -3
  181. package/build/server/chunks/{index.js-BrP1SRzN.js → index.js-C_WAkwJs.js} +4 -4
  182. package/build/server/chunks/{manifest.js-C4z6aoYx.js → manifest.js-DUy52VaP.js} +85 -64
  183. package/build/server/chunks/nodes/{0.js-BuB3t8Br.js → 0.js-CuV3dXVD.js} +3 -3
  184. package/build/server/chunks/nodes/1.js-Dc5QC-NJ.js +9 -0
  185. package/build/server/chunks/nodes/{2.js-C-o9KF10.js → 2.js-PwcF4_kT.js} +10 -10
  186. package/package.json +2 -2
  187. package/skills/{dsi-kb-scenario → dsi-fc-scenario}/SKILL.md +11 -6
  188. package/template/.dsi/prompts.sqlite +0 -0
  189. package/template/.dsi/prompts.sqlite-shm +0 -0
  190. package/template/.dsi/prompts.sqlite-wal +0 -0
  191. package/template/.dsi/settings.yaml +7 -2
  192. package/build/client/_app/immutable/assets/0.cswkTiBk.css +0 -2
  193. package/build/client/_app/immutable/assets/2.BPprd30B.css +0 -1
  194. package/build/client/_app/immutable/chunks/BHDqH9nE.js +0 -1
  195. package/build/client/_app/immutable/chunks/C7Sg_49n.js +0 -1
  196. package/build/client/_app/immutable/chunks/CAneZX4t.js +0 -8
  197. package/build/client/_app/immutable/chunks/D-Rolhzs.js +0 -1
  198. package/build/client/_app/immutable/chunks/DQXo7qdJ.js +0 -1
  199. package/build/client/_app/immutable/chunks/DY0MQ1mO.js +0 -1
  200. package/build/client/_app/immutable/chunks/K3xyLTzZ.js +0 -1
  201. package/build/client/_app/immutable/chunks/NcOjFWr3.js +0 -6
  202. package/build/client/_app/immutable/chunks/cHj8EuyS.js +0 -3
  203. package/build/client/_app/immutable/chunks/o7DVZODA.js +0 -1
  204. package/build/client/_app/immutable/chunks/pdYhlwhf.js +0 -1
  205. package/build/client/_app/immutable/entry/app.DYNedUxy.js +0 -2
  206. package/build/client/_app/immutable/entry/start.BzyrBssE.js +0 -1
  207. package/build/client/_app/immutable/nodes/0.DQYP6BCS.js +0 -1
  208. package/build/client/_app/immutable/nodes/1.CHB5qqQ9.js +0 -1
  209. package/build/client/_app/immutable/nodes/2.C6No1310.js +0 -340
  210. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/_server.ts.js-Cb8SBWVw.js +0 -46
  211. package/build/server/chunks/nodes/1.js-CW4V8ni8.js +0 -9
@@ -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
+ }
@@ -0,0 +1,99 @@
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
+ /**
30
+ * @typedef {Object} GlassSession
31
+ * @property {string} id
32
+ * @property {number} [port]
33
+ * @property {string|null} [ownerSessionId]
34
+ * @property {string} [createdAt]
35
+ * @typedef {Object} PickResult
36
+ * @property {GlassSession|null|undefined} session
37
+ * @property {boolean} [degraded]
38
+ * @property {string} [note]
39
+ * @property {string} [error]
40
+ */
41
+
42
+ const DSI = 'http://127.0.0.1:5175';
43
+
44
+ /** @param {string} msg @returns {never} */
45
+ export function die(msg) {
46
+ 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).' }));
47
+ process.exit(1);
48
+ }
49
+
50
+ /** @param {string[]} argv @returns {string|undefined} */
51
+ export function identityFrom(argv) {
52
+ const flag = argv.indexOf('--owner-session');
53
+ if (flag !== -1 && argv[flag + 1]) return argv[flag + 1];
54
+ if (process.env.GLASS_OWNER_SESSION) return process.env.GLASS_OWNER_SESSION;
55
+ if (process.env.DSH_SESSION_ID) return process.env.DSH_SESSION_ID;
56
+ return undefined;
57
+ }
58
+
59
+ /** @param {GlassSession[]|null|undefined} sessions @param {string|undefined} envId @returns {PickResult} */
60
+ export function pickSession(sessions, envId) {
61
+ const list = sessions ?? [];
62
+ if (envId) {
63
+ const mine = list.filter((s) => (s.ownerSessionId ?? null) === envId);
64
+ if (mine.length === 1) return { session: mine[0], degraded: false };
65
+ if (mine.length > 1) {
66
+ const newest = [...mine].sort((a, b) => String(a.createdAt ?? '').localeCompare(String(b.createdAt ?? ''))).at(-1);
67
+ return { session: newest, degraded: false, note: 'multiple glasses owned by ' + envId + ' — newest wins' };
68
+ }
69
+ if (list.length === 1 && (list[0].ownerSessionId ?? null) === null) {
70
+ return { session: list[0], degraded: true, note: 'legacy session without ownerSessionId — degraded match' };
71
+ }
72
+ 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)' };
73
+ }
74
+ if (list.length === 1) {
75
+ return { session: list[0], degraded: true, note: 'no explicit identity in env — degraded single-session resolution' };
76
+ }
77
+ 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)' };
78
+ }
79
+
80
+ /** @returns {Promise<{ session: GlassSession, browser: import('playwright-core').Browser, ctx: import('playwright-core').BrowserContext }>} */
81
+ export async function connect() {
82
+ let reg;
83
+ try {
84
+ reg = await (await fetch(DSI + '/api/browser')).json();
85
+ } catch {
86
+ die('DSI dev server not reachable on 5175 — floor not up (dsi dsh --sync --dev --playwright-mcp)');
87
+ }
88
+ const { session, degraded, note, error } = pickSession(reg.sessions, identityFrom(process.argv));
89
+ if (!session) die(error ?? 'no glass session resolved — operator must click the Browser chip');
90
+ if (degraded || note) console.error(JSON.stringify({ warn: note ?? 'degraded', sessionId: session.id }));
91
+ const browser = await chromium.connectOverCDP('http://127.0.0.1:' + session.port).catch(() => null);
92
+ if (!browser) die('CDP connect failed on port ' + session.port);
93
+ return { session, browser, ctx: browser.contexts()[0] };
94
+ }
95
+
96
+ /** @param {import('playwright-core').BrowserContext} ctx @param {string} substr @returns {import('playwright-core').Page|undefined} */
97
+ export function pick(ctx, substr) {
98
+ return ctx.pages().find((p) => p.url().includes(substr));
99
+ }
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * glass-url.mjs — the glass-url URL path (2026-10-29, hardened 2026-10-30,
4
+ * RCA "The Hardening That Missed the Token Burn").
5
+ *
6
+ * Drives NON-DSI surfaces (YouTube, docs, anything) on the operator's
7
+ * glass. Never touches the DSI tab. One command per intent:
8
+ *
9
+ * node …/glass-url.mjs yt <search terms…> --play "<title-substring>" [--shot f.png]
10
+ * search YouTube → normalized title match → open watch tab →
11
+ * unmute+play → gate twice (paused:false, rising t) → optional shot.
12
+ * Prints ONE JSON with every intermediate stage, then EXITS.
13
+ * node …/glass-url.mjs open <url>
14
+ * node …/glass-url.mjs pages
15
+ * node …/glass-url.mjs eval [url-substring] <js> # inline JS: LAST arg is the source
16
+ * node …/glass-url.mjs eval --b64 <base64-js> [url-substring]
17
+ * # base64 mode: quote-proof transport; anything left after the
18
+ * # payload IS the url-substring (parsed by shape — D10, _args.mjs).
19
+ * # yt --play consumes EVERY term (artist AND title) — D9.
20
+ * # A NO_MATCH / die is an ANSWER: report and stop (D11, SKILL.md).
21
+ * node …/glass-url.mjs shot [file.png] [url-substring]
22
+ *
23
+ * EXIT DISCIPLINE: this script always process.exit()s — a driver that
24
+ * played media once hung its caller for a full timeout (RCA trap 5).
25
+ */
26
+ import { connect, die, pick } from './_connect.mjs';
27
+ import { norm, parseEvalArgs, matchAllTerms } from './_args.mjs';
28
+
29
+ const argv = process.argv.slice(2);
30
+ const { session, browser, ctx } = await connect();
31
+ const out = (v) => { console.log(JSON.stringify(v, null, 1)); return process.exit(0); };
32
+
33
+ // target tab: url-substring when given; else last http(s) page that is
34
+ // neither the glass placeholder nor :5175 (contract, not position — D2).
35
+ const target = (substr) => {
36
+ if (substr) {
37
+ const p = pick(ctx, substr);
38
+ if (!p) die('no tab matching "' + substr + '" — run: pages');
39
+ return p;
40
+ }
41
+ const pages = ctx.pages().filter((p) => p.url().startsWith('http') && !p.url().includes(':5175'));
42
+ if (!pages.length) die('no non-DSI tab to drive — run: glass-url.mjs open <url>');
43
+ return pages[pages.length - 1];
44
+ };
45
+
46
+ // gate: read playback state; double-read proves time rises
47
+ const gate = async (page) => page.evaluate(() => { const v = document.querySelector('video'); if (!v) return { err: 'novideo' }; v.muted = false; try { v.play(); } catch {} return { t: Math.round(v.currentTime * 10) / 10, paused: v.paused }; });
48
+
49
+ const cmd = argv[0];
50
+
51
+ if (cmd === 'open') {
52
+ const url = argv[1];
53
+ if (!url) die('open needs a url');
54
+ const page = await ctx.newPage();
55
+ await page.goto(url, { waitUntil: 'domcontentloaded' }).catch((e) => die('goto failed: ' + e.message));
56
+ await page.waitForTimeout(1500); // let the SPA settle
57
+ await page.bringToFront(); // make the opened tab the active/visible one
58
+ out({ ok: true, sessionId: session.id, url: page.url(), title: await page.title() });
59
+ } else if (cmd === 'pages') {
60
+ out(await Promise.all(ctx.pages().map(async (p) => ({ url: p.url(), title: await p.title() }))));
61
+ } else if (cmd === 'eval') {
62
+ let rest = argv.slice(1);
63
+ let substr;
64
+ let src;
65
+ let b64 = false;
66
+ if (rest[0] === '--b64') { b64 = true; rest = rest.slice(1); } // payload stays in rest; parseEvalArgs takes it from here (D10)
67
+ const parsed = parseEvalArgs(rest, { b64 });
68
+ src = parsed.src; substr = parsed.substr;
69
+ if (b64 && src) src = Buffer.from(src, 'base64').toString('utf8');
70
+ if (!src) die('eval needs js (inline or --b64 <base64>)');
71
+ out(await target(substr).evaluate(async (s) => await eval(s), src));
72
+ } else if (cmd === 'shot') {
73
+ const file = argv[1] ?? 'tmp/glass-url-shot.png';
74
+ const substr = argv[2];
75
+ await target(substr).screenshot({ path: file });
76
+ out({ ok: true, file });
77
+ } else if (cmd === 'yt') {
78
+ const dash = argv.indexOf('--play');
79
+ const shotFlag = argv.indexOf('--shot');
80
+ const terms = argv.slice(1, dash === -1 ? (shotFlag === -1 ? argv.length : shotFlag) : dash).join(' ');
81
+ const matchSub = dash !== -1 ? argv[dash + 1] : null;
82
+ const shotFile = shotFlag !== -1 ? argv[shotFlag + 1] ?? 'tmp/glass-url-yt.png' : null;
83
+ if (!terms) die('yt needs search terms');
84
+ const stages = {};
85
+ const sp = await ctx.newPage();
86
+ await sp.goto('https://www.youtube.com/results?search_query=' + encodeURIComponent(terms), { waitUntil: 'domcontentloaded' });
87
+ await sp.waitForTimeout(3500);
88
+ const raw = await sp.evaluate(() => [...document.querySelectorAll('a#video-title')].slice(0, 25).map((a) => ({ t: a.title || a.textContent.trim(), h: a.href })));
89
+ stages.candidates = raw.length;
90
+ const hit = raw.find((r) => matchAllTerms(r.t, matchSub));
91
+ if (!hit) out({ ok: false, stage: 'match', play: matchSub, titles: raw.slice(0, 10).map((r) => r.t) }); // D9: a refusal is an answer
92
+ stages.matched = hit.t;
93
+ const wp = await ctx.newPage();
94
+ const watchUrl = 'https://www.youtube.com/watch?v=' + new URL(hit.h).searchParams.get('v');
95
+ await wp.goto(watchUrl, { waitUntil: 'domcontentloaded' });
96
+ await wp.waitForTimeout(6000);
97
+ await wp.bringToFront();
98
+ // gate loop: paused:false with RISING t on the last two reads. YouTube
99
+ // may restart the video once as settings settle (observed 2026-10-30:
100
+ // t 5.9 then 3.8) — re-read up to 3x instead of failing an honest play.
101
+ const reads = [await gate(wp)];
102
+ for (let i = 0; i < 2; i++) { await wp.waitForTimeout(4000); reads.push(await gate(wp)); }
103
+ stages.gates = reads;
104
+ const last = reads.slice(-2);
105
+ stages.passed = last.every((r) => r.paused === false && !r.err) && last[1].t > last[0].t;
106
+ if (shotFile) { await wp.screenshot({ path: shotFile }); stages.shot = shotFile; }
107
+ stages.watchUrl = wp.url();
108
+ await sp.close().catch(() => {});
109
+ out({ ok: stages.passed, sessionId: session.id, ...stages });
110
+ } else {
111
+ die('unknown command: ' + cmd + ' (see header usage)');
112
+ }
113
+ await browser.close().catch(() => {});
114
+ process.exit(0);
package/bin/dsi.mjs CHANGED
@@ -5,8 +5,11 @@
5
5
  // relative to this file, not the cwd, so a globally installed or npx-run
6
6
  // package serves its own bundled build from any directory.
7
7
  // `--zai` (on `dsi web` / `dsi dsh --sync`) bootstraps a fresh DSH install:
8
- // it adds the ZAI provider and the default model to ~/.dsh/settings.yaml
9
- // (idempotent — existing entries win). The standalone `dsi zai` command was
8
+ // it adds the ZAI provider and the default model as patch entries in the
9
+ // active profile's ~/.dsh/profiles/<profile>/cordis.patch.yml — the file the
10
+ // host composes entry config from (idempotent — existing entries win). The
11
+ // legacy flat ~/.dsh/settings.yaml is DSH's import-tombstoned past; the
12
+ // standalone `dsi zai` command was
10
13
  // decommissioned — the flag does the same work before anything boots.
11
14
  // `dsi dsh --token <token>` copies a dsh launch token into DSI's config
12
15
  // ($DSI_CONFIG_PATH or ~/.dsi/settings.yaml, key dsh.authToken — the same
@@ -30,6 +33,7 @@ import { parse, stringify } from 'yaml';
30
33
  import { mirrorSkills } from './lib/mirror-skills.mjs';
31
34
  import { dshLauncherCmd, parsePluginArgs, takeoverFloorPorts, hostBounceDecision, floorUiPort, parseDevFloorPids, launchUrl, tokenFromSettings } from './lib/plugin-chain.mjs';
32
35
  import { parseDevArg, devModeEnv, modeFromBoolean, resolveBounceMode, extractInspectArgs, parseInspectArgsFromEnv } from './lib/dev-mode.mjs';
36
+ import { addZaiProvider as addZaiPatch, zaiPatchPath } from './lib/zai-patch.mjs';
33
37
 
34
38
  // Layman-facing help: wrapped near 76 columns, continuation lines indented,
35
39
  // the recommended one-liner first. --zai is optional on purpose — no GLM
@@ -47,7 +51,8 @@ const USAGE = [
47
51
  '',
48
52
  ' --sync sync the one-time launch token into ~/.dsi/settings.yaml,',
49
53
  ' then serve host + page as one pair',
50
- ' --zai bootstrap the GLM (Z.AI) provider into ~/.dsh/settings.yaml',
54
+ ' --zai bootstrap the GLM (Z.AI) provider into the active profile',
55
+ ' ~/.dsh/profiles/<profile>/cordis.patch.yml',
51
56
  ' before anything boots. No GLM account? Skip it — drop this',
52
57
  ' flag and keep whatever provider you already configured:',
53
58
  '',
@@ -122,37 +127,6 @@ const OV_PLUGIN = '@openviking/dsh-memory-plugin';
122
127
 
123
128
  // ── dsi zai ────────────────────────────────────────────────────────────────
124
129
 
125
- /** The ZAI provider block, byte-for-byte the fresh-install shape. */
126
- const ZAI_PROVIDER = {
127
- apiKeyEnv: 'ZAI_API_KEY',
128
- api: 'openai-completions',
129
- baseURL: 'https://api.z.ai/api/coding/paas/v4',
130
- compat: { thinkingFormat: 'zai' },
131
- models: [
132
- { id: 'glm-4.7' },
133
- { id: 'glm-5-turbo' },
134
- { id: 'glm-5.1' },
135
- { id: 'glm-5.2' },
136
- {
137
- id: 'glm-5.3',
138
- name: 'GLM-5.3',
139
- contextWindow: 1_000_000,
140
- maxTokens: 131_072,
141
- input: ['text']
142
- },
143
- {
144
- id: 'glm-5.3-flash',
145
- name: 'GLM-5.3-Flash',
146
- contextWindow: 1_000_000,
147
- maxTokens: 131_072,
148
- input: ['text', 'image']
149
- }
150
- ]
151
- };
152
-
153
- /** The default-model block a fresh ZAI install wants. */
154
- const ZAI_DEFAULT_MODEL = { provider: 'zai', model: 'glm-5.3-flash' };
155
-
156
130
  function isRecord(value) {
157
131
  return typeof value === 'object' && value !== null && !Array.isArray(value);
158
132
  }
@@ -635,50 +609,25 @@ function readFloorEnv(pid) {
635
609
  }
636
610
  }
637
611
 
638
- /** Add the ZAI provider and default model to ~/.dsh/settings.yaml when
639
- * absent. Existing entries always win — an already-configured host is
640
- * rewritten only when at least one block was added. Exits non-zero when
641
- * the settings file exists but is not parseable YAML. */
612
+ /** Add the ZAI provider and default model as patch entries in the active
613
+ * profile's cordis.patch.yml (bin/lib/zai-patch.mjs, ADR D7-D10). Existing
614
+ * entries always win — an already-configured profile is untouched. Exits 65
615
+ * when the patch file exists but is not a parseable patch array. */
642
616
  function addZaiProvider() {
643
- const settingsPath =
644
- process.env.DSH_SETTINGS_PATH ?? path.join(homedir(), '.dsh', 'settings.yaml');
645
-
646
- let doc = {};
647
- if (existsSync(settingsPath)) {
648
- try {
649
- const parsed = parse(readFileSync(settingsPath, 'utf-8'));
650
- if (!isRecord(parsed)) throw new Error('not a YAML mapping');
651
- doc = parsed;
652
- } catch (error) {
653
- console.error(`dsi zai: cannot parse ${settingsPath}: ${error?.message ?? error}`);
654
- process.exit(65);
655
- }
656
- }
657
-
658
- const added = [];
659
- if (!isRecord(doc['llm-pi-ai']) || !isRecord(doc['llm-pi-ai'].providers)) {
660
- doc['llm-pi-ai'] = { providers: {} };
661
- }
662
- if (!isRecord(doc['llm-pi-ai'].providers.zai)) {
663
- doc['llm-pi-ai'].providers.zai = ZAI_PROVIDER;
664
- added.push('llm-pi-ai.providers.zai');
665
- }
666
- if (doc['agent-default-model'] === undefined) {
667
- doc['agent-default-model'] = ZAI_DEFAULT_MODEL;
668
- added.push('agent-default-model');
617
+ const target = zaiPatchPath();
618
+ let result;
619
+ try {
620
+ result = addZaiPatch(target);
621
+ } catch (error) {
622
+ console.error(`dsi zai: ${error?.message ?? error}`);
623
+ process.exit(65);
669
624
  }
670
-
671
- if (added.length === 0) {
672
- console.log(`dsi zai: ${settingsPath} already has the ZAI provider — nothing to do`);
625
+ if (result.added.length === 0) {
626
+ console.log(`dsi zai: ${target} already has the ZAI provider — nothing to do`);
673
627
  return;
674
628
  }
675
-
676
- mkdirSync(path.dirname(settingsPath), { recursive: true });
677
- const temp = `${settingsPath}.${process.pid}.tmp`;
678
- writeFileSync(temp, stringify(doc), 'utf-8');
679
- renameSync(temp, settingsPath);
680
- for (const entry of added) console.log(`dsi zai: added ${entry}`);
681
- console.log(`dsi zai: ${settingsPath} updated — set ZAI_API_KEY in the harness env, then restart dsh web`);
629
+ for (const entry of result.added) console.log(`dsi zai: added ${entry}`);
630
+ console.log(`dsi zai: ${target} updated — set ZAI_API_KEY in the harness env, then restart dsh web`);
682
631
  }
683
632
 
684
633
  /** Install the OpenViking memory plugin into the active dsh profile by
@@ -0,0 +1,115 @@
1
+ // The --zai bootstrap: add the GLM (Z.AI) provider and the default model to
2
+ // the ACTIVE dsh profile's Cordis patch file (~/.dsh/profiles/<profile>/
3
+ // cordis.patch.yml) — the file the host actually composes entry config from.
4
+ // The legacy flat ~/.dsh/settings.yaml was imported once and tombstoned as
5
+ // settings.yaml.imported by dsh-settings (ADR: The Packaged Insight 2026-09-11,
6
+ // amendment 2026-11-03, D7-D10), so writing it again only bought a re-import
7
+ // round-trip per boot. Idempotent — existing entries always win: only MISSING
8
+ // keys are added, the operator's other patch entries are never touched.
9
+ // Throws ZaiPatchError on an unparsable/non-array patch file; the bin wiring
10
+ // turns that into exit 65 (same fail-loud contract as before).
11
+
12
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
13
+ import { homedir } from 'node:os';
14
+ import path from 'node:path';
15
+ import { parse, stringify } from 'yaml';
16
+
17
+ export class ZaiPatchError extends Error {}
18
+
19
+ export const ZAI_PROVIDER = {
20
+ providers: {
21
+ zai: {
22
+ apiKeyEnv: 'ZAI_API_KEY',
23
+ api: 'openai-completions',
24
+ baseURL: 'https://api.z.ai/api/coding/paas/v4',
25
+ compat: { thinkingFormat: 'zai' },
26
+ models: [
27
+ { id: 'glm-4.7' },
28
+ { id: 'glm-5-turbo' },
29
+ { id: 'glm-5.1' },
30
+ { id: 'glm-5.2' },
31
+ {
32
+ id: 'glm-5.3',
33
+ name: 'GLM-5.3',
34
+ contextWindow: 1000000,
35
+ maxTokens: 131072,
36
+ input: ['text'],
37
+ },
38
+ {
39
+ id: 'glm-5.3-flash',
40
+ name: 'GLM-5.3-Flash',
41
+ contextWindow: 1000000,
42
+ maxTokens: 131072,
43
+ input: ['text', 'image'],
44
+ },
45
+ ],
46
+ },
47
+ },
48
+ };
49
+
50
+ export const ZAI_DEFAULT_MODEL = { provider: 'zai', model: 'glm-5.3-flash' };
51
+
52
+ const LLM_ENTRY_NAME = '@deepseek-ai/dsh-llm-pi-ai';
53
+ const MODEL_ENTRY_NAME = '@deepseek-ai/dsh-agent-default-model';
54
+
55
+ /** Resolve the patch file the bootstrap writes: DSH_PATCH_PATH override,
56
+ * else the active profile's cordis.patch.yml (DSH_PROFILE, default web). */
57
+ export function zaiPatchPath() {
58
+ if (process.env.DSH_PATCH_PATH !== undefined) return process.env.DSH_PATCH_PATH;
59
+ const profile = process.env.DSH_PROFILE ?? 'web';
60
+ return path.join(homedir(), '.dsh', 'profiles', profile, 'cordis.patch.yml');
61
+ }
62
+
63
+ function isRecord(value) {
64
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
65
+ }
66
+
67
+ /** Add the ZAI provider and default model as patch entries when absent.
68
+ * Returns { added, path } — added lists the dotted keys newly written.
69
+ * @param {string | undefined} target explicit patch path (tests); default zaiPatchPath() */
70
+ export function addZaiProvider(target = zaiPatchPath()) {
71
+ let entries = [];
72
+ if (existsSync(target)) {
73
+ let parsed;
74
+ try {
75
+ parsed = parse(readFileSync(target, 'utf-8'));
76
+ } catch (error) {
77
+ throw new ZaiPatchError(`cannot parse ${target}: ${error?.message ?? error}`);
78
+ }
79
+ if (!Array.isArray(parsed) || parsed.some((row) => !isRecord(row))) {
80
+ throw new ZaiPatchError(`${target} is not a Cordis patch array of entries`);
81
+ }
82
+ entries = parsed;
83
+ }
84
+
85
+ const added = [];
86
+
87
+ // llm-pi-ai — create the entry when absent, merge zai when its provider map lacks it.
88
+ let llm = entries.find((row) => row.id === 'llm-pi-ai');
89
+ if (!isRecord(llm)) {
90
+ llm = { id: 'llm-pi-ai', name: LLM_ENTRY_NAME, config: {} };
91
+ entries.push(llm);
92
+ }
93
+ if (!isRecord(llm.config)) llm.config = {};
94
+ if (!isRecord(llm.config.providers)) llm.config.providers = {};
95
+ if (!isRecord(llm.config.providers.zai)) {
96
+ llm.config.providers.zai = ZAI_PROVIDER.providers.zai;
97
+ added.push('llm-pi-ai.providers.zai');
98
+ }
99
+
100
+ // agent-default-model — the entry IS the setting; absent means unset.
101
+ if (!entries.some((row) => row.id === 'agent-default-model')) {
102
+ entries.push({ id: 'agent-default-model', name: MODEL_ENTRY_NAME, config: ZAI_DEFAULT_MODEL });
103
+ added.push('agent-default-model');
104
+ }
105
+
106
+ if (added.length === 0) {
107
+ return { added, path: target };
108
+ }
109
+
110
+ mkdirSync(path.dirname(target), { recursive: true });
111
+ const temp = `${target}.${process.pid}.tmp`;
112
+ writeFileSync(temp, stringify(entries), 'utf-8');
113
+ renameSync(temp, target);
114
+ return { added, path: target };
115
+ }