@design.estate/dees-catalog 6.0.0 → 6.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 (45) hide show
  1. package/dist_bundle/bundle.js +3105 -1500
  2. package/dist_ts_web/00_commitinfo_data.js +1 -1
  3. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +2 -0
  4. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.js +484 -8
  5. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +10 -1
  6. package/dist_ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.d.ts +3 -1
  7. package/dist_ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.js +24 -4
  8. package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.d.ts +26 -0
  9. package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.js +398 -94
  10. package/dist_ts_web/elements/00group-harness/dees-harness-overflow-text.d.ts +32 -0
  11. package/dist_ts_web/elements/00group-harness/dees-harness-overflow-text.demo.d.ts +1 -0
  12. package/dist_ts_web/elements/00group-harness/dees-harness-overflow-text.demo.js +31 -0
  13. package/dist_ts_web/elements/00group-harness/dees-harness-overflow-text.js +297 -0
  14. package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.js +1 -9
  15. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.d.ts +10 -1
  16. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.js +181 -2
  17. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.d.ts +17 -1
  18. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.js +480 -36
  19. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/renderers.js +28 -24
  20. package/dist_ts_web/elements/00group-harness/harness.helpers.d.ts +5 -1
  21. package/dist_ts_web/elements/00group-harness/harness.helpers.js +66 -1
  22. package/dist_ts_web/elements/00group-harness/index.d.ts +1 -0
  23. package/dist_ts_web/elements/00group-harness/index.js +2 -1
  24. package/dist_ts_web/elements/00group-harness/interfaces.d.ts +33 -2
  25. package/dist_ts_web/elements/00group-harness/toolregistry.d.ts +4 -0
  26. package/dist_ts_web/elements/00group-harness/toolregistry.js +8 -1
  27. package/package.json +2 -2
  28. package/readme.hints.md +16 -1
  29. package/readme.md +41 -9
  30. package/readme.playbook.md +8 -4
  31. package/ts_web/00_commitinfo_data.ts +1 -1
  32. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.ts +490 -7
  33. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +9 -0
  34. package/ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.ts +24 -3
  35. package/ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.ts +397 -84
  36. package/ts_web/elements/00group-harness/dees-harness-overflow-text.demo.ts +31 -0
  37. package/ts_web/elements/00group-harness/dees-harness-overflow-text.ts +236 -0
  38. package/ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.ts +0 -8
  39. package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.ts +193 -1
  40. package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.ts +484 -34
  41. package/ts_web/elements/00group-harness/dees-harness-tool-card/renderers.ts +29 -25
  42. package/ts_web/elements/00group-harness/harness.helpers.ts +68 -1
  43. package/ts_web/elements/00group-harness/index.ts +1 -0
  44. package/ts_web/elements/00group-harness/interfaces.ts +38 -2
  45. package/ts_web/elements/00group-harness/toolregistry.ts +12 -0
@@ -105,14 +105,15 @@ const renderTerminal = (call: IHarnessToolCall, helpers: IHarnessToolRenderHelpe
105
105
  const output = call.output;
106
106
  let stdout = '';
107
107
  let stderr = '';
108
- let exitCode: number | undefined;
108
+ let nestedExitCode: number | undefined;
109
109
  if (harnessIsRecord(output)) {
110
110
  stdout = typeof output.stdout === 'string' ? output.stdout : harnessStringifyValue(output.stdout ?? '');
111
111
  stderr = typeof output.stderr === 'string' ? output.stderr : '';
112
- exitCode = typeof output.exitCode === 'number' ? output.exitCode : undefined;
112
+ nestedExitCode = typeof output.exitCode === 'number' ? output.exitCode : undefined;
113
113
  } else {
114
114
  stdout = harnessStringifyValue(output);
115
115
  }
116
+ const exitCode = typeof call.exitCode === 'number' ? call.exitCode : nestedExitCode;
116
117
  const running = call.status === 'pending' || call.status === 'running';
117
118
  return html`
118
119
  <div class="harness-terminal">
@@ -125,8 +126,8 @@ const renderTerminal = (call: IHarnessToolCall, helpers: IHarnessToolRenderHelpe
125
126
  ${running && !stdout && !stderr
126
127
  ? html`<div class="harness-terminal-running"><span class="cursor"></span> running…</div>`
127
128
  : ''}
128
- ${exitCode !== undefined && exitCode !== 0
129
- ? html`<div class="harness-terminal-exit">exit ${exitCode}</div>`
129
+ ${exitCode !== undefined
130
+ ? html`<div class="harness-terminal-exit ${exitCode === 0 ? 'tone-success' : ''}">exit code ${exitCode}</div>`
130
131
  : ''}
131
132
  </div>
132
133
  `;
@@ -255,33 +256,36 @@ const renderSearch = (call: IHarnessToolCall, helpers: IHarnessToolRenderHelpers
255
256
  `;
256
257
  };
257
258
 
258
- const renderSubtask = (call: IHarnessToolCall, helpers: IHarnessToolRenderHelpers): TemplateResult => {
259
+ const renderSubtask = (call: IHarnessToolCall): TemplateResult => {
259
260
  const input = inputRecord(call);
260
261
  const prompt = String(input.prompt ?? input.description ?? '');
262
+ const projectedResult = call.subtask?.previewState === 'ready'
263
+ && call.subtask.status.type !== 'busy'
264
+ ? [...call.subtask.messages].reverse().find(
265
+ (message) => message.role === 'assistant' && Boolean(message.text),
266
+ )?.text ?? ''
267
+ : '';
268
+ const result = outputText(call) || projectedResult;
269
+ const terminal = call.subtask
270
+ ? call.subtask.status.type !== 'busy'
271
+ : call.status === 'completed' || call.status === 'error';
261
272
  return html`
262
- ${call.childSessionId
273
+ ${prompt
263
274
  ? html`
264
- <button
265
- class="harness-subtask-open"
266
- type="button"
267
- @click=${(event: Event) => {
268
- (event.currentTarget as HTMLElement).dispatchEvent(
269
- new CustomEvent('harness-subtask-open', {
270
- detail: { sessionId: call.childSessionId, call },
271
- bubbles: true,
272
- composed: true,
273
- }),
274
- );
275
- }}
276
- >
277
- ${call.status === 'completed' || call.status === 'error'
278
- ? 'Open subagent chat'
279
- : 'Follow subagent live'}
280
- </button>
275
+ <section class="harness-subtask-detail harness-subtask-detail-brief">
276
+ <div class="harness-subtask-detail-label">Agent Brief</div>
277
+ <div class="harness-subtask-detail-text">${prompt}</div>
278
+ </section>
279
+ `
280
+ : ''}
281
+ ${result || terminal
282
+ ? html`
283
+ <section class="harness-subtask-detail harness-subtask-detail-result">
284
+ <div class="harness-subtask-detail-label">Result</div>
285
+ <div class="harness-subtask-detail-text">${result || 'No result was returned.'}</div>
286
+ </section>
281
287
  `
282
288
  : ''}
283
- ${prompt ? helpers.monoBlock(prompt) : ''}
284
- ${outputText(call) ? helpers.monoBlock(outputText(call)) : ''}
285
289
  `;
286
290
  };
287
291
 
@@ -3,7 +3,13 @@
3
3
  * detection, attachment constraints, and defensive value summarization.
4
4
  * No DOM access; safe to import from anywhere including tests.
5
5
  */
6
- import type { IHarnessTodoItem } from './interfaces.js';
6
+ import type {
7
+ IHarnessMessage,
8
+ IHarnessTodoItem,
9
+ IHarnessToolCall,
10
+ THarnessMessageStreamDelta,
11
+ THarnessToolStatus,
12
+ } from './interfaces.js';
7
13
 
8
14
  export const harnessMaxAttachmentBytes = 10 * 1024 * 1024;
9
15
  export const harnessMaxTotalAttachmentBytes = 30 * 1024 * 1024;
@@ -89,6 +95,17 @@ export const harnessIsRecord = (value: unknown): value is Record<string, unknown
89
95
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
90
96
  };
91
97
 
98
+ /** Uses the child projection as the status authority for subagent calls. */
99
+ export const harnessEffectiveToolStatus = (callArg: IHarnessToolCall): THarnessToolStatus => {
100
+ if (callArg.subtask) {
101
+ if (callArg.subtask.status.type === 'busy') return 'running';
102
+ if (callArg.subtask.status.type === 'error') return 'error';
103
+ return 'completed';
104
+ }
105
+ if (callArg.isError || callArg.status === 'error') return 'error';
106
+ return callArg.status;
107
+ };
108
+
92
109
  export const harnessFormatBytes = (bytes: unknown): string => {
93
110
  const value = typeof bytes === 'number' && Number.isFinite(bytes) ? bytes : 0;
94
111
  if (value < 1024) return `${value} B`;
@@ -153,6 +170,56 @@ export const harnessAttachmentKindFor = (mediaType: string): 'image' | 'text' |
153
170
  return 'binary';
154
171
  };
155
172
 
173
+ /** Mutates one normalized message when no rendered message element owns it. */
174
+ export const harnessApplyMessageDelta = (
175
+ messages: IHarnessMessage[],
176
+ delta: THarnessMessageStreamDelta,
177
+ ): IHarnessMessage | undefined => {
178
+ const message = messages.find((candidate) => candidate.id === delta.messageId);
179
+ if (!message) return undefined;
180
+ switch (delta.type) {
181
+ case 'text':
182
+ message.text += delta.delta;
183
+ message.streaming = true;
184
+ break;
185
+ case 'reasoning-start':
186
+ message.reasoning ??= [];
187
+ if (!message.reasoning.some((part) => part.id === delta.partId)) {
188
+ message.reasoning.push({
189
+ id: delta.partId,
190
+ text: '',
191
+ startedAt: delta.startedAt ?? Date.now(),
192
+ });
193
+ }
194
+ break;
195
+ case 'reasoning': {
196
+ message.reasoning ??= [];
197
+ const part = message.reasoning.find((candidate) => candidate.id === delta.partId);
198
+ if (part) part.text += delta.delta;
199
+ else message.reasoning.push({ id: delta.partId, text: delta.delta, startedAt: Date.now() });
200
+ break;
201
+ }
202
+ case 'reasoning-end': {
203
+ const part = message.reasoning?.find((candidate) => candidate.id === delta.partId);
204
+ if (part && !part.endedAt) part.endedAt = delta.endedAt ?? Date.now();
205
+ break;
206
+ }
207
+ case 'tool-update':
208
+ message.toolCall = {
209
+ ...(message.toolCall ?? { id: delta.tool.id, name: '', status: 'pending' }),
210
+ ...delta.tool,
211
+ };
212
+ break;
213
+ case 'message-end':
214
+ message.streaming = false;
215
+ if (delta.usage) message.usage = delta.usage;
216
+ if (delta.error) message.error = delta.error;
217
+ message.updatedAt = Date.now();
218
+ break;
219
+ }
220
+ return message;
221
+ };
222
+
156
223
  export const harnessFileToBase64 = (file: File): Promise<string> =>
157
224
  new Promise<string>((resolve, reject) => {
158
225
  const reader = new FileReader();
@@ -7,6 +7,7 @@ export * from './harness.helpers.js';
7
7
  export { HarnessMarkdown, markdownStyles } from './harness.markdown.js';
8
8
  export { harnessCardStyles, harnessPillStyles, harnessMonoStyles } from './harness.styles.js';
9
9
  export * from './harness.demodata.js';
10
+ export * from './dees-harness-overflow-text.js';
10
11
 
11
12
  export * from './dees-harness-chat/index.js';
12
13
  export * from './dees-harness-composer/index.js';
@@ -170,6 +170,8 @@ export interface IHarnessToolCall {
170
170
  status: THarnessToolStatus;
171
171
  input?: unknown;
172
172
  output?: unknown;
173
+ /** Process exit code when output is a combined stream rather than stdout/stderr fields. */
174
+ exitCode?: number;
173
175
  /** MCP CallToolResult.content, rendered structurally when present */
174
176
  contentBlocks?: THarnessContentBlock[];
175
177
  /** MCP CallToolResult.structuredContent */
@@ -180,6 +182,8 @@ export interface IHarnessToolCall {
180
182
  mcp?: IHarnessMcpMeta;
181
183
  /** Session spawned by this call (subagent/task tools); enables drill-in. */
182
184
  childSessionId?: string;
185
+ /** Bounded live preview of the spawned session. Consumers own hydration. */
186
+ subtask?: IHarnessSubtaskStream;
183
187
  /** model the spawned session runs on, e.g. "anthropic/claude-opus-5" */
184
188
  model?: string;
185
189
  /** epoch ms */
@@ -187,6 +191,29 @@ export interface IHarnessToolCall {
187
191
  finishedAt?: number;
188
192
  }
189
193
 
194
+ interface IHarnessSubtaskStreamBase {
195
+ sessionId: string;
196
+ status: IHarnessStatus;
197
+ }
198
+
199
+ export type IHarnessSubtaskStream =
200
+ | (IHarnessSubtaskStreamBase & {
201
+ previewState: 'loading';
202
+ notice?: string;
203
+ })
204
+ | (IHarnessSubtaskStreamBase & {
205
+ previewState: 'ready';
206
+ messages: IHarnessMessage[];
207
+ permissions?: IHarnessPermissionRequest[];
208
+ questions?: IHarnessQuestionRequest[];
209
+ truncated?: boolean;
210
+ notice?: string;
211
+ })
212
+ | (IHarnessSubtaskStreamBase & {
213
+ previewState: 'unavailable';
214
+ notice: string;
215
+ });
216
+
190
217
  /** Detail of `harness-subtask-open`, fired when a subagent card is drilled into. */
191
218
  export interface IHarnessSubtaskOpenDetail {
192
219
  sessionId: string;
@@ -266,7 +293,7 @@ export interface IHarnessSessionMeta {
266
293
  icon?: string;
267
294
  /** Visual card state. Defaults to `normal`. */
268
295
  state?: THarnessSessionCardState;
269
- /** Independent activity signal used for idle-to-working auto-expansion. */
296
+ /** Independent activity signal for hosts that track work separately from the visual state. */
270
297
  working?: boolean;
271
298
  /** Set false for pinned, non-sortable entries such as terminals. Defaults to true. */
272
299
  draggable?: boolean;
@@ -338,10 +365,19 @@ export interface IHarnessComposerSendDetail {
338
365
  * re-assignment is idempotent) and re-render only the affected message
339
366
  * element.
340
367
  */
341
- export type THarnessStreamDelta =
368
+ export type THarnessMessageStreamDelta =
342
369
  | { type: 'text'; messageId: string; delta: string }
343
370
  | { type: 'reasoning-start'; messageId: string; partId: string; startedAt?: number }
344
371
  | { type: 'reasoning'; messageId: string; partId: string; delta: string }
345
372
  | { type: 'reasoning-end'; messageId: string; partId: string; endedAt?: number }
346
373
  | { type: 'tool-update'; messageId: string; tool: Partial<IHarnessToolCall> & { id: string } }
347
374
  | { type: 'message-end'; messageId: string; usage?: IHarnessUsage; error?: string };
375
+
376
+ /**
377
+ * A delta without `parentMessageId` addresses the outer transcript. Setting
378
+ * it routes the same update into one subtask transcript; inline recursion is
379
+ * intentionally limited to one level.
380
+ */
381
+ export type THarnessStreamDelta = THarnessMessageStreamDelta & {
382
+ parentMessageId?: string;
383
+ };
@@ -22,6 +22,8 @@ export interface IHarnessToolRenderHelpers {
22
22
  image(dataBase64: string, mimeType: string, alt?: string): TemplateResult;
23
23
  }
24
24
 
25
+ export type THarnessToolLayout = 'compact' | 'full-row' | 'subtask';
26
+
25
27
  export interface IHarnessToolDescriptor {
26
28
  /** stable kind id, e.g. 'terminal', 'file-read', 'mcp', 'unknown' */
27
29
  kind: string;
@@ -40,6 +42,8 @@ export interface IHarnessToolDescriptor {
40
42
  */
41
43
  renderBody?: (call: IHarnessToolCall, helpers: IHarnessToolRenderHelpers) => TemplateResult;
42
44
  defaultExpanded?: boolean | ((call: IHarnessToolCall) => boolean);
45
+ /** Transcript grid packing; omitted descriptors use the compact layout. */
46
+ layout?: THarnessToolLayout;
43
47
  /** styles the card with a destructive accent regardless of status */
44
48
  destructive?: boolean;
45
49
  }
@@ -81,6 +85,7 @@ const defaultDescriptors: IHarnessToolDescriptor[] = [
81
85
  return command ? `${command}${cwd ? ` — in ${cwd}` : ''}` : harnessSummaryLine(call.input);
82
86
  },
83
87
  defaultExpanded: true,
88
+ layout: 'full-row',
84
89
  },
85
90
  {
86
91
  kind: 'file-read',
@@ -111,6 +116,7 @@ const defaultDescriptors: IHarnessToolDescriptor[] = [
111
116
  return harnessSummaryLine(call.input);
112
117
  },
113
118
  defaultExpanded: true,
119
+ layout: 'full-row',
114
120
  },
115
121
  {
116
122
  kind: 'file-delete',
@@ -179,6 +185,8 @@ const defaultDescriptors: IHarnessToolDescriptor[] = [
179
185
  || harnessSummaryLine(call.input);
180
186
  return call.model ? `${description} — ${call.model}` : description;
181
187
  },
188
+ defaultExpanded: (call) => call.subtask?.status.type === 'busy',
189
+ layout: 'subtask',
182
190
  },
183
191
  {
184
192
  kind: 'question',
@@ -282,6 +290,10 @@ export class DeesHarnessToolRegistry {
282
290
  return this.resolve({ id: '', name, status: 'completed' }).kind;
283
291
  }
284
292
 
293
+ public resolveLayout(call: IHarnessToolCall): THarnessToolLayout {
294
+ return this.resolve(call).layout ?? 'compact';
295
+ }
296
+
285
297
  /** Isolated copy for demos, tests, or per-pane toolsets. */
286
298
  public fork(): DeesHarnessToolRegistry {
287
299
  return new DeesHarnessToolRegistry(this.descriptors.map((descriptor) => ({ ...descriptor })));