@opengeni/react 1.4.4 → 1.4.5-canary.37485542607001
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-5EEAS3IU.js → browser-viewer-CV23VIHB.js} +8 -6
- package/dist/{chunk-XS67YG5R.js → chunk-4O7OE7ON.js} +45 -4
- package/dist/chunk-4O7OE7ON.js.map +1 -0
- 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-QMMCJGFI.js → chunk-6BAMPGBV.js} +6 -3
- package/dist/chunk-6BAMPGBV.js.map +1 -0
- package/dist/{chunk-I6OY3MWC.js → chunk-6FOTSVWU.js} +2 -2
- 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-2OQA3CPB.js → chunk-CESBPQP5.js} +19 -5
- package/dist/chunk-CESBPQP5.js.map +1 -0
- package/dist/{chunk-YVFRBXST.js → chunk-GMNGUPMX.js} +2 -2
- 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-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-LHF6BVM4.js +83 -0
- package/dist/chunk-LHF6BVM4.js.map +1 -0
- package/dist/{chunk-C5BF4L26.js → chunk-LSMWZSCJ.js} +7 -7
- package/dist/chunk-LTKGTXUQ.js +174 -0
- package/dist/chunk-LTKGTXUQ.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-IYQCWGU5.js → chunk-RGTZ2VDR.js} +35 -62
- package/dist/chunk-RGTZ2VDR.js.map +1 -0
- package/dist/chunk-RI42H5IU.js +326 -0
- package/dist/chunk-RI42H5IU.js.map +1 -0
- package/dist/{chunk-EAOSEIXB.js → chunk-RRRS5D5T.js} +727 -1983
- package/dist/chunk-RRRS5D5T.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-IUHHPMAX.js → chunk-SZOCY5VG.js} +18 -87
- package/dist/chunk-SZOCY5VG.js.map +1 -0
- package/dist/{chunk-L2J3PU7A.js → chunk-VYIPNDUZ.js} +29 -100
- package/dist/chunk-VYIPNDUZ.js.map +1 -0
- package/dist/{chunk-G6YRCIYJ.js → chunk-YK6QMGVL.js} +55 -60
- package/dist/chunk-YK6QMGVL.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-ELNLZGHI.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-K7SOZVVZ.js} +6 -4
- package/dist/{embedded-voice-NIL4RDX3.js.map → embedded-voice-K7SOZVVZ.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-goal.d.ts +2 -1
- package/dist/hooks/use-new-session-draft.d.ts +74 -0
- 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-27HGRPVF.js} +3 -3
- package/dist/lib/clipboard.d.ts +7 -0
- package/dist/lib/provider-recovery.d.ts +49 -0
- package/dist/lib/transient-retry.d.ts +25 -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-I5KPC3D6.js} +6 -4
- package/dist/model-policy-picker-menu-I5KPC3D6.js.map +1 -0
- package/dist/model-policy.d.ts +10 -0
- package/dist/model-policy.js +5 -1
- package/dist/new-session-draft.d.ts +7 -0
- package/dist/new-session-draft.js +639 -0
- package/dist/new-session-draft.js.map +1 -0
- 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-2DGDO6NI.js} +5 -5
- package/dist/sandbox-files-2DGDO6NI.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-agents-model.d.ts +10 -0
- package/dist/session-agents-model.js +25 -0
- package/dist/session-agents-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 +119 -0
- package/dist/session-list-model.js +244 -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 +55 -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 +8 -146
- 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 +20 -150
- 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-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-client-config-flags.ts +8 -0
- package/src/hooks/use-goal.ts +66 -10
- package/src/hooks/use-new-session-draft.ts +813 -0
- 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/lib/transient-retry.ts +99 -0
- package/src/model-mark-paths.ts +53 -0
- package/src/model-picker-model.ts +330 -0
- package/src/model-policy.ts +75 -5
- package/src/new-session-draft.ts +22 -0
- 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-agents-model.ts +33 -0
- package/src/session-attention-model.ts +59 -0
- package/src/session-feedback-model.ts +95 -0
- package/src/session-list-model.ts +377 -0
- package/src/session-status-model.ts +62 -0
- package/src/testing/session-scenarios.ts +326 -0
- package/src/timeline/activity-rail.tsx +54 -24
- package/src/timeline/genie-copy.ts +19 -0
- package/src/timeline/genie-loading.tsx +15 -19
- 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/projection.ts +12 -1
- 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 +254 -1024
- 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 +17 -4
- package/styles/connect.css +4 -0
- package/styles/responsive.css +11 -2
- package/dist/chunk-2OQA3CPB.js.map +0 -1
- package/dist/chunk-CVYCLFMH.js.map +0 -1
- package/dist/chunk-EAOSEIXB.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-PHBFJCEU.js.map +0 -1
- package/dist/chunk-QMMCJGFI.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-5EEAS3IU.js.map → browser-viewer-CV23VIHB.js.map} +0 -0
- /package/dist/{chunk-I6OY3MWC.js.map → chunk-6FOTSVWU.js.map} +0 -0
- /package/dist/{chunk-YVFRBXST.js.map → chunk-GMNGUPMX.js.map} +0 -0
- /package/dist/{chunk-PBCZL4JP.js.map → chunk-INIZSNXT.js.map} +0 -0
- /package/dist/{chunk-C5BF4L26.js.map → chunk-LSMWZSCJ.js.map} +0 -0
- /package/dist/{computer-viewer-ELNLZGHI.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-27HGRPVF.js.map} +0 -0
- /package/dist/{sandbox-files-34CJJNOY.js.map → model-mark-paths.js.map} +0 -0
|
@@ -47,6 +47,16 @@ import {
|
|
|
47
47
|
usePortalTokenStyle,
|
|
48
48
|
} from "../lib/use-portal-token-style";
|
|
49
49
|
import { requestQueueDraftEdit } from "./queue-draft-policy";
|
|
50
|
+
import {
|
|
51
|
+
projectPendingQueueMove,
|
|
52
|
+
QUEUE_COLLAPSED_PREVIEW_CHARACTERS,
|
|
53
|
+
QUEUE_REPLACE_DRAFT_COPY,
|
|
54
|
+
QUEUE_ROW_PREVIEW_CHARACTERS,
|
|
55
|
+
queueContentPreview,
|
|
56
|
+
queueMovePlan,
|
|
57
|
+
queuePromptPreview,
|
|
58
|
+
queueTurnPreview,
|
|
59
|
+
} from "../queue-presentation-model";
|
|
50
60
|
import { QUEUE_ITEM_CONTENT_UNAVAILABLE, queueItemContent } from "./queue-item-content";
|
|
51
61
|
import { QueueErrorAlert, QueueStoppingStatus } from "./queue-surface-state";
|
|
52
62
|
import { TimelineAnnotationsChip } from "./timeline-annotations";
|
|
@@ -127,36 +137,21 @@ export function QueueSurface({
|
|
|
127
137
|
if (oldIndex < 0) return queue.queue;
|
|
128
138
|
return arrayMove(queue.queue, oldIndex, keyboardDrag.projectedIndex);
|
|
129
139
|
}
|
|
130
|
-
if (
|
|
131
|
-
!pendingMove ||
|
|
132
|
-
pendingMove.baseVersion === null ||
|
|
133
|
-
queue.snapshot?.version !== pendingMove.baseVersion
|
|
134
|
-
) {
|
|
135
|
-
return queue.queue;
|
|
136
|
-
}
|
|
137
|
-
const byId = new Map(queue.queue.map((turn) => [turn.id, turn]));
|
|
138
|
-
const projected = pendingMove.turnIds.map((turnId) => byId.get(turnId));
|
|
139
140
|
// Never let an optimistic ordering projection omit or invent a row. Any
|
|
140
141
|
// concurrent authoritative membership change wins immediately.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
}
|
|
144
|
-
return projected as SessionTurn[];
|
|
145
|
-
}, [keyboardDrag, pendingMove, queue.queue, queue.snapshot?.version]);
|
|
142
|
+
return projectPendingQueueMove(queue.queue, pendingMove, queue.snapshot);
|
|
143
|
+
}, [keyboardDrag, pendingMove, queue.queue, queue.snapshot]);
|
|
146
144
|
|
|
147
145
|
const ids = useMemo(() => displayedQueue.map((turn) => turn.id), [displayedQueue]);
|
|
148
146
|
const moveToIndex = useCallback(
|
|
149
147
|
async (turnId: string, nextIndex: number): Promise<void> => {
|
|
150
148
|
if (queue.mutating || pendingMove) return;
|
|
151
|
-
const
|
|
152
|
-
if (
|
|
153
|
-
const
|
|
154
|
-
if (oldIndex === boundedIndex) return;
|
|
155
|
-
const ordered = arrayMove(queue.queue, oldIndex, boundedIndex);
|
|
156
|
-
const beforeTurnId = ordered[boundedIndex + 1]?.id ?? null;
|
|
149
|
+
const plan = queueMovePlan(queue.queue, turnId, nextIndex);
|
|
150
|
+
if (!plan) return;
|
|
151
|
+
const { beforeTurnId, index: boundedIndex } = plan;
|
|
157
152
|
setPendingMove({
|
|
158
153
|
baseVersion: queue.snapshot?.version ?? null,
|
|
159
|
-
turnIds:
|
|
154
|
+
turnIds: plan.turnIds,
|
|
160
155
|
});
|
|
161
156
|
setAnnouncement(`Saving queued prompt at position ${boundedIndex + 1}.`);
|
|
162
157
|
try {
|
|
@@ -510,327 +505,6 @@ function PendingMachineInputs({
|
|
|
510
505
|
);
|
|
511
506
|
}
|
|
512
507
|
|
|
513
|
-
const QUEUE_ROW_PREVIEW_CHARACTERS = 360;
|
|
514
|
-
const QUEUE_COLLAPSED_PREVIEW_CHARACTERS = 180;
|
|
515
|
-
const QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS = 32;
|
|
516
|
-
const QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS = 32;
|
|
517
|
-
const QUEUE_VISIBLE_END_IDENTITY_CHARACTERS = 18;
|
|
518
|
-
const QUEUE_PREVIEW_SEPARATOR = " … ";
|
|
519
|
-
const queuePreviewSegmenter = new Intl.Segmenter(undefined, { granularity: "grapheme" });
|
|
520
|
-
const queuePromptNonRenderingCodePoint =
|
|
521
|
-
/[\p{White_Space}\p{Control}\p{Default_Ignorable_Code_Point}]/u;
|
|
522
|
-
|
|
523
|
-
type BoundedPromptSample = {
|
|
524
|
-
value: string;
|
|
525
|
-
characters: number;
|
|
526
|
-
truncated: boolean;
|
|
527
|
-
};
|
|
528
|
-
|
|
529
|
-
type QueuePromptPreview = {
|
|
530
|
-
summary: string;
|
|
531
|
-
collapsedVisual: string;
|
|
532
|
-
visibleStart: string;
|
|
533
|
-
visibleIdentity: string | null;
|
|
534
|
-
visibleIdentityLabel: "End" | "Safe boundary" | null;
|
|
535
|
-
isFallback: boolean;
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
function labelQueuePreview(summary: string): QueuePromptPreview {
|
|
539
|
-
return {
|
|
540
|
-
summary,
|
|
541
|
-
collapsedVisual: summary,
|
|
542
|
-
visibleStart: summary,
|
|
543
|
-
visibleIdentity: null,
|
|
544
|
-
visibleIdentityLabel: null,
|
|
545
|
-
isFallback: false,
|
|
546
|
-
};
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
function queueTurnPreview(
|
|
550
|
-
turn: SessionTurn | undefined,
|
|
551
|
-
maxCharacters: number,
|
|
552
|
-
): QueuePromptPreview {
|
|
553
|
-
if (!turn) return queuePromptPreview("", maxCharacters);
|
|
554
|
-
return queueContentPreview(turn.prompt, turn.annotations?.length ?? 0, maxCharacters);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
function queueContentPreview(
|
|
558
|
-
prompt: string,
|
|
559
|
-
annotationCount: number,
|
|
560
|
-
maxCharacters: number,
|
|
561
|
-
): QueuePromptPreview {
|
|
562
|
-
switch (queueItemContent(prompt, annotationCount)) {
|
|
563
|
-
case "text":
|
|
564
|
-
return queuePromptPreview(prompt, maxCharacters);
|
|
565
|
-
case "annotations":
|
|
566
|
-
return labelQueuePreview(
|
|
567
|
-
`${annotationCount} timeline ${annotationCount === 1 ? "annotation" : "annotations"}`,
|
|
568
|
-
);
|
|
569
|
-
case "unavailable":
|
|
570
|
-
return labelQueuePreview(QUEUE_ITEM_CONTENT_UNAVAILABLE);
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
/**
|
|
575
|
-
* Build a bounded head/tail summary of an arbitrary queued prompt. Sampling
|
|
576
|
-
* both ends distinguishes prompts with equal long prefixes. Each sampled edge
|
|
577
|
-
* has a small amount of grapheme context so ordinary emoji/combining sequences
|
|
578
|
-
* can be retained whole. A cluster that exceeds that context is omitted rather
|
|
579
|
-
* than fragmented, and malformed UTF-16 is replaced only in the summary. The
|
|
580
|
-
* durable prompt remains exact and no operation scans or copies it in full.
|
|
581
|
-
*/
|
|
582
|
-
function queuePromptPreview(prompt: string, maxCharacters: number): QueuePromptPreview {
|
|
583
|
-
const wholePromptProbe = samplePromptStart(prompt, maxCharacters + 1);
|
|
584
|
-
if (!wholePromptProbe.truncated && wholePromptProbe.characters <= maxCharacters) {
|
|
585
|
-
const summary = replaceLoneSurrogates(wholePromptProbe.value);
|
|
586
|
-
return hasVisiblePromptContent(summary)
|
|
587
|
-
? {
|
|
588
|
-
summary,
|
|
589
|
-
collapsedVisual: summary,
|
|
590
|
-
visibleStart: summary,
|
|
591
|
-
visibleIdentity: null,
|
|
592
|
-
visibleIdentityLabel: null,
|
|
593
|
-
isFallback: false,
|
|
594
|
-
}
|
|
595
|
-
: fallbackPromptPreview(prompt.length, wholePromptProbe.value, wholePromptProbe.value);
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const suffixCharacters = Math.min(Math.floor(maxCharacters / 3), 120);
|
|
599
|
-
const prefixCharacters =
|
|
600
|
-
maxCharacters - codePointLength(QUEUE_PREVIEW_SEPARATOR) - suffixCharacters;
|
|
601
|
-
const prefixSample = samplePromptStart(
|
|
602
|
-
prompt,
|
|
603
|
-
prefixCharacters + QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS,
|
|
604
|
-
);
|
|
605
|
-
const suffixSample = samplePromptEnd(
|
|
606
|
-
prompt,
|
|
607
|
-
suffixCharacters + QUEUE_PREVIEW_GRAPHEME_CONTEXT_CHARACTERS,
|
|
608
|
-
);
|
|
609
|
-
const prefixSegments = segmentPromptSample(prefixSample.value);
|
|
610
|
-
const suffixSegments = segmentPromptSample(suffixSample.value);
|
|
611
|
-
|
|
612
|
-
// A cluster at a truncated sampling edge may continue outside the sample.
|
|
613
|
-
// Prefix sampling starts at the true source start, so only its last segment
|
|
614
|
-
// is ambiguous. Suffix sampling ends at the true source end, so its first is.
|
|
615
|
-
if (prefixSample.truncated) prefixSegments.pop();
|
|
616
|
-
if (suffixSample.truncated) {
|
|
617
|
-
let ambiguousSegment = suffixSegments.shift();
|
|
618
|
-
// A locally segmented leading fragment ending in ZWJ can join the next
|
|
619
|
-
// pictographic segment when omitted left context supplies its base. Keep
|
|
620
|
-
// backing off until that uncertainty no longer propagates to the right.
|
|
621
|
-
while (ambiguousSegment?.endsWith("\u200d") && suffixSegments.length > 0) {
|
|
622
|
-
ambiguousSegment = suffixSegments.shift();
|
|
623
|
-
}
|
|
624
|
-
// Regional Indicator pairing depends on the parity of the preceding run.
|
|
625
|
-
// If that run reaches the unknown sample boundary, omit all of its visible
|
|
626
|
-
// leading segments rather than potentially recombining halves of flags.
|
|
627
|
-
while (suffixSegments[0] && startsWithRegionalIndicator(suffixSegments[0])) {
|
|
628
|
-
suffixSegments.shift();
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
const prefix = takeWholeGraphemesFromStart(prefixSegments, prefixCharacters);
|
|
633
|
-
const suffix = takeWholeGraphemesFromEnd(suffixSegments, suffixCharacters);
|
|
634
|
-
const reference = boundedPromptSampleReference(
|
|
635
|
-
prompt.length,
|
|
636
|
-
prefixSample.value,
|
|
637
|
-
suffixSample.value,
|
|
638
|
-
);
|
|
639
|
-
|
|
640
|
-
if (!hasVisiblePromptContent(prefix) && !hasVisiblePromptContent(suffix)) {
|
|
641
|
-
return fallbackPromptPreview(prompt.length, prefixSample.value, suffixSample.value);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
const safeSuffix = hasVisiblePromptContent(suffix)
|
|
645
|
-
? suffix
|
|
646
|
-
: promptPreviewFallbackLabel(reference);
|
|
647
|
-
const summary = `${prefix}${QUEUE_PREVIEW_SEPARATOR}${safeSuffix}`;
|
|
648
|
-
if (!hasVisiblePromptContent(prefix)) {
|
|
649
|
-
return {
|
|
650
|
-
summary,
|
|
651
|
-
collapsedVisual: summary,
|
|
652
|
-
visibleStart: safeSuffix,
|
|
653
|
-
visibleIdentity: null,
|
|
654
|
-
visibleIdentityLabel: null,
|
|
655
|
-
isFallback: false,
|
|
656
|
-
};
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
const endIdentity = takeWholeGraphemesFromEnd(
|
|
660
|
-
suffixSegments,
|
|
661
|
-
QUEUE_VISIBLE_END_IDENTITY_CHARACTERS,
|
|
662
|
-
);
|
|
663
|
-
return {
|
|
664
|
-
summary,
|
|
665
|
-
collapsedVisual: summary,
|
|
666
|
-
visibleStart: prefix,
|
|
667
|
-
visibleIdentity: hasVisiblePromptContent(endIdentity) ? endIdentity : `ref ${reference}`,
|
|
668
|
-
visibleIdentityLabel: hasVisiblePromptContent(endIdentity) ? "End" : "Safe boundary",
|
|
669
|
-
isFallback: false,
|
|
670
|
-
};
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
function fallbackPromptPreview(
|
|
674
|
-
promptLength: number,
|
|
675
|
-
startSample: string,
|
|
676
|
-
endSample: string,
|
|
677
|
-
): QueuePromptPreview {
|
|
678
|
-
const reference = boundedPromptSampleReference(promptLength, startSample, endSample);
|
|
679
|
-
const summary = promptPreviewFallbackLabel(reference);
|
|
680
|
-
return {
|
|
681
|
-
summary,
|
|
682
|
-
collapsedVisual: `Omitted · ${reference}`,
|
|
683
|
-
// The complete fallback remains the canonical accessible summary. Narrow
|
|
684
|
-
// collapsed/row layouts paint the bounded reference in a compact truthful
|
|
685
|
-
// form so ellipsis cannot hide the only identifying portion.
|
|
686
|
-
visibleStart: `Omitted · ${reference}`,
|
|
687
|
-
visibleIdentity: null,
|
|
688
|
-
visibleIdentityLabel: null,
|
|
689
|
-
isFallback: true,
|
|
690
|
-
};
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
function promptPreviewFallbackLabel(reference: string): string {
|
|
694
|
-
return `Content omitted at safe boundary · ref ${reference}`;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
function boundedPromptSampleReference(
|
|
698
|
-
promptLength: number,
|
|
699
|
-
startSample: string,
|
|
700
|
-
endSample: string,
|
|
701
|
-
): string {
|
|
702
|
-
const head = samplePromptStart(startSample, QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS).value;
|
|
703
|
-
const tail = samplePromptEnd(endSample, QUEUE_PREVIEW_REFERENCE_SAMPLE_CHARACTERS).value;
|
|
704
|
-
let hash = 0x811c9dc5;
|
|
705
|
-
for (const value of [String(promptLength), head, tail]) {
|
|
706
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
707
|
-
hash ^= value.charCodeAt(index);
|
|
708
|
-
hash = Math.imul(hash, 0x01000193);
|
|
709
|
-
}
|
|
710
|
-
hash ^= 0xffff;
|
|
711
|
-
hash = Math.imul(hash, 0x01000193);
|
|
712
|
-
}
|
|
713
|
-
return (hash >>> 0).toString(16).padStart(8, "0").toUpperCase();
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
function hasVisiblePromptContent(value: string): boolean {
|
|
717
|
-
// Callers pass only the already-bounded whole/head/tail preview samples.
|
|
718
|
-
// Default-ignorables and controls can survive trim() while painting no row
|
|
719
|
-
// identity at all (for example ZWJ, VS16, bidi controls, and tag characters).
|
|
720
|
-
for (const character of value) {
|
|
721
|
-
if (!queuePromptNonRenderingCodePoint.test(character)) return true;
|
|
722
|
-
}
|
|
723
|
-
return false;
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
function samplePromptStart(prompt: string, maxCharacters: number): BoundedPromptSample {
|
|
727
|
-
let end = 0;
|
|
728
|
-
let characters = 0;
|
|
729
|
-
while (end < prompt.length && characters < maxCharacters) {
|
|
730
|
-
const first = prompt.charCodeAt(end);
|
|
731
|
-
end +=
|
|
732
|
-
isHighSurrogate(first) &&
|
|
733
|
-
end + 1 < prompt.length &&
|
|
734
|
-
isLowSurrogate(prompt.charCodeAt(end + 1))
|
|
735
|
-
? 2
|
|
736
|
-
: 1;
|
|
737
|
-
characters += 1;
|
|
738
|
-
}
|
|
739
|
-
return { value: prompt.slice(0, end), characters, truncated: end < prompt.length };
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
function samplePromptEnd(prompt: string, maxCharacters: number): BoundedPromptSample {
|
|
743
|
-
let start = prompt.length;
|
|
744
|
-
let characters = 0;
|
|
745
|
-
while (start > 0 && characters < maxCharacters) {
|
|
746
|
-
start -= 1;
|
|
747
|
-
if (
|
|
748
|
-
isLowSurrogate(prompt.charCodeAt(start)) &&
|
|
749
|
-
start > 0 &&
|
|
750
|
-
isHighSurrogate(prompt.charCodeAt(start - 1))
|
|
751
|
-
) {
|
|
752
|
-
start -= 1;
|
|
753
|
-
}
|
|
754
|
-
characters += 1;
|
|
755
|
-
}
|
|
756
|
-
return { value: prompt.slice(start), characters, truncated: start > 0 };
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
function segmentPromptSample(sample: string): string[] {
|
|
760
|
-
return Array.from(
|
|
761
|
-
queuePreviewSegmenter.segment(replaceLoneSurrogates(sample)),
|
|
762
|
-
({ segment }) => segment,
|
|
763
|
-
);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
function replaceLoneSurrogates(value: string): string {
|
|
767
|
-
let sanitized = "";
|
|
768
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
769
|
-
const current = value.charCodeAt(index);
|
|
770
|
-
if (
|
|
771
|
-
isHighSurrogate(current) &&
|
|
772
|
-
index + 1 < value.length &&
|
|
773
|
-
isLowSurrogate(value.charCodeAt(index + 1))
|
|
774
|
-
) {
|
|
775
|
-
sanitized += value.slice(index, index + 2);
|
|
776
|
-
index += 1;
|
|
777
|
-
} else if (isHighSurrogate(current) || isLowSurrogate(current)) {
|
|
778
|
-
sanitized += "�";
|
|
779
|
-
} else {
|
|
780
|
-
sanitized += value[index];
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
return sanitized;
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
function takeWholeGraphemesFromStart(segments: string[], maxCharacters: number): string {
|
|
787
|
-
const selected: string[] = [];
|
|
788
|
-
let characters = 0;
|
|
789
|
-
for (const segment of segments) {
|
|
790
|
-
const segmentCharacters = codePointLength(segment);
|
|
791
|
-
if (characters + segmentCharacters > maxCharacters) break;
|
|
792
|
-
selected.push(segment);
|
|
793
|
-
characters += segmentCharacters;
|
|
794
|
-
}
|
|
795
|
-
while (selected.at(-1)?.trim().length === 0) selected.pop();
|
|
796
|
-
return selected.join("");
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
function takeWholeGraphemesFromEnd(segments: string[], maxCharacters: number): string {
|
|
800
|
-
const selected: string[] = [];
|
|
801
|
-
let characters = 0;
|
|
802
|
-
for (let index = segments.length - 1; index >= 0; index -= 1) {
|
|
803
|
-
const segment = segments[index];
|
|
804
|
-
if (!segment) continue;
|
|
805
|
-
const segmentCharacters = codePointLength(segment);
|
|
806
|
-
if (characters + segmentCharacters > maxCharacters) break;
|
|
807
|
-
selected.unshift(segment);
|
|
808
|
-
characters += segmentCharacters;
|
|
809
|
-
}
|
|
810
|
-
while (selected[0]?.trim().length === 0) selected.shift();
|
|
811
|
-
while (selected.at(-1)?.trim().length === 0) selected.pop();
|
|
812
|
-
return selected.join("");
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
function codePointLength(value: string): number {
|
|
816
|
-
let characters = 0;
|
|
817
|
-
for (const _character of value) characters += 1;
|
|
818
|
-
return characters;
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
function startsWithRegionalIndicator(value: string): boolean {
|
|
822
|
-
const codePoint = value.codePointAt(0);
|
|
823
|
-
return codePoint !== undefined && codePoint >= 0x1f1e6 && codePoint <= 0x1f1ff;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
function isHighSurrogate(codeUnit: number): boolean {
|
|
827
|
-
return codeUnit >= 0xd800 && codeUnit <= 0xdbff;
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
function isLowSurrogate(codeUnit: number): boolean {
|
|
831
|
-
return codeUnit >= 0xdc00 && codeUnit <= 0xdfff;
|
|
832
|
-
}
|
|
833
|
-
|
|
834
508
|
function QueuePrompt({
|
|
835
509
|
prompt,
|
|
836
510
|
annotations,
|
|
@@ -1192,25 +866,22 @@ function SortableQueueRow({
|
|
|
1192
866
|
</div>
|
|
1193
867
|
{confirmingReplace ? (
|
|
1194
868
|
<div className="mx-3 mb-2 rounded-md border border-status-waiting/30 bg-status-waiting/10 p-2 text-og-control text-fg">
|
|
1195
|
-
<p>
|
|
1196
|
-
<p className="mt-0.5 text-fg-muted">
|
|
1197
|
-
The current draft will be permanently discarded; this queued prompt is preserved until
|
|
1198
|
-
you confirm.
|
|
1199
|
-
</p>
|
|
869
|
+
<p>{QUEUE_REPLACE_DRAFT_COPY.title}</p>
|
|
870
|
+
<p className="mt-0.5 text-fg-muted">{QUEUE_REPLACE_DRAFT_COPY.detail}</p>
|
|
1200
871
|
<div className="mt-2 flex justify-end gap-1.5">
|
|
1201
872
|
<button
|
|
1202
873
|
type="button"
|
|
1203
874
|
className="rounded-md px-2 py-1 font-medium hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-ring/40"
|
|
1204
875
|
onClick={onCancelReplace}
|
|
1205
876
|
>
|
|
1206
|
-
|
|
877
|
+
{QUEUE_REPLACE_DRAFT_COPY.keep}
|
|
1207
878
|
</button>
|
|
1208
879
|
<button
|
|
1209
880
|
type="button"
|
|
1210
881
|
className="rounded-md 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-ring/40"
|
|
1211
882
|
onClick={onConfirmReplace}
|
|
1212
883
|
>
|
|
1213
|
-
|
|
884
|
+
{QUEUE_REPLACE_DRAFT_COPY.replace}
|
|
1214
885
|
</button>
|
|
1215
886
|
</div>
|
|
1216
887
|
</div>
|
|
@@ -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,
|