dsh-global-todo 0.6.3 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/README.md +3 -1
- package/README.zh.md +3 -1
- package/docs/screenshots/panel-detail.png +0 -0
- package/docs/screenshots/panel-select.png +0 -0
- package/docs/screenshots/panel-settings.png +0 -0
- package/docs/screenshots/panel.png +0 -0
- package/lib/client.js +186 -75
- package/lib/index.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [0.6.4] — 2026-10-20
|
|
2
|
+
|
|
3
|
+
The settings panel, rebuilt as an inspector instead of a stack of labelled rows.
|
|
4
|
+
|
|
5
|
+
- **Header and footer, finally.** A title row with a close button, three labelled groups divided
|
|
6
|
+
by hairlines, and a save row pinned at the bottom — the token field no longer pushes the save
|
|
7
|
+
buttons into the middle of the form with a field stranded beneath them.
|
|
8
|
+
- **Every field says what it does.** Help text sits under each label (`settings.*Hint`) rather than
|
|
9
|
+
being implied by the label; the label-and-control grid keeps number inputs aligned at a fixed
|
|
10
|
+
76px right-aligned box.
|
|
11
|
+
- **Ingest fields dim when ingest is off**, and `New token` becomes a quiet text link on the token
|
|
12
|
+
label row (`Rotate token`) instead of a third equal-weight button.
|
|
13
|
+
- **About section** shows the data file and version on labelled rows; the card sizes to its content
|
|
14
|
+
and scrolls internally when the window is short.
|
|
15
|
+
- `npm run screenshots` now also photographs a settings variant, so the README image is
|
|
16
|
+
reproducible instead of hand-made.
|
|
17
|
+
|
|
1
18
|
## [0.6.3] — 2026-10-20
|
|
2
19
|
|
|
3
20
|
States that were still speaking to nobody.
|
package/README.md
CHANGED
|
@@ -33,6 +33,8 @@ one record:
|
|
|
33
33
|
|
|
34
34
|

|
|
35
35
|
|
|
36
|
+

|
|
37
|
+
|
|
36
38
|
These are produced by `npm run screenshots` (which chains `npm run preview`): the real client
|
|
37
39
|
half is rendered to static HTML with no Host and no dependencies, then photographed at 1280×720
|
|
38
40
|
into `docs/screenshots/`. Playwright is not a dependency — the tool borrows the copy a DSH
|
|
@@ -339,7 +341,7 @@ npm run preview # render the panel to preview/panel.html (+ detail and sel
|
|
|
339
341
|
npm run screenshots # re-photograph those previews into docs/screenshots/, 1280×720
|
|
340
342
|
```
|
|
341
343
|
|
|
342
|
-
The
|
|
344
|
+
The PNGs under `docs/screenshots/` ship with the package and are embedded in both
|
|
343
345
|
READMEs, so re-run `npm run screenshots` whenever the panel UI changes.
|
|
344
346
|
|
|
345
347
|
```text
|
package/README.zh.md
CHANGED
|
@@ -30,6 +30,8 @@ DSH 自带的 `todo_write` 属于**某一个 agent 会话**:整表替换、三
|
|
|
30
30
|
|
|
31
31
|

|
|
32
32
|
|
|
33
|
+

|
|
34
|
+
|
|
33
35
|
图都由 `npm run screenshots`(内部串起 `npm run preview`)生成:先把真实的客户端半区渲染成静态
|
|
34
36
|
HTML(不依赖宿主、零依赖),再以 1280×720 拍进 `docs/screenshots/`。Playwright 不是依赖——工具
|
|
35
37
|
借的是 DSH profile 里已经装好的那份,或 `DSH_PLAYWRIGHT` 指向的那份。
|
|
@@ -230,7 +232,7 @@ npm run preview # 把面板渲染成 preview/panel.html(另附详情态
|
|
|
230
232
|
npm run screenshots # 把这些预览重新拍成 docs/screenshots/,1280×720
|
|
231
233
|
```
|
|
232
234
|
|
|
233
|
-
`docs/screenshots/`
|
|
235
|
+
`docs/screenshots/` 下那几张 PNG 会随包发布、并嵌在两份 README 里,所以面板 UI 一改就要重跑
|
|
234
236
|
`npm run screenshots`。
|
|
235
237
|
|
|
236
238
|
```text
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/client.js
CHANGED
|
@@ -50,7 +50,7 @@ window.__ModuleLoader__.load({
|
|
|
50
50
|
* different mechanisms (restart vs. hot reload), so "which one am I looking
|
|
51
51
|
* at" needs an answer that the bundle itself carries.
|
|
52
52
|
*/
|
|
53
|
-
const UI_REV = '
|
|
53
|
+
const UI_REV = 'ui40'
|
|
54
54
|
/** Last language resolved for the shell; module-level so a fetch failure can be worded too. */
|
|
55
55
|
let activeLang = 'zh'
|
|
56
56
|
|
|
@@ -100,12 +100,18 @@ window.__ModuleLoader__.load({
|
|
|
100
100
|
'settings.ingestEnable': '启用外部写入',
|
|
101
101
|
'settings.token': '访问 token',
|
|
102
102
|
'settings.tokenSet': '已设置,留空保持不变',
|
|
103
|
-
'settings.generate': '
|
|
104
|
-
'settings.confirmBelow': '
|
|
103
|
+
'settings.generate': '轮换 token',
|
|
104
|
+
'settings.confirmBelow': '置信度阈值',
|
|
105
105
|
'settings.save': '保存',
|
|
106
106
|
'settings.cancel': '取消',
|
|
107
107
|
'settings.saved': '设置已保存',
|
|
108
108
|
'settings.about': '关于',
|
|
109
|
+
'settings.remindersHint': '到期时在面板顶部提示,并按设置提前。',
|
|
110
|
+
'settings.ingestHint': '允许其他工具带 token 写入,先进收件箱。',
|
|
111
|
+
'settings.tokenHint': '留空表示不改动;轮换后旧 token 立刻失效。',
|
|
112
|
+
'settings.confirmBelowHint': '置信度低于这个值的条目进收件箱,不进清单。',
|
|
113
|
+
'settings.storeFile': '数据文件',
|
|
114
|
+
'settings.version': '版本',
|
|
109
115
|
'inbox.explain': '以下由外部写入或 Agent 提交,确认后才进入清单。',
|
|
110
116
|
'notice.exported': '已导出 {n} 条待办',
|
|
111
117
|
'notice.imported': '已导入 {n} 条(合并,现有共 {total} 条)',
|
|
@@ -347,12 +353,18 @@ window.__ModuleLoader__.load({
|
|
|
347
353
|
'settings.ingestEnable': 'Accept external writes',
|
|
348
354
|
'settings.token': 'Access token',
|
|
349
355
|
'settings.tokenSet': 'Set — leave blank to keep',
|
|
350
|
-
'settings.generate': '
|
|
351
|
-
'settings.confirmBelow': '
|
|
356
|
+
'settings.generate': 'Rotate token',
|
|
357
|
+
'settings.confirmBelow': 'Confidence threshold',
|
|
352
358
|
'settings.save': 'Save',
|
|
353
359
|
'settings.cancel': 'Cancel',
|
|
354
360
|
'settings.saved': 'Settings saved',
|
|
355
361
|
'settings.about': 'About',
|
|
362
|
+
'settings.remindersHint': 'Flag a deadline at the top of the panel when it comes due.',
|
|
363
|
+
'settings.ingestHint': 'Let other tools POST todos with a token; they start in the inbox.',
|
|
364
|
+
'settings.tokenHint': 'Leave blank to keep the current one; rotating invalidates the old token.',
|
|
365
|
+
'settings.confirmBelowHint': 'Items below this confidence go to the inbox instead of the list.',
|
|
366
|
+
'settings.storeFile': 'Data file',
|
|
367
|
+
'settings.version': 'Version',
|
|
356
368
|
'inbox.explain': 'Written by external sources or the agent. Confirm it before it joins the list.',
|
|
357
369
|
'notice.exported': 'Exported {n} todos',
|
|
358
370
|
'notice.imported': 'Imported {n} (merged; {total} in the list now)',
|
|
@@ -1102,9 +1114,35 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1102
1114
|
border-radius: 6px; cursor: pointer; max-width: 300px; overflow: hidden; text-overflow: ellipsis;
|
|
1103
1115
|
white-space: nowrap; }
|
|
1104
1116
|
.gt-reminder-item:hover { background: var(--dsw-alias-button-ghost-active-fill); }
|
|
1105
|
-
.gt-settings { display: flex; flex-direction: column;
|
|
1106
|
-
box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l2);
|
|
1107
|
-
background: var(--dsw-alias-bg-overlay); font-size: 13px; line-height: 20px; }
|
|
1117
|
+
.gt-settings { display: flex; flex-direction: column; width: 360px; max-width: 100%;
|
|
1118
|
+
box-sizing: border-box; overflow: hidden; border: 1px solid var(--dsw-alias-border-l2);
|
|
1119
|
+
border-radius: 12px; background: var(--dsw-alias-bg-overlay); font-size: 13px; line-height: 20px; }
|
|
1120
|
+
.gt-settings-head { display: flex; flex: 0 0 auto; align-items: center; justify-content: space-between;
|
|
1121
|
+
gap: 8px; padding: 10px 10px 10px 16px; border-bottom: 1px solid var(--dsw-alias-border-l1); }
|
|
1122
|
+
.gt-settings-title { font-size: 14px; font-weight: 600; }
|
|
1123
|
+
.gt-settings-body { display: flex; flex: 1 1 auto; flex-direction: column; gap: 16px;
|
|
1124
|
+
padding: 14px 16px; overflow: auto; min-height: 0; }
|
|
1125
|
+
.gt-settings-group { display: flex; flex-direction: column; gap: 8px; }
|
|
1126
|
+
.gt-settings-group + .gt-settings-group { border-top: 1px solid var(--dsw-alias-border-l1); padding-top: 14px; }
|
|
1127
|
+
.gt-settings-group-title { font-size: 12px; line-height: 18px; font-weight: 600;
|
|
1128
|
+
color: var(--dsw-alias-label-secondary); }
|
|
1129
|
+
.gt-check-row { display: flex; align-items: flex-start; gap: 8px; cursor: pointer; }
|
|
1130
|
+
.gt-check-row input { margin: 3px 0 0; flex: 0 0 auto; }
|
|
1131
|
+
.gt-check-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
1132
|
+
.gt-check-label { color: var(--dsw-alias-label-primary); }
|
|
1133
|
+
.gt-hint { font-size: 12px; line-height: 18px; color: var(--dsw-alias-label-secondary); }
|
|
1134
|
+
.gt-field { display: flex; flex-direction: column; gap: 6px; }
|
|
1135
|
+
.gt-field[data-muted="1"], .gt-field-row[data-muted="1"] { opacity: .55; }
|
|
1136
|
+
.gt-field-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
|
1137
|
+
.gt-field-label { font-size: 13px; color: var(--dsw-alias-label-primary); }
|
|
1138
|
+
.gt-field-row { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 8px; }
|
|
1139
|
+
.gt-input-num { width: 76px; text-align: right; font-variant-numeric: tabular-nums; }
|
|
1140
|
+
.gt-link-btn { border: none; background: transparent; padding: 0; font: inherit; font-size: 12px;
|
|
1141
|
+
color: var(--dsw-alias-link); cursor: pointer; }
|
|
1142
|
+
.gt-link-btn:disabled { color: var(--dsw-alias-label-secondary); cursor: default; }
|
|
1143
|
+
.gt-about-row { display: grid; grid-template-columns: 88px minmax(0, 1fr); align-items: baseline; gap: 8px; }
|
|
1144
|
+
.gt-settings-foot { display: flex; flex: 0 0 auto; justify-content: flex-end; gap: 8px;
|
|
1145
|
+
padding: 12px 16px; border-top: 1px solid var(--dsw-alias-border-l1); }
|
|
1108
1146
|
.gt-group-select { display: none; min-height: 28px; max-width: 150px; padding: 0 8px; font: inherit;
|
|
1109
1147
|
font-size: 12.5px; color: var(--dsw-alias-label-primary); background: var(--dsw-alias-bg-layer-1);
|
|
1110
1148
|
border: 1px solid var(--dsw-alias-border-l1); border-radius: 8px; }
|
|
@@ -1114,8 +1152,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
1114
1152
|
line-height: 20px; }
|
|
1115
1153
|
.gt-settings-path { font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
1116
1154
|
.gt-settings .gt-input { flex: 0 0 auto; width: 100%; min-height: 32px; }
|
|
1117
|
-
.gt-settings .gt-
|
|
1118
|
-
.gt-settings-head { font-weight: 650; font-size: 14px; }
|
|
1155
|
+
.gt-settings .gt-input-num { width: 76px; }
|
|
1119
1156
|
.gt-check-line { display: flex; align-items: center; gap: 8px; justify-content: flex-start;
|
|
1120
1157
|
color: var(--dsw-alias-label-primary); }
|
|
1121
1158
|
.gt-settings-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
|
|
@@ -2169,6 +2206,9 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2169
2206
|
// The preview harness cannot re-render after a click, so it may ask to start in
|
|
2170
2207
|
// selection mode; a person toggles it with the `选择` control.
|
|
2171
2208
|
const [selectMode, setSelectMode] = useState(props.initialSelectMode === true)
|
|
2209
|
+
// Only the static preview asks for this: the panel opens settings by click, but the
|
|
2210
|
+
// SSR harness cannot click, so the screenshot variant has to start there.
|
|
2211
|
+
const initialSettingsOpen = props.initialSettingsOpen === true
|
|
2172
2212
|
// The picker's filters mirror the shell's own visibility rule, but the shape of the
|
|
2173
2213
|
// real snapshot has never been observable from here — a preview fixture is written by
|
|
2174
2214
|
// the same hand as the filter, so it can only confirm itself. Report the shape once per
|
|
@@ -2187,7 +2227,7 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2187
2227
|
const [importAsk, setImportAsk] = useState(null)
|
|
2188
2228
|
// One settings popover: reminders and the external door both need a place a person can
|
|
2189
2229
|
// reach without curl.
|
|
2190
|
-
const [settingsOpen, setSettingsOpen] = useState(
|
|
2230
|
+
const [settingsOpen, setSettingsOpen] = useState(initialSettingsOpen)
|
|
2191
2231
|
const [settingsBox, setSettingsBox] = useState(null)
|
|
2192
2232
|
// The detail card's breakpoint follows the panel's own width, not the viewport: the
|
|
2193
2233
|
// slot is ~265px narrower than the window, so a viewport query opens the two-column
|
|
@@ -2436,13 +2476,15 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2436
2476
|
useEffect(() => {
|
|
2437
2477
|
const element = innerRef.current
|
|
2438
2478
|
if (element === null || typeof window === 'undefined') return undefined
|
|
2479
|
+
// The static preview supplies a `window` stub without event plumbing.
|
|
2480
|
+
const listen = typeof window.addEventListener === 'function'
|
|
2439
2481
|
const measure = () => setPanelWidth(element.getBoundingClientRect().width)
|
|
2440
2482
|
measure()
|
|
2441
|
-
window.addEventListener('resize', measure)
|
|
2483
|
+
if (listen === true) window.addEventListener('resize', measure)
|
|
2442
2484
|
const observer = typeof window.ResizeObserver === 'function' ? new window.ResizeObserver(measure) : null
|
|
2443
2485
|
if (observer !== null) observer.observe(element)
|
|
2444
2486
|
return () => {
|
|
2445
|
-
window.removeEventListener('resize', measure)
|
|
2487
|
+
if (listen === true) window.removeEventListener('resize', measure)
|
|
2446
2488
|
if (observer !== null) observer.disconnect()
|
|
2447
2489
|
}
|
|
2448
2490
|
}, [])
|
|
@@ -2457,14 +2499,19 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
2457
2499
|
if (element === null) return
|
|
2458
2500
|
const rect = element.getBoundingClientRect()
|
|
2459
2501
|
setSettingsBox({
|
|
2460
|
-
|
|
2502
|
+
// Just under the title block: high enough that the whole card fits, low enough
|
|
2503
|
+
// that it never covers the panel title or the header actions.
|
|
2504
|
+
top: Math.round(rect.top + 56),
|
|
2461
2505
|
right: Math.round(window.innerWidth - rect.right + 20),
|
|
2462
2506
|
bottom: Math.round(window.innerHeight - rect.bottom + 20),
|
|
2463
2507
|
})
|
|
2464
2508
|
}
|
|
2509
|
+
const listen = typeof window.addEventListener === 'function'
|
|
2465
2510
|
measure()
|
|
2466
|
-
window.addEventListener('resize', measure)
|
|
2467
|
-
return () =>
|
|
2511
|
+
if (listen === true) window.addEventListener('resize', measure)
|
|
2512
|
+
return () => {
|
|
2513
|
+
if (listen === true) window.removeEventListener('resize', measure)
|
|
2514
|
+
}
|
|
2468
2515
|
}, [settingsOpen, lang])
|
|
2469
2516
|
|
|
2470
2517
|
useEffect(() => {
|
|
@@ -3286,77 +3333,141 @@ button.gt-chip[data-on="1"] { color: var(--dsw-alias-label-primary); border-colo
|
|
|
3286
3333
|
position: 'fixed',
|
|
3287
3334
|
top: `${settingsBox.top}px`,
|
|
3288
3335
|
right: `${settingsBox.right}px`,
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3336
|
+
// Height follows the content, capped by the room below: stretching to
|
|
3337
|
+
// `bottom` left a tall empty card with the footer stranded at the floor.
|
|
3338
|
+
maxHeight: `calc(100dvh - ${settingsBox.top + 20}px)`,
|
|
3292
3339
|
zIndex: 40,
|
|
3293
3340
|
},
|
|
3294
3341
|
},
|
|
3295
|
-
h('div', { className: 'gt-settings-head' }, t('settings.title')),
|
|
3296
|
-
h('div', { className: 'gt-section-title' }, t('settings.reminders')),
|
|
3297
|
-
h(
|
|
3298
|
-
'label',
|
|
3299
|
-
{ className: 'gt-check-line' },
|
|
3300
|
-
h('input', { type: 'checkbox', checked: remindersDraft, onChange: (event) => setRemindersDraft(event.target.checked) }),
|
|
3301
|
-
t('settings.remindersEnable'),
|
|
3302
|
-
),
|
|
3303
3342
|
h(
|
|
3304
|
-
'
|
|
3305
|
-
{ className: 'gt-
|
|
3306
|
-
t('settings.
|
|
3307
|
-
h(
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3343
|
+
'div',
|
|
3344
|
+
{ className: 'gt-settings-head' },
|
|
3345
|
+
h('span', { className: 'gt-settings-title' }, t('settings.title')),
|
|
3346
|
+
h(
|
|
3347
|
+
'button',
|
|
3348
|
+
{
|
|
3349
|
+
type: 'button',
|
|
3350
|
+
className: 'gt-iconbtn',
|
|
3351
|
+
title: t('settings.cancel'),
|
|
3352
|
+
'aria-label': t('settings.cancel'),
|
|
3353
|
+
onClick: () => setSettingsOpen(false),
|
|
3354
|
+
},
|
|
3355
|
+
h(Icon, { name: 'close', size: 13 }),
|
|
3356
|
+
),
|
|
3315
3357
|
),
|
|
3316
|
-
h('div', { className: 'gt-section-title' }, t('settings.ingest')),
|
|
3317
3358
|
h(
|
|
3318
|
-
'
|
|
3319
|
-
{ className: 'gt-
|
|
3320
|
-
h(
|
|
3321
|
-
|
|
3359
|
+
'div',
|
|
3360
|
+
{ className: 'gt-settings-body' },
|
|
3361
|
+
h(
|
|
3362
|
+
'div',
|
|
3363
|
+
{ className: 'gt-settings-group' },
|
|
3364
|
+
h('div', { className: 'gt-settings-group-title' }, t('settings.reminders')),
|
|
3365
|
+
h(
|
|
3366
|
+
'label',
|
|
3367
|
+
{ className: 'gt-check-row' },
|
|
3368
|
+
h('input', { type: 'checkbox', checked: remindersDraft, onChange: (event) => setRemindersDraft(event.target.checked) }),
|
|
3369
|
+
h(
|
|
3370
|
+
'span',
|
|
3371
|
+
{ className: 'gt-check-main' },
|
|
3372
|
+
h('span', { className: 'gt-check-label' }, t('settings.remindersEnable')),
|
|
3373
|
+
h('span', { className: 'gt-hint' }, t('settings.remindersHint')),
|
|
3374
|
+
),
|
|
3375
|
+
),
|
|
3376
|
+
h(
|
|
3377
|
+
'div',
|
|
3378
|
+
{ className: 'gt-field-row' },
|
|
3379
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-lead' }, t('settings.lead')),
|
|
3380
|
+
h('input', {
|
|
3381
|
+
id: 'gt-lead',
|
|
3382
|
+
type: 'number',
|
|
3383
|
+
min: 0,
|
|
3384
|
+
max: 1440,
|
|
3385
|
+
className: 'gt-input gt-input-num',
|
|
3386
|
+
disabled: remindersDraft !== true,
|
|
3387
|
+
value: leadDraft,
|
|
3388
|
+
onChange: (event) => setLeadDraft(event.target.value),
|
|
3389
|
+
}),
|
|
3390
|
+
),
|
|
3391
|
+
),
|
|
3392
|
+
h(
|
|
3393
|
+
'div',
|
|
3394
|
+
{ className: 'gt-settings-group' },
|
|
3395
|
+
h('div', { className: 'gt-settings-group-title' }, t('settings.ingest')),
|
|
3396
|
+
h(
|
|
3397
|
+
'label',
|
|
3398
|
+
{ className: 'gt-check-row' },
|
|
3399
|
+
h('input', { type: 'checkbox', checked: ingestDraft, onChange: (event) => setIngestDraft(event.target.checked) }),
|
|
3400
|
+
h(
|
|
3401
|
+
'span',
|
|
3402
|
+
{ className: 'gt-check-main' },
|
|
3403
|
+
h('span', { className: 'gt-check-label' }, t('settings.ingestEnable')),
|
|
3404
|
+
h('span', { className: 'gt-hint' }, t('settings.ingestHint')),
|
|
3405
|
+
),
|
|
3406
|
+
),
|
|
3407
|
+
h(
|
|
3408
|
+
'div',
|
|
3409
|
+
{ className: 'gt-field', 'data-muted': ingestDraft === true ? '0' : '1' },
|
|
3410
|
+
h(
|
|
3411
|
+
'div',
|
|
3412
|
+
{ className: 'gt-field-head' },
|
|
3413
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-token' }, t('settings.token')),
|
|
3414
|
+
h('button', { type: 'button', className: 'gt-link-btn', disabled: ingestDraft !== true, onClick: generateToken }, t('settings.generate')),
|
|
3415
|
+
),
|
|
3416
|
+
h('input', {
|
|
3417
|
+
id: 'gt-token',
|
|
3418
|
+
className: 'gt-input',
|
|
3419
|
+
type: 'password',
|
|
3420
|
+
disabled: ingestDraft !== true,
|
|
3421
|
+
value: tokenDraft,
|
|
3422
|
+
placeholder:
|
|
3423
|
+
state.health?.settings?.ingest?.tokenSet === true ? t('settings.tokenSet') : t('settings.token'),
|
|
3424
|
+
autoComplete: 'new-password',
|
|
3425
|
+
onChange: (event) => setTokenDraft(event.target.value),
|
|
3426
|
+
}),
|
|
3427
|
+
h('span', { className: 'gt-hint' }, t('settings.tokenHint')),
|
|
3428
|
+
),
|
|
3429
|
+
h(
|
|
3430
|
+
'div',
|
|
3431
|
+
{ className: 'gt-field-row', 'data-muted': ingestDraft === true ? '0' : '1' },
|
|
3432
|
+
h('label', { className: 'gt-field-label', htmlFor: 'gt-below' }, t('settings.confirmBelow')),
|
|
3433
|
+
h('input', {
|
|
3434
|
+
id: 'gt-below',
|
|
3435
|
+
type: 'number',
|
|
3436
|
+
min: 0,
|
|
3437
|
+
max: 1,
|
|
3438
|
+
step: 0.05,
|
|
3439
|
+
className: 'gt-input gt-input-num',
|
|
3440
|
+
disabled: ingestDraft !== true,
|
|
3441
|
+
value: belowDraft,
|
|
3442
|
+
onChange: (event) => setBelowDraft(event.target.value),
|
|
3443
|
+
}),
|
|
3444
|
+
),
|
|
3445
|
+
h('span', { className: 'gt-hint' }, t('settings.confirmBelowHint')),
|
|
3446
|
+
),
|
|
3447
|
+
h(
|
|
3448
|
+
'div',
|
|
3449
|
+
{ className: 'gt-settings-group' },
|
|
3450
|
+
h('div', { className: 'gt-settings-group-title' }, t('settings.about')),
|
|
3451
|
+
h(
|
|
3452
|
+
'div',
|
|
3453
|
+
{ className: 'gt-about-row' },
|
|
3454
|
+
h('span', { className: 'gt-field-label' }, t('settings.storeFile')),
|
|
3455
|
+
h('span', { className: 'gt-mono gt-settings-path', title: state.health?.store?.file ?? '' }, state.health?.store?.file ?? ''),
|
|
3456
|
+
),
|
|
3457
|
+
h(
|
|
3458
|
+
'div',
|
|
3459
|
+
{ className: 'gt-about-row' },
|
|
3460
|
+
h('span', { className: 'gt-field-label' }, t('settings.version')),
|
|
3461
|
+
h('span', { className: 'gt-mono gt-hint' }, `v${state.health?.version ?? ''} · ${UI_REV}`),
|
|
3462
|
+
),
|
|
3463
|
+
),
|
|
3322
3464
|
),
|
|
3323
|
-
h('input', {
|
|
3324
|
-
className: 'gt-input',
|
|
3325
|
-
type: 'password',
|
|
3326
|
-
value: tokenDraft,
|
|
3327
|
-
placeholder:
|
|
3328
|
-
state.health?.settings?.ingest?.tokenSet === true ? t('settings.tokenSet') : t('settings.token'),
|
|
3329
|
-
autoComplete: 'new-password',
|
|
3330
|
-
onChange: (event) => setTokenDraft(event.target.value),
|
|
3331
|
-
}),
|
|
3332
3465
|
h(
|
|
3333
3466
|
'div',
|
|
3334
|
-
{ className: 'gt-settings-
|
|
3335
|
-
h('button', { type: 'button', className: 'gt-btn gt-btn-quiet', onClick: generateToken }, t('settings.generate')),
|
|
3467
|
+
{ className: 'gt-settings-foot' },
|
|
3336
3468
|
h('button', { type: 'button', className: 'gt-btn gt-btn-quiet', onClick: () => setSettingsOpen(false) }, t('settings.cancel')),
|
|
3337
3469
|
h('button', { type: 'button', className: 'gt-btn gt-btn-primary', onClick: () => void saveSettings() }, t('settings.save')),
|
|
3338
3470
|
),
|
|
3339
|
-
h(
|
|
3340
|
-
'label',
|
|
3341
|
-
{ className: 'gt-check-line' },
|
|
3342
|
-
t('settings.confirmBelow'),
|
|
3343
|
-
h('input', {
|
|
3344
|
-
type: 'number',
|
|
3345
|
-
min: 0,
|
|
3346
|
-
max: 1,
|
|
3347
|
-
step: 0.05,
|
|
3348
|
-
className: 'gt-input gt-input-xs',
|
|
3349
|
-
value: belowDraft,
|
|
3350
|
-
onChange: (event) => setBelowDraft(event.target.value),
|
|
3351
|
-
}),
|
|
3352
|
-
),
|
|
3353
|
-
h('div', { className: 'gt-section-title' }, t('settings.about')),
|
|
3354
|
-
h(
|
|
3355
|
-
'div',
|
|
3356
|
-
{ className: 'gt-muted gt-mono gt-settings-path', title: state.health?.store?.file ?? '' },
|
|
3357
|
-
state.health?.store?.file ?? '',
|
|
3358
|
-
),
|
|
3359
|
-
h('div', { className: 'gt-muted' }, `v${state.health?.version ?? ''} · ${UI_REV}`),
|
|
3360
3471
|
)
|
|
3361
3472
|
: null,
|
|
3362
3473
|
|
package/lib/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import { createStore, resolveStorePath } from './store.js'
|
|
|
36
36
|
import { createTools } from './tools.js'
|
|
37
37
|
|
|
38
38
|
/** Must equal `package.json`'s version; `npm run check` enforces that. */
|
|
39
|
-
export const VERSION = '0.6.
|
|
39
|
+
export const VERSION = '0.6.4'
|
|
40
40
|
|
|
41
41
|
/** Plugin id. Also the Loader row id in `cordis.patch.yml`. */
|
|
42
42
|
export const name = 'dsh-global-todo'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-global-todo",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"icon": "./docs/icon.svg",
|
|
5
5
|
"description": "Global, cross-session todos for DeepSeek Harness: one list owned by the human and the agent together, with creation time, attached documents and links, and one-click hand-off to an agent session. 全局待办:跨会话一份清单,记录加入时间,可挂文档与地址,可一键交给 Agent 继续干。",
|
|
6
6
|
"type": "module",
|