@opengeni/react 1.4.2 → 1.4.5-canary.37458084490001
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/README.md +17 -6
- package/dist/artifacts.d.ts +1 -0
- package/dist/artifacts.js +22 -15
- package/dist/artifacts.js.map +1 -1
- package/dist/{browser-viewer-WGJ43YGI.js → browser-viewer-CV23VIHB.js} +8 -6
- package/dist/chunk-3ZC6QPOM.js +174 -0
- package/dist/chunk-3ZC6QPOM.js.map +1 -0
- package/dist/{chunk-YVFRBXST.js → chunk-4BCVCJSU.js} +2 -2
- package/dist/{chunk-JHTIMBOL.js → chunk-5JSUNNQN.js} +26 -4
- package/dist/{chunk-JHTIMBOL.js.map → chunk-5JSUNNQN.js.map} +1 -1
- package/dist/{chunk-MDIXFKA3.js → chunk-6FOTSVWU.js} +303 -109
- package/dist/chunk-6FOTSVWU.js.map +1 -0
- package/dist/{chunk-IUHHPMAX.js → chunk-7RRBX5EM.js} +14 -85
- package/dist/chunk-7RRBX5EM.js.map +1 -0
- package/dist/{chunk-L2J3PU7A.js → chunk-7ZB7I3KP.js} +24 -98
- package/dist/chunk-7ZB7I3KP.js.map +1 -0
- package/dist/{chunk-LVS3MH5T.js → chunk-ATIRUHBZ.js} +128 -10
- package/dist/chunk-ATIRUHBZ.js.map +1 -0
- package/dist/chunk-BOFEQC6K.js +162 -0
- package/dist/chunk-BOFEQC6K.js.map +1 -0
- package/dist/{chunk-VCSERYXH.js → chunk-CESBPQP5.js} +309 -162
- package/dist/chunk-CESBPQP5.js.map +1 -0
- package/dist/{chunk-IYQCWGU5.js → chunk-GHJU7XG7.js} +35 -62
- package/dist/chunk-GHJU7XG7.js.map +1 -0
- package/dist/{chunk-G6YRCIYJ.js → chunk-HNVWMDNN.js} +55 -60
- package/dist/chunk-HNVWMDNN.js.map +1 -0
- package/dist/{chunk-PHBFJCEU.js → chunk-I5EGRXXG.js} +110 -7
- package/dist/chunk-I5EGRXXG.js.map +1 -0
- package/dist/{chunk-PBCZL4JP.js → chunk-INIZSNXT.js} +2 -2
- package/dist/{chunk-XS67YG5R.js → chunk-IX3K4THH.js} +24 -3
- package/dist/chunk-IX3K4THH.js.map +1 -0
- package/dist/chunk-IZV5FTJC.js +55 -0
- package/dist/chunk-IZV5FTJC.js.map +1 -0
- package/dist/chunk-JDJJMBB3.js +1883 -0
- package/dist/chunk-JDJJMBB3.js.map +1 -0
- package/dist/{chunk-C5BF4L26.js → chunk-KHF2VRXF.js} +7 -7
- package/dist/{chunk-QMMCJGFI.js → chunk-L5OKM2VX.js} +2 -2
- package/dist/chunk-LHF6BVM4.js +83 -0
- package/dist/chunk-LHF6BVM4.js.map +1 -0
- package/dist/chunk-N7S72EXK.js +25 -0
- package/dist/chunk-N7S72EXK.js.map +1 -0
- package/dist/{chunk-CVYCLFMH.js → chunk-PEHTX3V7.js} +19 -1
- package/dist/chunk-PEHTX3V7.js.map +1 -0
- package/dist/chunk-R5R5RQQD.js +51 -0
- package/dist/chunk-R5R5RQQD.js.map +1 -0
- package/dist/chunk-RI42H5IU.js +326 -0
- package/dist/chunk-RI42H5IU.js.map +1 -0
- package/dist/{chunk-JH7V627O.js → chunk-SHLZMAJN.js} +2 -11
- package/dist/chunk-SHLZMAJN.js.map +1 -0
- package/dist/{chunk-CREMJMVN.js → chunk-TZQSHCZN.js} +692 -1996
- package/dist/chunk-TZQSHCZN.js.map +1 -0
- package/dist/chunk-ZIB4H5LN.js +101 -0
- package/dist/chunk-ZIB4H5LN.js.map +1 -0
- package/dist/client.d.ts +9 -3
- package/dist/clipboard.js +1 -1
- package/dist/components/browser-viewer.d.ts +6 -0
- package/dist/components/composer.d.ts +3 -69
- package/dist/components/human-input-form.d.ts +3 -32
- package/dist/components/markdown.d.ts +8 -0
- package/dist/components/model-policy-picker.d.ts +4 -37
- package/dist/components/opper-mark.d.ts +7 -0
- package/dist/components/provider-recovery-notice.d.ts +15 -0
- package/dist/components/remark-soft-line-breaks.d.ts +38 -0
- package/dist/components/sandbox-workspace.d.ts +13 -0
- package/dist/components/session-chrome.d.ts +5 -3
- package/dist/components/session-conversation.d.ts +15 -3
- package/dist/composer-messages.d.ts +74 -0
- package/dist/composer-messages.js +9 -0
- package/dist/composer.js +15 -10
- package/dist/{computer-viewer-46UIN7F3.js → computer-viewer-K4CKYRX6.js} +4 -4
- package/dist/connect-setup.d.ts +2 -0
- package/dist/connect.d.ts +1 -1
- package/dist/connect.js +21 -6
- package/dist/connect.js.map +1 -1
- package/dist/{embedded-voice-NIL4RDX3.js → embedded-voice-3ZFWWJ6O.js} +6 -4
- package/dist/{embedded-voice-NIL4RDX3.js.map → embedded-voice-3ZFWWJ6O.js.map} +1 -1
- package/dist/hooks/shared-machines-list.d.ts +4 -0
- package/dist/hooks/use-client-config-flags.d.ts +6 -0
- package/dist/hooks/use-computer-session.d.ts +2 -0
- package/dist/hooks/use-goal.d.ts +2 -1
- package/dist/human-input-model.d.ts +40 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +116 -73
- package/dist/index.js.map +1 -1
- package/dist/interaction.js +5 -5
- package/dist/{latest-question-2POFPYNB.js → latest-question-SWC6QEVN.js} +3 -3
- package/dist/lib/clipboard.d.ts +7 -0
- package/dist/lib/provider-recovery.d.ts +49 -0
- package/dist/machines.js +2 -2
- package/dist/model-mark-paths.d.ts +34 -0
- package/dist/model-mark-paths.js +16 -0
- package/dist/model-picker-model.d.ts +111 -0
- package/dist/model-picker-model.js +25 -0
- package/dist/model-picker-model.js.map +1 -0
- package/dist/{model-policy-picker-menu-WRNSRFQC.js → model-policy-picker-menu-NM4RPTY6.js} +6 -4
- package/dist/model-policy-picker-menu-NM4RPTY6.js.map +1 -0
- package/dist/model-policy.d.ts +10 -0
- package/dist/model-policy.js +5 -1
- package/dist/organization-model.d.ts +32 -0
- package/dist/organization-model.js +65 -0
- package/dist/organization-model.js.map +1 -0
- package/dist/{platform-activity-row-PJJVATTZ.js → platform-activity-row-NJ47YBXW.js} +7 -84
- package/dist/platform-activity-row-NJ47YBXW.js.map +1 -0
- package/dist/queue-presentation-model.d.ts +72 -0
- package/dist/queue-presentation-model.js +38 -0
- package/dist/queue-presentation-model.js.map +1 -0
- package/dist/{queue-surface-implementation-67FS7FUI.js → queue-surface-implementation-YPJFQ3O6.js} +24 -252
- package/dist/queue-surface-implementation-YPJFQ3O6.js.map +1 -0
- package/dist/realtime.js +5 -3
- package/dist/{sandbox-files-34CJJNOY.js → sandbox-files-RCVCMXG7.js} +5 -5
- package/dist/sandbox-files-RCVCMXG7.js.map +1 -0
- package/dist/sandbox-label-model.d.ts +23 -0
- package/dist/sandbox-label-model.js +28 -0
- package/dist/sandbox-label-model.js.map +1 -0
- package/dist/session-attention-model.d.ts +8 -0
- package/dist/session-attention-model.js +46 -0
- package/dist/session-attention-model.js.map +1 -0
- package/dist/session-feedback-model.d.ts +20 -0
- package/dist/session-feedback-model.js +56 -0
- package/dist/session-feedback-model.js.map +1 -0
- package/dist/session-list-model.d.ts +96 -0
- package/dist/session-list-model.js +219 -0
- package/dist/session-list-model.js.map +1 -0
- package/dist/session-status-model.d.ts +19 -0
- package/dist/session-ui.js +26 -17
- package/dist/session-ui.js.map +1 -1
- package/dist/session.js +8 -6
- package/dist/testing/session-scenarios.d.ts +10 -0
- package/dist/testing/session-scenarios.js +303 -0
- package/dist/testing/session-scenarios.js.map +1 -0
- package/dist/timeline/genie-copy.d.ts +3 -0
- package/dist/timeline/genie-loading.d.ts +11 -0
- package/dist/timeline/index.d.ts +1 -1
- package/dist/timeline/notice-presentation.d.ts +7 -0
- package/dist/timeline/patch-apply-command.d.ts +18 -0
- package/dist/timeline/platform-activity-presentation.d.ts +7 -0
- package/dist/timeline/presented-image.d.ts +6 -1
- package/dist/timeline/question-nav-model.d.ts +23 -0
- package/dist/timeline/registry.d.ts +10 -1
- package/dist/timeline/retained-loaders.d.ts +1 -1
- package/dist/timeline/tool-presentation.d.ts +172 -0
- package/dist/timeline/turn-summary-model.d.ts +90 -0
- package/dist/timeline/turn-summary.d.ts +4 -74
- package/dist/timeline/work-presentation.d.ts +42 -0
- package/dist/timeline-model.d.ts +24 -0
- package/dist/timeline-model.js +152 -0
- package/dist/timeline-model.js.map +1 -0
- package/package.json +47 -3
- package/src/artifacts.ts +1 -0
- package/src/client.ts +9 -3
- package/src/components/browser-viewer.tsx +23 -2
- package/src/components/claude-mark.tsx +2 -1
- package/src/components/composer.tsx +4 -144
- package/src/components/computer-viewer.tsx +139 -30
- package/src/components/grok-mark.tsx +2 -1
- package/src/components/human-input-form.tsx +13 -124
- package/src/components/markdown.tsx +19 -1
- package/src/components/message-timeline.tsx +45 -99
- package/src/components/model-mark.tsx +2 -1
- package/src/components/model-policy-picker-menu.tsx +30 -85
- package/src/components/model-policy-picker.tsx +15 -148
- package/src/components/opper-mark.tsx +18 -0
- package/src/components/provider-recovery-notice.tsx +41 -0
- package/src/components/queue-surface-implementation.tsx +20 -349
- package/src/components/remark-soft-line-breaks.ts +166 -0
- package/src/components/sandbox-workspace.tsx +17 -1
- package/src/components/session-chrome.tsx +114 -99
- package/src/components/session-conversation.tsx +55 -6
- package/src/components/session-list.tsx +1 -1
- package/src/components/session-status.tsx +17 -16
- package/src/composer-messages.ts +150 -0
- package/src/connect-setup.tsx +45 -11
- package/src/connect.ts +1 -1
- package/src/hooks/shared-machines-list.ts +34 -1
- package/src/hooks/use-browser-session.ts +445 -168
- package/src/hooks/use-client-config-flags.ts +8 -0
- package/src/hooks/use-computer-session.ts +334 -98
- package/src/hooks/use-goal.ts +66 -10
- package/src/human-input-model.ts +147 -0
- package/src/index.ts +16 -0
- package/src/lib/clipboard.ts +29 -0
- package/src/lib/format.ts +7 -0
- package/src/lib/provider-recovery.ts +202 -0
- package/src/model-mark-paths.ts +53 -0
- package/src/model-picker-model.ts +330 -0
- package/src/model-policy.ts +43 -2
- package/src/organization-model.ts +118 -0
- package/src/queue-presentation-model.ts +464 -0
- package/src/sandbox-label-model.ts +41 -0
- package/src/session-attention-model.ts +59 -0
- package/src/session-feedback-model.ts +95 -0
- package/src/session-list-model.ts +327 -0
- package/src/session-status-model.ts +62 -0
- package/src/testing/session-scenarios.ts +326 -0
- package/src/timeline/activity-rail.tsx +5 -17
- package/src/timeline/genie-copy.ts +19 -0
- package/src/timeline/genie-loading.tsx +13 -18
- package/src/timeline/index.ts +1 -0
- package/src/timeline/notice-presentation.ts +22 -0
- package/src/timeline/patch-apply-command.tsx +135 -0
- package/src/timeline/platform-activity-presentation.ts +122 -0
- package/src/timeline/platform-activity-row.tsx +6 -96
- package/src/timeline/presented-image.ts +16 -2
- package/src/timeline/question-nav-model.ts +28 -0
- package/src/timeline/registry.ts +11 -1
- package/src/timeline/retained-loaders.ts +9 -4
- package/src/timeline/rolling-activity.tsx +7 -19
- package/src/timeline/tool-presentation.ts +1316 -0
- package/src/timeline/tool-renderers.tsx +226 -1025
- package/src/timeline/turn-summary-model.ts +338 -0
- package/src/timeline/turn-summary.tsx +21 -326
- package/src/timeline/work-presentation.ts +139 -0
- package/src/timeline-model.ts +108 -0
- package/styles/compiled.css +8 -0
- package/styles/connect.css +4 -0
- package/dist/chunk-CREMJMVN.js.map +0 -1
- package/dist/chunk-CVYCLFMH.js.map +0 -1
- package/dist/chunk-G6YRCIYJ.js.map +0 -1
- package/dist/chunk-HXYOSSQO.js +0 -117
- package/dist/chunk-HXYOSSQO.js.map +0 -1
- package/dist/chunk-IUHHPMAX.js.map +0 -1
- package/dist/chunk-IYQCWGU5.js.map +0 -1
- package/dist/chunk-JH7V627O.js.map +0 -1
- package/dist/chunk-L2J3PU7A.js.map +0 -1
- package/dist/chunk-LVS3MH5T.js.map +0 -1
- package/dist/chunk-MDIXFKA3.js.map +0 -1
- package/dist/chunk-PHBFJCEU.js.map +0 -1
- package/dist/chunk-VCSERYXH.js.map +0 -1
- package/dist/chunk-XS67YG5R.js.map +0 -1
- package/dist/platform-activity-row-PJJVATTZ.js.map +0 -1
- package/dist/queue-surface-implementation-67FS7FUI.js.map +0 -1
- /package/dist/{browser-viewer-WGJ43YGI.js.map → browser-viewer-CV23VIHB.js.map} +0 -0
- /package/dist/{chunk-YVFRBXST.js.map → chunk-4BCVCJSU.js.map} +0 -0
- /package/dist/{chunk-PBCZL4JP.js.map → chunk-INIZSNXT.js.map} +0 -0
- /package/dist/{chunk-C5BF4L26.js.map → chunk-KHF2VRXF.js.map} +0 -0
- /package/dist/{chunk-QMMCJGFI.js.map → chunk-L5OKM2VX.js.map} +0 -0
- /package/dist/{computer-viewer-46UIN7F3.js.map → composer-messages.js.map} +0 -0
- /package/dist/{model-policy-picker-menu-WRNSRFQC.js.map → computer-viewer-K4CKYRX6.js.map} +0 -0
- /package/dist/{latest-question-2POFPYNB.js.map → latest-question-SWC6QEVN.js.map} +0 -0
- /package/dist/{sandbox-files-34CJJNOY.js.map → model-mark-paths.js.map} +0 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* remark: render a single newline inside prose as a line break.
|
|
3
|
+
*
|
|
4
|
+
* CommonMark folds a lone line ending inside a paragraph into a space, so an
|
|
5
|
+
* agent writing `1\n2\n3` shows "1 2 3". Chat surfaces (ChatGPT, GitHub
|
|
6
|
+
* comments) keep the line, which is what message authors expect. This plugin
|
|
7
|
+
* turns every line ending inside an mdast `text` node into a `break` node — the
|
|
8
|
+
* same result as `remark-breaks` — while leaving code (`code` / `inlineCode`
|
|
9
|
+
* carry `value`, not `text` children), raw HTML, and block structure (lists,
|
|
10
|
+
* tables, blockquotes, headings, blank-line paragraphs) untouched.
|
|
11
|
+
*
|
|
12
|
+
* Unlike `remark-breaks` (built on `mdast-util-find-and-replace`, which drops
|
|
13
|
+
* positions on the split nodes), every split text node keeps a source position.
|
|
14
|
+
* Streaming tip ink (`rehypeStreamReveal`) keys fade-in on those offsets, so a
|
|
15
|
+
* positionless line would render without ink and snap in at the stream tail.
|
|
16
|
+
*
|
|
17
|
+
* Structural local types keep the module dependency-free, like
|
|
18
|
+
* `stream-reveal.ts`; the renderer casts once at the plugin seam.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
type MdPoint = {
|
|
22
|
+
line?: number | undefined;
|
|
23
|
+
column?: number | undefined;
|
|
24
|
+
offset?: number | undefined;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
type MdPosition = { start?: MdPoint | undefined; end?: MdPoint | undefined };
|
|
28
|
+
|
|
29
|
+
type MdNode = {
|
|
30
|
+
type: string;
|
|
31
|
+
value?: string | undefined;
|
|
32
|
+
position?: MdPosition | undefined;
|
|
33
|
+
children?: MdNode[] | undefined;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
type ExactPoint = { line: number; column: number; offset: number };
|
|
37
|
+
|
|
38
|
+
const LINE_ENDING = /\r\n|\r|\n/g;
|
|
39
|
+
const HAS_LINE_ENDING = /[\r\n]/;
|
|
40
|
+
/** Line-start syntax the parser strips from text values: indentation and blockquote markers. */
|
|
41
|
+
const LINE_PREFIX = /[\t >]*/y;
|
|
42
|
+
|
|
43
|
+
export function remarkSoftLineBreaks() {
|
|
44
|
+
return (tree: MdNode, file?: { value?: unknown } | undefined) => {
|
|
45
|
+
walk(tree, typeof file?.value === "string" ? file.value : undefined);
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function walk(node: MdNode, source: string | undefined): void {
|
|
50
|
+
if (!node.children) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
let next: MdNode[] | null = null;
|
|
54
|
+
for (let index = 0; index < node.children.length; index += 1) {
|
|
55
|
+
const child = node.children[index]!;
|
|
56
|
+
if (
|
|
57
|
+
child.type === "text" &&
|
|
58
|
+
typeof child.value === "string" &&
|
|
59
|
+
HAS_LINE_ENDING.test(child.value)
|
|
60
|
+
) {
|
|
61
|
+
next ??= node.children.slice(0, index);
|
|
62
|
+
next.push(...splitText(child, child.value, source));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
walk(child, source);
|
|
66
|
+
next?.push(child);
|
|
67
|
+
}
|
|
68
|
+
if (next !== null) {
|
|
69
|
+
node.children = next;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function splitText(node: MdNode, value: string, source: string | undefined): MdNode[] {
|
|
74
|
+
const segments: { value: string; index: number }[] = [];
|
|
75
|
+
let cursor = 0;
|
|
76
|
+
for (const match of value.matchAll(LINE_ENDING)) {
|
|
77
|
+
segments.push({ value: value.slice(cursor, match.index), index: cursor });
|
|
78
|
+
cursor = match.index + match[0].length;
|
|
79
|
+
}
|
|
80
|
+
segments.push({ value: value.slice(cursor), index: cursor });
|
|
81
|
+
|
|
82
|
+
const starts = segmentStarts(node, segments, source);
|
|
83
|
+
const nodeEnd = exactPoint(node.position?.end);
|
|
84
|
+
const out: MdNode[] = [];
|
|
85
|
+
segments.forEach((segment, k) => {
|
|
86
|
+
const start = starts?.[k];
|
|
87
|
+
const isLast = k === segments.length - 1;
|
|
88
|
+
const end =
|
|
89
|
+
start === undefined
|
|
90
|
+
? undefined
|
|
91
|
+
: isLast && nodeEnd !== undefined
|
|
92
|
+
? nodeEnd
|
|
93
|
+
: {
|
|
94
|
+
line: start.line,
|
|
95
|
+
column: start.column + segment.value.length,
|
|
96
|
+
offset: start.offset + segment.value.length,
|
|
97
|
+
};
|
|
98
|
+
if (segment.value.length > 0) {
|
|
99
|
+
out.push({
|
|
100
|
+
type: "text",
|
|
101
|
+
value: segment.value,
|
|
102
|
+
...(start !== undefined && end !== undefined ? { position: { start, end } } : {}),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (!isLast) {
|
|
106
|
+
const nextStart = starts?.[k + 1];
|
|
107
|
+
out.push({
|
|
108
|
+
type: "break",
|
|
109
|
+
...(end !== undefined && nextStart !== undefined
|
|
110
|
+
? { position: { start: end, end: nextStart } }
|
|
111
|
+
: {}),
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Source start of each line segment. Text values drop each continuation line's
|
|
120
|
+
* indentation / `>` prefix, so offsets are re-anchored on the real source line
|
|
121
|
+
* when the node's source slice has the same number of line endings; otherwise
|
|
122
|
+
* (e.g. a newline produced by a character reference) fall back to the value
|
|
123
|
+
* index, the same approximation tip ink already makes within one text node.
|
|
124
|
+
*/
|
|
125
|
+
function segmentStarts(
|
|
126
|
+
node: MdNode,
|
|
127
|
+
segments: readonly { index: number }[],
|
|
128
|
+
source: string | undefined,
|
|
129
|
+
): ExactPoint[] | undefined {
|
|
130
|
+
const start = exactPoint(node.position?.start);
|
|
131
|
+
if (start === undefined) {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
const endOffset = node.position?.end?.offset;
|
|
135
|
+
const lineStarts: number[] = [];
|
|
136
|
+
if (source !== undefined && endOffset !== undefined && endOffset >= start.offset) {
|
|
137
|
+
for (const match of source.slice(start.offset, endOffset).matchAll(LINE_ENDING)) {
|
|
138
|
+
lineStarts.push(start.offset + match.index + match[0].length);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const anchoredSource = lineStarts.length === segments.length - 1 ? source : undefined;
|
|
142
|
+
return segments.map((segment, k) => {
|
|
143
|
+
if (k === 0) {
|
|
144
|
+
return start;
|
|
145
|
+
}
|
|
146
|
+
if (anchoredSource !== undefined) {
|
|
147
|
+
const lineStart = lineStarts[k - 1]!;
|
|
148
|
+
LINE_PREFIX.lastIndex = lineStart;
|
|
149
|
+
const prefix = LINE_PREFIX.exec(anchoredSource)?.[0].length ?? 0;
|
|
150
|
+
return { line: start.line + k, column: prefix + 1, offset: lineStart + prefix };
|
|
151
|
+
}
|
|
152
|
+
return { line: start.line + k, column: 1, offset: start.offset + segment.index };
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function exactPoint(point: MdPoint | undefined): ExactPoint | undefined {
|
|
157
|
+
if (
|
|
158
|
+
point === undefined ||
|
|
159
|
+
typeof point.line !== "number" ||
|
|
160
|
+
typeof point.column !== "number" ||
|
|
161
|
+
typeof point.offset !== "number"
|
|
162
|
+
) {
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
return { line: point.line, column: point.column, offset: point.offset };
|
|
166
|
+
}
|
|
@@ -293,6 +293,13 @@ export type UseSandboxWorkspaceTabsOptions = ClientOverride & {
|
|
|
293
293
|
* attachment, and navigation callbacks are not activated.
|
|
294
294
|
*/
|
|
295
295
|
surfaces?: readonly SandboxWorkspaceSurface[] | undefined;
|
|
296
|
+
/**
|
|
297
|
+
* Whether this viewer may read the workspace machine fleet
|
|
298
|
+
* (`GET /machines`, permission `enrollments:read`). Defaults to true. Pass
|
|
299
|
+
* false for a viewer without it: the dock then never requests the fleet and
|
|
300
|
+
* the machine chip derives from the session's own capabilities alone.
|
|
301
|
+
*/
|
|
302
|
+
machinesEnabled?: boolean | undefined;
|
|
296
303
|
/** Override the source-driven default tab (e.g. a host landing tab id). When
|
|
297
304
|
* omitted the workbench picks Changes-vs-Files from capture or live Git. */
|
|
298
305
|
initialTab?: string | null | undefined;
|
|
@@ -397,6 +404,7 @@ export function useSandboxWorkspaceTabs(
|
|
|
397
404
|
const initialTab = options.initialTab ?? null;
|
|
398
405
|
const activeTab = options.activeTab ?? initialTab;
|
|
399
406
|
const workspaceVisible = options.workspaceVisible ?? true;
|
|
407
|
+
const machinesEnabled = options.machinesEnabled ?? true;
|
|
400
408
|
const requestedSurfaces = options.surfaces ?? WORKBENCH_SURFACES;
|
|
401
409
|
const surfaceSet = new Set<SandboxWorkspaceSurface>(requestedSurfaces);
|
|
402
410
|
const changesEnabled = surfaceSet.has(WORKBENCH_TAB_CHANGES);
|
|
@@ -465,7 +473,7 @@ export function useSandboxWorkspaceTabs(
|
|
|
465
473
|
workspaceId,
|
|
466
474
|
sessionId,
|
|
467
475
|
pollIntervalMs: MACHINES_SESSION_POLL_MS,
|
|
468
|
-
enabled: machineSurfaceEnabled,
|
|
476
|
+
enabled: machineSurfaceEnabled && machinesEnabled,
|
|
469
477
|
});
|
|
470
478
|
const activeMachine: MachineView | null =
|
|
471
479
|
machines.machines.find((m) => m.sandboxId === machines.activeSandboxId) ??
|
|
@@ -995,6 +1003,12 @@ export type SandboxWorkspaceProps = ClientOverride & {
|
|
|
995
1003
|
* Terminal, Browser, and Desktop. Disabled surfaces remain behaviorally dormant.
|
|
996
1004
|
*/
|
|
997
1005
|
surfaces?: readonly SandboxWorkspaceSurface[] | undefined;
|
|
1006
|
+
/**
|
|
1007
|
+
* Whether this viewer may read the workspace machine fleet
|
|
1008
|
+
* (`GET /machines`, permission `enrollments:read`). Defaults to true. Pass
|
|
1009
|
+
* false for a viewer without it so the dock never requests the fleet.
|
|
1010
|
+
*/
|
|
1011
|
+
machinesEnabled?: boolean | undefined;
|
|
998
1012
|
/** Host tabs injected BEFORE the workbench tabs (e.g. a "Run" landing tab). */
|
|
999
1013
|
leadingTabs?: WorkspaceTab[] | undefined;
|
|
1000
1014
|
/** Host tabs injected AFTER the workbench tabs (e.g. a "Debug" tab). */
|
|
@@ -1060,6 +1074,7 @@ export function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {
|
|
|
1060
1074
|
events,
|
|
1061
1075
|
primary,
|
|
1062
1076
|
surfaces,
|
|
1077
|
+
machinesEnabled,
|
|
1063
1078
|
leadingTabs,
|
|
1064
1079
|
trailingTabs,
|
|
1065
1080
|
initialTab,
|
|
@@ -1180,6 +1195,7 @@ export function SandboxWorkspace(props: SandboxWorkspaceProps): ReactNode {
|
|
|
1180
1195
|
sessionId,
|
|
1181
1196
|
events,
|
|
1182
1197
|
...(surfaces ? { surfaces } : {}),
|
|
1198
|
+
...(machinesEnabled !== undefined ? { machinesEnabled } : {}),
|
|
1183
1199
|
...(initialTab ? { initialTab } : {}),
|
|
1184
1200
|
activeTab: activeTabHint,
|
|
1185
1201
|
workspaceVisible: collapsed !== true,
|
|
@@ -26,6 +26,8 @@ import { ChildSessionLink } from "./child-session-link";
|
|
|
26
26
|
*
|
|
27
27
|
* Inbox and queue stay separate segments. Queue hover actions wire to
|
|
28
28
|
* `UseTurnQueueResult` (`editTurn` / `steerTurn` / `moveTurn` / `removeTurn`).
|
|
29
|
+
* The collapsed queue chip previews the latest queued message beside its Steer
|
|
30
|
+
* action; open queue rows keep Steer visible and reveal the rest on hover.
|
|
29
31
|
* Inbox has no product dismiss API; pass `onDismissIncoming` when the host
|
|
30
32
|
* wants a visible action (dev harness may use a local dummy).
|
|
31
33
|
*
|
|
@@ -75,6 +77,13 @@ import type { UseTurnQueueResult } from "../hooks/use-turn-queue";
|
|
|
75
77
|
import { cn } from "../lib/cn";
|
|
76
78
|
import { useErrorMessage } from "../lib/error-message";
|
|
77
79
|
import { formatClockTime } from "../lib/format";
|
|
80
|
+
import {
|
|
81
|
+
countAuthoritativeQueuedTurns,
|
|
82
|
+
isAuthoritativeQueuedTurn,
|
|
83
|
+
QUEUE_REPLACE_DRAFT_COPY,
|
|
84
|
+
queuedTurnPresentation,
|
|
85
|
+
queueNeighborAnchors,
|
|
86
|
+
} from "../queue-presentation-model";
|
|
78
87
|
import { requestQueueDraftEdit } from "./queue-draft-policy";
|
|
79
88
|
import { QUEUE_ITEM_CONTENT_UNAVAILABLE, queueItemContent } from "./queue-item-content";
|
|
80
89
|
import { TimelineAnnotationsChip, type TimelineAnnotationLike } from "./timeline-annotations";
|
|
@@ -143,11 +152,6 @@ type GoalPillState =
|
|
|
143
152
|
| "invariant_broken"
|
|
144
153
|
| "completed";
|
|
145
154
|
|
|
146
|
-
type QueuedTurnPresentation = {
|
|
147
|
-
kind: "prompt" | "realtime_voice" | "realtime_voice_handoff";
|
|
148
|
-
text: string;
|
|
149
|
-
};
|
|
150
|
-
|
|
151
155
|
const GOAL_LABEL: Record<GoalPillState, string> = {
|
|
152
156
|
pursuing: "Pursuing",
|
|
153
157
|
waiting: "Waiting",
|
|
@@ -252,35 +256,7 @@ export function sessionChromeGoalPillExplanation(
|
|
|
252
256
|
return null;
|
|
253
257
|
}
|
|
254
258
|
|
|
255
|
-
|
|
256
|
-
const realtimeDelegation = objectValue(turn.metadata.realtimeDelegation);
|
|
257
|
-
const inputTranscript = realtimeDelegation?.inputTranscript;
|
|
258
|
-
if (typeof inputTranscript === "string" && inputTranscript.trim()) {
|
|
259
|
-
return { kind: "realtime_voice", text: inputTranscript.trim() };
|
|
260
|
-
}
|
|
261
|
-
if (objectValue(turn.metadata.realtimeTailFlush)) {
|
|
262
|
-
return { kind: "realtime_voice_handoff", text: "Remaining voice context" };
|
|
263
|
-
}
|
|
264
|
-
return { kind: "prompt", text: turn.prompt };
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function isSteeringTurn(turn: SessionTurn): boolean {
|
|
268
|
-
return turn.metadata.delivery === "steer";
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
function isAuthoritativeQueuedTurn(
|
|
272
|
-
turn: SessionTurn,
|
|
273
|
-
mutationFor: UseTurnQueueResult["mutationFor"],
|
|
274
|
-
): boolean {
|
|
275
|
-
return !isSteeringTurn(turn) && mutationFor(turn.id) !== "steer";
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export function countAuthoritativeQueuedTurns(
|
|
279
|
-
turns: readonly SessionTurn[],
|
|
280
|
-
mutationFor: UseTurnQueueResult["mutationFor"],
|
|
281
|
-
): number {
|
|
282
|
-
return turns.filter((turn) => isAuthoritativeQueuedTurn(turn, mutationFor)).length;
|
|
283
|
-
}
|
|
259
|
+
export { countAuthoritativeQueuedTurns };
|
|
284
260
|
|
|
285
261
|
function isOptimisticQueuedMessage(
|
|
286
262
|
message: ComposerOptimisticMessage,
|
|
@@ -344,12 +320,6 @@ export function sessionChromeShouldOfferQueue(input: {
|
|
|
344
320
|
);
|
|
345
321
|
}
|
|
346
322
|
|
|
347
|
-
function objectValue(value: unknown): Record<string, unknown> | null {
|
|
348
|
-
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
349
|
-
? (value as Record<string, unknown>)
|
|
350
|
-
: null;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
323
|
/** Select pill state from the goal's authoritative continuation projection. */
|
|
354
324
|
export function sessionChromeGoalPillState(
|
|
355
325
|
goalStatus: "active" | "paused" | "completed",
|
|
@@ -831,6 +801,22 @@ export function SessionChrome({
|
|
|
831
801
|
}, [active, signals]);
|
|
832
802
|
|
|
833
803
|
const open = active !== null;
|
|
804
|
+
// Collapsed queue chip shows the latest queued message so a Send that lands
|
|
805
|
+
// in the queue is visible without opening the list; Steer acts on that
|
|
806
|
+
// message once the server has confirmed it.
|
|
807
|
+
const latestOptimisticQueued = optimisticQueued[optimisticQueued.length - 1];
|
|
808
|
+
const latestQueuedTurn = queuedTurns[queuedTurns.length - 1];
|
|
809
|
+
const queuePeek: { text: string | null; turnId: string | null } | null =
|
|
810
|
+
queue.error || queue.mutationError
|
|
811
|
+
? null
|
|
812
|
+
: latestOptimisticQueued
|
|
813
|
+
? { text: latestOptimisticQueued.text.trim() || null, turnId: null }
|
|
814
|
+
: latestQueuedTurn
|
|
815
|
+
? {
|
|
816
|
+
text: queuedTurnPresentation(latestQueuedTurn).text.trim() || null,
|
|
817
|
+
turnId: latestQueuedTurn.id,
|
|
818
|
+
}
|
|
819
|
+
: null;
|
|
834
820
|
|
|
835
821
|
if (signals.length === 0 && !stopping) return null;
|
|
836
822
|
|
|
@@ -1056,7 +1042,14 @@ export function SessionChrome({
|
|
|
1056
1042
|
<span className={cn("shrink-0", toneClass(signal.tone, selected))}>
|
|
1057
1043
|
{signal.icon}
|
|
1058
1044
|
</span>
|
|
1059
|
-
<span
|
|
1045
|
+
<span
|
|
1046
|
+
className={cn(
|
|
1047
|
+
"font-medium text-og-fg",
|
|
1048
|
+
signal.id === "queue" && queuePeek?.text && !selected
|
|
1049
|
+
? "shrink-0"
|
|
1050
|
+
: "min-w-0 truncate",
|
|
1051
|
+
)}
|
|
1052
|
+
>
|
|
1060
1053
|
{signal.id === "goal" ? "Goal · " : null}
|
|
1061
1054
|
{signal.id === "goal"
|
|
1062
1055
|
? goalState === "pursuing"
|
|
@@ -1068,6 +1061,21 @@ export function SessionChrome({
|
|
|
1068
1061
|
: `${queuedTurns.length + optimisticQueued.length} queued`
|
|
1069
1062
|
: signal.label}
|
|
1070
1063
|
</span>
|
|
1064
|
+
{signal.id === "queue" && queuePeek?.text && !selected ? (
|
|
1065
|
+
<AnimatePresence initial={false} mode="popLayout">
|
|
1066
|
+
<motion.span
|
|
1067
|
+
key={queuePeek.text}
|
|
1068
|
+
data-testid="session-chrome-queue-peek"
|
|
1069
|
+
className="min-w-0 max-w-[min(24rem,60vw)] truncate text-og-fg-muted"
|
|
1070
|
+
initial={reduceMotion ? false : { opacity: 0, y: 3 }}
|
|
1071
|
+
animate={{ opacity: 1, y: 0 }}
|
|
1072
|
+
exit={{ opacity: 0, transition: { duration: crossfadeDuration } }}
|
|
1073
|
+
transition={{ duration: crossfadeDuration, ease }}
|
|
1074
|
+
>
|
|
1075
|
+
{queuePeek.text}
|
|
1076
|
+
</motion.span>
|
|
1077
|
+
</AnimatePresence>
|
|
1078
|
+
) : null}
|
|
1071
1079
|
</button>
|
|
1072
1080
|
{signal.id === "goal" && goal && record && !readOnly ? (
|
|
1073
1081
|
<div className="flex shrink-0 items-center pr-1 pl-0.5">
|
|
@@ -1101,19 +1109,27 @@ export function SessionChrome({
|
|
|
1101
1109
|
<Trash2Icon className="size-3" />
|
|
1102
1110
|
</IconAction>
|
|
1103
1111
|
</div>
|
|
1104
|
-
) : signal.id === "queue" && canMutateQueue &&
|
|
1112
|
+
) : signal.id === "queue" && canMutateQueue && queuePeek && !selected ? (
|
|
1105
1113
|
<div className="flex shrink-0 items-center pr-1 pl-0.5">
|
|
1106
1114
|
<IconAction
|
|
1107
|
-
label="Steer
|
|
1115
|
+
label="Steer latest queued message"
|
|
1108
1116
|
analyticsAction="steer"
|
|
1109
1117
|
text="Steer"
|
|
1110
1118
|
tip={QUEUE_STEER_TIP}
|
|
1111
1119
|
disabled={
|
|
1112
|
-
|
|
1120
|
+
!queuePeek.turnId ||
|
|
1121
|
+
queue.mutating ||
|
|
1122
|
+
Boolean(queue.mutationFor(queuePeek.turnId))
|
|
1113
1123
|
}
|
|
1114
|
-
onClick={() =>
|
|
1124
|
+
onClick={() => {
|
|
1125
|
+
if (queuePeek.turnId) void queue.steerTurn(queuePeek.turnId);
|
|
1126
|
+
}}
|
|
1115
1127
|
>
|
|
1116
|
-
|
|
1128
|
+
{queuePeek.turnId && queue.mutationFor(queuePeek.turnId) === "steer" ? (
|
|
1129
|
+
<Loader2Icon className="size-3 animate-og-spin" />
|
|
1130
|
+
) : (
|
|
1131
|
+
<CornerDownRightIcon className="size-3" />
|
|
1132
|
+
)}
|
|
1117
1133
|
</IconAction>
|
|
1118
1134
|
</div>
|
|
1119
1135
|
) : null}
|
|
@@ -1426,8 +1442,7 @@ function QueuePanel({
|
|
|
1426
1442
|
const voice = presentation.kind !== "prompt";
|
|
1427
1443
|
const pending = mutationFor(turn.id);
|
|
1428
1444
|
const settling = !interactiveTurnIds.has(turn.id);
|
|
1429
|
-
const beforeUp
|
|
1430
|
-
const beforeDown = index < turns.length - 1 ? (turns[index + 2]?.id ?? null) : null;
|
|
1445
|
+
const { beforeUp, beforeDown } = queueNeighborAnchors(turns, index);
|
|
1431
1446
|
const showActions = !readOnly && (onEdit || onSteer || onRemove || onMove);
|
|
1432
1447
|
const confirmingReplace = replaceDraftFor === turn.id;
|
|
1433
1448
|
return (
|
|
@@ -1453,27 +1468,59 @@ function QueuePanel({
|
|
|
1453
1468
|
annotations={turn.annotations ?? []}
|
|
1454
1469
|
/>
|
|
1455
1470
|
{showActions ? (
|
|
1456
|
-
<div className="flex shrink-0 items-center gap-0.5
|
|
1457
|
-
{
|
|
1458
|
-
|
|
1471
|
+
<div className="flex shrink-0 items-center gap-0.5">
|
|
1472
|
+
{/* Reorder, edit and delete stay on hover; Steer is always visible. */}
|
|
1473
|
+
<div className="flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100 max-sm:opacity-100">
|
|
1474
|
+
{onMove && turns.length > 1 ? (
|
|
1475
|
+
<>
|
|
1476
|
+
<IconAction
|
|
1477
|
+
label={`Move queued prompt ${index + 1} up`}
|
|
1478
|
+
tip="Move up"
|
|
1479
|
+
disabled={settling || pending !== null || index === 0}
|
|
1480
|
+
onClick={() => onMove(turn.id, beforeUp)}
|
|
1481
|
+
>
|
|
1482
|
+
<ArrowUpIcon className="size-3" />
|
|
1483
|
+
</IconAction>
|
|
1484
|
+
<IconAction
|
|
1485
|
+
label={`Move queued prompt ${index + 1} down`}
|
|
1486
|
+
tip="Move down"
|
|
1487
|
+
disabled={settling || pending !== null || index >= turns.length - 1}
|
|
1488
|
+
onClick={() => onMove(turn.id, beforeDown)}
|
|
1489
|
+
>
|
|
1490
|
+
<ArrowDownIcon className="size-3" />
|
|
1491
|
+
</IconAction>
|
|
1492
|
+
</>
|
|
1493
|
+
) : null}
|
|
1494
|
+
{onEdit ? (
|
|
1459
1495
|
<IconAction
|
|
1460
|
-
label={`
|
|
1461
|
-
tip=
|
|
1462
|
-
disabled={settling || pending !== null
|
|
1463
|
-
onClick={() =>
|
|
1496
|
+
label={`Edit queued prompt ${index + 1}`}
|
|
1497
|
+
tip={QUEUE_EDIT_TIP}
|
|
1498
|
+
disabled={settling || pending !== null}
|
|
1499
|
+
onClick={() => onEdit(turn)}
|
|
1464
1500
|
>
|
|
1465
|
-
|
|
1501
|
+
{pending === "edit" ? (
|
|
1502
|
+
<Loader2Icon className="size-3 animate-og-spin" />
|
|
1503
|
+
) : (
|
|
1504
|
+
<PencilIcon className="size-3" />
|
|
1505
|
+
)}
|
|
1466
1506
|
</IconAction>
|
|
1507
|
+
) : null}
|
|
1508
|
+
{onRemove ? (
|
|
1467
1509
|
<IconAction
|
|
1468
|
-
label={`
|
|
1469
|
-
tip=
|
|
1470
|
-
disabled={settling || pending !== null
|
|
1471
|
-
onClick={() =>
|
|
1510
|
+
label={`Remove queued prompt ${index + 1}`}
|
|
1511
|
+
tip={QUEUE_DELETE_TIP}
|
|
1512
|
+
disabled={settling || pending !== null}
|
|
1513
|
+
onClick={() => onRemove(turn.id)}
|
|
1514
|
+
danger
|
|
1472
1515
|
>
|
|
1473
|
-
|
|
1516
|
+
{pending === "delete" ? (
|
|
1517
|
+
<Loader2Icon className="size-3 animate-og-spin" />
|
|
1518
|
+
) : (
|
|
1519
|
+
<Trash2Icon className="size-3" />
|
|
1520
|
+
)}
|
|
1474
1521
|
</IconAction>
|
|
1475
|
-
|
|
1476
|
-
|
|
1522
|
+
) : null}
|
|
1523
|
+
</div>
|
|
1477
1524
|
{onSteer ? (
|
|
1478
1525
|
<IconAction
|
|
1479
1526
|
label={`Steer queued prompt ${index + 1}`}
|
|
@@ -1490,59 +1537,27 @@ function QueuePanel({
|
|
|
1490
1537
|
)}
|
|
1491
1538
|
</IconAction>
|
|
1492
1539
|
) : null}
|
|
1493
|
-
{onEdit ? (
|
|
1494
|
-
<IconAction
|
|
1495
|
-
label={`Edit queued prompt ${index + 1}`}
|
|
1496
|
-
tip={QUEUE_EDIT_TIP}
|
|
1497
|
-
disabled={settling || pending !== null}
|
|
1498
|
-
onClick={() => onEdit(turn)}
|
|
1499
|
-
>
|
|
1500
|
-
{pending === "edit" ? (
|
|
1501
|
-
<Loader2Icon className="size-3 animate-og-spin" />
|
|
1502
|
-
) : (
|
|
1503
|
-
<PencilIcon className="size-3" />
|
|
1504
|
-
)}
|
|
1505
|
-
</IconAction>
|
|
1506
|
-
) : null}
|
|
1507
|
-
{onRemove ? (
|
|
1508
|
-
<IconAction
|
|
1509
|
-
label={`Remove queued prompt ${index + 1}`}
|
|
1510
|
-
tip={QUEUE_DELETE_TIP}
|
|
1511
|
-
disabled={settling || pending !== null}
|
|
1512
|
-
onClick={() => onRemove(turn.id)}
|
|
1513
|
-
danger
|
|
1514
|
-
>
|
|
1515
|
-
{pending === "delete" ? (
|
|
1516
|
-
<Loader2Icon className="size-3 animate-og-spin" />
|
|
1517
|
-
) : (
|
|
1518
|
-
<Trash2Icon className="size-3" />
|
|
1519
|
-
)}
|
|
1520
|
-
</IconAction>
|
|
1521
|
-
) : null}
|
|
1522
1540
|
</div>
|
|
1523
1541
|
) : null}
|
|
1524
1542
|
</div>
|
|
1525
1543
|
{confirmingReplace ? (
|
|
1526
1544
|
<div className="rounded-og-sm border border-og-status-waiting/30 bg-og-status-waiting/10 p-2 text-og-xs text-og-fg">
|
|
1527
|
-
<p>
|
|
1528
|
-
<p className="mt-0.5 text-og-fg-muted">
|
|
1529
|
-
The current draft will be permanently discarded; this queued prompt is preserved
|
|
1530
|
-
until you confirm.
|
|
1531
|
-
</p>
|
|
1545
|
+
<p>{QUEUE_REPLACE_DRAFT_COPY.title}</p>
|
|
1546
|
+
<p className="mt-0.5 text-og-fg-muted">{QUEUE_REPLACE_DRAFT_COPY.detail}</p>
|
|
1532
1547
|
<div className="mt-2 flex justify-end gap-1.5">
|
|
1533
1548
|
<button
|
|
1534
1549
|
type="button"
|
|
1535
1550
|
className="rounded-og-sm px-2 py-1 font-medium hover:bg-og-surface-3/70 focus-visible:ring-2 focus-visible:ring-og-accent/40"
|
|
1536
1551
|
onClick={onCancelReplace}
|
|
1537
1552
|
>
|
|
1538
|
-
|
|
1553
|
+
{QUEUE_REPLACE_DRAFT_COPY.keep}
|
|
1539
1554
|
</button>
|
|
1540
1555
|
<button
|
|
1541
1556
|
type="button"
|
|
1542
1557
|
className="rounded-og-sm border border-og-primary-border bg-og-primary text-og-primary-fg px-2 py-1 font-medium hover:bg-og-primary-hover focus-visible:ring-2 focus-visible:ring-og-accent/40"
|
|
1543
1558
|
onClick={onConfirmReplace}
|
|
1544
1559
|
>
|
|
1545
|
-
|
|
1560
|
+
{QUEUE_REPLACE_DRAFT_COPY.replace}
|
|
1546
1561
|
</button>
|
|
1547
1562
|
</div>
|
|
1548
1563
|
</div>
|