dsh-codinput 0.1.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 (54) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +18 -0
  4. package/README.en.md +167 -0
  5. package/README.md +167 -0
  6. package/TESTING.md +95 -0
  7. package/assets/en/preview-ball-detail.png +0 -0
  8. package/assets/en/preview-float.png +0 -0
  9. package/assets/en/preview-normal.png +0 -0
  10. package/assets/en/preview-side.png +0 -0
  11. package/assets/en/preview-split.png +0 -0
  12. package/assets/icon.svg +1 -0
  13. package/assets/preview-ball-detail.png +0 -0
  14. package/assets/preview-float.png +0 -0
  15. package/assets/preview-normal.png +0 -0
  16. package/assets/preview-side.png +0 -0
  17. package/assets/preview-split.png +0 -0
  18. package/cordis.patch.yml +5 -0
  19. package/lib/client.js +544 -0
  20. package/lib/index.js +5 -0
  21. package/package.json +79 -0
  22. package/src/client/attachments.ts +43 -0
  23. package/src/client/cm.ts +207 -0
  24. package/src/client/command.ts +78 -0
  25. package/src/client/components/AttachmentRail.tsx +241 -0
  26. package/src/client/components/CodinputBar.tsx +357 -0
  27. package/src/client/components/CodinputSurface.tsx +375 -0
  28. package/src/client/components/EditorPane.tsx +214 -0
  29. package/src/client/components/ExpandBall.tsx +122 -0
  30. package/src/client/components/MenuSurface.tsx +72 -0
  31. package/src/client/components/ModelMenu.tsx +234 -0
  32. package/src/client/components/PermissionMenu.tsx +257 -0
  33. package/src/client/components/PopupSelectView.tsx +140 -0
  34. package/src/client/components/SlashMenu.tsx +255 -0
  35. package/src/client/components/StatsRow.tsx +188 -0
  36. package/src/client/components/Toolbar.tsx +239 -0
  37. package/src/client/components/popup-filter.ts +13 -0
  38. package/src/client/components/useSnapshot.ts +18 -0
  39. package/src/client/diag.ts +58 -0
  40. package/src/client/host-types.ts +328 -0
  41. package/src/client/hotkey.ts +82 -0
  42. package/src/client/i18n.ts +312 -0
  43. package/src/client/icons.tsx +296 -0
  44. package/src/client/index.tsx +178 -0
  45. package/src/client/modeldir.ts +42 -0
  46. package/src/client/permission.ts +123 -0
  47. package/src/client/prefs.ts +123 -0
  48. package/src/client/services.ts +78 -0
  49. package/src/client/settings.tsx +236 -0
  50. package/src/client/sidebar.tsx +114 -0
  51. package/src/client/sideinput.ts +171 -0
  52. package/src/client/stats.ts +166 -0
  53. package/src/client/styles.ts +489 -0
  54. package/src/client/triggers.ts +84 -0
@@ -0,0 +1,489 @@
1
+ /**
2
+ * 样式:dci- 前缀,注入一次。
3
+ * 工具行/菜单/发送按钮的属性值逐条复刻官方 InputBar.module.css 与
4
+ * PermissionSelect/ModelSelection 的触发器与菜单(含 --dsw-* 主题变量,
5
+ * 随宿主主题自动切换);编辑器/设置等自有部分用 currentColor 适配。
6
+ */
7
+
8
+ const STYLE_ID = 'dsh-codinput-styles';
9
+
10
+ const CSS = `
11
+ /* ===== 拖文件入卡片:落区提示(粘贴/拖入附件入口)===== */
12
+ .dci-card[data-drop] { outline: 2px solid var(--dsw-alias-state-business-primary, currentColor); outline-offset: -2px; }
13
+
14
+ /* ===== 侧栏重复标签提示(同会话第二个 Codinput 标签不渲染第二个编辑面)===== */
15
+ .dci-side-notice { box-sizing: border-box; width: 100%; padding: 24px 16px; text-align: center;
16
+ color: var(--dsw-alias-label-tertiary, currentColor); font-size: 13px; line-height: 20px; }
17
+
18
+ /* ===== 官方卡片(InputBar .card):编辑器+预览+工具行合入一张卡 ===== */
19
+ .dci-surface { display: flex; flex-direction: column; gap: 6px; min-width: 0; color: inherit; }
20
+ /* 宽度默认继承空白态(hero)卡宽(官方 max-width 变量,回退 760px):
21
+ 会话态(无包裹约束)不再被拉满,左右居中;拖边调节后由内联 max-width 接管。 */
22
+ .dci-card { box-sizing: border-box; width: 100%; max-width: var(--dsh-composer-card-max-width, 760px); margin-inline: auto;
23
+ background: var(--dsw-specific-input-major, color-mix(in srgb, currentColor 4%, transparent));
24
+ box-shadow: var(--dsw-elevation-soft, none); font-size: 14px; line-height: 24px;
25
+ border: 0; border-radius: 22px; flex-direction: column; gap: 0; padding-top: 4px; display: flex; position: relative; min-width: 0; }
26
+ /* 卡片边缘调节把手:左右调宽、上下调高(对称灵敏度),悬停显形。 */
27
+ .dci-rip { position: absolute; z-index: 60; touch-action: none; }
28
+ .dci-rip[data-axis="y"] { left: 12px; right: 12px; height: 9px; cursor: ns-resize; }
29
+ .dci-rip[data-axis="y"][data-side="top"] { top: -4px; }
30
+ .dci-rip::after { content: ''; position: absolute; inset: 0; margin: auto; border-radius: 3px; background: transparent; transition: background 0.12s; }
31
+ .dci-rip[data-axis="y"]::after { height: 3px; width: 44px; }
32
+ .dci-rip:hover::after, .dci-rip[data-dragging="true"]::after { background: var(--dsw-alias-state-business-primary, currentColor); }
33
+ .dci-accessory { align-items: center; gap: 2px; padding: 6px 12px 0; display: flex; }
34
+ .dci-iconbtn {
35
+ display: inline-flex; align-items: center; justify-content: center;
36
+ width: 26px; height: 26px; padding: 0; border: none; border-radius: 6px;
37
+ background: transparent; color: inherit; opacity: 0.62; cursor: pointer;
38
+ }
39
+ .dci-iconbtn:hover { opacity: 1; background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent)); }
40
+ .dci-iconbtn[data-on="true"] { opacity: 1; background: var(--dsw-alias-interactive-bg-hover-solid, color-mix(in srgb, currentColor 12%, transparent)); }
41
+ .dci-iconbtn:disabled { opacity: 0.3; cursor: default; background: transparent; }
42
+
43
+ /* ===== 编辑区(无框,由卡片承担外观)===== */
44
+ /* 拖过上下缘后 body 固定高(--dci-body-h),未拖时高度随内容、46vh 封顶。 */
45
+ .dci-body { position: relative; display: flex; gap: 0; min-height: 60px; max-height: var(--dci-body-max, 46vh); overflow: hidden; }
46
+ .dci-body[style*="--dci-body-h"] { height: var(--dci-body-h); }
47
+ /* 分屏:grid 等宽两栏(fr 计入 padding/border,两栏边界严格居中;flex
48
+ * 会把预览栏的横向 padding 泄漏进空间分配,做不到对半)。 */
49
+ .dci-body[data-split="true"] { display: grid; grid-template-columns: 1fr 1fr; }
50
+ .dci-body[data-split="true"] .dci-editor-wrap { border-right: 1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 12%, transparent)); }
51
+ .dci-editor-wrap { position: relative; flex: 1 1 100%; min-width: 0; box-sizing: border-box; display: flex; flex-direction: column; }
52
+ .dci-editor-wrap[data-solo="true"] { flex-basis: 100%; }
53
+ .dci-cm-host { flex: 1; min-height: 0; overflow-y: auto; }
54
+ .dci-cm-host .cm-editor { height: 100%; background: transparent; }
55
+ .dci-pos { position: absolute; right: 10px; bottom: 6px; font-size: 11px; color: var(--dsw-alias-label-caption, currentColor); opacity: 0.75;
56
+ pointer-events: none; font-variant-numeric: tabular-nums; z-index: 3; }
57
+
58
+ .dci-preview { flex: 1 1 100%; min-width: 0; box-sizing: border-box; overflow-y: auto; padding: 8px 14px 10px; font-size: 13px; line-height: 1.65; }
59
+ .dci-preview h1, .dci-preview h2, .dci-preview h3, .dci-preview h4 { margin: 0.7em 0 0.35em; line-height: 1.3; }
60
+ .dci-preview h1 { font-size: 1.35em; } .dci-preview h2 { font-size: 1.2em; } .dci-preview h3 { font-size: 1.08em; }
61
+ .dci-preview p { margin: 0.45em 0; } .dci-preview ul, .dci-preview ol { margin: 0.45em 0; padding-left: 1.5em; }
62
+ .dci-preview code { font-family: inherit; background: color-mix(in srgb, currentColor 9%, transparent);
63
+ border-radius: 4px; padding: 0.1em 0.35em; font-size: 0.92em; }
64
+ .dci-preview pre { background: color-mix(in srgb, currentColor 7%, transparent); border-radius: 8px;
65
+ padding: 10px 12px; overflow-x: auto; } .dci-preview pre code { background: transparent; padding: 0; }
66
+ .dci-preview blockquote { margin: 0.5em 0; padding: 0.1em 0.9em; border-left: 3px solid color-mix(in srgb, currentColor 22%, transparent); opacity: 0.85; }
67
+ .dci-preview table { border-collapse: collapse; margin: 0.6em 0; }
68
+ .dci-preview th, .dci-preview td { border: 1px solid color-mix(in srgb, currentColor 18%, transparent); padding: 4px 9px; }
69
+ .dci-preview a { color: #4c8dff; } .dci-preview img { max-width: 100%; } .dci-preview hr { border: none;
70
+ border-top: 1px solid color-mix(in srgb, currentColor 14%, transparent); }
71
+
72
+ /* ===== 工具行(官方 InputBar .row / .tools / .trailing)===== */
73
+ .dci-row { flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 12px; min-width: 0; padding: 2px 8px 6px; display: flex; }
74
+ .dci-tools { align-items: center; min-width: 0; gap: 12px; display: flex; }
75
+ .dci-trailing { align-items: center; flex: none; min-width: 0; gap: 12px; margin-left: auto; display: flex; }
76
+
77
+ /* 圆形图标按钮(官方 .add)*/
78
+ .dci-add { background: var(--dsw-specific-selector, color-mix(in srgb, currentColor 8%, transparent));
79
+ width: 28px; height: 28px; color: var(--dsw-alias-label-primary, currentColor); cursor: pointer; border: none;
80
+ border-radius: 999px; flex: none; place-items: center; display: grid; }
81
+ .dci-add:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover-solid, color-mix(in srgb, currentColor 14%, transparent)); }
82
+ .dci-add:disabled { opacity: 0.5; cursor: default; }
83
+
84
+ /* 下拉触发(官方 PermissionSelect / ModelSelection .trigger)*/
85
+ .dci-trigger { min-width: 0; max-width: 220px; height: 28px; color: var(--dsw-alias-label-secondary, currentColor); cursor: pointer;
86
+ background: transparent; border: none; border-radius: 24px; outline: none; align-items: center; gap: 4px;
87
+ padding: 0 4px 0 8px; font-size: 13px; font-weight: 500; line-height: 20px; display: inline-flex; }
88
+ .dci-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent)); }
89
+ .dci-trigger:focus-visible { box-shadow: 0 0 0 2px var(--dsw-alias-border-l3, transparent); }
90
+ .dci-trigger:disabled { color: var(--dsw-alias-label-dimmed, currentColor); cursor: default; opacity: 0.5; }
91
+ .dci-triggerIcon { flex: none; display: inline-flex; }
92
+ .dci-triggerIcon svg { width: 14px; height: 14px; }
93
+ .dci-triggerLabel { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }
94
+ .dci-triggerEffort { color: var(--dsw-alias-label-caption, currentColor); flex-shrink: 1000; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
95
+ .dci-chev { color: var(--dsw-alias-label-caption, currentColor); flex: none; transition: transform 0.12s; display: inline-flex; }
96
+ .dci-chev[data-open="true"] { transform: rotate(180deg); }
97
+
98
+ /* 发送(官方 .primary)*/
99
+ .dci-send { background: var(--dsw-alias-button-info-fill, color-mix(in srgb, currentColor 85%, transparent)); color: #fff; cursor: pointer;
100
+ border: none; border-radius: 999px; flex: none; place-items: center; width: 34px; height: 34px;
101
+ transition: background-color 0.1s; display: grid; transform: translateY(-2px); }
102
+ .dci-send:hover:not(:disabled) { background: var(--dsw-alias-button-info-hover, color-mix(in srgb, currentColor 70%, transparent)); }
103
+ .dci-send:disabled { opacity: 0.4; cursor: default; }
104
+
105
+ /* ===== 菜单(官方 primitives Menu:r20 卡片 / item r10 / side-top 弹出)===== */
106
+ .dci-menu { position: fixed; z-index: 1100; box-sizing: border-box; padding: 4px; display: flex; flex-direction: column;
107
+ min-width: 218px; max-width: min(360px, 100vw - 24px); max-height: calc(100vh - 24px); overflow-y: auto;
108
+ background: var(--dsw-specific-menu, rgba(28, 28, 32, 0.98)); color: var(--dsw-alias-label-primary, #ececf1);
109
+ --dsw-elevation-stroke-color: var(--dsw-alias-border-l1, transparent);
110
+ box-shadow: var(--dsw-elevation-prominent, 0 10px 34px rgba(0, 0, 0, 0.35)); border: 0; border-radius: 20px; font-size: 13px; }
111
+ .dci-viewport { display: flex; flex-direction: column; min-height: 0; }
112
+ .dci-menuLabel { padding: 8px 10px; font-size: 12px; line-height: 16px; color: var(--dsw-alias-label-tertiary, currentColor);
113
+ user-select: none; text-align: left; }
114
+ .dci-item { display: flex; align-items: center; gap: 8px; width: 100%; min-height: 40px; padding: 8px 10px; border: none;
115
+ border-radius: 10px; background: transparent; cursor: pointer; font-size: 14px; line-height: 22px;
116
+ color: var(--dsw-alias-label-primary, inherit); text-align: left; }
117
+ .dci-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 10%, transparent)); }
118
+ .dci-item:disabled { opacity: 0.4; cursor: not-allowed; }
119
+ .dci-itemIcon { display: inline-flex; flex: none; width: 16px; height: 16px; align-items: center; justify-content: center;
120
+ color: var(--dsw-alias-label-tertiary, currentColor); }
121
+ .dci-itemIcon svg { width: 14px; height: 14px; }
122
+ .dci-itemLabel { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
123
+ .dci-check { flex: none; color: var(--dsw-alias-label-primary, currentColor); display: grid; place-items: center; }
124
+
125
+ /* ===== 候选菜单(官方 MenuView.module.css 逐值复刻:卡片顶锚定全宽浮层)===== */
126
+ .dci-slash-menu { z-index: 100; --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2, transparent);
127
+ --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2, transparent);
128
+ background: var(--dsw-specific-menu, rgba(30, 30, 34, 0.98)); color: var(--dsw-alias-label-primary, inherit);
129
+ --dsw-elevation-stroke-color: var(--dsw-alias-border-l1, transparent);
130
+ max-height: 320px; box-shadow: var(--dsw-elevation-prominent, 0 10px 34px rgba(0, 0, 0, 0.35));
131
+ border: 0; border-radius: 20px; flex-direction: column; padding: 4px; display: flex; position: absolute;
132
+ bottom: calc(100% + 4px); left: 0; right: 0; overflow: hidden; }
133
+ .dci-slash-viewport { flex-direction: column; min-height: 0; display: flex; overflow-y: auto; }
134
+ .dci-slash-item { cursor: pointer; width: 100%; min-height: 40px; color: var(--dsw-alias-label-primary, inherit);
135
+ text-align: left; background: transparent; border: none; border-radius: 10px; align-items: center; gap: 8px;
136
+ padding: 8px 10px; font-size: 14px; line-height: 22px; display: flex; }
137
+ .dci-slash-item[data-active="true"], .dci-slash-item:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent)); }
138
+ .dci-slash-sectionTitle { min-height: 26px; color: var(--dsw-alias-label-tertiary, currentColor); flex: none;
139
+ padding: 6px 10px 2px; font-size: 12px; font-weight: 500; line-height: 18px; }
140
+ .dci-slash-sectionTitle:not(:first-child) { margin-top: 4px; }
141
+ .dci-slash-itemIcon { width: 16px; height: 16px; color: var(--dsw-alias-label-tertiary, currentColor); flex: none;
142
+ justify-content: center; align-items: center; display: inline-flex; }
143
+ .dci-slash-itemIcon svg { width: 16px; height: 16px; }
144
+ .dci-slash-itemName { text-overflow: ellipsis; white-space: nowrap; flex: none; max-width: 40%; overflow: hidden; }
145
+ .dci-slash-itemAlias { text-overflow: ellipsis; white-space: nowrap; max-width: 20%; color: var(--dsw-alias-label-tertiary, currentColor); flex: none; overflow: hidden; }
146
+ .dci-slash-itemDescription { text-overflow: ellipsis; white-space: nowrap; min-width: 0;
147
+ color: var(--dsw-alias-label-tertiary, currentColor); flex: 1; overflow: hidden; }
148
+ .dci-slash-trailing { flex: none; align-items: center; gap: 4px; margin-left: auto; display: inline-flex; }
149
+ .dci-slash-drillHintText { color: var(--dsw-alias-label-caption, currentColor); white-space: nowrap; font-size: 11px;
150
+ line-height: 18px; display: none; }
151
+ .dci-slash-drillHint { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent));
152
+ color: var(--dsw-alias-label-caption, currentColor); border-radius: 4px; padding: 0 5px; font-family: inherit;
153
+ font-size: 11px; line-height: 18px; display: none; }
154
+ .dci-slash-item[data-active="true"] .dci-slash-drillHintText, .dci-slash-item[data-active="true"] .dci-slash-drillHint { display: inline-flex; }
155
+ .dci-slash-drill { width: 20px; height: 20px; color: var(--dsw-alias-label-caption, currentColor); border-radius: 4px;
156
+ flex: none; place-items: center; display: inline-grid; cursor: pointer; }
157
+ .dci-slash-drill:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent));
158
+ color: var(--dsw-alias-label-primary, inherit); }
159
+ .dci-slash-groupTitle { color: var(--dsw-alias-label-tertiary, currentColor); padding: 8px 10px; font-size: 12px; line-height: 16px; }
160
+ .dci-slash-skeletonRow { box-sizing: border-box; align-items: center; min-height: 40px; padding: 8px 10px; display: flex; }
161
+ .dci-slash-skeletonBar { background: var(--dsw-alias-bg-skeleton, color-mix(in srgb, currentColor 10%, transparent));
162
+ border-radius: 4px; height: 20px; animation: dci-slash-skeleton 2s cubic-bezier(0.36, 0, 0.64, 1) infinite; }
163
+ @keyframes dci-slash-skeleton { 0% { opacity: 1; } 40% { opacity: 0.6; } 80%, 100% { opacity: 1; } }
164
+ .dci-slash-crumbs { border-bottom: 0.5px solid var(--dsw-alias-border-l1, transparent); flex-wrap: wrap; flex: none;
165
+ align-items: center; gap: 2px; margin-bottom: 2px; padding: 4px 4px 6px; display: flex; }
166
+ .dci-slash-crumb { max-width: 40%; color: var(--dsw-alias-label-tertiary, currentColor); cursor: pointer;
167
+ text-overflow: ellipsis; white-space: nowrap; background: transparent; border: none; border-radius: 6px;
168
+ flex: 0 1 auto; padding: 2px 6px; font-family: inherit; font-size: 12px; line-height: 18px; overflow: hidden; }
169
+ .dci-slash-crumb:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent));
170
+ color: var(--dsw-alias-label-primary, inherit); }
171
+ .dci-slash-crumb:disabled { color: var(--dsw-alias-label-primary, inherit); cursor: default; background: transparent; }
172
+ .dci-slash-crumbSeparator { color: var(--dsw-alias-label-caption, currentColor); flex: none; display: inline-flex; }
173
+
174
+ .dci-crumb-row { display: flex; flex-wrap: wrap; gap: 2px; padding: 4px 6px; }
175
+ .dci-crumb { border: none; background: transparent; color: var(--dsw-alias-label-secondary, inherit); cursor: pointer;
176
+ padding: 2px 6px; border-radius: 5px; font-size: 11.5px; display: inline-flex; }
177
+ .dci-crumb:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 9%, transparent)); }
178
+ .dci-crumb[data-current="true"] { color: var(--dsw-alias-label-primary, inherit); cursor: default; }
179
+ .dci-empty { padding: 10px; color: var(--dsw-alias-label-tertiary, currentColor); text-align: left; }
180
+ .dci-search { width: calc(100% - 8px); margin: 2px 4px 4px; padding: 5px 9px; font-size: 13px;
181
+ border-radius: 8px; border: 1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 18%, transparent));
182
+ background: transparent; color: inherit; outline: none; }
183
+ .dci-error { padding: 6px 10px; color: var(--dsw-alias-state-error-primary, #ff6b6b); font-size: 12px; }
184
+
185
+ /* ===== 模型/推理等级 cell 行(官方 ModelSelection .cell)===== */
186
+ .dci-cell { box-sizing: border-box; width: auto; min-width: 100%; height: 40px; color: var(--dsw-alias-label-primary, inherit);
187
+ cursor: pointer; text-align: left; background: transparent; border: none; border-radius: 10px;
188
+ align-items: center; gap: 8px; padding: 0 10px; font-size: 14px; line-height: 22px; display: flex; }
189
+ .dci-cell:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 10%, transparent)); }
190
+ .dci-cellLabel { white-space: nowrap; flex: none; }
191
+ .dci-cellValue { text-overflow: ellipsis; white-space: nowrap; text-align: right; min-width: 0;
192
+ color: var(--dsw-alias-label-tertiary, currentColor); flex: auto; overflow: hidden; }
193
+ .dci-cellChevron { color: var(--dsw-alias-label-tertiary, currentColor); flex: none; display: inline-flex; }
194
+
195
+ /* ===== 完全权限确认(官方 RiskConfirmation 语义)===== */
196
+ .dci-confirm-warning { display: flex; align-items: flex-start; gap: 10px; color: var(--dsw-alias-label-secondary, currentColor);
197
+ font-size: 14px; line-height: 22px; padding: 6px 8px 0; }
198
+ .dci-confirm-warning svg { flex: none; margin-top: 2px; color: var(--dsw-alias-state-error-primary, #ff6b6b); }
199
+ .dci-confirm-warning p { margin: 0; }
200
+ .dci-confirm-ack { display: flex; align-items: flex-start; gap: 10px; margin: 14px 8px 0; cursor: pointer;
201
+ color: var(--dsw-alias-label-primary, inherit); font-size: 14px; line-height: 22px; }
202
+ .dci-confirm-ack input { flex: none; width: 16px; height: 16px; margin: 3px 0 0;
203
+ accent-color: var(--dsw-alias-button-primary-fill, currentColor); cursor: pointer; }
204
+ .dci-confirm-actions { display: flex; justify-content: flex-end; gap: 8px; padding: 16px 8px 4px; }
205
+ .dci-confirm-actions .dci-btn { min-width: 72px; }
206
+ .dci-confirm-actions .dci-btn[data-primary="true"] { min-width: 136px; }
207
+ .dci-btn { border: 1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 22%, transparent)); border-radius: 10px;
208
+ background: transparent; color: inherit; padding: 6px 14px; cursor: pointer; font-size: 14px; line-height: 20px; }
209
+ .dci-btn[data-primary="true"] { background: var(--dsw-alias-button-primary-fill, color-mix(in srgb, currentColor 85%, transparent));
210
+ color: #fff; border-color: transparent; }
211
+ .dci-btn:disabled { opacity: 0.4; cursor: default; }
212
+
213
+ /* ===== 草稿附件轨(官方 ComposerAttachments/AttachmentRail/FileCard 逐值复刻)=====
214
+ * 值取自官方 dsh-client-ui-attachment:轨道 gap 10 / 隐藏滚动条 / 64px 项;
215
+ * 图片缩略图 64×64 r16 cover;文件卡 240×64 r16(icon 28 + name 14/500 +
216
+ * meta 12);移除钮 18px 圆(button-contrast-fill,悬停显形);翻页箭头 24px 圆。 */
217
+ .dci-attach-root { position: relative; min-width: 0; margin: 6px 12px 0; }
218
+ .dci-attach-rail { display: flex; align-items: stretch; gap: 10px; overflow: auto hidden;
219
+ scrollbar-width: none; --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2, transparent);
220
+ --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2, transparent); }
221
+ .dci-attach-rail::-webkit-scrollbar { display: none; }
222
+ .dci-attach-item { position: relative; flex: none; height: 64px; }
223
+ .dci-attach-thumb { box-sizing: border-box; width: 64px; height: 64px; padding: 0; overflow: hidden;
224
+ cursor: zoom-in; border: 0.5px solid var(--dsw-alias-border-l2-darkmode-thin, color-mix(in srgb, currentColor 12%, transparent));
225
+ border-radius: 16px; background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent));
226
+ display: grid; place-items: center; color: var(--dsw-alias-label-tertiary, currentColor); }
227
+ .dci-attach-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
228
+ /* 移除钮(图片项:卡片右上角浮层)。 */
229
+ .dci-attach-remove { position: absolute; top: 4px; right: 4px; z-index: 1; box-sizing: border-box;
230
+ width: 18px; height: 18px; padding: 0; border: none; border-radius: 50%; corner-shape: round;
231
+ background: var(--dsw-alias-button-contrast-fill, rgba(0, 0, 0, 0.72));
232
+ color: var(--dsw-alias-label-primary-inverted, #fff); cursor: pointer; opacity: 0;
233
+ display: grid; place-items: center; transition: opacity 0.2s ease-in-out; }
234
+ .dci-attach-item:hover .dci-attach-remove, .dci-attach-remove:focus-visible { opacity: 1; }
235
+ @media (pointer: coarse) { .dci-attach-remove { opacity: 1; } }
236
+ @media (prefers-reduced-motion: reduce) { .dci-attach-remove { transition: none; } }
237
+ /* 文件卡(非图片)。 */
238
+ .dci-attach-card { box-sizing: border-box; position: relative; display: inline-flex; align-items: center;
239
+ gap: 10px; width: 240px; height: 64px; padding: 0 12px; text-align: left;
240
+ border: 0.5px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 12%, transparent));
241
+ border-radius: 16px; background: var(--dsw-specific-input-major, color-mix(in srgb, currentColor 4%, transparent)); }
242
+ .dci-attach-cardFailed { border-color: var(--dsw-alias-state-error-primary, #d54941); }
243
+ .dci-attach-icon { flex: none; display: inline-flex; align-items: center; justify-content: center;
244
+ width: 28px; height: 28px; color: var(--dsw-alias-label-secondary, currentColor); }
245
+ .dci-attach-spinner { box-sizing: border-box; width: 20px; height: 20px; border: 2px solid; border-top-color: transparent;
246
+ border-radius: 50%; corner-shape: round; animation: dci-attach-spin 0.8s linear infinite; }
247
+ @keyframes dci-attach-spin { to { transform: rotate(360deg); } }
248
+ .dci-attach-body { display: flex; flex-direction: column; flex: 1; min-width: 0; padding: 8px 0; }
249
+ button.dci-attach-body { color: inherit; font: inherit; text-align: left; background: none; border: 0; cursor: pointer; }
250
+ .dci-attach-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
251
+ color: var(--dsw-alias-label-primary, inherit); font-size: 14px; font-weight: 500; line-height: 22px; }
252
+ .dci-attach-card:hover .dci-attach-name, .dci-attach-card:focus-within .dci-attach-name { padding-right: 18px; }
253
+ .dci-attach-meta { overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
254
+ color: var(--dsw-alias-label-tertiary, currentColor); font-size: 12px; line-height: 15px; }
255
+ .dci-attach-metaFailed { color: var(--dsw-alias-state-error-primary, #d54941); }
256
+ /* 文件卡的移除钮(卡内右下角,非浮层)。 */
257
+ .dci-attach-removeInline { position: absolute; top: 6px; right: 6px; box-sizing: border-box;
258
+ width: 18px; height: 18px; padding: 0; border: none; border-radius: 50%; corner-shape: round;
259
+ background: var(--dsw-alias-button-contrast-fill, rgba(0, 0, 0, 0.72));
260
+ color: var(--dsw-alias-label-primary-inverted, #fff); cursor: pointer; opacity: 0;
261
+ display: inline-flex; align-items: center; justify-content: center; transition: opacity 0.2s ease-in-out; }
262
+ .dci-attach-card:hover .dci-attach-removeInline, .dci-attach-removeInline:focus-visible { opacity: 1; }
263
+ .dci-attach-cardFailedRemove { background: var(--dsw-alias-state-error-primary, #d54941); color: #fff; opacity: 1; }
264
+ /* 上传进度(有 loaded/total 时按比例,否则官方同款往返动画)。 */
265
+ .dci-attach-progress { position: absolute; bottom: 5px; left: 12px; right: 12px; height: 2px;
266
+ border-radius: 1px; background: var(--dsw-alias-fill-tertiary, color-mix(in srgb, currentColor 8%, transparent));
267
+ overflow: hidden; }
268
+ .dci-attach-item .dci-attach-progress { left: 4px; right: 4px; }
269
+ .dci-attach-progressBar { display: block; height: 100%; border-radius: inherit;
270
+ background: var(--dsw-alias-brand-primary, currentColor); animation: dci-attach-progress 1.2s ease-in-out infinite alternate; }
271
+ .dci-attach-progressBar[style*="width"] { animation: none; }
272
+ @keyframes dci-attach-progress { 0% { transform: translate(-70%); } to { transform: translate(220%); } }
273
+ /* 翻页箭头(轨道两端,溢出时才出现)。 */
274
+ .dci-attach-arrow { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; box-sizing: border-box;
275
+ width: 24px; height: 24px; padding: 0; border: 0; border-radius: 999px; corner-shape: round;
276
+ background: var(--dsw-specific-input-major, color-mix(in srgb, currentColor 8%, transparent));
277
+ color: var(--dsw-alias-label-secondary, currentColor); box-shadow: var(--dsw-elevation-panel, none);
278
+ --dsw-elevation-stroke-color: var(--dsw-alias-border-l2-darkmode-thin, transparent);
279
+ cursor: pointer; display: grid; place-items: center; }
280
+ .dci-attach-arrow:hover { background: var(--dsw-alias-interactive-bg-hover-solid, color-mix(in srgb, currentColor 14%, transparent)); }
281
+ .dci-attach-arrowLeft { left: 4px; }
282
+ .dci-attach-arrowRight { right: 4px; }
283
+
284
+ /* ===== 数据行(卡片下方,官方 data-composer-stats 位置)===== */
285
+ .dci-stats { display: flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--dsw-alias-label-caption, currentColor);
286
+ padding: 0 6px; font-variant-numeric: tabular-nums; user-select: none; }
287
+
288
+ /* ===== 悬浮模式(拖顶部行空白区脱出;拖回底部输入区回普通;prefs 记忆)===== */
289
+ .dci-float { position: fixed; z-index: 940; min-width: 0; display: flex; flex-direction: column; }
290
+ .dci-float .dci-surface { flex: 1 1 auto; min-height: 0; }
291
+ .dci-float .dci-card { max-width: none; margin-inline: 0; width: 100%; }
292
+ /* 手动缩放过高度后(data-sized):卡片吃满外壳,编辑区吃满卡片剩余高度。 */
293
+ .dci-float[data-sized="true"] .dci-card { flex: 1 1 auto; min-height: 0; }
294
+ .dci-float[data-sized="true"] .dci-body { flex: 1 1 auto; max-height: none; min-height: 0; }
295
+ /* 缩放把手:四条边 + 四个角落,1:1 跟手(窗口式);透明热区,骑在卡片边缘上。 */
296
+ .dci-float-grip { position: absolute; z-index: 61; touch-action: none; }
297
+ .dci-float-grip[data-dir="n"] { top: calc(-1 * var(--dci-grip-edge)); left: var(--dci-grip-corner); right: var(--dci-grip-corner);
298
+ height: var(--dci-grip-edge); cursor: ns-resize; }
299
+ .dci-float-grip[data-dir="s"] { bottom: calc(-1 * var(--dci-grip-edge)); left: var(--dci-grip-corner); right: var(--dci-grip-corner);
300
+ height: var(--dci-grip-edge); cursor: ns-resize; }
301
+ .dci-float-grip[data-dir="w"] { left: calc(-1 * var(--dci-grip-edge)); top: var(--dci-grip-corner); bottom: var(--dci-grip-corner);
302
+ width: var(--dci-grip-edge); cursor: ew-resize; }
303
+ .dci-float-grip[data-dir="e"] { right: calc(-1 * var(--dci-grip-edge)); top: var(--dci-grip-corner); bottom: var(--dci-grip-corner);
304
+ width: var(--dci-grip-edge); cursor: ew-resize; }
305
+ .dci-float-grip[data-dir="nw"] { top: calc(-1 * var(--dci-grip-edge)); left: calc(-1 * var(--dci-grip-edge));
306
+ width: var(--dci-grip-corner); height: var(--dci-grip-corner); cursor: nwse-resize; }
307
+ .dci-float-grip[data-dir="ne"] { top: calc(-1 * var(--dci-grip-edge)); right: calc(-1 * var(--dci-grip-edge));
308
+ width: var(--dci-grip-corner); height: var(--dci-grip-corner); cursor: nesw-resize; }
309
+ .dci-float-grip[data-dir="sw"] { bottom: calc(-1 * var(--dci-grip-edge)); left: calc(-1 * var(--dci-grip-edge));
310
+ width: var(--dci-grip-corner); height: var(--dci-grip-corner); cursor: nesw-resize; }
311
+ .dci-float-grip[data-dir="se"] { bottom: calc(-1 * var(--dci-grip-edge)); right: calc(-1 * var(--dci-grip-edge));
312
+ width: var(--dci-grip-corner); height: var(--dci-grip-corner); cursor: nwse-resize; }
313
+ /* 拖动区:accessory 行里开关右侧的空白,按住移动整卡(普通态拖出=悬浮)。 */
314
+ .dci-float-dragzone { flex: 1 1 auto; align-self: stretch; min-width: 24px; cursor: grab; touch-action: none; }
315
+ .dci-float-dragzone[data-dragging="true"] { cursor: grabbing; }
316
+ /* 悬浮卡片:数据行收进卡片底部;高度拖把不适用。 */
317
+ .dci-surface[data-float] .dci-rip { display: none; }
318
+ .dci-surface[data-float] .dci-stat-root { padding: 2px 16px 8px; }
319
+ .dci-surface[data-float] .dci-card { box-shadow: var(--dsw-elevation-prominent, 0 10px 34px rgba(0, 0, 0, 0.35)); }
320
+
321
+ /* ===== 右上角小球(侧栏收起后的 Codinput 唤出入口)=====
322
+ * 位置由 JS 量标题栏(会话头部)后内联注入:标题栏下方、右对齐(与官方角落
323
+ * 按钮同内缩 12px、贴头部底边下 8px)——不占官方槽位,因此官方侧栏展开/
324
+ * 收起按钮原样留在标题栏里,小球不覆盖它。悬于内容之上,故带圆形描边与
325
+ * 极淡底色(取值同官方控件的 resting 面色)以免被对话内容淹没;图标为品牌
326
+ * glyph(lucide file-code-corner,README 图标)。
327
+ * corner-shape: round 是必需的:宿主设计语言在根节点设了
328
+ * corner-shape: superellipse(1.5)(全局超椭圆/squircle),只写 50% 会渲染
329
+ * 成圆角方而非圆——官方自己的圆形控件(spinner/dot/tag/switch/thumb)也都
330
+ * 逐条 opt-out 回 round,此处照同一约定。 */
331
+ .dci-ball { position: fixed; z-index: 900; box-sizing: border-box; width: 36px; height: 36px;
332
+ color: var(--dsw-alias-label-secondary, currentColor); cursor: pointer;
333
+ background: var(--dsw-alias-bg-module-platform, color-mix(in srgb, currentColor 6%, transparent));
334
+ border: 2px solid var(--dsw-alias-border-l3, color-mix(in srgb, currentColor 30%, transparent));
335
+ border-radius: 50%; corner-shape: round; flex: none; justify-content: center; align-items: center; padding: 0; display: inline-flex;
336
+ transition: background-color 0.12s, border-color 0.12s; }
337
+ .dci-ball svg { width: 18px; height: 18px; }
338
+ /* 悬停:描边提亮到标签色 + 面色加深,指针在内容之上也能看出可点。 */
339
+ .dci-ball:hover { background: var(--dsw-alias-interactive-bg-hover-solid, color-mix(in srgb, currentColor 14%, transparent));
340
+ border-color: var(--dsw-alias-label-tertiary, currentColor); color: var(--dsw-alias-label-primary, inherit); }
341
+ .dci-ball:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, currentColor); outline-offset: 2px; }
342
+
343
+ /* ===== 侧栏形态(dockkit 标签页):适应整个面板而非照搬主输入卡片 =====
344
+ * 卡片去壳铺满 paneBody(官方 _paneBody 为 position:relative + overflow:auto,
345
+ * 包裹层 absolute inset:0 精确铺满),编辑区吃满剩余高度——VS Code 面板式。 */
346
+ .dci-surface[data-side] { flex: 1 1 auto; min-height: 0; }
347
+ .dci-surface[data-side] .dci-card { flex: 1 1 auto; min-height: 0; max-width: none; margin-inline: 0;
348
+ background: transparent; box-shadow: none; border-radius: 0; padding-top: 0; }
349
+ .dci-surface[data-side] .dci-rip { display: none; }
350
+ .dci-surface[data-side] .dci-accessory { padding: 8px 12px 6px;
351
+ border-bottom: 0.5px solid var(--dsw-alias-border-l1, transparent); }
352
+ .dci-surface[data-side] .dci-body { flex: 1 1 auto; max-height: none; min-height: 0; }
353
+ .dci-surface[data-side] .dci-row { padding: 6px 8px;
354
+ border-top: 0.5px solid var(--dsw-alias-border-l1, transparent); }
355
+ /* 候选菜单向下弹出(侧栏/悬浮形态:头部行下方),留在卡片边界内不被裁剪。 */
356
+ .dci-surface[data-side] .dci-slash-menu, .dci-surface[data-float] .dci-slash-menu { bottom: auto; }
357
+
358
+ /* ===== 设置分区(官方 T1PP 行结构 + 控件样式)===== */
359
+ .dci-settings { display: flex; flex-direction: column; font-size: 14px; color: inherit; }
360
+ .dci-set-row { border-bottom: 0.5px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 10%, transparent));
361
+ align-items: center; gap: 8px; padding: 16px 0; display: flex; }
362
+ .dci-set-rowText { flex-direction: column; flex: 1 1 0%; gap: 4px; min-width: 0; padding-right: 48px; display: flex; }
363
+ .dci-set-title { color: var(--dsw-alias-label-primary, inherit); font-size: 14px; font-weight: 400; line-height: 22px; }
364
+ .dci-set-desc { color: var(--dsw-alias-label-tertiary, currentColor); font-size: 12px; font-weight: 400; line-height: 18px; }
365
+ .dci-set-control { display: flex; align-items: center; }
366
+ .dci-set-selector { background: var(--dsw-alias-bg-module-platform, color-mix(in srgb, currentColor 6%, transparent));
367
+ height: 36px; color: var(--dsw-alias-label-primary, inherit); cursor: pointer; border: none; border-radius: 18px;
368
+ align-items: center; gap: 12px; padding: 0 14px; font-size: 14px; line-height: 22px; display: inline-flex; }
369
+ .dci-set-selector:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 10%, transparent)); }
370
+ .dci-set-selector[data-recording="true"] { color: var(--dsw-alias-state-business-primary, currentColor); }
371
+ .dci-set-selector[data-conflict="true"] { color: var(--dsw-alias-state-error-primary, currentColor); }
372
+ .dci-set-input { background: var(--dsw-alias-bg-module-platform, color-mix(in srgb, currentColor 6%, transparent));
373
+ height: 36px; color: var(--dsw-alias-label-primary, inherit); border: none; border-radius: 18px; outline: none;
374
+ padding: 0 14px; font-size: 13px; min-width: 260px; max-width: 320px; }
375
+ .dci-set-input:focus { outline: 2px solid var(--dsw-alias-border-l3, transparent); }
376
+ .dci-switch { box-sizing: border-box; position: relative; flex: none; width: 36px; height: 20px; padding: 2px;
377
+ border: 0; border-radius: 10px; background: var(--dsw-alias-border-l3, color-mix(in srgb, currentColor 30%, transparent));
378
+ cursor: pointer; }
379
+ .dci-switch[aria-checked="true"] { background: var(--dsw-alias-brand-primary, color-mix(in srgb, currentColor 70%, transparent)); }
380
+ .dci-switch:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, currentColor); outline-offset: 2px; }
381
+ .dci-switch::after { content: ''; display: block; width: 16px; height: 16px; border-radius: 50%;
382
+ background: var(--dsw-alias-label-primary-foreground, #fff); transition: transform 120ms ease; }
383
+ .dci-switch[aria-checked="true"]::after { transform: translateX(16px); }
384
+
385
+ /* ===== 数据行(官方 bOPqQW 复刻:居中双胶囊)===== */
386
+ .dci-stat-root { max-width: var(--dsh-chat-content-width, 100%); box-sizing: border-box; width: 100%;
387
+ padding: 4px calc(var(--dsh-composer-side-clearance, 0px) + 16px) 0; font-size: 13px; line-height: 20px;
388
+ justify-content: center; gap: 12px; margin: 0 auto; display: flex; }
389
+ .dci-stat-anchor { min-width: 0; display: inline-flex; position: relative; }
390
+
391
+ /* 数据行详情面板(官方 bRhRbq 复刻:锚点上方弹出) */
392
+ .dci-stat-panel { z-index: 1100; box-sizing: border-box; background: var(--dsw-specific-menu, rgba(30, 30, 34, 0.98));
393
+ color: var(--dsw-alias-label-secondary, inherit); --dsw-elevation-stroke-color: var(--dsw-alias-border-l1, transparent);
394
+ width: max-content; min-width: min(300px, 100vw - 24px); max-width: min(440px, 100vw - 24px); text-align: left;
395
+ box-shadow: var(--dsw-elevation-prominent, 0 10px 34px rgba(0, 0, 0, 0.35)); cursor: default; border: 0;
396
+ border-radius: 12px; padding: 16px; font-size: 12px; line-height: 18px; position: absolute; bottom: calc(100% + 8px); left: 0; }
397
+ .dci-stat-panelTitle { color: var(--dsw-alias-label-primary, inherit); justify-content: space-between; gap: 16px;
398
+ margin-bottom: 8px; font-weight: 500; display: flex; }
399
+ .dci-stat-panelLabel { align-items: center; gap: 6px; min-width: 0; display: inline-flex; }
400
+ .dci-stat-panelLabel svg { flex: none; width: 14px; height: 14px; }
401
+ .dci-stat-panelValue { font-variant-numeric: tabular-nums; }
402
+ .dci-stat-panelRule { border-top: 0.5px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 10%, transparent)); margin-bottom: 10px; }
403
+ .dci-stat-details { color: var(--dsw-alias-label-tertiary, currentColor); grid-template-columns: minmax(76px, auto) minmax(0, 1fr);
404
+ gap: 6px 16px; margin: 0; display: grid; }
405
+ .dci-stat-details dt, .dci-stat-details dd { min-width: 0; margin: 0; }
406
+ .dci-stat-details dd { color: var(--dsw-alias-label-secondary, inherit); font-variant-numeric: tabular-nums; text-align: right; }
407
+ .dci-stat-pill { box-sizing: border-box; max-width: 100%; color: var(--dsw-alias-label-tertiary, currentColor);
408
+ white-space: nowrap; background: transparent; border: none; border-radius: 24px; align-items: center; gap: 6px;
409
+ padding: 1px 8px; display: inline-flex; cursor: pointer; font-variant-numeric: tabular-nums; }
410
+ .dci-stat-pill svg { flex: none; width: 14px; height: 14px; }
411
+ .dci-stat-pill:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent));
412
+ color: var(--dsw-alias-label-secondary, inherit); }
413
+ .dci-stat-label { text-overflow: ellipsis; min-width: 0; overflow: hidden; }
414
+ .dci-stat-sep { color: var(--dsw-alias-separator-primary, currentColor); margin: 0 6px; }
415
+
416
+ /* ===== 上下文小圈(官方 JObwrW 复刻:双环仪表 + 分段面板)===== */
417
+ .dci-gauge-root { display: inline-flex; position: relative; }
418
+ .dci-gauge-trigger { width: 28px; height: 28px; color: var(--dsw-alias-label-secondary, currentColor); cursor: pointer;
419
+ background: transparent; border: none; border-radius: 999px; flex: none; place-items: center; display: grid; }
420
+ .dci-gauge-trigger:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent)); }
421
+ .dci-gauge-track { fill: none; stroke: var(--dsw-alias-border-l3, currentColor); stroke-width: 2px; }
422
+ .dci-gauge-fill { fill: none; stroke: var(--dsw-alias-label-tertiary, currentColor); stroke-width: 2px; stroke-linecap: round; }
423
+ .dci-gauge-panel { z-index: 1100; box-sizing: border-box; background: var(--dsw-specific-menu, rgba(30, 30, 34, 0.98));
424
+ --dsw-elevation-stroke-color: var(--dsw-alias-border-l1, transparent); width: 264px;
425
+ box-shadow: var(--dsw-elevation-prominent, 0 10px 34px rgba(0, 0, 0, 0.35));
426
+ color: var(--dsw-alias-label-secondary, inherit); cursor: default; border: 0; border-radius: 12px; padding: 12px;
427
+ font-size: 12px; line-height: 20px; position: absolute; bottom: calc(100% + 8px); right: 0; }
428
+ .dci-gauge-header { align-items: center; gap: 6px; display: flex; }
429
+ .dci-gauge-figures { font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-primary, inherit); margin-left: auto; font-weight: 500; }
430
+ .dci-gauge-percent { color: var(--dsw-alias-label-primary, inherit); font-weight: 500; }
431
+ .dci-gauge-headline { color: var(--dsw-alias-label-tertiary, currentColor); }
432
+ .dci-gauge-bar { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent));
433
+ border-radius: 999px; gap: 1px; height: 4px; margin: 10px 0 12px; display: flex; overflow: hidden; }
434
+ .dci-gauge-segment { background: var(--meter-tint, var(--dsw-alias-label-tertiary, currentColor)); border-radius: 1px;
435
+ flex: 0 0 auto; min-width: 2px; height: 100%; }
436
+ .dci-gauge-swatch { background: var(--meter-tint, currentColor); vertical-align: baseline; border-radius: 2px;
437
+ width: 8px; height: 8px; margin-right: 6px; display: inline-block; }
438
+ .dci-gauge-colorSystem { --meter-tint: var(--dsw-static-neutral-bluish-400, #7d8590); }
439
+ .dci-gauge-colorTools { --meter-tint: #a78bfa; }
440
+ .dci-gauge-colorMessages { --meter-tint: var(--dsw-static-blue-450, #4c8dff); }
441
+ .dci-gauge-rows { margin: 6px 0 0; }
442
+ .dci-gauge-row { justify-content: space-between; align-items: center; gap: 12px; padding: 2px 0; display: flex; }
443
+ .dci-gauge-row dt { color: var(--dsw-alias-label-secondary, inherit); }
444
+ .dci-gauge-row dd { font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-primary, inherit); margin: 0; }
445
+
446
+ /* ===== 完全权限确认(官方 Modal + RiskConfirmation 复刻)===== */
447
+ .dci-modal-root { position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center; padding: 24px; }
448
+ .dci-modal-mask { position: absolute; inset: 0; background: var(--dsw-alias-bg-mask-1, rgba(0, 0, 0, 0.5));
449
+ backdrop-filter: var(--dsw-mask-blur, blur(2px)); }
450
+ .dci-modal-dialog { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 20px;
451
+ width: min(440px, 100%); max-height: calc(100vh - 48px); padding: 0 0 24px; overflow: hidden; border: 0;
452
+ border-radius: 24px; background: var(--dsw-alias-bg-layer-2, #232327); color: var(--dsw-alias-label-primary, #ececf1);
453
+ --dsw-elevation-stroke-color: var(--dsw-alias-border-l1, transparent);
454
+ box-shadow: var(--dsw-elevation-prominent, 0 10px 34px rgba(0, 0, 0, 0.35)); }
455
+ .dci-modal-content { display: flex; flex-direction: column; width: 100%; min-height: 0; overflow-y: auto; }
456
+ .dci-modal-header { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 22px 14px 12px 24px; }
457
+ .dci-modal-title { margin: 0; font-size: 16px; line-height: 24px; font-weight: 500; color: var(--dsw-alias-label-primary, inherit); }
458
+ .dci-modal-close { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px;
459
+ border: none; border-radius: 8px; background: transparent; cursor: pointer; color: var(--dsw-alias-label-secondary, inherit); }
460
+ .dci-modal-close:hover { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent)); }
461
+ .dci-modal-body { display: flex; flex-direction: column; min-width: 0; margin-top: 20px; padding: 0 24px; }
462
+ .dci-modal-footer { display: flex; align-items: center; justify-content: flex-end; gap: 8px; padding: 0 24px; }
463
+ .dci-confirm-warning { display: flex; align-items: flex-start; gap: 10px; color: var(--dsw-alias-label-secondary, inherit);
464
+ font-size: 14px; line-height: 22px; }
465
+ .dci-confirm-warning p { margin: 0; }
466
+ .dci-confirm-warningIcon { flex: none; margin-top: 2px; color: var(--dsw-alias-state-error-primary, #e5484d); }
467
+ .dci-confirm-ack { display: flex; align-items: flex-start; gap: 10px; margin-top: 20px; cursor: pointer;
468
+ color: var(--dsw-alias-label-primary, inherit); font-size: 14px; line-height: 22px; }
469
+ .dci-confirm-ack input { flex: none; width: 16px; height: 16px; margin: 3px 0 0; cursor: pointer;
470
+ accent-color: var(--dsw-alias-button-primary-fill, currentColor); }
471
+ .dci-btn { display: inline-flex; align-items: center; justify-content: center; gap: 4px; border: none; border-radius: 18px;
472
+ cursor: pointer; font-size: 14px; line-height: 22px; color: var(--dsw-alias-label-primary, inherit);
473
+ background: transparent; padding: 0 14px; height: 36px; }
474
+ .dci-btn:disabled { cursor: not-allowed; opacity: 0.4; }
475
+ .dci-btn-outline { border: 0.5px solid var(--dsw-alias-border-l3, color-mix(in srgb, currentColor 25%, transparent)); background: transparent; }
476
+ .dci-btn-outline:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, color-mix(in srgb, currentColor 8%, transparent)); }
477
+ .dci-btn-primary { background: var(--dsw-alias-button-primary-fill, currentColor); color: var(--dsw-alias-label-primary-foreground, #fff); }
478
+ .dci-btn-primary:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover, currentColor); }
479
+ .dci-btn-cancel { min-width: 72px; }
480
+ .dci-btn-confirm { min-width: 136px; }
481
+ `;
482
+
483
+ export function injectStyles(): void {
484
+ if (document.getElementById(STYLE_ID)) return;
485
+ const el = document.createElement('style');
486
+ el.id = STYLE_ID;
487
+ el.textContent = CSS;
488
+ document.head.appendChild(el);
489
+ }
@@ -0,0 +1,84 @@
1
+ /** 触发管线对接:track 上报、键盘仲裁(仅菜单打开时路由)、指令按钮的程序化唤起。 */
2
+
3
+ import type { ComposerKeyboard, InputState, InputTriggerController, MenuState, TriggerHit } from './host-types';
4
+ import { diagDebug } from './diag';
5
+
6
+ /** 由输入机 phase 派生触发可用档:plain 全活、claimed 抑 '/'、frozen 全停。 */
7
+ export function triggerTier(phase: InputState['phase']): { readonly tier: 'plain' | 'claimed' | 'frozen' } {
8
+ if (phase === 'plain') return { tier: 'plain' };
9
+ if (phase === 'claimed') return { tier: 'claimed' };
10
+ return { tier: 'frozen' };
11
+ }
12
+
13
+ export function reportTrack(
14
+ triggers: InputTriggerController | undefined,
15
+ draft: string,
16
+ caret: number,
17
+ state: InputState | undefined,
18
+ ): void {
19
+ if (!triggers || !state) return;
20
+ try {
21
+ triggers.track(draft, caret, triggerTier(state.phase), state.draftRev);
22
+ } catch (error) {
23
+ diagDebug('track failed', error);
24
+ }
25
+ }
26
+
27
+ /** 程序化唤起 '/' 候选菜单(工具行指令按钮;同官方 toggleCommandMenu 实现)。 */
28
+ export function openCommandMenu(
29
+ triggers: InputTriggerController | undefined,
30
+ keyboard: ComposerKeyboard | undefined,
31
+ caret: number,
32
+ ): void {
33
+ if (!triggers) return;
34
+ const snapshot = keyboard?.snapshot;
35
+ const draft = snapshot?.draft ?? '';
36
+ const draftRev = snapshot?.draftRev ?? 0;
37
+ keyboard?.dismissPopup();
38
+ const hit: TriggerHit = {
39
+ trigger: '/',
40
+ query: '',
41
+ quoted: false,
42
+ position: draft.slice(0, caret).trim() === '' ? 'leading' : 'inline',
43
+ span: { start: caret, end: caret, draftRev },
44
+ };
45
+ triggers.toggleSource('command', hit);
46
+ }
47
+
48
+ const ARBITRATE_KEYS: Record<string, 'up' | 'down' | 'enter' | 'escape' | 'tab'> = {
49
+ ArrowUp: 'up',
50
+ ArrowDown: 'down',
51
+ Enter: 'enter',
52
+ Escape: 'escape',
53
+ Tab: 'tab',
54
+ };
55
+
56
+ /**
57
+ * 键盘仲裁:只在候选菜单实际打开时路由(工程事实 #4——菜单关闭时
58
+ * arbitrate 对 Enter 也返回 consumed,会吞换行)。
59
+ *
60
+ * @returns true 表示事件已被菜单消费(调用方 preventDefault)。
61
+ */
62
+ export function arbitrateForMenu(
63
+ triggers: InputTriggerController | undefined,
64
+ event: KeyboardEvent,
65
+ composing: boolean,
66
+ ): boolean {
67
+ if (!triggers) return false;
68
+ const menu: MenuState = triggers.menu.getSnapshot();
69
+ if (!menu.open) return false;
70
+ const key = ARBITRATE_KEYS[event.key];
71
+ if (!key) return false;
72
+ const outcome = triggers.arbitrate(key, composing);
73
+ return outcome !== 'pass';
74
+ }
75
+
76
+ /** 空格裁决:真 = 输入机已应用 claim(调用方 preventDefault)。 */
77
+ export function adjudicateSpace(triggers: InputTriggerController | undefined): boolean {
78
+ if (!triggers) return false;
79
+ try {
80
+ return triggers.onSpace();
81
+ } catch {
82
+ return false;
83
+ }
84
+ }