@shendeguize/dsh-agent-sidecar 0.1.0 → 0.1.1
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/lib/client.js +874 -168
- package/lib/client.js.map +1 -1
- package/package.json +1 -1
- package/src/client/board/Board.tsx +168 -15
- package/src/client/board/board.module.css +100 -0
- package/src/client/board/logic.ts +99 -21
- package/src/client/board/project-view-logic.ts +9 -3
- package/src/client/board/project-view.module.css +18 -0
- package/src/client/board/project-view.tsx +27 -1
- package/src/client/board/strings.ts +29 -5
- package/src/client/controller.ts +27 -7
- package/src/client/detail/SessionDetail.tsx +177 -14
- package/src/client/detail/detail.module.css +105 -2
- package/src/client/detail/logic.ts +220 -29
- package/src/client/detail/strings.ts +13 -0
- package/src/client/detail-glue.ts +33 -0
- package/src/client/detail-view.module.css +36 -3
- package/src/client/detail-view.tsx +76 -28
- package/src/client/dsh-tools/dsh-tools.module.css +6 -4
- package/src/client/inject/InjectPanel.tsx +57 -4
- package/src/client/inject/inject.module.css +68 -67
- package/src/client/inject/logic.ts +38 -0
- package/src/client/inject/overlay.module.css +1 -1
- package/src/client/locales/en.ts +17 -2
- package/src/client/locales/zh.ts +17 -2
- package/src/client/mount.tsx +3 -3
- package/src/client/widget.tsx +37 -12
|
@@ -30,9 +30,11 @@ import css from './inject.module.css'
|
|
|
30
30
|
import {
|
|
31
31
|
byteUsage,
|
|
32
32
|
classifyExecuteResponse,
|
|
33
|
+
classifyPanelKey,
|
|
33
34
|
classifyPrepareResponse,
|
|
34
35
|
deriveEditorGate,
|
|
35
36
|
errorCopy,
|
|
37
|
+
isDeliveredResult,
|
|
36
38
|
initialPanelState,
|
|
37
39
|
messageInvalidCopy,
|
|
38
40
|
MODE_COPY,
|
|
@@ -82,6 +84,12 @@ export interface InjectPanelProps {
|
|
|
82
84
|
onExecute(req: PanelExecuteRequest): Promise<InjectResultView | ApiErrorLike>
|
|
83
85
|
/** Close/dismiss the panel (the hosting modal owns the lifecycle). */
|
|
84
86
|
onClose?(): void
|
|
87
|
+
/**
|
|
88
|
+
* UX-05 observation loop: when given, the delivered result page offers a
|
|
89
|
+
* 「开启监听观察反应」 button (the host typically enables listen mode on
|
|
90
|
+
* the detail timeline and closes the panel).
|
|
91
|
+
*/
|
|
92
|
+
onObserve?(): void
|
|
85
93
|
/** Clock injection for the token countdown; defaults to Date.now. */
|
|
86
94
|
nowMs?: () => number
|
|
87
95
|
/** Locale seat override; defaults to the module-local table. */
|
|
@@ -240,6 +248,32 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
|
|
|
240
248
|
dispatch(event)
|
|
241
249
|
}
|
|
242
250
|
|
|
251
|
+
// Keyboard affordances (UX-10): Esc closes in every zone; Cmd/Ctrl+Enter
|
|
252
|
+
// triggers PREPARE only (classifyPanelKey refuses everything else, so no
|
|
253
|
+
// keyboard path can shortcut the explicit confirm click).
|
|
254
|
+
const handleKeyDown = (event: {
|
|
255
|
+
key: string
|
|
256
|
+
metaKey: boolean
|
|
257
|
+
ctrlKey: boolean
|
|
258
|
+
stopPropagation(): void
|
|
259
|
+
preventDefault(): void
|
|
260
|
+
}): void => {
|
|
261
|
+
const intent = classifyPanelKey({
|
|
262
|
+
key: event.key,
|
|
263
|
+
metaKey: event.metaKey,
|
|
264
|
+
ctrlKey: event.ctrlKey,
|
|
265
|
+
phase: state.phase,
|
|
266
|
+
canPrepare: gate.canPrepare,
|
|
267
|
+
})
|
|
268
|
+
if (intent === 'close' && props.onClose !== undefined) {
|
|
269
|
+
event.stopPropagation()
|
|
270
|
+
props.onClose()
|
|
271
|
+
} else if (intent === 'prepare') {
|
|
272
|
+
event.preventDefault()
|
|
273
|
+
void handlePrepare()
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
243
277
|
const closeButton = props.onClose !== undefined
|
|
244
278
|
? (
|
|
245
279
|
<button type="button" className={css['btn']} onClick={props.onClose}>
|
|
@@ -251,7 +285,7 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
|
|
|
251
285
|
// ── whole-panel gate: injection capability off ─────────────────────────
|
|
252
286
|
if (!props.capability.inject) {
|
|
253
287
|
return (
|
|
254
|
-
<section className={css['panel']} aria-label={t('inject.title')}>
|
|
288
|
+
<section className={css['panel']} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
|
|
255
289
|
<header className={css['header']}>
|
|
256
290
|
<h3 className={css['title']}>{t('inject.title')}</h3>
|
|
257
291
|
</header>
|
|
@@ -275,7 +309,7 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
|
|
|
275
309
|
? css['resultFail']
|
|
276
310
|
: css['resultUnknown']
|
|
277
311
|
return (
|
|
278
|
-
<section className={css['panel']} aria-label={t('inject.title')}>
|
|
312
|
+
<section className={css['panel']} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
|
|
279
313
|
<header className={css['header']}>
|
|
280
314
|
<h3 className={css['title']}>{t('inject.title')}</h3>
|
|
281
315
|
</header>
|
|
@@ -293,6 +327,18 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
|
|
|
293
327
|
: null}
|
|
294
328
|
<div className={css['footer']}>
|
|
295
329
|
{closeButton}
|
|
330
|
+
{isDeliveredResult(result) && props.onObserve !== undefined
|
|
331
|
+
? (
|
|
332
|
+
<button
|
|
333
|
+
type="button"
|
|
334
|
+
className={css['btnPrimary']}
|
|
335
|
+
onClick={props.onObserve}
|
|
336
|
+
data-testid="agent-sidecar-inject-observe"
|
|
337
|
+
>
|
|
338
|
+
{t('inject.observeListen')}
|
|
339
|
+
</button>
|
|
340
|
+
)
|
|
341
|
+
: null}
|
|
296
342
|
{actions.canReprepare
|
|
297
343
|
? (
|
|
298
344
|
<button
|
|
@@ -328,7 +374,11 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
|
|
|
328
374
|
? tokenCountdown(state.expiresAt, clock)
|
|
329
375
|
: null
|
|
330
376
|
return (
|
|
331
|
-
<section
|
|
377
|
+
<section
|
|
378
|
+
className={css['panel']}
|
|
379
|
+
aria-label={t('inject.confirmTitle')}
|
|
380
|
+
onKeyDown={handleKeyDown}
|
|
381
|
+
>
|
|
332
382
|
<header className={css['header']}>
|
|
333
383
|
<h3 className={css['title']}>{t('inject.confirmTitle')}</h3>
|
|
334
384
|
</header>
|
|
@@ -373,7 +423,7 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
|
|
|
373
423
|
const showInvalid = !validation.ok && validation.code !== 'empty'
|
|
374
424
|
|
|
375
425
|
return (
|
|
376
|
-
<section className={css['panel']} aria-label={t('inject.title')}>
|
|
426
|
+
<section className={css['panel']} aria-label={t('inject.title')} onKeyDown={handleKeyDown}>
|
|
377
427
|
<header className={css['header']}>
|
|
378
428
|
<h3 className={css['title']}>{t('inject.title')}</h3>
|
|
379
429
|
</header>
|
|
@@ -419,6 +469,9 @@ export function InjectPanel(props: InjectPanelProps): ReactNode {
|
|
|
419
469
|
placeholder={t('inject.messagePlaceholder')}
|
|
420
470
|
disabled={!canEdit}
|
|
421
471
|
rows={5}
|
|
472
|
+
// eslint-disable-next-line jsx-a11y/no-autofocus -- the panel is
|
|
473
|
+
// a modal whose single task starts in this field (UX-10).
|
|
474
|
+
autoFocus
|
|
422
475
|
onChange={(event) => { setDraft(event.target.value) }}
|
|
423
476
|
/>
|
|
424
477
|
<div className={css['byteRow']}>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/* Inject panel (design §5.1 view 3). Every color rides a dsh --dsw-alias-*
|
|
2
|
-
* design token
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* design token WITH a neutral fallback (UX-16: same token+fallback
|
|
3
|
+
* discipline as every other CSS module), and error tones ride the
|
|
4
|
+
* state-error-* family the board uses. The confirm-injection button is
|
|
5
|
+
* the one danger affordance: eye-catching (error-toned border/text,
|
|
6
|
+
* filled on hover) but restrained (no permanent solid red block). */
|
|
6
7
|
|
|
7
8
|
.panel {
|
|
8
|
-
border: 1px solid var(--dsw-alias-border-l2);
|
|
9
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12));
|
|
9
10
|
border-radius: 12px;
|
|
10
|
-
background: var(--dsw-alias-bg-layer-2);
|
|
11
|
+
background: var(--dsw-alias-bg-layer-2, rgba(0, 0, 0, 0.04));
|
|
11
12
|
max-width: 560px;
|
|
12
13
|
display: flex;
|
|
13
14
|
flex-direction: column;
|
|
@@ -20,7 +21,7 @@
|
|
|
20
21
|
align-items: center;
|
|
21
22
|
gap: 12px;
|
|
22
23
|
padding: 14px 16px 10px;
|
|
23
|
-
border-bottom: 1px solid var(--dsw-alias-border-l2);
|
|
24
|
+
border-bottom: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12));
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
.title {
|
|
@@ -30,7 +31,7 @@
|
|
|
30
31
|
font-size: 15px;
|
|
31
32
|
font-weight: 600;
|
|
32
33
|
line-height: 1.4;
|
|
33
|
-
color: var(--dsw-alias-label-primary);
|
|
34
|
+
color: var(--dsw-alias-label-primary, #1f2328);
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
/* ── body ──────────────────────────────────────────────────────────────── */
|
|
@@ -48,8 +49,8 @@
|
|
|
48
49
|
padding: 10px 12px;
|
|
49
50
|
font-size: 13px;
|
|
50
51
|
line-height: 1.6;
|
|
51
|
-
background: var(--dsw-alias-bg-module-platform);
|
|
52
|
-
color: var(--dsw-alias-label-secondary);
|
|
52
|
+
background: var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.03));
|
|
53
|
+
color: var(--dsw-alias-label-secondary, #57606a);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
/* ── notices (editor banners after a failed/expired attempt) ───────────── */
|
|
@@ -61,17 +62,17 @@
|
|
|
61
62
|
padding: 8px 10px;
|
|
62
63
|
font-size: 12px;
|
|
63
64
|
line-height: 1.6;
|
|
64
|
-
background: var(--dsw-alias-bg-module-platform);
|
|
65
|
-
color: var(--dsw-alias-label-secondary);
|
|
65
|
+
background: var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.03));
|
|
66
|
+
color: var(--dsw-alias-label-secondary, #57606a);
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
.noticeError {
|
|
69
|
-
border: 1px solid var(--dsw-alias-
|
|
70
|
-
color: var(--dsw-alias-
|
|
70
|
+
border: 1px solid var(--dsw-alias-state-error-primary, #cf222e);
|
|
71
|
+
color: var(--dsw-alias-state-error-primary, #cf222e);
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
.noticeDetail {
|
|
74
|
-
color: var(--dsw-alias-label-tertiary);
|
|
75
|
+
color: var(--dsw-alias-label-tertiary, #6e7781);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
/* ── target row ────────────────────────────────────────────────────────── */
|
|
@@ -86,7 +87,7 @@
|
|
|
86
87
|
.noTarget {
|
|
87
88
|
font-size: 12px;
|
|
88
89
|
line-height: 1.5;
|
|
89
|
-
color: var(--dsw-alias-label-tertiary);
|
|
90
|
+
color: var(--dsw-alias-label-tertiary, #6e7781);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
.agentTag {
|
|
@@ -96,8 +97,8 @@
|
|
|
96
97
|
font-size: 11px;
|
|
97
98
|
line-height: 17px;
|
|
98
99
|
font-weight: 500;
|
|
99
|
-
background: var(--dsw-alias-bg-module-platform);
|
|
100
|
-
color: var(--dsw-alias-label-secondary);
|
|
100
|
+
background: var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.03));
|
|
101
|
+
color: var(--dsw-alias-label-secondary, #57606a);
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
.planTitle {
|
|
@@ -107,7 +108,7 @@
|
|
|
107
108
|
white-space: nowrap;
|
|
108
109
|
font-size: 13px;
|
|
109
110
|
line-height: 1.5;
|
|
110
|
-
color: var(--dsw-alias-label-primary);
|
|
111
|
+
color: var(--dsw-alias-label-primary, #1f2328);
|
|
111
112
|
}
|
|
112
113
|
|
|
113
114
|
/* ── editor field ──────────────────────────────────────────────────────── */
|
|
@@ -121,30 +122,30 @@
|
|
|
121
122
|
.label {
|
|
122
123
|
font-size: 13px;
|
|
123
124
|
line-height: 1.5;
|
|
124
|
-
color: var(--dsw-alias-label-primary);
|
|
125
|
+
color: var(--dsw-alias-label-primary, #1f2328);
|
|
125
126
|
}
|
|
126
127
|
|
|
127
128
|
.textarea {
|
|
128
129
|
appearance: none;
|
|
129
130
|
resize: vertical;
|
|
130
131
|
min-height: 96px;
|
|
131
|
-
border: 1px solid var(--dsw-alias-border-l2);
|
|
132
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12));
|
|
132
133
|
border-radius: 8px;
|
|
133
|
-
background: var(--dsw-alias-bg-layer-3);
|
|
134
|
+
background: var(--dsw-alias-bg-layer-3, #ffffff);
|
|
134
135
|
padding: 8px 10px;
|
|
135
136
|
font: inherit;
|
|
136
137
|
font-size: 13px;
|
|
137
138
|
line-height: 1.6;
|
|
138
|
-
color: var(--dsw-alias-label-primary);
|
|
139
|
+
color: var(--dsw-alias-label-primary, #1f2328);
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
.textarea:focus-visible {
|
|
142
143
|
outline: none;
|
|
143
|
-
border-color: var(--dsw-alias-brand-primary);
|
|
144
|
+
border-color: var(--dsw-alias-brand-primary, #4d6bfe);
|
|
144
145
|
}
|
|
145
146
|
|
|
146
147
|
.textarea::placeholder {
|
|
147
|
-
color: var(--dsw-alias-label-tertiary);
|
|
148
|
+
color: var(--dsw-alias-label-tertiary, #6e7781);
|
|
148
149
|
}
|
|
149
150
|
|
|
150
151
|
.textarea:disabled {
|
|
@@ -163,20 +164,20 @@
|
|
|
163
164
|
flex: 1;
|
|
164
165
|
height: 3px;
|
|
165
166
|
border-radius: 2px;
|
|
166
|
-
background: var(--dsw-alias-bg-module-platform);
|
|
167
|
+
background: var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.03));
|
|
167
168
|
overflow: hidden;
|
|
168
169
|
}
|
|
169
170
|
|
|
170
171
|
.byteFill {
|
|
171
172
|
height: 100%;
|
|
172
173
|
border-radius: 2px;
|
|
173
|
-
background: var(--dsw-alias-brand-primary);
|
|
174
|
+
background: var(--dsw-alias-brand-primary, #4d6bfe);
|
|
174
175
|
transition: width .12s;
|
|
175
176
|
}
|
|
176
177
|
|
|
177
178
|
/* Modifier applied ALONGSIDE .byteFill (no `composes`; see settings card). */
|
|
178
179
|
.byteFillOver {
|
|
179
|
-
background: var(--dsw-alias-
|
|
180
|
+
background: var(--dsw-alias-state-error-primary, #cf222e);
|
|
180
181
|
}
|
|
181
182
|
|
|
182
183
|
.byteText,
|
|
@@ -185,18 +186,18 @@
|
|
|
185
186
|
font-size: 11px;
|
|
186
187
|
line-height: 1.5;
|
|
187
188
|
font-variant-numeric: tabular-nums;
|
|
188
|
-
color: var(--dsw-alias-label-tertiary);
|
|
189
|
+
color: var(--dsw-alias-label-tertiary, #6e7781);
|
|
189
190
|
}
|
|
190
191
|
|
|
191
192
|
.byteTextOver {
|
|
192
|
-
color: var(--dsw-alias-
|
|
193
|
+
color: var(--dsw-alias-state-error-primary, #cf222e);
|
|
193
194
|
}
|
|
194
195
|
|
|
195
196
|
.invalid {
|
|
196
197
|
margin: 0;
|
|
197
198
|
font-size: 12px;
|
|
198
199
|
line-height: 1.5;
|
|
199
|
-
color: var(--dsw-alias-
|
|
200
|
+
color: var(--dsw-alias-state-error-primary, #cf222e);
|
|
200
201
|
}
|
|
201
202
|
|
|
202
203
|
/* ── mode radios ───────────────────────────────────────────────────────── */
|
|
@@ -218,7 +219,7 @@
|
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
.modeOption input {
|
|
221
|
-
accent-color: var(--dsw-alias-brand-primary);
|
|
222
|
+
accent-color: var(--dsw-alias-brand-primary, #4d6bfe);
|
|
222
223
|
width: 14px;
|
|
223
224
|
height: 14px;
|
|
224
225
|
margin: 3px 0 0;
|
|
@@ -239,26 +240,26 @@
|
|
|
239
240
|
.modeLabel {
|
|
240
241
|
font-size: 13px;
|
|
241
242
|
line-height: 1.5;
|
|
242
|
-
color: var(--dsw-alias-label-primary);
|
|
243
|
+
color: var(--dsw-alias-label-primary, #1f2328);
|
|
243
244
|
}
|
|
244
245
|
|
|
245
246
|
.modeHint {
|
|
246
247
|
font-size: 12px;
|
|
247
248
|
line-height: 1.5;
|
|
248
|
-
color: var(--dsw-alias-label-tertiary);
|
|
249
|
+
color: var(--dsw-alias-label-tertiary, #6e7781);
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
/* ── warnings & audit note ─────────────────────────────────────────────── */
|
|
252
253
|
|
|
253
254
|
.warnBar {
|
|
254
255
|
margin: 0;
|
|
255
|
-
border: 1px solid var(--dsw-alias-
|
|
256
|
+
border: 1px solid var(--dsw-alias-state-error-primary, #cf222e);
|
|
256
257
|
border-radius: 8px;
|
|
257
258
|
padding: 8px 10px;
|
|
258
259
|
font-size: 12px;
|
|
259
260
|
line-height: 1.6;
|
|
260
|
-
background: var(--dsw-alias-bg-module-platform);
|
|
261
|
-
color: var(--dsw-alias-
|
|
261
|
+
background: var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.03));
|
|
262
|
+
color: var(--dsw-alias-state-error-primary, #cf222e);
|
|
262
263
|
}
|
|
263
264
|
|
|
264
265
|
.auditNote {
|
|
@@ -267,16 +268,16 @@
|
|
|
267
268
|
padding: 8px 10px;
|
|
268
269
|
font-size: 12px;
|
|
269
270
|
line-height: 1.6;
|
|
270
|
-
background: var(--dsw-alias-bg-module-platform);
|
|
271
|
-
color: var(--dsw-alias-label-secondary);
|
|
271
|
+
background: var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.03));
|
|
272
|
+
color: var(--dsw-alias-label-secondary, #57606a);
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
/* ── confirm plan ──────────────────────────────────────────────────────── */
|
|
275
276
|
|
|
276
277
|
.planBox {
|
|
277
|
-
border: 1px solid var(--dsw-alias-border-l2);
|
|
278
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12));
|
|
278
279
|
border-radius: 8px;
|
|
279
|
-
background: var(--dsw-alias-bg-layer-3);
|
|
280
|
+
background: var(--dsw-alias-bg-layer-3, #ffffff);
|
|
280
281
|
padding: 10px 12px;
|
|
281
282
|
display: flex;
|
|
282
283
|
flex-direction: column;
|
|
@@ -294,7 +295,7 @@
|
|
|
294
295
|
flex: none;
|
|
295
296
|
font-size: 12px;
|
|
296
297
|
line-height: 1.5;
|
|
297
|
-
color: var(--dsw-alias-label-tertiary);
|
|
298
|
+
color: var(--dsw-alias-label-tertiary, #6e7781);
|
|
298
299
|
}
|
|
299
300
|
|
|
300
301
|
.planValue {
|
|
@@ -304,14 +305,14 @@
|
|
|
304
305
|
min-width: 0;
|
|
305
306
|
font-size: 13px;
|
|
306
307
|
line-height: 1.5;
|
|
307
|
-
color: var(--dsw-alias-label-primary);
|
|
308
|
+
color: var(--dsw-alias-label-primary, #1f2328);
|
|
308
309
|
}
|
|
309
310
|
|
|
310
311
|
.observedNote {
|
|
311
312
|
margin: 0;
|
|
312
313
|
font-size: 11px;
|
|
313
314
|
line-height: 1.5;
|
|
314
|
-
color: var(--dsw-alias-label-tertiary);
|
|
315
|
+
color: var(--dsw-alias-label-tertiary, #6e7781);
|
|
315
316
|
}
|
|
316
317
|
|
|
317
318
|
.planPreview {
|
|
@@ -323,9 +324,9 @@
|
|
|
323
324
|
|
|
324
325
|
.preview {
|
|
325
326
|
margin: 0;
|
|
326
|
-
border: 1px solid var(--dsw-alias-border-l2);
|
|
327
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12));
|
|
327
328
|
border-radius: 6px;
|
|
328
|
-
background: var(--dsw-alias-bg-layer-2);
|
|
329
|
+
background: var(--dsw-alias-bg-layer-2, rgba(0, 0, 0, 0.04));
|
|
329
330
|
padding: 8px 10px;
|
|
330
331
|
max-height: 120px;
|
|
331
332
|
overflow: auto;
|
|
@@ -333,7 +334,7 @@
|
|
|
333
334
|
line-height: 1.6;
|
|
334
335
|
white-space: pre-wrap;
|
|
335
336
|
word-break: break-word;
|
|
336
|
-
color: var(--dsw-alias-label-secondary);
|
|
337
|
+
color: var(--dsw-alias-label-secondary, #57606a);
|
|
337
338
|
}
|
|
338
339
|
|
|
339
340
|
.countdown {
|
|
@@ -341,7 +342,7 @@
|
|
|
341
342
|
font-size: 12px;
|
|
342
343
|
line-height: 1.5;
|
|
343
344
|
font-variant-numeric: tabular-nums;
|
|
344
|
-
color: var(--dsw-alias-label-secondary);
|
|
345
|
+
color: var(--dsw-alias-label-secondary, #57606a);
|
|
345
346
|
}
|
|
346
347
|
|
|
347
348
|
/* ── results ───────────────────────────────────────────────────────────── */
|
|
@@ -354,29 +355,29 @@
|
|
|
354
355
|
padding: 10px 12px;
|
|
355
356
|
font-size: 13px;
|
|
356
357
|
line-height: 1.6;
|
|
357
|
-
background: var(--dsw-alias-bg-module-platform);
|
|
358
|
-
color: var(--dsw-alias-label-primary);
|
|
358
|
+
background: var(--dsw-alias-bg-module-platform, rgba(0, 0, 0, 0.03));
|
|
359
|
+
color: var(--dsw-alias-label-primary, #1f2328);
|
|
359
360
|
}
|
|
360
361
|
|
|
361
362
|
.resultOk {
|
|
362
|
-
border: 1px solid var(--dsw-alias-brand-primary);
|
|
363
|
+
border: 1px solid var(--dsw-alias-brand-primary, #4d6bfe);
|
|
363
364
|
}
|
|
364
365
|
|
|
365
366
|
.resultFail {
|
|
366
|
-
border: 1px solid var(--dsw-alias-
|
|
367
|
-
color: var(--dsw-alias-
|
|
367
|
+
border: 1px solid var(--dsw-alias-state-error-primary, #cf222e);
|
|
368
|
+
color: var(--dsw-alias-state-error-primary, #cf222e);
|
|
368
369
|
}
|
|
369
370
|
|
|
370
371
|
.resultUnknown {
|
|
371
|
-
border: 1px solid var(--dsw-alias-label-dimmed);
|
|
372
|
-
color: var(--dsw-alias-label-secondary);
|
|
372
|
+
border: 1px solid var(--dsw-alias-label-dimmed, #8c959f);
|
|
373
|
+
color: var(--dsw-alias-label-secondary, #57606a);
|
|
373
374
|
}
|
|
374
375
|
|
|
375
376
|
.resultDetail {
|
|
376
377
|
margin: 0;
|
|
377
378
|
font-size: 12px;
|
|
378
379
|
line-height: 1.6;
|
|
379
|
-
color: var(--dsw-alias-label-tertiary);
|
|
380
|
+
color: var(--dsw-alias-label-tertiary, #6e7781);
|
|
380
381
|
}
|
|
381
382
|
|
|
382
383
|
/* ── footer buttons ────────────────────────────────────────────────────── */
|
|
@@ -403,32 +404,32 @@
|
|
|
403
404
|
}
|
|
404
405
|
|
|
405
406
|
.btn {
|
|
406
|
-
border-color: var(--dsw-alias-border-l2);
|
|
407
|
+
border-color: var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12));
|
|
407
408
|
background: none;
|
|
408
|
-
color: var(--dsw-alias-label-secondary);
|
|
409
|
+
color: var(--dsw-alias-label-secondary, #57606a);
|
|
409
410
|
}
|
|
410
411
|
|
|
411
412
|
.btn:hover:not(:disabled) {
|
|
412
|
-
color: var(--dsw-alias-label-primary);
|
|
413
|
-
border-color: var(--dsw-alias-label-dimmed);
|
|
413
|
+
color: var(--dsw-alias-label-primary, #1f2328);
|
|
414
|
+
border-color: var(--dsw-alias-label-dimmed, #8c959f);
|
|
414
415
|
}
|
|
415
416
|
|
|
416
417
|
.btnPrimary {
|
|
417
|
-
background: var(--dsw-alias-label-primary);
|
|
418
|
-
color: var(--dsw-alias-bg-layer-3);
|
|
418
|
+
background: var(--dsw-alias-label-primary, #1f2328);
|
|
419
|
+
color: var(--dsw-alias-bg-layer-3, #ffffff);
|
|
419
420
|
}
|
|
420
421
|
|
|
421
422
|
/* The danger action: outlined error tone at rest, fills on hover. */
|
|
422
423
|
.btnDanger {
|
|
423
|
-
border-color: var(--dsw-alias-
|
|
424
|
+
border-color: var(--dsw-alias-state-error-primary, #cf222e);
|
|
424
425
|
background: none;
|
|
425
|
-
color: var(--dsw-alias-
|
|
426
|
+
color: var(--dsw-alias-state-error-primary, #cf222e);
|
|
426
427
|
font-weight: 600;
|
|
427
428
|
}
|
|
428
429
|
|
|
429
430
|
.btnDanger:hover:not(:disabled) {
|
|
430
|
-
background: var(--dsw-alias-
|
|
431
|
-
color: var(--dsw-alias-bg-layer-3);
|
|
431
|
+
background: var(--dsw-alias-state-error-primary, #cf222e);
|
|
432
|
+
color: var(--dsw-alias-bg-layer-3, #ffffff);
|
|
432
433
|
}
|
|
433
434
|
|
|
434
435
|
.btn:disabled,
|
|
@@ -441,6 +442,6 @@
|
|
|
441
442
|
.btn:focus-visible,
|
|
442
443
|
.btnPrimary:focus-visible,
|
|
443
444
|
.btnDanger:focus-visible {
|
|
444
|
-
outline: 2px solid var(--dsw-alias-brand-primary);
|
|
445
|
+
outline: 2px solid var(--dsw-alias-brand-primary, #4d6bfe);
|
|
445
446
|
outline-offset: 1px;
|
|
446
447
|
}
|
|
@@ -418,6 +418,33 @@ export function deriveEditorGate(input: {
|
|
|
418
418
|
return { canPrepare: true, block: null }
|
|
419
419
|
}
|
|
420
420
|
|
|
421
|
+
// ---------------------------------------------------------------------------
|
|
422
|
+
// Keyboard affordances (UX-10).
|
|
423
|
+
// ---------------------------------------------------------------------------
|
|
424
|
+
|
|
425
|
+
export type PanelKeyIntent = 'close' | 'prepare' | null
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Map a keydown to a panel intent: Escape closes in every phase;
|
|
429
|
+
* Cmd/Ctrl+Enter submits the PREPARE step only (editor phase with a valid
|
|
430
|
+
* message). The confirm phase deliberately binds nothing — executing the
|
|
431
|
+
* injection stays an explicit click (two-phase discipline, §5.3), so no
|
|
432
|
+
* keyboard path can shortcut the confirmation.
|
|
433
|
+
*/
|
|
434
|
+
export function classifyPanelKey(input: {
|
|
435
|
+
key: string
|
|
436
|
+
metaKey: boolean
|
|
437
|
+
ctrlKey: boolean
|
|
438
|
+
phase: InjectPhase
|
|
439
|
+
canPrepare: boolean
|
|
440
|
+
}): PanelKeyIntent {
|
|
441
|
+
if (input.key === 'Escape') return 'close'
|
|
442
|
+
if (input.key === 'Enter' && (input.metaKey || input.ctrlKey)) {
|
|
443
|
+
return input.phase === 'idle' && input.canPrepare ? 'prepare' : null
|
|
444
|
+
}
|
|
445
|
+
return null
|
|
446
|
+
}
|
|
447
|
+
|
|
421
448
|
// ---------------------------------------------------------------------------
|
|
422
449
|
// Result actions (S6: unknown is terminal).
|
|
423
450
|
// ---------------------------------------------------------------------------
|
|
@@ -437,6 +464,17 @@ export function resultActions(outcome: InjectOutcome): ResultActions {
|
|
|
437
464
|
}
|
|
438
465
|
}
|
|
439
466
|
|
|
467
|
+
/**
|
|
468
|
+
* True when an execute response reports the message actually reached the
|
|
469
|
+
* target (UX-05 observation loop): a delivered outcome — including an
|
|
470
|
+
* idempotent replay of one — never an error envelope. failed/unknown must
|
|
471
|
+
* NOT trigger observation aids: unknown is a locked terminal state (S6)
|
|
472
|
+
* and any follow-up activity could read as "retrying is fine".
|
|
473
|
+
*/
|
|
474
|
+
export function isDeliveredResult(value: InjectResultView | ApiErrorLike): boolean {
|
|
475
|
+
return !isApiErrorLike(value) && value.outcome === 'delivered'
|
|
476
|
+
}
|
|
477
|
+
|
|
440
478
|
// ---------------------------------------------------------------------------
|
|
441
479
|
// Copy mapping (keys live in the T2.3 locale table, inject.* domain).
|
|
442
480
|
// ---------------------------------------------------------------------------
|
package/src/client/locales/en.ts
CHANGED
|
@@ -69,7 +69,7 @@ export const en = {
|
|
|
69
69
|
'settings.sectionInject': 'Message injection',
|
|
70
70
|
'settings.injectEnabledLabel': 'Enable injection',
|
|
71
71
|
'settings.injectEnabledHint':
|
|
72
|
-
'When off, the
|
|
72
|
+
'When off, the inject panel renders read-only and disabled, and the server rejects write actions.',
|
|
73
73
|
'settings.injectDefaultModeLabel': 'Default injection mode',
|
|
74
74
|
'settings.injectDefaultModeHint': 'The mode preselected when the inject panel opens.',
|
|
75
75
|
'settings.injectModeQueue': 'queue (next turn)',
|
|
@@ -147,6 +147,7 @@ export const en = {
|
|
|
147
147
|
'inject.resultReplayed':
|
|
148
148
|
'Idempotent replay: this is the earlier result of the same request — no second injection happened.',
|
|
149
149
|
'inject.reprepare': 'Prepare again',
|
|
150
|
+
'inject.observeListen': 'Listen for the reaction',
|
|
150
151
|
|
|
151
152
|
// ── inject panel: error vocabulary (gateway + transport) ─────────────
|
|
152
153
|
'inject.errInjectDisabled': 'Injection is disabled on the server; enable it in Settings.',
|
|
@@ -178,6 +179,11 @@ export const en = {
|
|
|
178
179
|
'detail.header.listenOn': 'Listening',
|
|
179
180
|
'detail.header.listenOff': 'Listen',
|
|
180
181
|
'detail.header.listenHint': 'New events append live and get highlighted while on',
|
|
182
|
+
'detail.header.refresh': 'Refresh',
|
|
183
|
+
'detail.header.refreshing': 'Refreshing…',
|
|
184
|
+
'detail.header.refreshHint': 'Pull the newest timeline window',
|
|
185
|
+
'detail.header.copyIdTitle': 'Click to copy the session ID',
|
|
186
|
+
'detail.header.copied': 'Copied',
|
|
181
187
|
'detail.header.untitled': '(untitled)',
|
|
182
188
|
'detail.header.unknownProject': 'Unknown project',
|
|
183
189
|
'detail.header.observedDisclaimer':
|
|
@@ -204,6 +210,9 @@ export const en = {
|
|
|
204
210
|
'detail.kind.other': 'Event',
|
|
205
211
|
'detail.gap.label':
|
|
206
212
|
'Gap: about {n} events may be uncaptured (256-slot queue cap or not persisted)',
|
|
213
|
+
'detail.filter.conversation': 'Conversation only',
|
|
214
|
+
'detail.filter.all': 'All events',
|
|
215
|
+
'detail.filter.hiddenNotice': '{n} protocol events hidden',
|
|
207
216
|
'detail.timeline.loadMore': 'Load older history',
|
|
208
217
|
'detail.timeline.loadingMore': 'Loading…',
|
|
209
218
|
'detail.timeline.noMore': 'Start of the timeline',
|
|
@@ -213,6 +222,7 @@ export const en = {
|
|
|
213
222
|
'detail.timeline.seq': 'seq {n}',
|
|
214
223
|
'detail.timeline.hiddenNotice': '{n} earlier entries collapsed to stay smooth',
|
|
215
224
|
'detail.timeline.showAll': 'Show all',
|
|
225
|
+
'detail.timeline.chunkRun': '{n} streaming chunks',
|
|
216
226
|
'detail.states.loadingTitle': 'Loading the timeline…',
|
|
217
227
|
'detail.states.emptyTitle': 'No events yet',
|
|
218
228
|
'detail.states.emptyHint': 'This session has no normalized events to show yet.',
|
|
@@ -233,6 +243,9 @@ export const en = {
|
|
|
233
243
|
'detail.actions.analyze': 'AI analysis',
|
|
234
244
|
'detail.actions.analyzeDisabledHint':
|
|
235
245
|
'Enable "AI bypass analysis" in Settings to use this',
|
|
246
|
+
'detail.tools.title': 'Lineage & search',
|
|
247
|
+
'detail.tools.show': 'Show',
|
|
248
|
+
'detail.tools.hide': 'Hide',
|
|
236
249
|
|
|
237
250
|
// ── dsh deep-query tools ────────────────────────────────────────────────
|
|
238
251
|
'dshtools.lineage.title': 'Session lineage',
|
|
@@ -287,6 +300,8 @@ export const en = {
|
|
|
287
300
|
'project.lastActive': 'Last active {time}',
|
|
288
301
|
'project.liveChip': 'Live',
|
|
289
302
|
'project.untitled': '(untitled)',
|
|
303
|
+
'project.showAllSessions': 'Show all {n} sessions',
|
|
304
|
+
'project.showLessSessions': 'Show first {n} only',
|
|
290
305
|
'project.empty.title': 'No project correlation yet',
|
|
291
306
|
'project.empty.hint':
|
|
292
307
|
'No cross-agent project activity within the time window; projects appear here once an agent works inside a project directory.',
|
|
@@ -357,7 +372,7 @@ export const en = {
|
|
|
357
372
|
'command.noSessions': 'No observed sessions yet',
|
|
358
373
|
'command.unknownProject': 'Unknown project',
|
|
359
374
|
'command.untitled': '(untitled)',
|
|
360
|
-
'command.truncated': '{n} more
|
|
375
|
+
'command.truncated': '{n} more sessions not listed',
|
|
361
376
|
'command.boardHint': 'Open the "Sidecar" tab in the conversation view for the full board',
|
|
362
377
|
'command.unreachable': 'sidecar is not connected',
|
|
363
378
|
'command.unreachableHint':
|