@linxin666/dsh-client-ui-task-board 0.2.2 → 0.2.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@linxin666/dsh-client-ui-task-board",
3
3
  "description": "Host-authoritative task board for the DSH Web GUI with real session execution, Host cron scheduling, and optional cross-platform idle-sleep protection; mounted without DSH source changes.",
4
- "version": "0.2.2",
4
+ "version": "0.2.4",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/types/index.d.ts",
@@ -42,15 +42,15 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@deepseek-ai/cordis": "^4.0.1",
45
- "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.7",
46
- "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.7",
47
- "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.7",
48
- "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.7",
49
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.7",
50
- "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.7",
51
- "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.7",
52
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.7",
53
- "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.7",
45
+ "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8",
46
+ "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8",
47
+ "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8",
48
+ "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8",
49
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.8",
50
+ "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8",
51
+ "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8",
52
+ "@deepseek-ai/dsh-settings": "^0.1.0-rc.8",
53
+ "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8",
54
54
  "@types/react": "~18.3.1",
55
55
  "@types/react-dom": "^18.3.5",
56
56
  "@types/node": "^22.20.0",
@@ -333,9 +333,11 @@ export class CardForm<T> {
333
333
  const valid = plan.filter(item => item.run !== undefined)
334
334
  if (plan.length === 0 || this.saving || valid.length !== plan.length) return
335
335
  const plannedWrites = valid.map(item => item.op)
336
- // Snapshot the fields this save writes, so edits staged while it is in
337
- // flight survive: only the staged keys this save actually wrote are cleared.
338
- const fields = new Set(plan.map(item => item.field))
336
+ // Snapshot the staged entries this save writes, so an edit staged while it
337
+ // is in flight (which replaces the same key) survives: only delete the key
338
+ // when the entry is still the one this save started from.
339
+ const pending = new Map<string, StagedEdit | undefined>()
340
+ for (const item of plan) pending.set(item.field, this.staged.get(item.field))
339
341
  this.saving = true
340
342
  this.failed = false
341
343
  this.failedReason = undefined
@@ -356,11 +358,11 @@ export class CardForm<T> {
356
358
  if (await item.run!()) landed.add(item.field)
357
359
  }
358
360
  }
359
- for (const field of fields) {
360
- if (landed.has(field)) this.staged.delete(field)
361
+ for (const [field, before] of pending) {
362
+ if (landed.has(field) && this.staged.get(field) === before) this.staged.delete(field)
361
363
  }
362
364
  this.saving = false
363
- this.failed = landed.size !== fields.size
365
+ this.failed = landed.size !== pending.size
364
366
  this.publish()
365
367
  }
366
368
 
@@ -509,7 +509,15 @@ export class BoardController {
509
509
  /** Settle tasks left 'running' whose sessions already finished. */
510
510
  private async reconcileRunningTasks(): Promise<void> {
511
511
  if (this.deps.exec === undefined) return
512
- if (this.reconcileInFlight) return
512
+ if (this.reconcileInFlight) {
513
+ // A session change arrived while a pass was in flight. The in-flight
514
+ // pass already captured the task list it iterates and will not revisit
515
+ // this task, so dropping the notification would leave it stuck
516
+ // 'running'. Re-arm the debounce so the change is reconciled once the
517
+ // current pass settles.
518
+ this.scheduleReconcile()
519
+ return
520
+ }
513
521
  this.reconcileInFlight = true
514
522
  try {
515
523
  type Settled = Extract<ExecutionEvent, { kind: 'settled' }>