@deepseek-insight/dsi 0.5.17 → 0.5.18

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 (90) hide show
  1. package/README.md +1 -0
  2. package/build/client/_app/immutable/assets/2.GTtLKMiQ.css +1 -0
  3. package/build/client/_app/immutable/chunks/7MCZCUsX.js +1 -0
  4. package/build/client/_app/immutable/chunks/{DQgaJgp5.js → Bx7fD5zN.js} +2 -2
  5. package/build/client/_app/immutable/chunks/CAZxZSEb.js +1 -0
  6. package/build/client/_app/immutable/chunks/CLNDb8QN.js +6 -0
  7. package/build/client/_app/immutable/chunks/{Bl6W6XsZ.js → DWBqt9Io.js} +1 -1
  8. package/build/client/_app/immutable/chunks/DvLq-YzL.js +1 -0
  9. package/build/client/_app/immutable/entry/{app.DhFsVx9Q.js → app.CnWnvioB.js} +2 -2
  10. package/build/client/_app/immutable/entry/start.DrunaWOx.js +1 -0
  11. package/build/client/_app/immutable/nodes/{0.DSOF-uUw.js → 0.B3qXb7lb.js} +1 -1
  12. package/build/client/_app/immutable/nodes/{1.wYU7SDRw.js → 1.DdjrT3tT.js} +1 -1
  13. package/build/client/_app/immutable/nodes/2.o9KKAujP.js +170 -0
  14. package/build/client/_app/version.json +1 -1
  15. package/build/handler.js +4 -4
  16. package/build/index.js +4 -4
  17. package/build/server/chunks/chunks/app-config.svelte.js-rN4N5yAI.js +305 -0
  18. package/build/server/chunks/chunks/{config.js-D2vQdial.js → config.js-iG_1bK3r.js} +16 -2
  19. package/build/server/chunks/chunks/{db.js-B7zd2qLf.js → db.js-DbbYS9o8.js} +2 -2
  20. package/build/server/chunks/chunks/{db2.js-CCmqoCC8.js → db2.js-BQWa7bEG.js} +52 -41
  21. package/build/server/chunks/chunks/{dsh-connection.js-qRBqNOg4.js → dsh-connection.js-CpcCtA42.js} +3 -3
  22. package/build/server/chunks/chunks/{git-probe.js-Dw7WYQIb.js → git-probe.js-CvkToKO4.js} +2 -2
  23. package/build/server/chunks/chunks/{insight-config.js-BcJiCZlZ.js → insight-config.js-Dw_Qi0fO.js} +60 -11
  24. package/build/server/chunks/chunks/{internal.js-Y8BDUVWO.js → internal.js-DKO0SoY7.js} +3 -3
  25. package/build/server/chunks/chunks/{settings-document.js-BIwLIxnE.js → settings-document.js-BKnRkLVq.js} +2 -2
  26. package/build/server/chunks/chunks/{state.js-C1kUoUk4.js → state.js-C7gJT4Un.js} +3 -3
  27. package/build/server/chunks/chunks/{watcher.js-CUAJN9lS.js → watcher.js-C97Xyorx.js} +4 -4
  28. package/build/server/chunks/entries/endpoints/api/a2a/_id_/{_server.ts.js-DZyjEufw.js → _server.ts.js-Cqh1iqgu.js} +5 -5
  29. package/build/server/chunks/entries/endpoints/api/a2a/{_server.ts.js-sqxh02Ab.js → _server.ts.js-DNKD4rZu.js} +7 -7
  30. package/build/server/chunks/entries/endpoints/api/a2a/register/{_server.ts.js-CUnQYezc.js → _server.ts.js-CJ-FwkrZ.js} +7 -7
  31. package/build/server/chunks/entries/endpoints/api/config/{_server.ts.js-BZhBgOdD.js → _server.ts.js-CMM4kYVx.js} +6 -5
  32. package/build/server/chunks/entries/endpoints/api/dsh/directory/{_server.ts.js-Dm7aSfmb.js → _server.ts.js-epVplzwB.js} +5 -5
  33. package/build/server/chunks/entries/endpoints/api/dsh/pick-directory/{_server.ts.js-CLZoIW4v.js → _server.ts.js-bXHb97gT.js} +5 -5
  34. package/build/server/chunks/entries/endpoints/api/dsh/presets/{_server.ts.js-DBklPI3F.js → _server.ts.js-BNOHhtzy.js} +5 -5
  35. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/{_server.ts.js-Cuq-JEHL.js → _server.ts.js-BBi6jeVj.js} +5 -5
  36. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/cancel/{_server.ts.js-C2M3e5l-.js → _server.ts.js-N0nKPuqL.js} +5 -5
  37. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/catalog/{_server.ts.js-J64QhcMH.js → _server.ts.js-VGFCPAbs.js} +5 -5
  38. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/command/{_server.ts.js-BSAQMYfS.js → _server.ts.js-na_sUb0Z.js} +5 -5
  39. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/events/{_server.ts.js-BF9MvjDa.js → _server.ts.js-CeNf028P.js} +5 -5
  40. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/fork/{_server.ts.js-CrJB2-mv.js → _server.ts.js-DfqO-GO4.js} +5 -5
  41. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/goal/{_server.ts.js-BzvIAbjd.js → _server.ts.js-Dj9GYNl7.js} +5 -5
  42. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/history/{_server.ts.js-CpID_rFC.js → _server.ts.js-DqShsRl9.js} +5 -5
  43. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/models/{_server.ts.js-B_uu8lbl.js → _server.ts.js-BQSBUf70.js} +5 -5
  44. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/path/{_server.ts.js-DjvyuSLb.js → _server.ts.js-CeCKDyKB.js} +4 -4
  45. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/permission/{_server.ts.js-DX8nvoLd.js → _server.ts.js-CadTCNUJ.js} +5 -5
  46. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/prompt/{_server.ts.js-BSFv1R4Z.js → _server.ts.js-BXzgi8xX.js} +5 -5
  47. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/rename/{_server.ts.js-I0dJrnyq.js → _server.ts.js-BfD5FXiL.js} +5 -5
  48. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/respond/{_server.ts.js-w_eF8BVI.js → _server.ts.js-CiDPC9TY.js} +5 -5
  49. package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/select-model/{_server.ts.js-Bvw_1JCx.js → _server.ts.js-DGcZgN96.js} +5 -5
  50. package/build/server/chunks/entries/endpoints/api/dsh/sessions/{_server.ts.js-DHsKo688.js → _server.ts.js-DnU1CCOw.js} +5 -5
  51. package/build/server/chunks/entries/endpoints/api/dsh/workspace-file/{_server.ts.js-BTIrnyBK.js → _server.ts.js-BZ0UV1n2.js} +5 -5
  52. package/build/server/chunks/entries/endpoints/api/dsh/workspace-file-bytes/{_server.ts.js-Deb3yET3.js → _server.ts.js-lxLpuPFL.js} +5 -5
  53. package/build/server/chunks/entries/endpoints/api/dsh/workspace-tree/{_server.ts.js-DYifOFKl.js → _server.ts.js-Cw3vl704.js} +5 -5
  54. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/{_server.ts.js-DW12qsWc.js → _server.ts.js-KKnR2UO4.js} +5 -5
  55. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/delete/{_server.ts.js-BeTfsMv4.js → _server.ts.js-I1eSZn60.js} +5 -5
  56. package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/rename/{_server.ts.js-BOvj8cc1.js → _server.ts.js-B0zqAKnV.js} +5 -5
  57. package/build/server/chunks/entries/endpoints/api/prompts/_id_/{_server.ts.js-CcewTyD0.js → _server.ts.js-C-QN0enK.js} +10 -8
  58. package/build/server/chunks/entries/endpoints/api/prompts/{_server.ts.js-CkFYi6-s.js → _server.ts.js-CwTGUPIp.js} +16 -8
  59. package/build/server/chunks/entries/endpoints/api/prompts/use/_server.ts.js-Bvotxm37.js +45 -0
  60. package/build/server/chunks/entries/endpoints/api/settings/{_server.ts.js-xkyh8Bsn.js → _server.ts.js-CRRLXk0y.js} +4 -4
  61. package/build/server/chunks/entries/endpoints/api/workspace/file-write/{_server.ts.js-C8h4skba.js → _server.ts.js-DY_NDlYl.js} +6 -6
  62. package/build/server/chunks/entries/endpoints/api/workspace/git-events/{_server.ts.js-WGYYK-PJ.js → _server.ts.js-DHEaymrG.js} +6 -6
  63. package/build/server/chunks/entries/endpoints/api/workspace/git-file-head/{_server.ts.js-CG64CyF8.js → _server.ts.js-AQgNkfCV.js} +6 -6
  64. package/build/server/chunks/entries/endpoints/api/workspace/git-map/{_server.ts.js-DLf26VXY.js → _server.ts.js-C9vxPbB3.js} +6 -6
  65. package/build/server/chunks/entries/endpoints/api/workspace/git-status/{_server.ts.js-Db2kgLys.js → _server.ts.js-BlMRR11v.js} +6 -6
  66. package/build/server/chunks/entries/{hooks.server.js-B7FsvqtT.js → hooks.server.js-B_E1wCwG.js} +3 -3
  67. package/build/server/chunks/entries/pages/{_error.svelte.js-BRTO_bKK.js → _error.svelte.js-C73uxSol.js} +4 -4
  68. package/build/server/chunks/entries/pages/{_page.server.ts.js-DFo2_s9d.js → _page.server.ts.js-ze2dUhXW.js} +2 -2
  69. package/build/server/chunks/entries/pages/{_page.svelte.js-T6ftg3_-.js → _page.svelte.js-C1cGitkt.js} +728 -492
  70. package/build/server/chunks/{handler-Xeib4Xb9.js → handler-CTOEBU52.js} +3 -3
  71. package/build/server/chunks/{index.js-DDqgzbFD.js → index.js-Bifh9-nS.js} +2 -2
  72. package/build/server/chunks/{manifest.js-CmazPK88.js → manifest.js-Da5_i6lM.js} +43 -43
  73. package/build/server/chunks/nodes/{0.js-DDgHSLf5.js → 0.js-DIgCB7dX.js} +2 -2
  74. package/build/server/chunks/nodes/1.js-DPBXm0Gt.js +9 -0
  75. package/build/server/chunks/nodes/{2.js-BIByS7ug.js → 2.js-DXw1-iEf.js} +9 -9
  76. package/package.json +1 -1
  77. package/template/.dsi/prompts.sqlite +0 -0
  78. package/template/.dsi/prompts.sqlite-shm +0 -0
  79. package/template/.dsi/prompts.sqlite-wal +0 -0
  80. package/template/.dsi/settings.yaml +1 -1
  81. package/build/client/_app/immutable/assets/2.DHY7FpOZ.css +0 -1
  82. package/build/client/_app/immutable/chunks/BuVjHIij.js +0 -1
  83. package/build/client/_app/immutable/chunks/C88qhAPJ.js +0 -1
  84. package/build/client/_app/immutable/chunks/Ct7xT-0E.js +0 -1
  85. package/build/client/_app/immutable/chunks/DFtKrqgo.js +0 -1
  86. package/build/client/_app/immutable/entry/start.CyefizPA.js +0 -1
  87. package/build/client/_app/immutable/nodes/2.Bu226K9e.js +0 -174
  88. package/build/server/chunks/chunks/app-config.svelte.js-BkhuJ9bF.js +0 -52
  89. package/build/server/chunks/entries/endpoints/api/prompts/use/_server.ts.js-yxG3ypD4.js +0 -55
  90. package/build/server/chunks/nodes/1.js-DleiYihI.js +0 -9
@@ -1,13 +1,13 @@
1
- import { c as onDestroy } from '../../chunks/internal.js-Y8BDUVWO.js';
1
+ import { c as onDestroy } from '../../chunks/internal.js-DKO0SoY7.js';
2
2
  import { V as head, y as derived, X as bind_props, W as escape_html, Y as attr, Z as attr_style, _ as attr_class, x as setContext, $ as spread_props, a0 as attributes, a1 as clsx, a2 as ensure_array_like, a3 as element, J as getContext, a4 as stringify, a5 as html, a6 as props_id, F as run } from '../../chunks/server.js-11-pxAWV.js';
3
- import { U as UI_LOCALES } from '../../chunks/config.js-D2vQdial.js';
3
+ import { U as UI_LOCALES } from '../../chunks/config.js-iG_1bK3r.js';
4
4
  import { m as mergeEntries, c as collapseSystemPromptEntries, t as truncate } from '../../chunks/dsh-events.js-BtDxaV6Q.js';
5
5
  import { p as parseA2aSignature, m as mintA2aId, b as buildDeliveredText } from '../../chunks/a2a-protocol.js-C77mVg2Q.js';
6
6
  import { b as applyKnobEvent, E as EMPTY_KNOBS, r as resolvePermission, l as localPermission, c as presetLabel, d as presetDescription } from '../../chunks/permission-state.js-yvwUSnug.js';
7
7
  import { D as DEFAULT_IMAGE_LIMITS } from '../../chunks/image-limits.js-CUdJ0f7r.js';
8
- import { a as appConfig } from '../../chunks/app-config.svelte.js-BkhuJ9bF.js';
8
+ import { a as appConfig, t as textPreviewOf, b as triggerMode, g as getTrigger, p as previewSegments, i as isValidTagWord, s as searchKey, c as shouldRecordPrompt } from '../../chunks/app-config.svelte.js-rN4N5yAI.js';
9
9
  import { c as getLocale } from '../../chunks/runtime.js-BPLc5RLR.js';
10
- import { p as page, a as afterNavigate, t, r as replaceState, c as currentLocale } from '../../chunks/state.js-C1kUoUk4.js';
10
+ import { p as page, a as afterNavigate, t, r as replaceState, c as currentLocale } from '../../chunks/state.js-C7gJT4Un.js';
11
11
  import 'yaml';
12
12
  import 'html-to-image';
13
13
  import hljs from 'highlight.js/lib/core';
@@ -79,34 +79,6 @@ var accessmodecurrent2 = ((inputs, options = {}) => {
79
79
  return en_accessmodecurrent2(inputs);
80
80
  });
81
81
  //#endregion
82
- //#region src/lib/paraglide/messages/actions.js
83
- /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
84
- /** @typedef {{}} ActionsInputs */
85
- var en_actions = () => {
86
- return `Actions`;
87
- };
88
- var zh_actions = () => {
89
- return `操作`;
90
- };
91
- var id_actions = () => {
92
- return `Tindakan`;
93
- };
94
- /**
95
- * | output |
96
- * | --- |
97
- * | "Actions" |
98
- *
99
- * @param {ActionsInputs} inputs
100
- * @param {{ locale?: "en" | "zh" | "id" }} options
101
- * @returns {LocalizedString}
102
- */
103
- var actions = ((inputs = {}, options = {}) => {
104
- const locale = options.locale ?? getLocale();
105
- if (locale === "zh") return zh_actions();
106
- if (locale === "id") return id_actions();
107
- return en_actions();
108
- });
109
- //#endregion
110
82
  //#region src/lib/paraglide/messages/allowonce1.js
111
83
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
112
84
  /** @typedef {{}} Allowonce1Inputs */
@@ -303,34 +275,6 @@ var attachedimages1 = ((inputs = {}, options = {}) => {
303
275
  return en_attachedimages1();
304
276
  });
305
277
  //#endregion
306
- //#region src/lib/paraglide/messages/autochecktitle2.js
307
- /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
308
- /** @typedef {{}} Autochecktitle2Inputs */
309
- var en_autochecktitle2 = () => {
310
- return `Auto-check rows with this many uses (0 = off)`;
311
- };
312
- var zh_autochecktitle2 = () => {
313
- return `自动勾选达到此使用次数的行(0 = 关)`;
314
- };
315
- var id_autochecktitle2 = () => {
316
- return `Centang otomatis baris dengan pakai sebanyak ini (0 = mati)`;
317
- };
318
- /**
319
- * | output |
320
- * | --- |
321
- * | "Auto-check rows with this many uses (0 = off)" |
322
- *
323
- * @param {Autochecktitle2Inputs} inputs
324
- * @param {{ locale?: "en" | "zh" | "id" }} options
325
- * @returns {LocalizedString}
326
- */
327
- var autochecktitle2 = ((inputs = {}, options = {}) => {
328
- const locale = options.locale ?? getLocale();
329
- if (locale === "zh") return zh_autochecktitle2();
330
- if (locale === "id") return id_autochecktitle2();
331
- return en_autochecktitle2();
332
- });
333
- //#endregion
334
278
  //#region src/lib/paraglide/messages/cancel.js
335
279
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
336
280
  /** @typedef {{}} CancelInputs */
@@ -1619,6 +1563,34 @@ var fileeyetogglelabel3 = ((inputs = {}, options = {}) => {
1619
1563
  return en_fileeyetogglelabel3();
1620
1564
  });
1621
1565
  //#endregion
1566
+ //#region src/lib/paraglide/messages/filterbytags2.js
1567
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1568
+ /** @typedef {{}} Filterbytags2Inputs */
1569
+ var en_filterbytags2 = () => {
1570
+ return `Filter by tags`;
1571
+ };
1572
+ var zh_filterbytags2 = () => {
1573
+ return `按标签筛选`;
1574
+ };
1575
+ var id_filterbytags2 = () => {
1576
+ return `Filter menurut tag`;
1577
+ };
1578
+ /**
1579
+ * | output |
1580
+ * | --- |
1581
+ * | "Filter by tags" |
1582
+ *
1583
+ * @param {Filterbytags2Inputs} inputs
1584
+ * @param {{ locale?: "en" | "zh" | "id" }} options
1585
+ * @returns {LocalizedString}
1586
+ */
1587
+ var filterbytags2 = ((inputs = {}, options = {}) => {
1588
+ const locale = options.locale ?? getLocale();
1589
+ if (locale === "zh") return zh_filterbytags2();
1590
+ if (locale === "id") return id_filterbytags2();
1591
+ return en_filterbytags2();
1592
+ });
1593
+ //#endregion
1622
1594
  //#region src/lib/paraglide/messages/fixmarkedanswers2.js
1623
1595
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
1624
1596
  /** @typedef {{}} Fixmarkedanswers2Inputs */
@@ -2627,6 +2599,34 @@ var nooutput1 = ((inputs = {}, options = {}) => {
2627
2599
  return en_nooutput1();
2628
2600
  });
2629
2601
  //#endregion
2602
+ //#region src/lib/paraglide/messages/nopromptsmatch2.js
2603
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
2604
+ /** @typedef {{}} Nopromptsmatch2Inputs */
2605
+ var en_nopromptsmatch2 = () => {
2606
+ return `No prompts match your search.`;
2607
+ };
2608
+ var zh_nopromptsmatch2 = () => {
2609
+ return `没有匹配搜索的提示。`;
2610
+ };
2611
+ var id_nopromptsmatch2 = () => {
2612
+ return `Tidak ada prompt yang cocok dengan pencarian.`;
2613
+ };
2614
+ /**
2615
+ * | output |
2616
+ * | --- |
2617
+ * | "No prompts match your search." |
2618
+ *
2619
+ * @param {Nopromptsmatch2Inputs} inputs
2620
+ * @param {{ locale?: "en" | "zh" | "id" }} options
2621
+ * @returns {LocalizedString}
2622
+ */
2623
+ var nopromptsmatch2 = ((inputs = {}, options = {}) => {
2624
+ const locale = options.locale ?? getLocale();
2625
+ if (locale === "zh") return zh_nopromptsmatch2();
2626
+ if (locale === "id") return id_nopromptsmatch2();
2627
+ return en_nopromptsmatch2();
2628
+ });
2629
+ //#endregion
2630
2630
  //#region src/lib/paraglide/messages/nopromptsyet2.js
2631
2631
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
2632
2632
  /** @typedef {{}} Nopromptsyet2Inputs */
@@ -3775,34 +3775,6 @@ var searchprompts1 = ((inputs = {}, options = {}) => {
3775
3775
  return en_searchprompts1();
3776
3776
  });
3777
3777
  //#endregion
3778
- //#region src/lib/paraglide/messages/selectedrows1.js
3779
- /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3780
- /** @typedef {{}} Selectedrows1Inputs */
3781
- var en_selectedrows1 = () => {
3782
- return `☑ Selected`;
3783
- };
3784
- var zh_selectedrows1 = () => {
3785
- return `☑ 已选`;
3786
- };
3787
- var id_selectedrows1 = () => {
3788
- return `☑ Dipilih`;
3789
- };
3790
- /**
3791
- * | output |
3792
- * | --- |
3793
- * | "☑ Selected" |
3794
- *
3795
- * @param {Selectedrows1Inputs} inputs
3796
- * @param {{ locale?: "en" | "zh" | "id" }} options
3797
- * @returns {LocalizedString}
3798
- */
3799
- var selectedrows1 = ((inputs = {}, options = {}) => {
3800
- const locale = options.locale ?? getLocale();
3801
- if (locale === "zh") return zh_selectedrows1();
3802
- if (locale === "id") return id_selectedrows1();
3803
- return en_selectedrows1();
3804
- });
3805
- //#endregion
3806
3778
  //#region src/lib/paraglide/messages/sendmessage1.js
3807
3779
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3808
3780
  /** @typedef {{}} Sendmessage1Inputs */
@@ -3915,34 +3887,6 @@ var showfullresult2 = ((inputs = {}, options = {}) => {
3915
3887
  return en_showfullresult2();
3916
3888
  });
3917
3889
  //#endregion
3918
- //#region src/lib/paraglide/messages/showonlyselected2.js
3919
- /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3920
- /** @typedef {{}} Showonlyselected2Inputs */
3921
- var en_showonlyselected2 = () => {
3922
- return `Show only selected rows`;
3923
- };
3924
- var zh_showonlyselected2 = () => {
3925
- return `仅显示已选行`;
3926
- };
3927
- var id_showonlyselected2 = () => {
3928
- return `Hanya tampilkan baris terpilih`;
3929
- };
3930
- /**
3931
- * | output |
3932
- * | --- |
3933
- * | "Show only selected rows" |
3934
- *
3935
- * @param {Showonlyselected2Inputs} inputs
3936
- * @param {{ locale?: "en" | "zh" | "id" }} options
3937
- * @returns {LocalizedString}
3938
- */
3939
- var showonlyselected2 = ((inputs = {}, options = {}) => {
3940
- const locale = options.locale ?? getLocale();
3941
- if (locale === "zh") return zh_showonlyselected2();
3942
- if (locale === "id") return id_showonlyselected2();
3943
- return en_showonlyselected2();
3944
- });
3945
- //#endregion
3946
3890
  //#region src/lib/paraglide/messages/skills.js
3947
3891
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
3948
3892
  /** @typedef {{}} SkillsInputs */
@@ -4279,6 +4223,34 @@ var systemprompt1 = ((inputs = {}, options = {}) => {
4279
4223
  return en_systemprompt1();
4280
4224
  });
4281
4225
  //#endregion
4226
+ //#region src/lib/paraglide/messages/tags.js
4227
+ /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
4228
+ /** @typedef {{}} TagsInputs */
4229
+ var en_tags = () => {
4230
+ return `Tags`;
4231
+ };
4232
+ var zh_tags = () => {
4233
+ return `标签`;
4234
+ };
4235
+ var id_tags = () => {
4236
+ return `Tag`;
4237
+ };
4238
+ /**
4239
+ * | output |
4240
+ * | --- |
4241
+ * | "Tags" |
4242
+ *
4243
+ * @param {TagsInputs} inputs
4244
+ * @param {{ locale?: "en" | "zh" | "id" }} options
4245
+ * @returns {LocalizedString}
4246
+ */
4247
+ var tags = ((inputs = {}, options = {}) => {
4248
+ const locale = options.locale ?? getLocale();
4249
+ if (locale === "zh") return zh_tags();
4250
+ if (locale === "id") return id_tags();
4251
+ return en_tags();
4252
+ });
4253
+ //#endregion
4282
4254
  //#region src/lib/paraglide/messages/text.js
4283
4255
  /** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
4284
4256
  /** @typedef {{}} TextInputs */
@@ -5960,252 +5932,6 @@ function SlashMenu($$renderer, $$props) {
5960
5932
  });
5961
5933
  }
5962
5934
  //#endregion
5963
- //#region src/lib/services/chat/prompt-trigger.ts
5964
- /** Which mode a trigger query is in — the char after nothing: the FIRST
5965
- * character of the query string decides ("?load" → find, "!oci" → run).
5966
- * A non-trigger string answers 'find' (callers gate on getTrigger). */
5967
- function triggerMode(query) {
5968
- return query[0] === "!" ? "run" : "find";
5969
- }
5970
- /**
5971
- * Extract the finder trigger from input text + caret position.
5972
- * Active when the text before the caret starts with a trigger char
5973
- * ("?" find, "!" run — identical rules) and carries at least one more
5974
- * character, with no newline in the before-caret slice (the finder is
5975
- * single-line). Spaces are fine — multi-keyword queries are the
5976
- * ";"-and-whitespace AND search.
5977
- * Returns the query including the trigger char, or null when inactive.
5978
- */
5979
- function getTrigger(text, caret) {
5980
- const before = text.slice(0, caret);
5981
- const lead = before[0];
5982
- if (lead !== "?" && lead !== "!") return null;
5983
- if (before.length < 2) return null;
5984
- if (before.includes("\n")) return null;
5985
- return before;
5986
- }
5987
- /** Query-less search key sent to the server ("?load" → "load"; "!oci"
5988
- * → "oci" — the bang strips exactly like the question mark). */
5989
- function searchKey(query) {
5990
- return query.slice(1);
5991
- }
5992
- /**
5993
- * Split a search key into keyword terms (AND semantics): split on ";" and
5994
- * whitespace, trim, drop empties, dedupe case-insensitively (first
5995
- * spelling wins). Mirrors the server-side splitQueryTerms in prompts/db.ts
5996
- * — a shared unit test pins the parity (a single source would cross the
5997
- * server/client boundary). `?load;skill;feature-spec` → ["load", "skill",
5998
- * "feature-spec"].
5999
- */
6000
- function splitKey(key) {
6001
- const seen = /* @__PURE__ */ new Set();
6002
- const terms = [];
6003
- for (const frag of key.split(/[;\s]+/)) {
6004
- const raw = frag.trim();
6005
- if (!raw) continue;
6006
- const lower = raw.toLowerCase();
6007
- if (seen.has(lower)) continue;
6008
- seen.add(lower);
6009
- terms.push(raw);
6010
- }
6011
- return terms;
6012
- }
6013
- /**
6014
- * Should this sent text be recorded (use-count upsert)? Plain prompts
6015
- * only — slash commands, @mentions, and "."-, "?"- or "!"-prefixed lines
6016
- * are control traffic and never touch the ledger.
6017
- */
6018
- function shouldRecordPrompt(text) {
6019
- const trimmed = text.trim();
6020
- if (!trimmed) return false;
6021
- if (trimmed.startsWith("/") || trimmed.startsWith("@") || trimmed.startsWith(".") || trimmed.startsWith("?") || trimmed.startsWith("!")) return false;
6022
- return true;
6023
- }
6024
- /**
6025
- * One-line preview for strip rows (ADR D8): first non-empty line of the
6026
- * label-or-text handle. Multiline rows preview their first line and carry
6027
- * the ⏎ badge in the strip instead of spilling newlines into one line.
6028
- */
6029
- function previewOf(row) {
6030
- return (row.label ?? row.text).split("\n").find((l) => l.trim().length > 0) ?? "";
6031
- }
6032
- /**
6033
- * First non-empty line of the row's TEXT only — the label is never
6034
- * consulted. For surfaces that render the label as its own element beside
6035
- * the preview (the manager's label tag + text preview) so the two never
6036
- * duplicate each other.
6037
- */
6038
- function textPreviewOf(row) {
6039
- return row.text.split("\n").find((l) => l.trim().length > 0) ?? "";
6040
- }
6041
- /** Similarity bar a fuzzy word must clear to be highlighted (below = noise). */
6042
- var WORD_HL_FLOOR = .5;
6043
- /**
6044
- * Split a strip preview into plain/highlighted segments (F4).
6045
- *
6046
- * - No query / not a "?" query → single plain previewOf segment.
6047
- * - "?" contains hit (S4) → first line containing ALL terms previews with
6048
- * EVERY term's span marked, longest-match-first (no overlapping spans);
6049
- * label first, then text lines, so a match on line 3 previews line 3.
6050
- * - "?" contains miss (S4) → per-term best-matching word highlighted when
6051
- * it clears 0.5 similarity ("lod" → "load" 0.75); weaker words stay
6052
- * plain.
6053
- *
6054
- * Matching is case-insensitive (parity with the server LIKE/FTS); segments
6055
- * render the row's original casing.
6056
- */
6057
- function previewSegments(row, query) {
6058
- const plain = [{
6059
- text: previewOf(row),
6060
- hit: false
6061
- }];
6062
- if (!query.startsWith("?")) return plain;
6063
- const key = searchKey(query).toLowerCase();
6064
- if (!key) return plain;
6065
- const lines = row.label !== null ? [row.label, ...row.text.split("\n")] : row.text.split("\n");
6066
- const terms = splitKey(key);
6067
- if (terms.length > 0) for (const line of lines) {
6068
- const spans = markTermSpans(line, terms);
6069
- if (spans) return segmentsFromSpans(line, spans);
6070
- }
6071
- const perTerm = terms.length > 0 ? terms : key.split(/\s+/).filter(Boolean);
6072
- let bestLine = null;
6073
- let bestScore = 0;
6074
- for (const line of lines) {
6075
- let lineScore = 0;
6076
- const spans = [];
6077
- for (const t of perTerm) {
6078
- let best = null;
6079
- let bestTermScore = 0;
6080
- for (const word of line.split(/\s+/)) {
6081
- if (!word) continue;
6082
- const score = wordSimilarity(t, word.toLowerCase());
6083
- if (score > bestTermScore) {
6084
- bestTermScore = score;
6085
- best = {
6086
- at: line.indexOf(word),
6087
- len: word.length
6088
- };
6089
- }
6090
- }
6091
- lineScore += bestTermScore;
6092
- if (best && bestTermScore >= WORD_HL_FLOOR) spans.push(best);
6093
- }
6094
- if (spans.length > 0 && lineScore > bestScore) {
6095
- bestScore = lineScore;
6096
- bestLine = {
6097
- line,
6098
- spans: resolveOverlaps(spans)
6099
- };
6100
- }
6101
- }
6102
- if (bestLine) return segmentsFromSpans(bestLine.line, bestLine.spans);
6103
- return plain;
6104
- }
6105
- /** Tier-1 span set for one line against every term: null when ANY term is
6106
- * missing (the line must contain ALL terms to preview — AND semantics);
6107
- * spans collected for every term, longest-first overlap-resolved. */
6108
- function markTermSpans(line, terms) {
6109
- const l = line.toLowerCase();
6110
- const spans = [];
6111
- for (const t of terms) {
6112
- const at = l.indexOf(t);
6113
- if (at === -1) return null;
6114
- spans.push({
6115
- at,
6116
- len: t.length
6117
- });
6118
- }
6119
- return resolveOverlaps(spans);
6120
- }
6121
- /** Overlap resolution (S4): longest-match-first — a longer term's span wins
6122
- * any overlap, shorter overlapping spans are dropped entirely (never
6123
- * nested-rendered). Non-overlapping spans pass through unchanged. */
6124
- function resolveOverlaps(spans) {
6125
- const sorted = [...spans].sort((a, b) => b.at + b.len - (a.at + a.len) || b.len - a.len || a.at - b.at);
6126
- const kept = [];
6127
- for (const span of sorted) {
6128
- if (kept.some((k) => span.at < k.at + k.len && k.at < span.at + span.len)) continue;
6129
- kept.push(span);
6130
- }
6131
- return kept.sort((a, b) => a.at - b.at);
6132
- }
6133
- /** Render a line as plain/hit segments over the given hit spans. Full-width
6134
- * rows: the whole line renders — no sliding window, no ellipses; CSS
6135
- * ellipsis on the label guards only the extreme case. */
6136
- function segmentsFromSpans(line, spans) {
6137
- const segments = [];
6138
- let cursor = 0;
6139
- for (const sp of spans) {
6140
- if (sp.at > cursor) segments.push({
6141
- text: line.slice(cursor, sp.at),
6142
- hit: false
6143
- });
6144
- segments.push({
6145
- text: line.slice(sp.at, sp.at + sp.len),
6146
- hit: true
6147
- });
6148
- cursor = sp.at + sp.len;
6149
- }
6150
- if (cursor < line.length) segments.push({
6151
- text: line.slice(cursor),
6152
- hit: false
6153
- });
6154
- return segments;
6155
- }
6156
- /**
6157
- * Trigram-bag Dice coefficient (Sørensen): 2·|A ∩ B| / (|A| + |B|) over
6158
- * multiset trigram counts. Returns 0 when either side has no trigrams
6159
- * (length < 3). Parity copy of the server's fuzzy math (prompts/db.ts) —
6160
- * the boundary keeps the two implementations separate; unit vectors pin
6161
- * them together.
6162
- */
6163
- function diceSimilarity(a, b) {
6164
- const grams = /* @__PURE__ */ new Map();
6165
- for (let i = 0; i + 3 <= a.length; i++) {
6166
- const g = a.slice(i, i + 3);
6167
- grams.set(g, (grams.get(g) ?? 0) + 1);
6168
- }
6169
- if (grams.size === 0) return 0;
6170
- let bCount = 0;
6171
- let shared = 0;
6172
- for (let i = 0; i + 3 <= b.length; i++) {
6173
- bCount++;
6174
- const g = b.slice(i, i + 3);
6175
- const have = grams.get(g) ?? 0;
6176
- if (have > 0) {
6177
- shared++;
6178
- if (have === 1) grams.delete(g);
6179
- else grams.set(g, have - 1);
6180
- }
6181
- }
6182
- if (bCount === 0) return 0;
6183
- const aCount = a.length - 2;
6184
- return 2 * shared / (aCount + bCount);
6185
- }
6186
- /**
6187
- * Word-level similarity: max of Dice and normalized edit distance — Dice is
6188
- * meaningless for words shorter than 3 trigrams/chars, edit covers them
6189
- * ("lod" vs "load": Dice 0, edit 0.75 → 0.75).
6190
- */
6191
- function wordSimilarity(a, b) {
6192
- const edit = 1 - levenshtein(a, b) / Math.max(a.length, b.length);
6193
- return Math.max(diceSimilarity(a, b), edit);
6194
- }
6195
- /** Wagner–Fischer edit distance (two-row DP), case handled by callers. */
6196
- function levenshtein(a, b) {
6197
- if (a === b) return 0;
6198
- if (!a.length) return b.length;
6199
- if (!b.length) return a.length;
6200
- let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
6201
- for (let i = 1; i <= a.length; i++) {
6202
- const cur = [i];
6203
- for (let j = 1; j <= b.length; j++) cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
6204
- prev = cur;
6205
- }
6206
- return prev[b.length];
6207
- }
6208
- //#endregion
6209
5935
  //#region src/lib/utils/markdown.ts
6210
5936
  /**
6211
5937
  * markdown — render markdown to sanitized HTML (Wave 2, task 2.1;
@@ -6576,6 +6302,56 @@ function StripChip($$renderer, $$props) {
6576
6302
  });
6577
6303
  }
6578
6304
  //#endregion
6305
+ //#region src/lib/components/chat/SuggestLine.svelte
6306
+ function SuggestLine($$renderer, $$props) {
6307
+ $$renderer.component(($$renderer) => {
6308
+ /**
6309
+ * SuggestLine — the "Manage prompts" footer line of the SuggestStrip
6310
+ * (extracted from SuggestStrip.svelte). Renders nothing unless
6311
+ * `onmanage` is provided; the click hands back to the host, which
6312
+ * opens the Prompts Manager (Wave 3).
6313
+ */
6314
+ let { onmanage } = $$props;
6315
+ if (onmanage) {
6316
+ $$renderer.push("<!--[0-->");
6317
+ $$renderer.push(`<button data-svelte="SuggestLine" type="button" class="strip-manage svelte-rgc8xj">${escape_html(t(manageprompts1))}</button>`);
6318
+ } else $$renderer.push("<!--[-1-->");
6319
+ $$renderer.push(`<!--]-->`);
6320
+ });
6321
+ }
6322
+ //#endregion
6323
+ //#region src/lib/components/chat/StripTagChips.svelte
6324
+ function StripTagChips($$renderer, $$props) {
6325
+ $$renderer.component(($$renderer) => {
6326
+ /**
6327
+ * StripTagChips — the strip's recommended-tag checkbox chips (The
6328
+ * Prompt Tags ADR, 2026-09-14, D10): rendered AFTER SuggestLine, at
6329
+ * the bottom of the strip where the eye finishes. Presentational —
6330
+ * recTags and checked arrive as props; toggles report the word up
6331
+ * (the strip owns the desk-slot persistence and the local filter).
6332
+ */
6333
+ let { recTags, checked} = $$props;
6334
+ if (recTags.length > 0) {
6335
+ $$renderer.push("<!--[0-->");
6336
+ $$renderer.push(`<div data-svelte="StripTagChips" class="strip-tag-chips svelte-1dki9fw" role="group"${attr("aria-label", t(filterbytags2))}><!--[-->`);
6337
+ const each_array = ensure_array_like(recTags);
6338
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
6339
+ let word = each_array[$$index];
6340
+ $$renderer.push(`<label${attr_class("strip-tag-chip svelte-1dki9fw", void 0, { "on": checked.includes(word) })}><input type="checkbox"${attr("checked", checked.includes(word), true)} class="svelte-1dki9fw"/> ${escape_html(word)}</label>`);
6341
+ }
6342
+ $$renderer.push(`<!--]--></div>`);
6343
+ } else $$renderer.push("<!--[-1-->");
6344
+ $$renderer.push(`<!--]-->`);
6345
+ });
6346
+ }
6347
+ /** Persist a tag-filter word array to its desk slot (best-effort). */
6348
+ function saveTagFilter(base, words, profile) {
6349
+ if (typeof localStorage === "undefined") return;
6350
+ try {
6351
+ localStorage.setItem(dsiKey(base, profile), JSON.stringify(words));
6352
+ } catch {}
6353
+ }
6354
+ //#endregion
6579
6355
  //#region src/lib/components/chat/SuggestStrip.svelte
6580
6356
  function SuggestStrip($$renderer, $$props) {
6581
6357
  $$renderer.component(($$renderer) => {
@@ -6603,29 +6379,60 @@ function SuggestStrip($$renderer, $$props) {
6603
6379
  /** Row whose ⋯ menu is open — null when closed. Exclusive: StripChips
6604
6380
  * report open/close and only the matching row shows its popup. */
6605
6381
  let menuForId = null;
6382
+ /** The row's tag words (the stored space-joined form, split). */
6383
+ function rowTags(row) {
6384
+ return row.tags ? row.tags.split(" ").filter(Boolean) : [];
6385
+ }
6386
+ /** recTags: the deduped FIRST-SEEN union of the rows' tags — recomputed
6387
+ * on every rows change (a $derived over the prop, no fetch: recTags
6388
+ * describe what is ON SCREEN, not what exists in the library). */
6389
+ const recTags = derived(() => {
6390
+ const seen = /* @__PURE__ */ new Set();
6391
+ for (const row of rows) for (const w of rowTags(row)) seen.add(w);
6392
+ return [...seen];
6393
+ });
6394
+ /** Checked words — persisted per desk slot. Words that no longer occur
6395
+ * in recTags STAY persisted but filter nothing (the rows set changed
6396
+ * under them); they surface again when a row regains the tag. */
6397
+ let checkedTags = [];
6398
+ /** visibleItems: the local AND over the ARRIVED rows, applied BEFORE the
6399
+ * each — never a refetch. Each item carries the row's ORIGINAL index so
6400
+ * pick/step callbacks and the host's activeIndex keep their meaning
6401
+ * when the view is narrowed. Checked words absent from recTags filter
6402
+ * nothing (D10's persistence rule). */
6403
+ const visibleItems = derived(() => {
6404
+ const effective = checkedTags.filter((w) => recTags().includes(w));
6405
+ const all = rows.map((row, index) => ({
6406
+ row,
6407
+ index
6408
+ }));
6409
+ if (effective.length === 0) return all;
6410
+ return all.filter(({ row }) => effective.every((t) => rowTags(row).includes(t)));
6411
+ });
6606
6412
  if (rows.length > 0) {
6607
6413
  $$renderer.push("<!--[0-->");
6608
6414
  $$renderer.push(`<div data-svelte="SuggestStrip" class="suggest-strip svelte-17pdojr" role="listbox"${attr("aria-label", t(promptsuggestions1))} data-testid="suggest-strip"><!--[-->`);
6609
- const each_array = ensure_array_like(rows);
6610
- for (let i = 0, $$length = each_array.length; i < $$length; i++) {
6611
- let row = each_array[i];
6415
+ const each_array = ensure_array_like(visibleItems());
6416
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
6417
+ let { row, index } = each_array[$$index];
6612
6418
  StripChip($$renderer, {
6613
6419
  row,
6614
- active: i === activeIndex,
6420
+ active: index === activeIndex,
6615
6421
  menuOpen: menuForId === row.id,
6616
6422
  anyMenuOpen: menuForId !== null,
6617
6423
  query,
6618
6424
  mode,
6619
- onstep: onstep === void 0 ? void 0 : () => onstep(i),
6425
+ onstep: onstep === void 0 ? void 0 : () => onstep(index),
6620
6426
  onrename,
6621
6427
  ondelete});
6622
6428
  }
6623
6429
  $$renderer.push(`<!--]--> `);
6624
- if (onmanage) {
6625
- $$renderer.push("<!--[0-->");
6626
- $$renderer.push(`<button type="button" class="strip-manage svelte-17pdojr">${escape_html(t(manageprompts1))}</button>`);
6627
- } else $$renderer.push("<!--[-1-->");
6628
- $$renderer.push(`<!--]--></div>`);
6430
+ SuggestLine($$renderer, { onmanage });
6431
+ $$renderer.push(`<!----> `);
6432
+ StripTagChips($$renderer, {
6433
+ recTags: recTags(),
6434
+ checked: checkedTags});
6435
+ $$renderer.push(`<!----></div>`);
6629
6436
  } else $$renderer.push("<!--[-1-->");
6630
6437
  $$renderer.push(`<!--]-->`);
6631
6438
  });
@@ -8275,6 +8082,263 @@ function PromptManagerTDLabel($$renderer, $$props) {
8275
8082
  });
8276
8083
  }
8277
8084
  //#endregion
8085
+ //#region src/lib/components/chat/PromptManagerSearch.svelte
8086
+ function PromptManagerSearch($$renderer, $$props) {
8087
+ $$renderer.component(($$renderer) => {
8088
+ /**
8089
+ * PromptManagerSearch — the debounced search input of the prompts
8090
+ * manager toolbar (extracted from PromptManagerPanel.svelte).
8091
+ * Value binds to the host's `searchQ`; each keystroke calls `oninput`
8092
+ * (the host owns the 300ms debounce + refresh).
8093
+ */
8094
+ let { value = "", oninput } = $$props;
8095
+ $$renderer.push(`<input data-svelte="PromptManagerSearch" type="text" class="mgr-search svelte-w3lpt8"${attr("placeholder", t(searchprompts1))}${attr("value", value)}/>`);
8096
+ bind_props($$props, { value });
8097
+ });
8098
+ }
8099
+ //#endregion
8100
+ //#region src/lib/components/chat/PromptManagerTDTags.svelte
8101
+ function PromptManagerTDTags($$renderer, $$props) {
8102
+ $$renderer.component(($$renderer) => {
8103
+ /**
8104
+ * PromptManagerTDTags — the tags body cell (The Prompt Tags ADR,
8105
+ * 2026-09-14, D4; the TDUses/TDLabel cell seam). Up to TWO tag chips
8106
+ * inline, then a +n overflow badge whose title carries the FULL list —
8107
+ * two is the widest honest fit under the fixed column-width contract.
8108
+ * Untagged ('') renders the em-dash, same as the macro column.
8109
+ */
8110
+ let { row } = $$props;
8111
+ const words = derived(() => row.tags ? row.tags.split(" ").filter(Boolean) : []);
8112
+ const shown = derived(() => words().slice(0, 2));
8113
+ const overflow = derived(() => words().length - shown().length);
8114
+ $$renderer.push(`<td data-svelte="PromptManagerTDTags" class="mgr-tags-cell svelte-108d03j">`);
8115
+ if (words().length === 0) {
8116
+ $$renderer.push("<!--[0-->");
8117
+ $$renderer.push(`<span class="mgr-tag-none svelte-108d03j">—</span>`);
8118
+ } else {
8119
+ $$renderer.push("<!--[-1-->");
8120
+ $$renderer.push(`<!--[-->`);
8121
+ const each_array = ensure_array_like(shown());
8122
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
8123
+ let w = each_array[$$index];
8124
+ $$renderer.push(`<span class="mgr-tag-chip svelte-108d03j">${escape_html(w)}</span>`);
8125
+ }
8126
+ $$renderer.push(`<!--]--> `);
8127
+ if (overflow() > 0) {
8128
+ $$renderer.push("<!--[0-->");
8129
+ $$renderer.push(`<span class="mgr-tag-more svelte-108d03j"${attr("title", words().join(" "))}>+${escape_html(overflow())}</span>`);
8130
+ } else $$renderer.push("<!--[-1-->");
8131
+ $$renderer.push(`<!--]-->`);
8132
+ }
8133
+ $$renderer.push(`<!--]--></td>`);
8134
+ });
8135
+ }
8136
+ //#endregion
8137
+ //#region src/lib/components/chat/PromptManagerTagFilter.svelte
8138
+ function PromptManagerTagFilter($$renderer, $$props) {
8139
+ $$renderer.component(($$renderer) => {
8140
+ /**
8141
+ * PromptManagerTagFilter — the vocabulary chip row of the prompts
8142
+ * manager toolbar (The Prompt Tags ADR, 2026-09-14, D5): the CHIP view
8143
+ * of the active filter state. The words come from /api/config
8144
+ * prompts.tags (the operator's settings.yaml vocabulary); toggling a
8145
+ * chip reports the word up — the HOST owns the state, its persistence
8146
+ * (the dsi-prompt-tags-filter desk slot), and the search-box plus-word
8147
+ * twins (D11).
8148
+ */
8149
+ let { vocabulary, selected} = $$props;
8150
+ $$renderer.push(`<div data-svelte="PromptManagerTagFilter" class="mgr-tag-row svelte-1uamgti" role="group"${attr("aria-label", t(filterbytags2))}${attr("title", t(filterbytags2))}><!--[-->`);
8151
+ const each_array = ensure_array_like(vocabulary);
8152
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
8153
+ let word = each_array[$$index];
8154
+ $$renderer.push(`<button type="button"${attr_class("mgr-tag-filter-chip svelte-1uamgti", void 0, { "on": selected.includes(word) })}${attr("aria-pressed", selected.includes(word))}>${escape_html(word)}</button>`);
8155
+ }
8156
+ $$renderer.push(`<!--]--></div>`);
8157
+ });
8158
+ }
8159
+ //#endregion
8160
+ //#region src/lib/components/chat/PromptManagerTDUses.svelte
8161
+ function PromptManagerTDUses($$renderer, $$props) {
8162
+ $$renderer.component(($$renderer) => {
8163
+ /** Prompt row whose use-count cell this component renders. */
8164
+ let { row } = $$props;
8165
+ $$renderer.push(`<td data-svelte="PromptManagerTDUses" class="mgr-count svelte-sqcp1g">${escape_html(row.use_count)}</td>`);
8166
+ });
8167
+ }
8168
+ //#endregion
8169
+ //#region src/lib/components/chat/PromptManagerPanel.svelte
8170
+ function PromptManagerPanel($$renderer, $$props) {
8171
+ $$renderer.component(($$renderer) => {
8172
+ /**
8173
+ * PromptManagerPanel — the CONTENT of the prompts manager (extracted
8174
+ * 2026-09-06 from PromptsManagerDialog ln 256-442): sticky toolbar +
8175
+ * head table, error strip, add-row, body table, footer — plus the
8176
+ * edit dialog, which travels with the panel because its form state
8177
+ * (editingRow/editText/…) is the table's own.
8178
+ *
8179
+ * Presentational: rows arrive via /api/prompts fetch, the panel owns
8180
+ * inline-edit + search + sort + selection state. Callbacks: onclose
8181
+ * (Escape with nothing open — the dialog's backdrop/× own the other
8182
+ * close gestures), onchanged (CRUD happened — host refreshes nothing
8183
+ * eagerly; the strip refetches on the next trigger).
8184
+ *
8185
+ * ALL data flows through the HTTP contract — this component never
8186
+ * imports db.ts (no cross-module bleed; the manager and the strip
8187
+ * family meet only at /api/prompts).
8188
+ */
8189
+ let { onclose, onchanged, escapeScope = "window", host = "modal" } = $$props;
8190
+ let rows = [];
8191
+ let total = 0;
8192
+ let searchQ = "";
8193
+ let loading$1 = false;
8194
+ let editingId = null;
8195
+ let errorMsg = null;
8196
+ let searchTimer = null;
8197
+ const profile = derived(() => null);
8198
+ /** The operator's vocabulary (settings.yaml prompts.tags via /api/config). */
8199
+ const vocabulary = derived(() => appConfig().prompts.tags);
8200
+ /** Active filter words — lowercased, grammar-valid, deduped. */
8201
+ let tagFilter = [];
8202
+ const TAG_FILTER_KEY = "dsi-prompt-tags-filter";
8203
+ /** Plain (un-prefixed) words of the search box — the q param. */
8204
+ function plainWords(v) {
8205
+ return v.split(/[\s;]+/).filter((tok) => tok && !tok.startsWith("+")).join(" ");
8206
+ }
8207
+ /** Selected row ids (checkbox column). */
8208
+ let selected = /* @__PURE__ */ new Set();
8209
+ async function refresh() {
8210
+ loading$1 = true;
8211
+ errorMsg = null;
8212
+ try {
8213
+ const params = new URLSearchParams({ limit: "200" });
8214
+ params.set("sort", "last_used");
8215
+ if (tagFilter.length > 0) params.set("tags", tagFilter.join(","));
8216
+ const q = plainWords(searchQ).trim();
8217
+ if (q) params.set("q", q);
8218
+ const res = await fetch(`/api/prompts?${params}`);
8219
+ if (!res.ok) {
8220
+ errorMsg = "Failed to load";
8221
+ return;
8222
+ }
8223
+ const data = await res.json();
8224
+ rows = data.rows;
8225
+ total = data.total;
8226
+ } catch {
8227
+ errorMsg = "Network error";
8228
+ }
8229
+ loading$1 = false;
8230
+ }
8231
+ function onSearchInput() {
8232
+ const parsed = searchQ.split(/[\s;]+/).filter((tok) => tok.startsWith("+")).map((tok) => tok.slice(1).toLowerCase()).filter((w) => w && isValidTagWord(w));
8233
+ const next = [...new Set(parsed)];
8234
+ if (next.length !== tagFilter.length || next.some((w) => !tagFilter.includes(w))) {
8235
+ tagFilter = next;
8236
+ saveTagFilter(TAG_FILTER_KEY, tagFilter, profile());
8237
+ }
8238
+ if (searchTimer) clearTimeout(searchTimer);
8239
+ searchTimer = setTimeout(refresh, 300);
8240
+ }
8241
+ /** Visible rows: the server-ordered list as loaded. */
8242
+ let visibleRows = derived(() => rows);
8243
+ /** Direction icon for a column header. */
8244
+ function sortIcon(col) {
8245
+ return "↕";
8246
+ }
8247
+ let $$settled = true;
8248
+ let $$inner_renderer;
8249
+ function $$render_inner($$renderer) {
8250
+ $$renderer.push(`<div data-svelte="PromptManagerPanel" class="mgr-panel-root" role="region"${attr("aria-label", t(promptsmanager1))}${attr("tabindex", escapeScope === "root" ? -1 : void 0)}><div class="mgr-sticky svelte-1kuoadm"><div class="mgr-sticky-bar svelte-1kuoadm"><button type="button" class="mgr-btn mgr-btn-danger svelte-1kuoadm"${attr("disabled", selected.size === 0, true)}${attr("title", selected.size > 0 ? `Delete ${selected.size} selected` : "Select rows to enable delete")}>${escape_html(t(del))}${escape_html(selected.size > 0 ? ` (${selected.size})` : "")}</button> <div class="mgr-toolbar svelte-1kuoadm">`);
8251
+ if (vocabulary().length > 0) {
8252
+ $$renderer.push("<!--[0-->");
8253
+ PromptManagerTagFilter($$renderer, {
8254
+ vocabulary: vocabulary(),
8255
+ selected: tagFilter});
8256
+ } else $$renderer.push("<!--[-1-->");
8257
+ $$renderer.push(`<!--]--> `);
8258
+ PromptManagerSearch($$renderer, {
8259
+ oninput: onSearchInput,
8260
+ get value() {
8261
+ return searchQ;
8262
+ },
8263
+ set value($$value) {
8264
+ searchQ = $$value;
8265
+ $$settled = false;
8266
+ }
8267
+ });
8268
+ $$renderer.push(`<!----> `);
8269
+ {
8270
+ $$renderer.push("<!--[-1-->");
8271
+ $$renderer.push(`<button type="button" class="mgr-btn mgr-btn-add svelte-1kuoadm">${escape_html(t(plusadd1))}</button>`);
8272
+ }
8273
+ $$renderer.push(`<!--]--></div></div> `);
8274
+ if (!loading$1 && rows.length > 0) {
8275
+ $$renderer.push("<!--[0-->");
8276
+ $$renderer.push(`<table class="mgr-table mgr-head-table svelte-1kuoadm"><thead class="svelte-1kuoadm"><tr><th class="mgr-sel-col svelte-1kuoadm">`);
8277
+ if (selected.size > 0) {
8278
+ $$renderer.push("<!--[0-->");
8279
+ $$renderer.push(`<button type="button" class="mgr-unselect-all svelte-1kuoadm"${attr("title", t(unselectall1))}>☐</button>`);
8280
+ } else $$renderer.push("<!--[-1-->");
8281
+ $$renderer.push(`<!--]--></th><th class="svelte-1kuoadm"><button type="button"${attr_class("mgr-sort-btn svelte-1kuoadm", void 0, { "active": false })}>${escape_html(t(uses))} ${escape_html(sortIcon())}</button></th><th class="svelte-1kuoadm"><button type="button"${attr_class("mgr-sort-btn svelte-1kuoadm", void 0, { "active": false })}>${escape_html(t(labelslashtext2))} ${escape_html(sortIcon())}</button></th><th class="mgr-macro-col svelte-1kuoadm">${escape_html(t(macro))}</th><th class="mgr-tags-col svelte-1kuoadm">${escape_html(t(tags))}</th></tr></thead></table>`);
8282
+ } else $$renderer.push("<!--[-1-->");
8283
+ $$renderer.push(`<!--]--></div> `);
8284
+ if (errorMsg) {
8285
+ $$renderer.push("<!--[0-->");
8286
+ $$renderer.push(`<div class="mgr-error svelte-1kuoadm">${escape_html(errorMsg)}</div>`);
8287
+ } else $$renderer.push("<!--[-1-->");
8288
+ $$renderer.push(`<!--]--> `);
8289
+ $$renderer.push("<!--[-1-->");
8290
+ $$renderer.push(`<!--]--> `);
8291
+ if (loading$1) {
8292
+ $$renderer.push("<!--[0-->");
8293
+ $$renderer.push(`<div class="mgr-loading svelte-1kuoadm">${escape_html(t(loading))}</div>`);
8294
+ } else if (rows.length === 0) {
8295
+ $$renderer.push("<!--[1-->");
8296
+ $$renderer.push(`<div class="mgr-empty svelte-1kuoadm">${escape_html(searchQ ? t(nopromptsmatch2) : t(nopromptsyet2))}</div>`);
8297
+ } else {
8298
+ $$renderer.push("<!--[-1-->");
8299
+ $$renderer.push(`<table class="mgr-table mgr-body-table svelte-1kuoadm"><tbody class="svelte-1kuoadm"><!--[-->`);
8300
+ const each_array = ensure_array_like(visibleRows());
8301
+ for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
8302
+ let row = each_array[$$index];
8303
+ if (editingId === row.id) {
8304
+ $$renderer.push("<!--[0-->");
8305
+ $$renderer.push(`<tr class="mgr-editing svelte-1kuoadm"><td class="svelte-1kuoadm"></td><td class="svelte-1kuoadm">${escape_html(row.use_count)}</td>`);
8306
+ PromptManagerTDLabel($$renderer, { row });
8307
+ $$renderer.push(`<!----><td class="mgr-macro-col svelte-1kuoadm">${escape_html(row.macro === 1 ? "✓" : "—")}</td>`);
8308
+ PromptManagerTDTags($$renderer, { row });
8309
+ $$renderer.push(`<!----></tr>`);
8310
+ } else {
8311
+ $$renderer.push("<!--[-1-->");
8312
+ $$renderer.push(`<tr${attr_class("svelte-1kuoadm", void 0, { "sel": selected.has(row.id) })}><td class="mgr-sel-col svelte-1kuoadm"><input type="checkbox" class="mgr-check svelte-1kuoadm"${attr("checked", selected.has(row.id), true)} aria-label="Select prompt"/></td>`);
8313
+ PromptManagerTDUses($$renderer, { row });
8314
+ $$renderer.push(`<!---->`);
8315
+ PromptManagerTDLabel($$renderer, { row });
8316
+ $$renderer.push(`<!----><td class="mgr-macro-col svelte-1kuoadm"><button type="button"${attr_class("mgr-macro-toggle svelte-1kuoadm", void 0, { "on": row.macro === 1 })}${attr("aria-pressed", row.macro === 1)}${attr("title", row.macro === 1 ? "Macro — click to turn off" : "Not a macro — click to turn on")}>${escape_html(row.macro === 1 ? "✓" : "—")}</button></td>`);
8317
+ PromptManagerTDTags($$renderer, { row });
8318
+ $$renderer.push(`<!----></tr>`);
8319
+ }
8320
+ $$renderer.push(`<!--]-->`);
8321
+ }
8322
+ $$renderer.push(`<!--]--></tbody></table> `);
8323
+ if (total > rows.length) {
8324
+ $$renderer.push("<!--[0-->");
8325
+ $$renderer.push(`<div class="mgr-footer svelte-1kuoadm">${escape_html(total - rows.length)} ${escape_html(t(morerefine1))}</div>`);
8326
+ } else $$renderer.push("<!--[-1-->");
8327
+ $$renderer.push(`<!--]-->`);
8328
+ }
8329
+ $$renderer.push(`<!--]--></div> `);
8330
+ $$renderer.push("<!--[-1-->");
8331
+ $$renderer.push(`<!--]-->`);
8332
+ }
8333
+ do {
8334
+ $$settled = true;
8335
+ $$inner_renderer = $$renderer.copy();
8336
+ $$render_inner($$inner_renderer);
8337
+ } while (!$$settled);
8338
+ $$renderer.subsume($$inner_renderer);
8339
+ });
8340
+ }
8341
+ //#endregion
8278
8342
  //#region src/lib/services/lineage/lineage-move.ts
8279
8343
  /** Session id of a floor panel — null for non-conversation kinds (ADR D6:
8280
8344
  * a manager panel belongs to no family; it is its own unit, never a
@@ -8841,96 +8905,6 @@ function rowFactsByPanelId(rows) {
8841
8905
  return new Map(rows.map((r) => [r.panel.id, r]));
8842
8906
  }
8843
8907
  //#endregion
8844
- //#region src/lib/components/chat/PromptManagerPanel.svelte
8845
- function PromptManagerPanel($$renderer, $$props) {
8846
- $$renderer.component(($$renderer) => {
8847
- /**
8848
- * PromptManagerPanel — the CONTENT of the prompts manager (extracted
8849
- * 2026-09-06 from PromptsManagerDialog ln 256-442): sticky toolbar +
8850
- * head table, error strip, add-row, body table, footer — plus the
8851
- * edit dialog, which travels with the panel because its form state
8852
- * (editingRow/editText/…) is the table's own.
8853
- *
8854
- * Presentational: rows arrive via /api/prompts fetch, the panel owns
8855
- * inline-edit + search + sort + selection state. Callbacks: onclose
8856
- * (Escape with nothing open — the dialog's backdrop/× own the other
8857
- * close gestures), onchanged (CRUD happened — host refreshes nothing
8858
- * eagerly; the strip refetches on the next trigger).
8859
- *
8860
- * ALL data flows through the HTTP contract — this component never
8861
- * imports db.ts (no cross-module bleed; the manager and the strip
8862
- * family meet only at /api/prompts).
8863
- */
8864
- let { onclose, onchanged, escapeScope = "window", host = "modal" } = $$props;
8865
- let rows = [];
8866
- let total = 0;
8867
- let searchQ = "";
8868
- let editingId = null;
8869
- /** Selected row ids (checkbox column). */
8870
- let selected = /* @__PURE__ */ new Set();
8871
- /** When true, table shows ONLY selected rows; search input disabled. */
8872
- let showSelectedOnly = false;
8873
- /** use_count value whose rows are auto-checked; 0 disables auto-checking. */
8874
- let autoSelectCount = 1;
8875
- /** Visible rows: server rows, filtered by selection when toggle is on. */
8876
- let visibleRows = derived(() => rows);
8877
- /** Direction icon for a column header. */
8878
- function sortIcon(col) {
8879
- return "↕";
8880
- }
8881
- $$renderer.push(`<div data-svelte="PromptManagerPanel" class="mgr-panel-root" role="region"${attr("aria-label", t(promptsmanager1))}${attr("tabindex", escapeScope === "root" ? -1 : void 0)}><div class="mgr-sticky svelte-1kuoadm"><div class="mgr-sticky-bar svelte-1kuoadm"><button type="button" class="mgr-btn mgr-btn-danger svelte-1kuoadm"${attr("disabled", selected.size === 0, true)}${attr("title", selected.size > 0 ? `Delete ${selected.size} selected` : "Select rows to enable delete")}>${escape_html(t(del))}${escape_html(selected.size > 0 ? ` (${selected.size})` : "")}</button> <h2 class="mgr-title svelte-1kuoadm">${escape_html(MANAGER_ROW_TITLE)}</h2> <div class="mgr-toolbar svelte-1kuoadm"><input type="number" class="mgr-autosel svelte-1kuoadm" min="0" step="1"${attr("value", autoSelectCount)}${attr("title", t(autochecktitle2))}/> <button type="button"${attr_class("mgr-btn mgr-btn-toggle svelte-1kuoadm", void 0, { "active": showSelectedOnly })}${attr("title", t(showonlyselected2))}>${escape_html(t(selectedrows1))}</button> <input type="text" class="mgr-search svelte-1kuoadm"${attr("placeholder", t(searchprompts1))}${attr("value", searchQ)}${attr("disabled", showSelectedOnly, true)}${attr("title", "")}/> `);
8882
- $$renderer.push("<!--[-1-->");
8883
- $$renderer.push(`<button type="button" class="mgr-btn mgr-btn-add svelte-1kuoadm">${escape_html(t(plusadd1))}</button>`);
8884
- $$renderer.push(`<!--]--> <button type="button" class="mgr-close svelte-1kuoadm"${attr("aria-label", t(close))}>×</button></div></div> `);
8885
- if (rows.length > 0) {
8886
- $$renderer.push("<!--[0-->");
8887
- $$renderer.push(`<table class="mgr-table mgr-head-table svelte-1kuoadm"><thead class="svelte-1kuoadm"><tr><th class="mgr-sel-col svelte-1kuoadm">`);
8888
- if (selected.size > 0) {
8889
- $$renderer.push("<!--[0-->");
8890
- $$renderer.push(`<button type="button" class="mgr-unselect-all svelte-1kuoadm"${attr("title", t(unselectall1))}>☐</button>`);
8891
- } else $$renderer.push("<!--[-1-->");
8892
- $$renderer.push(`<!--]--></th><th class="svelte-1kuoadm"><button type="button"${attr_class("mgr-sort-btn svelte-1kuoadm", void 0, { "active": false })}>${escape_html(t(uses))} ${escape_html(sortIcon())}</button></th><th class="svelte-1kuoadm"><button type="button"${attr_class("mgr-sort-btn svelte-1kuoadm", void 0, { "active": false })}>${escape_html(t(labelslashtext2))} ${escape_html(sortIcon())}</button></th><th class="mgr-macro-col svelte-1kuoadm">${escape_html(t(macro))}</th><th class="svelte-1kuoadm">${escape_html(t(actions))}</th></tr></thead></table>`);
8893
- } else $$renderer.push("<!--[-1-->");
8894
- $$renderer.push(`<!--]--></div> `);
8895
- $$renderer.push("<!--[-1-->");
8896
- $$renderer.push(`<!--]--> `);
8897
- $$renderer.push("<!--[-1-->");
8898
- $$renderer.push(`<!--]--> `);
8899
- if (rows.length === 0) {
8900
- $$renderer.push("<!--[1-->");
8901
- $$renderer.push(`<div class="mgr-empty svelte-1kuoadm">${escape_html(t(nopromptsyet2))}</div>`);
8902
- } else {
8903
- $$renderer.push("<!--[-1-->");
8904
- $$renderer.push(`<table class="mgr-table mgr-body-table svelte-1kuoadm"><tbody class="svelte-1kuoadm"><!--[-->`);
8905
- const each_array = ensure_array_like(visibleRows());
8906
- for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
8907
- let row = each_array[$$index];
8908
- if (editingId === row.id) {
8909
- $$renderer.push("<!--[0-->");
8910
- $$renderer.push(`<tr class="mgr-editing svelte-1kuoadm"><td class="svelte-1kuoadm"></td><td class="svelte-1kuoadm">${escape_html(row.use_count)}</td>`);
8911
- PromptManagerTDLabel($$renderer, { row });
8912
- $$renderer.push(`<!----><td class="mgr-macro-col svelte-1kuoadm">${escape_html(row.macro === 1 ? "✓" : "—")}</td><td class="svelte-1kuoadm"></td></tr>`);
8913
- } else {
8914
- $$renderer.push("<!--[-1-->");
8915
- $$renderer.push(`<tr${attr_class("svelte-1kuoadm", void 0, { "sel": selected.has(row.id) })}><td class="mgr-sel-col svelte-1kuoadm"><input type="checkbox" class="mgr-check svelte-1kuoadm"${attr("checked", selected.has(row.id), true)} aria-label="Select prompt"/></td><td class="mgr-count svelte-1kuoadm">${escape_html(row.use_count)}</td>`);
8916
- PromptManagerTDLabel($$renderer, { row });
8917
- $$renderer.push(`<!----><td class="mgr-macro-col svelte-1kuoadm"><button type="button"${attr_class("mgr-macro-toggle svelte-1kuoadm", void 0, { "on": row.macro === 1 })}${attr("aria-pressed", row.macro === 1)}${attr("title", row.macro === 1 ? "Macro — click to turn off" : "Not a macro — click to turn on")}>${escape_html(row.macro === 1 ? "✓" : "—")}</button></td><td class="svelte-1kuoadm"><button type="button" class="mgr-btn mgr-btn-edit svelte-1kuoadm">Edit</button></td></tr>`);
8918
- }
8919
- $$renderer.push(`<!--]-->`);
8920
- }
8921
- $$renderer.push(`<!--]--></tbody></table> `);
8922
- if (total > rows.length) {
8923
- $$renderer.push("<!--[0-->");
8924
- $$renderer.push(`<div class="mgr-footer svelte-1kuoadm">${escape_html(total - rows.length)} ${escape_html(t(morerefine1))}</div>`);
8925
- } else $$renderer.push("<!--[-1-->");
8926
- $$renderer.push(`<!--]-->`);
8927
- }
8928
- $$renderer.push(`<!--]--></div> `);
8929
- $$renderer.push("<!--[-1-->");
8930
- $$renderer.push(`<!--]-->`);
8931
- });
8932
- }
8933
- //#endregion
8934
8908
  //#region src/lib/components/chat/PromptsManagerDialog.svelte
8935
8909
  function PromptsManagerDialog($$renderer, $$props) {
8936
8910
  $$renderer.component(($$renderer) => {
@@ -8953,12 +8927,12 @@ function PromptsManagerDialog($$renderer, $$props) {
8953
8927
  * {#if} — onclose unmounts it.
8954
8928
  */
8955
8929
  let { onclose, onchanged } = $$props;
8956
- $$renderer.push(`<div data-svelte="PromptsManagerDialog" class="mgr-backdrop svelte-13xs6jp" role="presentation"></div> <div data-svelte="PromptsManagerDialog" class="mgr-modal svelte-13xs6jp" role="dialog"${attr("aria-label", t(managesavedprompts2))} tabindex="-1">`);
8930
+ $$renderer.push(`<div data-svelte="PromptsManagerDialog" class="mgr-backdrop svelte-13xs6jp" role="presentation"></div> <div data-svelte="PromptsManagerDialog" class="mgr-modal svelte-13xs6jp" role="dialog"${attr("aria-label", t(managesavedprompts2))} tabindex="-1"><div class="mgr-dialog-header svelte-13xs6jp"><div class="mgr-dialog-title svelte-13xs6jp">${escape_html(MANAGER_ROW_TITLE)}</div> <button type="button" class="mgr-dialog-close svelte-13xs6jp"${attr("aria-label", t(close))}>×</button></div> <div class="mgr-dialog-body svelte-13xs6jp">`);
8957
8931
  PromptManagerPanel($$renderer, {
8958
8932
  onclose,
8959
8933
  onchanged
8960
8934
  });
8961
- $$renderer.push(`<!----></div>`);
8935
+ $$renderer.push(`<!----></div></div>`);
8962
8936
  });
8963
8937
  }
8964
8938
  //#endregion
@@ -9003,19 +8977,56 @@ function parseCommand(text) {
9003
8977
  args
9004
8978
  };
9005
8979
  case "/new": {
9006
- const m = /^@(\S+)(?:\s+(--add))?$|^(--add)$/.exec(args);
9007
- if (m === null) return {
8980
+ let rest = args === "" ? [] : args.split(/\s+/);
8981
+ let agentId;
8982
+ let ws;
8983
+ let addPanel = false;
8984
+ if (rest.length > 0 && rest[0].startsWith("@") && rest[0].length > 1) {
8985
+ agentId = rest[0].slice(1);
8986
+ rest = rest.slice(1);
8987
+ }
8988
+ if (rest.length > 0 && rest[rest.length - 1] === "--add") {
8989
+ addPanel = true;
8990
+ rest = rest.slice(0, -1);
8991
+ }
8992
+ if (rest.length === 1 && !rest[0].startsWith("@") && !rest[0].startsWith("--") && rest[0] !== "?") {
8993
+ ws = rest[0];
8994
+ rest = [];
8995
+ }
8996
+ if (rest.length !== 0) return {
9008
8997
  type: "new",
9009
8998
  args
9010
8999
  };
9011
- const addPanel = m[2] !== void 0 || m[3] !== void 0;
9012
9000
  return {
9013
9001
  type: "new",
9014
9002
  args: "",
9015
- ...m[1] !== void 0 ? { agentId: m[1] } : {},
9003
+ ...agentId !== void 0 ? { agentId } : {},
9004
+ ...ws !== void 0 ? { ws } : {},
9016
9005
  ...addPanel ? { addPanel: true } : {}
9017
9006
  };
9018
9007
  }
9008
+ case "/workspace": {
9009
+ if (args === "" || args === "?") return {
9010
+ type: "workspace",
9011
+ args
9012
+ };
9013
+ const toks = args.split(/\s+/);
9014
+ if (toks.length === 1) return {
9015
+ type: "workspace",
9016
+ args: "",
9017
+ wsPath: toks[0]
9018
+ };
9019
+ if (toks.length === 2) return {
9020
+ type: "workspace",
9021
+ args: "",
9022
+ wsPath: toks[0],
9023
+ wsName: toks[1]
9024
+ };
9025
+ return {
9026
+ type: "workspace",
9027
+ args
9028
+ };
9029
+ }
9019
9030
  case "/promptmanager":
9020
9031
  case "/dsisettings":
9021
9032
  case "/dshsettings":
@@ -9093,15 +9104,22 @@ function commandHelpTopic(text) {
9093
9104
  * PRESET_TABLE (permission-state); ids/examples mirror command-parser. */
9094
9105
  var COMMAND_HELP = {
9095
9106
  new: {
9096
- usage: "/new [@agent] [--add]",
9097
- summary: "Creates a fresh session — it inherits this session's workspace and agent. Default: it replaces this panel. With --add: it opens in a NEW panel to the right, and focus stays here.",
9098
- params: [{
9099
- name: "@agent",
9100
- description: "Optional agent preset id for the new session (overrides the inherited agent). The host validates the id."
9101
- }, {
9102
- name: "--add",
9103
- description: "Open the new session in a NEW panel placed to the RIGHT of the current panel; the current panel keeps the selection and the caret (the default panel swap never runs)."
9104
- }],
9107
+ usage: "/new [@agent] [workspace] [--add]",
9108
+ summary: "Creates a fresh session — it inherits this session's workspace and agent. Name a registered workspace to land THERE instead of inheriting (unique title, or the full path). Default: it replaces this panel. With --add: it opens in a NEW panel to the right, and focus stays here.",
9109
+ params: [
9110
+ {
9111
+ name: "@agent",
9112
+ description: "Optional agent preset id for the new session (overrides the inherited agent). The host validates the id."
9113
+ },
9114
+ {
9115
+ name: "workspace",
9116
+ description: "Optional registered workspace — a unique title (recipe-ws) or the full path (/home/u/recipe-ws). The new session runs there instead of inheriting; an ambiguous name lists the candidates instead of guessing."
9117
+ },
9118
+ {
9119
+ name: "--add",
9120
+ description: "Open the new session in a NEW panel placed to the RIGHT of the current panel; the current panel keeps the selection and the caret (the default panel swap never runs)."
9121
+ }
9122
+ ],
9105
9123
  examples: [
9106
9124
  {
9107
9125
  line: "/new",
@@ -9111,12 +9129,41 @@ var COMMAND_HELP = {
9111
9129
  line: "/new @reviewer",
9112
9130
  description: "New session running the reviewer agent preset."
9113
9131
  },
9132
+ {
9133
+ line: "/new recipe-ws",
9134
+ description: "New session inside the registered recipe-ws workspace."
9135
+ },
9114
9136
  {
9115
9137
  line: "/new @app-dev --add",
9116
9138
  description: "New app-dev session in a panel to the right — this panel keeps focus."
9117
9139
  }
9118
9140
  ]
9119
9141
  },
9142
+ workspace: {
9143
+ usage: "/workspace <full-path> [name]",
9144
+ summary: "Adopts a folder on the host as a workspace — the typed twin of the sidebar’s Add-workspace picker. The folder must already exist (DSI never writes the filesystem; ask the agent to mkdir first). An optional name titles the workspace WHEN this command created it; the fresh-desk recipe: /workspace ~/workspace-ai, then /new workspace-ai.",
9145
+ params: [{
9146
+ name: "<full-path>",
9147
+ description: "Absolute or ~ path to the folder (a ~ expands against the host’s home). A relative path is refused before anything is sent."
9148
+ }, {
9149
+ name: "[name]",
9150
+ description: "Optional display title — applied only when this command created the workspace; an already-adopted folder keeps its title (rename it from the chip menu)."
9151
+ }],
9152
+ examples: [
9153
+ {
9154
+ line: "/workspace ~/workspace-ai",
9155
+ description: "Adopt the folder — the host titles it workspace-ai (the path’s last segment)."
9156
+ },
9157
+ {
9158
+ line: "/workspace ~/workspace-ai MyWS",
9159
+ description: "Adopt AND title it MyWS — the rename applies only when this command created it."
9160
+ },
9161
+ {
9162
+ line: "/new workspace-ai",
9163
+ description: "The follow-up: a fresh session running inside the adopted workspace."
9164
+ }
9165
+ ]
9166
+ },
9120
9167
  promptmanager: {
9121
9168
  usage: "/promptmanager [--add]",
9122
9169
  summary: "Opens the prompts manager as a floor panel beside your conversations. Default: it replaces this panel. With --add: it opens in a NEW panel to the right — and takes the focus (unlike /new --add, which leaves focus here).",
@@ -9228,6 +9275,12 @@ var MENU_GESTURES = [
9228
9275
  seed: "/new ",
9229
9276
  description: COMMAND_HELP.new.summary
9230
9277
  },
9278
+ {
9279
+ name: "workspace",
9280
+ display: "/workspace",
9281
+ seed: "/workspace ",
9282
+ description: COMMAND_HELP.workspace.summary
9283
+ },
9231
9284
  {
9232
9285
  name: "promptmanager",
9233
9286
  display: "/promptmanager",
@@ -9620,7 +9673,8 @@ function PromptInput($$renderer, $$props) {
9620
9673
  async function fetchSuggestions() {
9621
9674
  const el = textareaEl;
9622
9675
  const caret = el?.selectionStart ?? value.length;
9623
- const query = getTrigger(el?.value ?? value, caret);
9676
+ const current = el?.value ?? value;
9677
+ const query = getTrigger(current, caret);
9624
9678
  if (!query) {
9625
9679
  suggestRows = [];
9626
9680
  return;
@@ -10754,24 +10808,31 @@ function MarkdownContent($$renderer, $$props) {
10754
10808
  function SavePromptButton($$renderer, $$props) {
10755
10809
  $$renderer.component(($$renderer) => {
10756
10810
  /**
10757
- * SavePromptButton — add a bubble's text to the prompts library (ADR E4;
10758
- * ported from OCI's SavePromptButton.svelte, Suggest Strip Wave 3).
10759
- *
10760
- * Check-then-POST: GET /api/prompts?q= (exact-text match against the
10761
- * library) first — a hit shows the duplicate state; a miss POSTs the
10762
- * text. A 409 on POST is a lost race (added between check and POST) —
10763
- * same UX as a hit. States idle → checking → saved | duplicate | error,
10764
- * inline on the button (icon swap + note as the title tooltip), mir
10765
- * CopyButton's feedback pattern (size/class contract, 2.6 s note).
10811
+ * SavePromptButton — add a bubble's text to the prompts library
10812
+ * (The Prompt Tags ADR, 2026-09-14, D6): the click OPENS a small
10813
+ * anchored popup — bubble text preview, the operator's vocabulary
10814
+ * chips (settings.yaml prompts.tags via /api/config store), an
10815
+ * optional label, then Save. The state machine behind Save is the
10816
+ * original check-then-POST verbatim: GET /api/prompts?q= exact-text
10817
+ * check → duplicate state on a hit; a miss POSTs { text, label?,
10818
+ * tags } (tags always an array — [] = untagged, additive for stale
10819
+ * callers). A 409 on POST is a lost race — same UX as a hit. States
10820
+ * idle → checking → saved | duplicate | error, inline on the trigger
10821
+ * (icon swap + note as the title tooltip, 2.6 s note). Tagging at
10822
+ * birth is the ONLY birth path a row has (D7 — /use inserts nothing).
10766
10823
  */
10767
10824
  let { text, size = 12, title = "Save prompt", class: className = "" } = $$props;
10768
- $$renderer.push(`<button data-svelte="SavePromptButton" type="button"${attr_class(`${stringify(className)} shrink-0`)}${attr("title", title)}${attr("aria-label", title)} data-testid="save-prompt-button"${attr("disabled", !text.trim(), true)}>`);
10825
+ /** Popup visibility — ephemeral; the POST is the only hand-off (D6). */
10826
+ let open = false;
10827
+ $$renderer.push(`<span data-svelte="SavePromptButton"${attr_class(`save-prompt-wrap ${stringify(className)}`, "svelte-78up8f")}><button type="button" class="shrink-0"${attr("title", title)}${attr("aria-label", title)}${attr("aria-expanded", open)} data-testid="save-prompt-button"${attr("disabled", !text.trim(), true)}>`);
10769
10828
  $$renderer.push("<!--[-1-->");
10770
10829
  Bookmark_plus($$renderer, {
10771
10830
  size,
10772
10831
  class: ""
10773
10832
  });
10774
- $$renderer.push(`<!--]--></button>`);
10833
+ $$renderer.push(`<!--]--></button> `);
10834
+ $$renderer.push("<!--[-1-->");
10835
+ $$renderer.push(`<!--]--></span>`);
10775
10836
  });
10776
10837
  }
10777
10838
  //#endregion
@@ -14430,12 +14491,13 @@ async function sendPrompt(text, ctx, submit) {
14430
14491
  */
14431
14492
  async function executeCommand(command, ctx, onNote) {
14432
14493
  if (command.type === "permission") return runPermissionLine(`/permission${command.args === "" ? "" : " " + command.args}`, ctx, onNote);
14494
+ if (command.type === "workspace") return runWorkspaceLine(command.wsPath, command.wsName, ctx, onNote);
14433
14495
  if (command.type === "mention") return runMention(command.sessionId ?? "", command.args, command.a2aId, ctx, onNote);
14434
14496
  if (command.type === "promptmanager") return runPromptManager(command.args, command.addPanel === true, ctx, onNote);
14435
14497
  if (command.type === "dsisettings" || command.type === "dshsettings") return runSettingsEditor(command.type === "dsisettings" ? "dsi" : "dsh", "/" + command.type, command.args, command.addPanel === true, ctx, onNote);
14436
14498
  if (command.type === "loadinjected") return runLoadInjected(command.filename, command.addPanel === true, ctx, onNote);
14437
14499
  if (command.args !== "") {
14438
- const usage = "usage: /new [@agent] [--add]";
14500
+ const usage = "usage: /new [@agent] [workspace] [--add]";
14439
14501
  onNote?.(false, usage);
14440
14502
  return {
14441
14503
  ok: false,
@@ -14450,13 +14512,26 @@ async function executeCommand(command, ctx, onNote) {
14450
14512
  note
14451
14513
  };
14452
14514
  }
14515
+ let cwd = ctx.workspace;
14516
+ if (command.ws !== void 0) {
14517
+ const resolved = await resolveWorkspaceToken(command.ws);
14518
+ if (resolved.note !== void 0) {
14519
+ onNote?.(false, resolved.note);
14520
+ return {
14521
+ ok: false,
14522
+ note: resolved.note
14523
+ };
14524
+ }
14525
+ cwd = resolved.path ?? null;
14526
+ }
14527
+ const freshInstallNote = cwd === null ? "/new: no workspace inherited — this session lands UNGROUPED; adopt one with /workspace <full-path>, then aim with /new <name>" : void 0;
14453
14528
  const preset = command.agentId ?? ctx.agent;
14454
14529
  try {
14455
14530
  const res = await fetch("/api/dsh/sessions", {
14456
14531
  method: "POST",
14457
14532
  headers: { "content-type": "application/json" },
14458
14533
  body: JSON.stringify({
14459
- ...ctx.workspace !== null ? { cwd: ctx.workspace } : {},
14534
+ ...cwd !== null ? { cwd } : {},
14460
14535
  ...preset !== null ? { agentPreset: preset } : {}
14461
14536
  })
14462
14537
  });
@@ -14483,6 +14558,14 @@ async function executeCommand(command, ctx, onNote) {
14483
14558
  note
14484
14559
  };
14485
14560
  }
14561
+ if (freshInstallNote !== void 0) {
14562
+ onNote?.(true, freshInstallNote);
14563
+ return {
14564
+ ok: true,
14565
+ newSessionId: body.sessionId,
14566
+ note: freshInstallNote
14567
+ };
14568
+ }
14486
14569
  return {
14487
14570
  ok: true,
14488
14571
  newSessionId: body.sessionId
@@ -14504,6 +14587,14 @@ async function executeCommand(command, ctx, onNote) {
14504
14587
  note
14505
14588
  };
14506
14589
  }
14590
+ if (freshInstallNote !== void 0) {
14591
+ onNote?.(true, freshInstallNote);
14592
+ return {
14593
+ ok: true,
14594
+ newSessionId: body.sessionId,
14595
+ note: freshInstallNote
14596
+ };
14597
+ }
14507
14598
  return {
14508
14599
  ok: true,
14509
14600
  newSessionId: body.sessionId
@@ -14885,6 +14976,151 @@ async function executeHostCommand(line, ctx, onNote) {
14885
14976
  };
14886
14977
  }
14887
14978
  }
14979
+ /**
14980
+ * /workspace <full-path> [name] (ADR D1/D2): adopt a host folder into the
14981
+ * workspace registry — the typed twin of the sidebar's Add-workspace picker
14982
+ * (which is untouched, F9). Flow, per the ADR:
14983
+ * D3 the handler expands a leading `~` against the HOST home (read off
14984
+ * the directory-listing endpoint — the crumbs precedent) BEFORE the
14985
+ * wire; a relative path usage-notes before any RPC.
14986
+ * D4 a missing folder is the host's own refusal surfaced honestly with
14987
+ * the mkdir remedy — DSI NEVER writes the filesystem, never retries.
14988
+ * D2 the optional name renames ONLY what THIS command created
14989
+ * (created=true); an already-adopted path skips the rename (the chip
14990
+ * menu owns renames of existing workspaces) and says so.
14991
+ * F9 a successful adopt fires the sidebar nudge `dsi:workspaces-changed`
14992
+ * (the AddWorkspaceButton precedent) so the pill is immediate.
14993
+ * The success note carries the ready follow-up `/new <name-or-tail>` —
14994
+ * the recipe's next line, typed for the operator.
14995
+ */
14996
+ async function runWorkspaceLine(wsPath, wsName, _ctx, onNote) {
14997
+ if (wsPath === void 0) {
14998
+ const usage = "usage: /workspace <full-path> [name]";
14999
+ onNote?.(false, usage);
15000
+ return {
15001
+ ok: false,
15002
+ note: usage
15003
+ };
15004
+ }
15005
+ if (!wsPath.startsWith("~") && !wsPath.startsWith("/")) {
15006
+ const note = "usage: /workspace <full-path> [name] — pass an absolute or ~ path (a relative one never reaches the wire)";
15007
+ onNote?.(false, note);
15008
+ return {
15009
+ ok: false,
15010
+ note
15011
+ };
15012
+ }
15013
+ let path = wsPath;
15014
+ if (path.startsWith("~")) try {
15015
+ const res = await fetch("/api/dsh/directory");
15016
+ const body = await res.json().catch(() => null);
15017
+ const home = body?.listing?.home;
15018
+ if (!res.ok || body?.ok !== true || typeof home !== "string" || home === "") {
15019
+ const note = `/workspace: could not read the host home (${body?.error?.message ?? `HTTP ${res.status}`}) — the ~ path was not expanded; use the absolute path (e.g. /Users/<you>/…) instead`;
15020
+ onNote?.(false, note);
15021
+ return {
15022
+ ok: false,
15023
+ note
15024
+ };
15025
+ }
15026
+ path = home + path.slice(1);
15027
+ } catch (err) {
15028
+ const note = `/workspace: could not read the host home (${err instanceof Error ? err.message : String(err)})`;
15029
+ onNote?.(false, note);
15030
+ return {
15031
+ ok: false,
15032
+ note
15033
+ };
15034
+ }
15035
+ try {
15036
+ const res = await fetch("/api/dsh/workspaces", {
15037
+ method: "POST",
15038
+ headers: { "content-type": "application/json" },
15039
+ body: JSON.stringify({ path })
15040
+ });
15041
+ const body = await res.json().catch(() => null);
15042
+ if (!res.ok || body?.ok !== true || !body.workspace) {
15043
+ const note = `/workspace refused: ${body?.error?.message ?? `HTTP ${res.status}`} — if the folder is missing, ask the agent to mkdir ${path} first (DSI never writes the filesystem)`;
15044
+ onNote?.(false, note);
15045
+ return {
15046
+ ok: false,
15047
+ note
15048
+ };
15049
+ }
15050
+ const wsId = typeof body.workspace.workspaceId === "string" ? body.workspace.workspaceId : "";
15051
+ const hostTitle = typeof body.workspace.title === "string" ? body.workspace.title : "";
15052
+ if (body.created === false) {
15053
+ const note = `/workspace: ${path} is already adopted as "${hostTitle}"${wsName !== void 0 ? " — the name is NOT applied to an existing workspace (rename it from the chip menu)" : ""} — try /new ${wsName ?? hostTitle}`;
15054
+ onNote?.(true, note);
15055
+ return {
15056
+ ok: true,
15057
+ note
15058
+ };
15059
+ }
15060
+ let finalTitle = hostTitle;
15061
+ if (wsName !== void 0) {
15062
+ const rn = await fetch(`/api/dsh/workspaces/${encodeURIComponent(wsId)}/rename`, {
15063
+ method: "POST",
15064
+ headers: { "content-type": "application/json" },
15065
+ body: JSON.stringify({ title: wsName })
15066
+ });
15067
+ const rnBody = await rn.json().catch(() => null);
15068
+ if (!rn.ok || rnBody?.ok !== true) {
15069
+ const reason = rnBody?.error?.message ?? `HTTP ${rn.status}`;
15070
+ const note = `/workspace: adopted ${path}, but the rename to "${wsName}" failed — ${reason} (the workspace keeps the host default title; rename it from the chip menu)`;
15071
+ onNote?.(true, note);
15072
+ window.dispatchEvent(new Event("dsi:workspaces-changed"));
15073
+ return {
15074
+ ok: true,
15075
+ note
15076
+ };
15077
+ }
15078
+ finalTitle = wsName;
15079
+ }
15080
+ window.dispatchEvent(new Event("dsi:workspaces-changed"));
15081
+ const note = `/workspace: adopted ${path}${wsName !== void 0 ? ` as "${finalTitle}"` : ` as "${hostTitle}"`} — ready: /new ${wsName ?? finalTitle}`;
15082
+ onNote?.(true, note);
15083
+ return {
15084
+ ok: true,
15085
+ note
15086
+ };
15087
+ } catch (err) {
15088
+ const note = `/workspace failed (${err instanceof Error ? err.message : String(err)})`;
15089
+ onNote?.(false, note);
15090
+ return {
15091
+ ok: false,
15092
+ note
15093
+ };
15094
+ }
15095
+ }
15096
+ /**
15097
+ * The D5 resolution (2026-09-15): one workspace token against the host
15098
+ * registry (GET /api/dsh/sessions carries the rows). Match order — a
15099
+ * UNIQUE exact title first, then an exact canonical path; anything else is
15100
+ * an honest note (ambiguous → the candidates, path + title; miss → the
15101
+ * /workspace pointer). Never a guess, never a client-side registry.
15102
+ */
15103
+ async function resolveWorkspaceToken(token) {
15104
+ let rows = [];
15105
+ try {
15106
+ const res = await fetch("/api/dsh/sessions");
15107
+ const body = await res.json().catch(() => null);
15108
+ if (!res.ok || body?.ok !== true || !Array.isArray(body.workspaces)) return { note: `/new: the workspace registry is unavailable (HTTP ${res.status}) — try again` };
15109
+ rows = body.workspaces.filter((w) => typeof w.title === "string" && typeof w.path === "string").map((w) => ({
15110
+ title: w.title,
15111
+ path: w.path
15112
+ }));
15113
+ } catch {
15114
+ return { note: "/new: the workspace registry is unavailable — try again" };
15115
+ }
15116
+ const byTitle = rows.filter((w) => w.title === token);
15117
+ if (byTitle.length === 1) return { path: byTitle[0].path };
15118
+ if (byTitle.length > 1) return { note: `/new: "${token}" matches several workspaces — ${byTitle.map((w) => `${w.path} ("${w.title}")`).join(", ")} — repeat with the full path` };
15119
+ const byPath = rows.find((w) => w.path === token);
15120
+ if (byPath !== void 0) return { path: byPath.path };
15121
+ if (rows.length === 0) return { note: `/new: no workspace "${token}" — the registry is empty; adopt one with /workspace <full-path>` };
15122
+ return { note: `/new: no workspace "${token}" — the registry holds: ${rows.map((w) => w.title).join(", ")}; adopt a new one with /workspace <full-path>` };
15123
+ }
14888
15124
  //#endregion
14889
15125
  //#region src/lib/components/chat/InjectedShelfButton.svelte
14890
15126
  function InjectedShelfButton($$renderer, $$props) {
@@ -18787,4 +19023,4 @@ function _page($$renderer, $$props) {
18787
19023
  }
18788
19024
 
18789
19025
  export { _page as default };
18790
- //# sourceMappingURL=_page.svelte.js-T6ftg3_-.js.map
19026
+ //# sourceMappingURL=_page.svelte.js-C1cGitkt.js.map