@shendeguize/dsh-agent-sidecar 0.1.1 → 0.2.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 (53) hide show
  1. package/README.md +78 -11
  2. package/lib/client.js +8659 -7589
  3. package/lib/client.js.map +1 -1
  4. package/package.json +3 -1
  5. package/src/client/analysis/AnalysisPanel.tsx +19 -27
  6. package/src/client/analysis/analysis.module.css +36 -97
  7. package/src/client/board/Board.tsx +115 -61
  8. package/src/client/board/board.module.css +72 -151
  9. package/src/client/board/project-view-logic.ts +21 -34
  10. package/src/client/board/project-view.module.css +41 -96
  11. package/src/client/board/project-view.tsx +29 -13
  12. package/src/client/board/strings.ts +68 -107
  13. package/src/client/commands.ts +30 -15
  14. package/src/client/detail/SessionDetail.tsx +92 -58
  15. package/src/client/detail/detail.module.css +62 -218
  16. package/src/client/detail/strings.ts +64 -88
  17. package/src/client/detail-view.module.css +30 -55
  18. package/src/client/detail-view.tsx +80 -108
  19. package/src/client/dsh-tools/LineageTree.tsx +22 -13
  20. package/src/client/dsh-tools/SearchPanel.tsx +18 -11
  21. package/src/client/dsh-tools/dsh-tools.module.css +50 -139
  22. package/src/client/dsh-tools/strings.ts +42 -77
  23. package/src/client/index.ts +285 -124
  24. package/src/client/inject/InjectPanel.tsx +31 -64
  25. package/src/client/inject/inject.module.css +97 -198
  26. package/src/client/lifecycle/handoff.ts +83 -0
  27. package/src/client/locales/en.ts +74 -2
  28. package/src/client/locales/host.ts +131 -0
  29. package/src/client/locales/index.ts +196 -8
  30. package/src/client/locales/react.ts +10 -0
  31. package/src/client/locales/view.ts +38 -0
  32. package/src/client/locales/zh.ts +194 -134
  33. package/src/client/mount.tsx +72 -38
  34. package/src/client/navigation/CenterOverlay.tsx +40 -0
  35. package/src/client/navigation/center-overlay.module.css +51 -0
  36. package/src/client/navigation/center.ts +45 -0
  37. package/src/client/navigation/modal-isolation.ts +152 -0
  38. package/src/client/navigation/modal-surface-anchor.ts +72 -0
  39. package/src/client/navigation/sidebar-entry.module.css +73 -0
  40. package/src/client/navigation/sidebar-entry.ts +309 -0
  41. package/src/client/primitives/StaticPill.tsx +21 -0
  42. package/src/client/settings-card.module.css +35 -119
  43. package/src/client/settings-card.tsx +31 -153
  44. package/src/client/settings-fields.tsx +131 -0
  45. package/src/client/sidebar/SidebarTab.tsx +156 -0
  46. package/src/client/sidebar/model.ts +65 -0
  47. package/src/client/sidebar/sidebar-tab.module.css +118 -0
  48. package/src/client/sidebar-tab.tsx +46 -320
  49. package/src/client/theme/agsc.module.css +31 -0
  50. package/src/client/theme/parts.ts +56 -0
  51. package/src/client/ui-integration.ts +86 -0
  52. package/src/client/widget.tsx +9 -8
  53. package/src/client/inject/overlay.module.css +0 -22
@@ -1,31 +1,9 @@
1
- /**
2
- * Inject panel (design §5.1 view 3): the two-phase confirmation UI for
3
- * message injection. Fully controlled and presentational — the component
4
- * does NO data fetching; the integration layer supplies `onPrepare` /
5
- * `onExecute` callbacks that speak to `POST <prefix>/action` and resolve
6
- * with either the wire success shape or the data layer's normalized
7
- * ApiError (matched structurally, never imported).
8
- *
9
- * Three zones, driven by the pure reducer in ./logic.ts:
10
- *
11
- * 1. editor — message textarea + live UTF-8 byte counter, queue/steer mode
12
- * radios, target row, cursor-cli process-list warning (§4.d/S7) and the
13
- * audit-fingerprint note (§5.3);
14
- * 2. confirm — the prepare plan (live target-status snapshot + message
15
- * digest), the 60s confirmToken countdown, and the deliberately
16
- * restrained danger button;
17
- * 3. result — delivered / failed (re-prepare offered) / unknown (terminal:
18
- * the reducer itself refuses a reset, so no retry affordance can exist —
19
- * S6 — and the copy points at the session to verify).
20
- *
21
- * `capability.inject === false` disables the whole panel with the
22
- * "enable injection in Settings" note.
23
- */
24
-
1
+ import { Button, Pill } from '@deepseek-ai/dsh-client-ui-primitives'
25
2
  import { useEffect, useId, useReducer, useState } from 'react'
26
3
  import type { ReactNode } from 'react'
27
4
  import { t as defaultT } from '../locales/index.ts'
28
5
  import type { SidecarLocaleKey } from '../locales/index.ts'
6
+ import { surfaceProps } from '../theme/parts.ts'
29
7
  import css from './inject.module.css'
30
8
  import {
31
9
  byteUsage,
@@ -103,10 +81,6 @@ function renderCopy(t: InjectTranslate, copy: CopyRef): string {
103
81
  return t(copy.key, copy.params)
104
82
  }
105
83
 
106
- // ---------------------------------------------------------------------------
107
- // Zone building blocks.
108
- // ---------------------------------------------------------------------------
109
-
110
84
  interface WarningsProps {
111
85
  t: InjectTranslate
112
86
  agent: string | null
@@ -141,7 +115,7 @@ function PlanBox(props: PlanBoxProps): ReactNode {
141
115
  <div className={css['planRow']}>
142
116
  <span className={css['planKey']}>{t('inject.planTargetLabel')}</span>
143
117
  <span className={css['planValue']}>
144
- <span className={css['agentTag']}>{plan.target.agent}</span>
118
+ <Pill className={css['agentTag']}>{plan.target.agent}</Pill>
145
119
  <span className={css['planTitle']} title={plan.target.sessionId}>{targetName}</span>
146
120
  </span>
147
121
  </div>
@@ -165,15 +139,6 @@ function PlanBox(props: PlanBoxProps): ReactNode {
165
139
  )
166
140
  }
167
141
 
168
- // ---------------------------------------------------------------------------
169
- // Panel.
170
- // ---------------------------------------------------------------------------
171
-
172
- /**
173
- * Render the two-phase inject panel.
174
- * @param props - capability, target, and the integration callbacks.
175
- * @returns the panel.
176
- */
177
142
  export function InjectPanel(props: InjectPanelProps): ReactNode {
178
143
  const t = props.t ?? defaultT
179
144
  const now = props.nowMs ?? Date.now
@@ -274,18 +239,18 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
274
239
  }
275
240
  }
276
241
 
242
+ const panelSurface = surfaceProps('inject-panel', css['panel'])
277
243
  const closeButton = props.onClose !== undefined
278
244
  ? (
279
- <button type="button" className={css['btn']} onClick={props.onClose}>
245
+ <Button type="button" size="sm" variant="outline" onClick={props.onClose}>
280
246
  {t('inject.close')}
281
- </button>
247
+ </Button>
282
248
  )
283
249
  : null
284
250
 
285
- // ── whole-panel gate: injection capability off ─────────────────────────
286
251
  if (!props.capability.inject) {
287
252
  return (
288
- <section className={css['panel']} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
253
+ <section {...panelSurface} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
289
254
  <header className={css['header']}>
290
255
  <h3 className={css['title']}>{t('inject.title')}</h3>
291
256
  </header>
@@ -299,7 +264,6 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
299
264
  )
300
265
  }
301
266
 
302
- // ── zone 3: result ──────────────────────────────────────────────────────
303
267
  if (state.phase === 'result') {
304
268
  const { result } = state
305
269
  const actions = resultActions(result.outcome)
@@ -309,7 +273,7 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
309
273
  ? css['resultFail']
310
274
  : css['resultUnknown']
311
275
  return (
312
- <section className={css['panel']} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
276
+ <section {...panelSurface} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
313
277
  <header className={css['header']}>
314
278
  <h3 className={css['title']}>{t('inject.title')}</h3>
315
279
  </header>
@@ -329,36 +293,39 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
329
293
  {closeButton}
330
294
  {isDeliveredResult(result) && props.onObserve !== undefined
331
295
  ? (
332
- <button
296
+ <Button
333
297
  type="button"
334
- className={css['btnPrimary']}
298
+ size="sm"
299
+ variant="primary"
335
300
  onClick={props.onObserve}
336
301
  data-testid="agent-sidecar-inject-observe"
337
302
  >
338
303
  {t('inject.observeListen')}
339
- </button>
304
+ </Button>
340
305
  )
341
306
  : null}
342
307
  {actions.canReprepare
343
308
  ? (
344
- <button
309
+ <Button
345
310
  type="button"
346
- className={css['btnPrimary']}
311
+ size="sm"
312
+ variant="primary"
347
313
  onClick={() => { dispatch({ type: 'RESET' }) }}
348
314
  >
349
315
  {t('inject.reprepare')}
350
- </button>
316
+ </Button>
351
317
  )
352
318
  : null}
353
319
  {result.outcome === 'delivered' && props.onClose === undefined
354
320
  ? (
355
- <button
321
+ <Button
356
322
  type="button"
357
- className={css['btnPrimary']}
323
+ size="sm"
324
+ variant="primary"
358
325
  onClick={() => { dispatch({ type: 'RESET' }) }}
359
326
  >
360
327
  {t('inject.done')}
361
- </button>
328
+ </Button>
362
329
  )
363
330
  : null}
364
331
  </div>
@@ -367,7 +334,6 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
367
334
  )
368
335
  }
369
336
 
370
- // ── zone 2: confirm / executing ─────────────────────────────────────────
371
337
  if (state.phase === 'confirm' || state.phase === 'executing') {
372
338
  const executing = state.phase === 'executing'
373
339
  const countdown = state.phase === 'confirm'
@@ -375,7 +341,7 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
375
341
  : null
376
342
  return (
377
343
  <section
378
- className={css['panel']}
344
+ {...panelSurface}
379
345
  aria-label={t('inject.confirmTitle')}
380
346
  onKeyDown={handleKeyDown}
381
347
  >
@@ -393,14 +359,15 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
393
359
  )
394
360
  : null}
395
361
  <div className={css['footer']}>
396
- <button
362
+ <Button
397
363
  type="button"
398
- className={css['btn']}
364
+ size="sm"
365
+ variant="outline"
399
366
  disabled={executing}
400
367
  onClick={() => { dispatch({ type: 'CANCEL' }) }}
401
368
  >
402
369
  {t('inject.cancel')}
403
- </button>
370
+ </Button>
404
371
  <button
405
372
  type="button"
406
373
  className={css['btnDanger']}
@@ -415,7 +382,6 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
415
382
  )
416
383
  }
417
384
 
418
- // ── zone 1: editor (idle / preparing) ───────────────────────────────────
419
385
  const preparing = state.phase === 'preparing'
420
386
  const canEdit = props.target !== null && !preparing
421
387
  const usage = byteUsage(validation.bytes)
@@ -423,7 +389,7 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
423
389
  const showInvalid = !validation.ok && validation.code !== 'empty'
424
390
 
425
391
  return (
426
- <section className={css['panel']} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
392
+ <section {...panelSurface} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
427
393
  <header className={css['header']}>
428
394
  <h3 className={css['title']}>{t('inject.title')}</h3>
429
395
  </header>
@@ -447,7 +413,7 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
447
413
  {props.target !== null
448
414
  ? (
449
415
  <span className={css['planValue']}>
450
- <span className={css['agentTag']}>{props.target.agent}</span>
416
+ <Pill className={css['agentTag']}>{props.target.agent}</Pill>
451
417
  <span className={css['planTitle']} title={props.target.sessionId}>
452
418
  {props.target.title !== undefined && props.target.title !== ''
453
419
  ? props.target.title
@@ -520,14 +486,15 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
520
486
 
521
487
  <div className={css['footer']}>
522
488
  {closeButton}
523
- <button
489
+ <Button
524
490
  type="button"
525
- className={css['btnPrimary']}
491
+ size="sm"
492
+ variant="primary"
526
493
  disabled={!gate.canPrepare}
527
494
  onClick={() => { void handlePrepare() }}
528
495
  >
529
496
  {t(preparing ? 'inject.preparing' : 'inject.prepare')}
530
- </button>
497
+ </Button>
531
498
  </div>
532
499
  </div>
533
500
  </section>