@datalayer/agent-runtimes 1.5.33 → 1.5.34

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.
@@ -0,0 +1,17 @@
1
+ /**
2
+ * What a coding agent changed in one file, as a unified diff (SHIELD §4.3,
3
+ * SH-16): the path and the count in the header, each line signed and
4
+ * coloured, the file's language on the block for a highlighter. What it
5
+ * reads is `portable/displays`' (`protocolDisplayOf`, `unifiedDiffLines`),
6
+ * so the phone draws the same thing from the same contract.
7
+ *
8
+ * @module apps/plugins/shield-displays/DiffCard
9
+ */
10
+ import type { JSX } from 'react';
11
+ import { type ProtocolDisplay } from '../../../portable';
12
+ export type DiffCardProps = {
13
+ display: Extract<ProtocolDisplay, {
14
+ kind: 'diff';
15
+ }>;
16
+ };
17
+ export declare function DiffCard({ display }: DiffCardProps): JSX.Element;
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text } from '@primer/react';
3
+ import { Box } from '@datalayer/primer-addons';
4
+ import { displayLine, unifiedDiffLines, } from '../../../portable';
5
+ const COLOURS = {
6
+ context: { bg: 'transparent', fg: 'fg.muted', sign: ' ' },
7
+ add: { bg: 'success.subtle', fg: 'success.fg', sign: '+' },
8
+ remove: { bg: 'danger.subtle', fg: 'danger.fg', sign: '-' },
9
+ };
10
+ export function DiffCard({ display }) {
11
+ const lines = unifiedDiffLines(display.oldText, display.newText);
12
+ return (_jsxs(Box, { "data-shield-display": "diff", "data-language": display.language, sx: {
13
+ width: '100%',
14
+ border: '1px solid',
15
+ borderColor: 'border.default',
16
+ borderRadius: 2,
17
+ overflow: 'hidden',
18
+ fontSize: 0,
19
+ }, children: [_jsxs(Box, { sx: {
20
+ px: 2,
21
+ py: 1,
22
+ bg: 'canvas.subtle',
23
+ borderBottom: '1px solid',
24
+ borderColor: 'border.default',
25
+ display: 'flex',
26
+ justifyContent: 'space-between',
27
+ }, children: [_jsx(Text, { sx: { fontFamily: 'mono', fontWeight: 'bold' }, children: display.path }), _jsx(Text, { sx: { color: 'fg.muted' }, children: displayLine(display) })] }), _jsx(Box, { as: "pre", className: `language-${display.language}`, sx: { m: 0, overflowX: 'auto', fontFamily: 'mono' }, children: lines.map((line, index) => (_jsxs(Box, { as: "span", "data-diff-line": line.kind, sx: {
28
+ display: 'block',
29
+ px: 2,
30
+ bg: COLOURS[line.kind].bg,
31
+ color: COLOURS[line.kind].fg,
32
+ whiteSpace: 'pre',
33
+ }, children: [COLOURS[line.kind].sign, line.text] }, index))) })] }));
34
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * What a coding agent ran (SHIELD §4.3, SH-16): the command in the header,
3
+ * the output kept after the terminal was released, and how it ended — the
4
+ * exit code, or *running* while it runs. What it reads is
5
+ * `portable/displays`' (`protocolDisplayOf`), the phone's contract too.
6
+ *
7
+ * @module apps/plugins/shield-displays/TerminalCard
8
+ */
9
+ import type { JSX } from 'react';
10
+ import { type ProtocolDisplay } from '../../../portable';
11
+ export type TerminalCardProps = {
12
+ display: Extract<ProtocolDisplay, {
13
+ kind: 'terminal';
14
+ }>;
15
+ };
16
+ export declare function TerminalCard({ display }: TerminalCardProps): JSX.Element;
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Text } from '@primer/react';
3
+ import { Box } from '@datalayer/primer-addons';
4
+ import { displayLine } from '../../../portable';
5
+ export function TerminalCard({ display }) {
6
+ const failed = display.exitCode !== null && display.exitCode !== 0;
7
+ return (_jsxs(Box, { "data-shield-display": "terminal", "data-exit-code": display.exitCode === null ? 'running' : display.exitCode, sx: {
8
+ width: '100%',
9
+ border: '1px solid',
10
+ borderColor: failed ? 'danger.muted' : 'border.default',
11
+ borderRadius: 2,
12
+ overflow: 'hidden',
13
+ fontSize: 0,
14
+ }, children: [_jsxs(Box, { sx: {
15
+ px: 2,
16
+ py: 1,
17
+ bg: 'canvas.subtle',
18
+ borderBottom: '1px solid',
19
+ borderColor: 'border.default',
20
+ display: 'flex',
21
+ justifyContent: 'space-between',
22
+ }, children: [_jsx(Text, { sx: { fontFamily: 'mono', fontWeight: 'bold' }, children: display.command ? `$ ${display.command}` : display.terminalId }), _jsx(Text, { sx: { color: failed ? 'danger.fg' : 'fg.muted' }, children: displayLine(display) })] }), _jsx(Box, { as: "pre", sx: {
23
+ m: 0,
24
+ px: 2,
25
+ py: 1,
26
+ overflowX: 'auto',
27
+ fontFamily: 'mono',
28
+ whiteSpace: 'pre-wrap',
29
+ bg: 'canvas.default',
30
+ }, children: display.output || (display.exitCode === null ? '…' : '(no output)') })] }));
31
+ }
@@ -0,0 +1,9 @@
1
+ import type { ReactorPlugin } from '@datalayer/reactor';
2
+ export declare const SHIELD_DISPLAYS_PLUGIN_NAME = "@datalayer/loop-plugin-shield-displays";
3
+ /** The plugin: two renderers, no tool binding. */
4
+ export declare function createShieldDisplaysPlugin(): ReactorPlugin<Record<string, never>, unknown, unknown>;
5
+ /** The instance the preset mounts. */
6
+ export declare const ShieldDisplaysPlugin: ReactorPlugin<Record<string, never>, unknown, unknown>;
7
+ export { DiffCard, type DiffCardProps } from './DiffCard';
8
+ export { TerminalCard, type TerminalCardProps } from './TerminalCard';
9
+ export default ShieldDisplaysPlugin;
@@ -0,0 +1,63 @@
1
+ /*
2
+ * Copyright (c) 2025-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * `@datalayer/loop-plugin-shield-displays` — a coding agent's *diff* and
7
+ * *terminal*, drawn where its tool results carry them (SHIELD §4.3, SH-16).
8
+ *
9
+ * The runtime sends each beside the tool's result in
10
+ * `_meta["reactor.ui/display"]`, as every protocol display travels
11
+ * (REACTOR_UI RU-1): `application/vnd.datalayer.shield.diff+json` and
12
+ * `application/vnd.datalayer.shield.terminal+json`, typed in Python as
13
+ * `agent_runtimes.adapters.harness_displays`. This plugin contributes one
14
+ * renderer per type; it binds no tool, since a harness names its tools as it
15
+ * likes (*Edit hello.py*, *Run pytest*) and the display is what says what
16
+ * it is. The web chat and the embed mount it through the preset; the phone
17
+ * reads the same contract from `portable/displays` (MOBILE M-037).
18
+ *
19
+ * @module apps/plugins/shield-displays
20
+ */
21
+ import { createElement } from 'react';
22
+ import { contribution, definePlugin } from '@datalayer/reactor';
23
+ import { Renderers } from '@datalayer/reactor/ui';
24
+ import { defineRenderer, } from '@datalayer/reactor/ui/react';
25
+ import { protocolDisplayOf, SHIELD_DIFF_TYPE, SHIELD_TERMINAL_TYPE, } from '../../../portable';
26
+ import { DiffCard } from './DiffCard';
27
+ import { TerminalCard } from './TerminalCard';
28
+ export const SHIELD_DISPLAYS_PLUGIN_NAME = '@datalayer/loop-plugin-shield-displays';
29
+ function Diff({ display, context, }) {
30
+ const read = protocolDisplayOf(display);
31
+ if (!read || read.kind !== 'diff') {
32
+ // Does not read as a diff: the chat's own row says what it can.
33
+ return createElement('span', null, context?.defaultUI ?? display.text);
34
+ }
35
+ return createElement(DiffCard, { key: display.id, display: read });
36
+ }
37
+ function Terminal({ display, context, }) {
38
+ const read = protocolDisplayOf(display);
39
+ if (!read || read.kind !== 'terminal') {
40
+ return createElement('span', null, context?.defaultUI ?? display.text);
41
+ }
42
+ return createElement(TerminalCard, { key: display.id, display: read });
43
+ }
44
+ /** The plugin: two renderers, no tool binding. */
45
+ export function createShieldDisplaysPlugin() {
46
+ const plugin = definePlugin({
47
+ name: SHIELD_DISPLAYS_PLUGIN_NAME,
48
+ displayName: 'Diffs and terminals',
49
+ description: 'What a coding agent changed, as a unified diff, and what it ran, with its output.',
50
+ octicon: 'diff',
51
+ emoji: '\u{1F6E1}',
52
+ contributes: [
53
+ contribution(Renderers, defineRenderer({ type: SHIELD_DIFF_TYPE, component: Diff }), { id: 'shield-diff' }),
54
+ contribution(Renderers, defineRenderer({ type: SHIELD_TERMINAL_TYPE, component: Terminal }), { id: 'shield-terminal' }),
55
+ ],
56
+ });
57
+ return plugin;
58
+ }
59
+ /** The instance the preset mounts. */
60
+ export const ShieldDisplaysPlugin = createShieldDisplaysPlugin();
61
+ export { DiffCard } from './DiffCard';
62
+ export { TerminalCard } from './TerminalCard';
63
+ export default ShieldDisplaysPlugin;
@@ -40,6 +40,7 @@ import { ChatPlugin, } from './plugins/chat';
40
40
  import { ChatHeaderPlugin } from './plugins/chat-header';
41
41
  import { A2uiSurfacePlugin } from './plugins/a2ui-surface';
42
42
  import { PapSignInPlugin } from './plugins/pap-sign-in';
43
+ import { ShieldDisplaysPlugin } from './plugins/shield-displays';
43
44
  import { ChatViewPlugin } from './plugins/chat-view';
44
45
  import { DocumentViewPlugin } from './plugins/document-view';
45
46
  import { InputPromptPlugin } from './plugins/input-prompt';
@@ -109,6 +110,9 @@ export function loopPlugins(options = {}) {
109
110
  // *Sign in at a company*, where the gateway's `pap_sign_in` answers: its
110
111
  // own renderer and binding, beside the surfaces rather than inside them.
111
112
  PapSignInPlugin,
113
+ // A coding agent's diff and terminal, where its tool results carry them
114
+ // (SHIELD §4.3): two renderers, no binding — the display says what it is.
115
+ ShieldDisplaysPlugin,
112
116
  // One footer icon per view, in the composer where the writing hand
113
117
  // already is. Each editor's icon withdraws while its editor is not
114
118
  // contributed, so mounting these unconditionally costs an absent editor
@@ -18,6 +18,11 @@
18
18
  * where the conversation stands — participation.
19
19
  * - **A handoff** (`pap_handoff`'s answer): handed to the company's people,
20
20
  * or why not.
21
+ * - **A diff** (`…shield.diff+json`, SHIELD §4.3): what a coding agent
22
+ * changed in one file — its path, what it held, what it holds now, the
23
+ * file's language — drawn as a unified diff (`unifiedDiffLines`).
24
+ * - **A terminal** (`…shield.terminal+json`): what it ran — the command, the
25
+ * output kept after release, the exit code.
21
26
  *
22
27
  * Anything else — an unknown type, a known one whose data does not read — is
23
28
  * `unknown`: its type, version and model-safe text, nothing drawn from its
@@ -30,6 +35,8 @@ export declare const PAP_SIGN_IN_TYPE = "application/vnd.datalayer.pap.sign-in+j
30
35
  export declare const PAP_CONFIRM_TYPE = "application/vnd.datalayer.pap.confirm+json";
31
36
  export declare const PAP_OUTCOME_TYPE = "application/vnd.datalayer.pap.outcome+json";
32
37
  export declare const PAP_REPLIES_TYPE = "application/vnd.datalayer.pap.replies+json";
38
+ export declare const SHIELD_DIFF_TYPE = "application/vnd.datalayer.shield.diff+json";
39
+ export declare const SHIELD_TERMINAL_TYPE = "application/vnd.datalayer.shield.terminal+json";
33
40
  /** Where a tool result carries its display for the page. */
34
41
  export declare const DISPLAY_META_KEY = "reactor.ui/display";
35
42
  /** What confirming an operation does, as an application's Rules class it. */
@@ -86,6 +93,27 @@ export type ProtocolDisplay = ({
86
93
  handed: boolean;
87
94
  responder: 'agent' | 'human' | null;
88
95
  note: string;
96
+ } | {
97
+ kind: 'diff';
98
+ id: string;
99
+ /** The file, as the agent named it, relative to its workspace. */
100
+ path: string;
101
+ /** What it held; `null` for a file that did not exist. */
102
+ oldText: string | null;
103
+ newText: string;
104
+ /** A highlighter's language name, from the file's suffix (`text` when none). */
105
+ language: string;
106
+ } | {
107
+ kind: 'terminal';
108
+ id: string;
109
+ terminalId: string;
110
+ /** What it ran, when known. */
111
+ command: string;
112
+ /** The output, kept after the terminal was released. */
113
+ output: string;
114
+ /** `null` while it runs. */
115
+ exitCode: number | null;
116
+ released: boolean;
89
117
  } | {
90
118
  kind: 'unknown';
91
119
  id: string;
@@ -107,3 +135,22 @@ export declare function displayOfToolResult(toolName: string, result: unknown, i
107
135
  export declare function displayLine(display: ProtocolDisplay): string;
108
136
  /** Who wrote a reply, said apart from the person's words and the agent's summaries (PAP-7.8-01). */
109
137
  export declare const replyAuthor: (company: string, sender: "agent" | "human") => string;
138
+ /** The language a file's suffix says, for highlighting; `text` when none. */
139
+ export declare function languageOf(path: string): string;
140
+ /** One line of a unified diff: kept, added or removed. */
141
+ export type DiffLine = {
142
+ kind: 'context' | 'add' | 'remove';
143
+ text: string;
144
+ };
145
+ /** Over this many lines on a side, the diff is shown whole (all removed, all added), not computed. */
146
+ export declare const DIFF_LINES_LIMIT = 2000;
147
+ /**
148
+ * The lines of a unified diff between what a file held and what it holds,
149
+ * by a longest common subsequence of lines; a file over `DIFF_LINES_LIMIT`
150
+ * lines on a side is shown removed and added whole.
151
+ */
152
+ export declare function unifiedDiffLines(oldText: string | null, newText: string): DiffLine[];
153
+ /** The unified diff as text (`--- a/path`, `+++ b/path`, one sign per line), as a terminal shows it. */
154
+ export declare function unifiedDiffText(display: Extract<ProtocolDisplay, {
155
+ kind: 'diff';
156
+ }>): string;
@@ -22,6 +22,11 @@
22
22
  * where the conversation stands — participation.
23
23
  * - **A handoff** (`pap_handoff`'s answer): handed to the company's people,
24
24
  * or why not.
25
+ * - **A diff** (`…shield.diff+json`, SHIELD §4.3): what a coding agent
26
+ * changed in one file — its path, what it held, what it holds now, the
27
+ * file's language — drawn as a unified diff (`unifiedDiffLines`).
28
+ * - **A terminal** (`…shield.terminal+json`): what it ran — the command, the
29
+ * output kept after release, the exit code.
25
30
  *
26
31
  * Anything else — an unknown type, a known one whose data does not read — is
27
32
  * `unknown`: its type, version and model-safe text, nothing drawn from its
@@ -34,6 +39,8 @@ export const PAP_SIGN_IN_TYPE = 'application/vnd.datalayer.pap.sign-in+json';
34
39
  export const PAP_CONFIRM_TYPE = 'application/vnd.datalayer.pap.confirm+json';
35
40
  export const PAP_OUTCOME_TYPE = 'application/vnd.datalayer.pap.outcome+json';
36
41
  export const PAP_REPLIES_TYPE = 'application/vnd.datalayer.pap.replies+json';
42
+ export const SHIELD_DIFF_TYPE = 'application/vnd.datalayer.shield.diff+json';
43
+ export const SHIELD_TERMINAL_TYPE = 'application/vnd.datalayer.shield.terminal+json';
37
44
  /** Where a tool result carries its display for the page. */
38
45
  export const DISPLAY_META_KEY = 'reactor.ui/display';
39
46
  const record = (value) => value && typeof value === 'object' && !Array.isArray(value)
@@ -185,6 +192,46 @@ export function protocolDisplayOf(wire) {
185
192
  responder: who(data.responder),
186
193
  };
187
194
  }
195
+ case SHIELD_DIFF_TYPE: {
196
+ const path = words(data.path);
197
+ if (!path ||
198
+ typeof data.new_text !== 'string' ||
199
+ !(data.old_text === null ||
200
+ data.old_text === undefined ||
201
+ typeof data.old_text === 'string')) {
202
+ return unknown;
203
+ }
204
+ return {
205
+ kind: 'diff',
206
+ id,
207
+ path,
208
+ oldText: typeof data.old_text === 'string' ? data.old_text : null,
209
+ newText: data.new_text,
210
+ language: words(data.language) || languageOf(path),
211
+ };
212
+ }
213
+ case SHIELD_TERMINAL_TYPE: {
214
+ const terminalId = words(data.terminal_id);
215
+ if (!terminalId)
216
+ return unknown;
217
+ const exitCode = typeof data.exit_code === 'number' && Number.isInteger(data.exit_code)
218
+ ? data.exit_code
219
+ : null;
220
+ if (data.exit_code !== null &&
221
+ data.exit_code !== undefined &&
222
+ exitCode === null) {
223
+ return unknown;
224
+ }
225
+ return {
226
+ kind: 'terminal',
227
+ id,
228
+ terminalId,
229
+ command: text(data.command),
230
+ output: text(data.output),
231
+ exitCode,
232
+ released: data.released === true,
233
+ };
234
+ }
188
235
  default:
189
236
  return unknown;
190
237
  }
@@ -245,6 +292,21 @@ export function displayLine(display) {
245
292
  return display.handed
246
293
  ? `Handed to ${display.responder === 'human' ? 'one of the company’s people' : 'the company'}`
247
294
  : display.note || 'Nothing was handed over.';
295
+ case 'diff': {
296
+ const added = countLines(display.newText);
297
+ if (display.oldText === null) {
298
+ return `Wrote ${display.path} (${added} lines)`;
299
+ }
300
+ return `Changed ${display.path} (+${added} −${countLines(display.oldText)} lines)`;
301
+ }
302
+ case 'terminal': {
303
+ const what = display.command
304
+ ? `Ran \`${display.command}\``
305
+ : `Terminal ${display.terminalId}`;
306
+ return display.exitCode === null
307
+ ? `${what}: running`
308
+ : `${what}: exit ${display.exitCode}`;
309
+ }
248
310
  case 'unknown':
249
311
  return display.text || `A display this app cannot draw (${display.type})`;
250
312
  }
@@ -259,3 +321,111 @@ const OUTCOME_LEADS = {
259
321
  export const replyAuthor = (company, sender) => sender === 'human'
260
322
  ? `${company}, one of its people`
261
323
  : `${company}, its agent`;
324
+ // -- a diff and a terminal (SHIELD §4.3, SH-16) ------------------------------------
325
+ const countLines = (value) => value === '' ? 0 : value.split('\n').length - (value.endsWith('\n') ? 1 : 0);
326
+ /** A file's language from its suffix, the same table the runtime uses. */
327
+ const LANGUAGES = {
328
+ py: 'python',
329
+ pyi: 'python',
330
+ ts: 'typescript',
331
+ tsx: 'tsx',
332
+ js: 'javascript',
333
+ jsx: 'jsx',
334
+ mjs: 'javascript',
335
+ json: 'json',
336
+ md: 'markdown',
337
+ mdx: 'markdown',
338
+ yaml: 'yaml',
339
+ yml: 'yaml',
340
+ toml: 'toml',
341
+ sh: 'bash',
342
+ bash: 'bash',
343
+ css: 'css',
344
+ scss: 'scss',
345
+ html: 'html',
346
+ xml: 'xml',
347
+ sql: 'sql',
348
+ rs: 'rust',
349
+ go: 'go',
350
+ java: 'java',
351
+ c: 'c',
352
+ h: 'c',
353
+ cpp: 'cpp',
354
+ rb: 'ruby',
355
+ ipynb: 'json',
356
+ txt: 'text',
357
+ };
358
+ /** The language a file's suffix says, for highlighting; `text` when none. */
359
+ export function languageOf(path) {
360
+ const name = path.split('/').pop() ?? '';
361
+ if (name === 'Dockerfile' || name === 'Makefile')
362
+ return name.toLowerCase();
363
+ const dot = name.lastIndexOf('.');
364
+ return dot > 0
365
+ ? (LANGUAGES[name.slice(dot + 1).toLowerCase()] ?? 'text')
366
+ : 'text';
367
+ }
368
+ /** Over this many lines on a side, the diff is shown whole (all removed, all added), not computed. */
369
+ export const DIFF_LINES_LIMIT = 2000;
370
+ const lines = (value) => value === '' ? [] : value.replace(/\n$/, '').split('\n');
371
+ /**
372
+ * The lines of a unified diff between what a file held and what it holds,
373
+ * by a longest common subsequence of lines; a file over `DIFF_LINES_LIMIT`
374
+ * lines on a side is shown removed and added whole.
375
+ */
376
+ export function unifiedDiffLines(oldText, newText) {
377
+ const before = oldText === null ? [] : lines(oldText);
378
+ const after = lines(newText);
379
+ if (before.length > DIFF_LINES_LIMIT || after.length > DIFF_LINES_LIMIT) {
380
+ return [
381
+ ...before.map(text => ({ kind: 'remove', text })),
382
+ ...after.map(text => ({ kind: 'add', text })),
383
+ ];
384
+ }
385
+ // The LCS table, one row per line of `before`.
386
+ const table = [];
387
+ for (let i = 0; i <= before.length; i++) {
388
+ table.push(new Uint32Array(after.length + 1));
389
+ }
390
+ for (let i = before.length - 1; i >= 0; i--) {
391
+ for (let j = after.length - 1; j >= 0; j--) {
392
+ table[i][j] =
393
+ before[i] === after[j]
394
+ ? table[i + 1][j + 1] + 1
395
+ : Math.max(table[i + 1][j], table[i][j + 1]);
396
+ }
397
+ }
398
+ const out = [];
399
+ let i = 0;
400
+ let j = 0;
401
+ while (i < before.length && j < after.length) {
402
+ if (before[i] === after[j]) {
403
+ out.push({ kind: 'context', text: before[i] });
404
+ i++;
405
+ j++;
406
+ }
407
+ else if (table[i + 1][j] >= table[i][j + 1]) {
408
+ out.push({ kind: 'remove', text: before[i] });
409
+ i++;
410
+ }
411
+ else {
412
+ out.push({ kind: 'add', text: after[j] });
413
+ j++;
414
+ }
415
+ }
416
+ while (i < before.length)
417
+ out.push({ kind: 'remove', text: before[i++] });
418
+ while (j < after.length)
419
+ out.push({ kind: 'add', text: after[j++] });
420
+ return out;
421
+ }
422
+ /** The unified diff as text (`--- a/path`, `+++ b/path`, one sign per line), as a terminal shows it. */
423
+ export function unifiedDiffText(display) {
424
+ const from = display.oldText === null ? '/dev/null' : `a/${display.path}`;
425
+ const signs = { context: ' ', add: '+', remove: '-' };
426
+ return [
427
+ `--- ${from}`,
428
+ `+++ b/${display.path}`,
429
+ ...unifiedDiffLines(display.oldText, display.newText).map(line => `${signs[line.kind]}${line.text}`),
430
+ ].join('\n');
431
+ }
@@ -8,4 +8,13 @@
8
8
  */
9
9
  import { type ConversationState } from './conversation';
10
10
  /** A fresh copy of the fixture conversation. */
11
+ /**
12
+ * A coding agent's diff and terminal, as the runtime sends them beside a tool
13
+ * result (`_meta["reactor.ui/display"]`, SHIELD §4.3, SH-16): what the phone
14
+ * draws for MOBILE M-037, read by `protocolDisplayOf`.
15
+ */
16
+ export declare function shieldDisplayFixtures(): {
17
+ diff: Record<string, unknown>;
18
+ terminal: Record<string, unknown>;
19
+ };
11
20
  export declare function conversationFixture(): ConversationState;
@@ -13,6 +13,42 @@
13
13
  import { emptyConversation } from './conversation';
14
14
  import { RUN_END_WORDS } from './records';
15
15
  /** A fresh copy of the fixture conversation. */
16
+ /**
17
+ * A coding agent's diff and terminal, as the runtime sends them beside a tool
18
+ * result (`_meta["reactor.ui/display"]`, SHIELD §4.3, SH-16): what the phone
19
+ * draws for MOBILE M-037, read by `protocolDisplayOf`.
20
+ */
21
+ export function shieldDisplayFixtures() {
22
+ return {
23
+ diff: {
24
+ type: 'application/vnd.datalayer.shield.diff+json',
25
+ version: 1,
26
+ id: 'c1-diff',
27
+ text: 'Changed hello.py (+2 −1 lines)',
28
+ data: {
29
+ path: 'hello.py',
30
+ old_text: 'print("hi")\n',
31
+ new_text: 'def hello():\n print("hi, shield")\n',
32
+ language: 'python',
33
+ },
34
+ actions: [],
35
+ },
36
+ terminal: {
37
+ type: 'application/vnd.datalayer.shield.terminal+json',
38
+ version: 1,
39
+ id: 'c3-terminal',
40
+ text: 'Ran `pytest -q`: exit 0',
41
+ data: {
42
+ terminal_id: 'term_1',
43
+ command: 'pytest -q',
44
+ output: '3 passed in 0.12s\n',
45
+ exit_code: 0,
46
+ released: true,
47
+ },
48
+ actions: [],
49
+ },
50
+ };
51
+ }
16
52
  export function conversationFixture() {
17
53
  return {
18
54
  ...emptyConversation(),
@@ -17,7 +17,8 @@ export { conversationEventsOf, sanitizeAssistantContent, snapshotOfMessages, typ
17
17
  export { PRESENCE_LINES, presenceOfConversation, presenceState, presenceToolOf, type PresenceState, type PresenceTool, } from './presence';
18
18
  export { ANSWER_BELOW, ANSWER_COMPLETE, composerOf, droppedWords, ENDED_WORDS, messageLabel, OPENING_WORDS, presenceLine, showsQuestion, stepLine, TOOL_STATUS_WORDS, toolLabel, type ComposerProps, type ComposerState, type ConversationViewProps, type ErrorItem, type ErrorRowProps, type MessageItem, type MessageRowProps, type PresenceLineProps, type ProtocolDisplayProps, type QuestionCardProps, type StepItem, type StepRowProps, type ToolItem, type ToolRowProps, type TurnEndItem, type TurnEndRowProps, } from './views';
19
19
  export { conversationFixture } from './fixtures';
20
- export { DISPLAY_META_KEY, displayLine, displayOfToolResult, PAP_CONFIRM_TYPE, PAP_HANDOFF_TOOL, PAP_OUTCOME_TYPE, PAP_REPLIES_TYPE, PAP_SIGN_IN_TYPE, protocolDisplayOf, replyAuthor, type ActionClass, type ProtocolDisplay, } from './displays';
20
+ export { DISPLAY_META_KEY, displayLine, displayOfToolResult, PAP_CONFIRM_TYPE, PAP_HANDOFF_TOOL, PAP_OUTCOME_TYPE, PAP_REPLIES_TYPE, PAP_SIGN_IN_TYPE, protocolDisplayOf, replyAuthor, type ActionClass, type ProtocolDisplay, DIFF_LINES_LIMIT, SHIELD_DIFF_TYPE, SHIELD_TERMINAL_TYPE, languageOf, unifiedDiffLines, unifiedDiffText, type DiffLine, } from './displays';
21
+ export { shieldDisplayFixtures } from './fixtures';
21
22
  export { isPapSignInTool, PAP_SIGN_IN_WORDS, readPapSignIn, safeSignInUrl, type PapSignInWaiting, } from './signIn';
22
23
  export { DIRECT_MAX, DIRECT_WORDS, directAnswerOf, directAuthor, directClient, openDirect, withDirectAnswer, type DirectAnswer, type DirectClient, type DirectClientOptions, type DirectLine, type DirectOpen, type DirectReply, type DirectTarget, } from './direct';
23
24
  export { SIGN_IN_POLL_MS, SIGN_IN_STATUS_PATH, signInStandsOf, signInStatusClient, type SignInStands, } from './signInStatus';
@@ -29,7 +29,10 @@ export { PRESENCE_LINES, presenceOfConversation, presenceState, presenceToolOf,
29
29
  export { ANSWER_BELOW, ANSWER_COMPLETE, composerOf, droppedWords, ENDED_WORDS, messageLabel, OPENING_WORDS, presenceLine, showsQuestion, stepLine, TOOL_STATUS_WORDS, toolLabel, } from './views';
30
30
  export { conversationFixture } from './fixtures';
31
31
  // The protocol displays a run's tool results carry (MOBILE M-037).
32
- export { DISPLAY_META_KEY, displayLine, displayOfToolResult, PAP_CONFIRM_TYPE, PAP_HANDOFF_TOOL, PAP_OUTCOME_TYPE, PAP_REPLIES_TYPE, PAP_SIGN_IN_TYPE, protocolDisplayOf, replyAuthor, } from './displays';
32
+ export { DISPLAY_META_KEY, displayLine, displayOfToolResult, PAP_CONFIRM_TYPE, PAP_HANDOFF_TOOL, PAP_OUTCOME_TYPE, PAP_REPLIES_TYPE, PAP_SIGN_IN_TYPE, protocolDisplayOf, replyAuthor,
33
+ // A coding agent's diff and terminal (SHIELD §4.3, SH-16).
34
+ DIFF_LINES_LIMIT, SHIELD_DIFF_TYPE, SHIELD_TERMINAL_TYPE, languageOf, unifiedDiffLines, unifiedDiffText, } from './displays';
35
+ export { shieldDisplayFixtures } from './fixtures';
33
36
  export { isPapSignInTool, PAP_SIGN_IN_WORDS, readPapSignIn, safeSignInUrl, } from './signIn';
34
37
  // A Direct Conversation the person types in themselves (PAP_DATALAYER P-08, MOBILE M-038).
35
38
  export { DIRECT_MAX, DIRECT_WORDS, directAnswerOf, directAuthor, directClient, openDirect, withDirectAnswer, } from './direct';
@@ -61,7 +61,9 @@ export type QuestionCardProps = {
61
61
  };
62
62
  /**
63
63
  * A protocol display under its tool row (MOBILE M-037): what it shows is
64
- * `displayLine`'s and the display's own; what the person does goes out
64
+ * `displayLine`'s and the display's own — a coding agent's `diff` as a
65
+ * unified diff in the file's language (`unifiedDiffLines`), its `terminal`
66
+ * as the command and the output kept (SHIELD §4.3); what the person does goes out
65
67
  * through the host — a sign-in page opened outside the conversation, an
66
68
  * operation answered where approvals are, *I have signed in* said as their
67
69
  * next message. Nothing is answered from the card itself.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/agent-runtimes",
3
- "version": "1.5.33",
3
+ "version": "1.5.34",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",