Skip to content

Commit 07de275

Browse files
wip v28
1 parent 383ec97 commit 07de275

6 files changed

Lines changed: 516 additions & 3 deletions

uapi/app/terminal/TerminalDepositReadWorkbench.tsx

Lines changed: 108 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client';
22

3-
import { useEffect, useMemo, useState } from 'react';
3+
import { useCallback, useEffect, useMemo, useState } from 'react';
44

55
import BitcodeMetricGrid from '@/components/base/bitcode/execution/BitcodeMetricGrid';
66

@@ -21,6 +21,12 @@ import {
2121
type TerminalDepositedSourceRevision,
2222
type TerminalDepositReadWorkbench as TerminalDepositReadWorkbenchState,
2323
} from './terminal-deposit-read-workbench';
24+
import {
25+
buildTerminalFitPipelineHarnessRequest,
26+
streamTerminalFitPipelineHarness,
27+
summarizeTerminalFitPipelineHarnessEvent,
28+
type TerminalFitPipelineHarnessEvent,
29+
} from './terminal-pipeline-harness-client';
2430
import { useTerminalShellBridge } from './terminal-shell-bridge';
2531
import { jumpToShellSection } from './terminal-shell-reading';
2632

@@ -37,20 +43,28 @@ type ReadFitProgressState = 'draft' | 'measured' | 'admitted' | 'fit-recorded';
3743
interface TerminalDepositReadWorkbenchProps {
3844
repositoryContext?: TerminalRepositoryContextState | null;
3945
depositedSourceRevision?: TerminalDepositedSourceRevision | null;
46+
admittedReadActivityId?: string | null;
4047
onRecordActivity?: (draft: TerminalActivityRecordDraft) => Promise<unknown>;
48+
onHarnessCompleted?: () => Promise<unknown> | unknown;
4149
showDemonstrationWorkbench?: boolean;
4250
}
4351

4452
export default function TerminalDepositReadWorkbench({
4553
repositoryContext = null,
4654
depositedSourceRevision = null,
55+
admittedReadActivityId = null,
4756
onRecordActivity,
57+
onHarnessCompleted,
4858
showDemonstrationWorkbench = true,
4959
}: TerminalDepositReadWorkbenchProps) {
5060
const { snapshot } = useTerminalShellBridge();
5161
const [recordingKey, setRecordingKey] = useState<'deposit' | 'read' | 'read-admission' | 'fit' | null>(null);
5262
const [recordMessage, setRecordMessage] = useState<string | null>(null);
5363
const [readFitProgress, setReadFitProgress] = useState<ReadFitProgressState>('draft');
64+
const [recordedAdmittedReadActivityId, setRecordedAdmittedReadActivityId] = useState<string | null>(null);
65+
const [harnessState, setHarnessState] = useState<'idle' | 'running' | 'completed' | 'failed'>('idle');
66+
const [harnessMessage, setHarnessMessage] = useState<string | null>(null);
67+
const [harnessEvents, setHarnessEvents] = useState<TerminalFitPipelineHarnessEvent[]>([]);
5468
const workbenchSnapshot = useMemo(() => {
5569
if (showDemonstrationWorkbench) return snapshot;
5670
return buildLiveTerminalDepositReadWorkbenchSnapshot(repositoryContext, depositedSourceRevision);
@@ -63,8 +77,17 @@ export default function TerminalDepositReadWorkbench({
6377

6478
useEffect(() => {
6579
setReadFitProgress('draft');
80+
setRecordedAdmittedReadActivityId(null);
81+
setHarnessState('idle');
82+
setHarnessMessage(null);
83+
setHarnessEvents([]);
6684
}, [scenarioKey]);
6785

86+
useEffect(() => {
87+
if (!admittedReadActivityId) return;
88+
setReadFitProgress((currentProgress) => (currentProgress === 'draft' ? 'admitted' : currentProgress));
89+
}, [admittedReadActivityId]);
90+
6891
const selectedEntryChips = useMemo(() => {
6992
if (!workbench?.deposit.selectedEntries.length) return [];
7093
return workbench.deposit.selectedEntries.slice(0, 6).map((entry) => entry.label);
@@ -83,6 +106,34 @@ export default function TerminalDepositReadWorkbench({
83106
: readFitProgress === 'fit-recorded'
84107
? 'Fit result recorded'
85108
: 'Record fit result posture';
109+
const liveFitActionLabel =
110+
harnessState === 'running'
111+
? 'Running live fit...'
112+
: harnessState === 'completed'
113+
? 'Run live fit again'
114+
: 'Run live AssetPack fit';
115+
const harnessReadActivityId = recordedAdmittedReadActivityId || admittedReadActivityId;
116+
const harnessRequestState = useMemo(
117+
() =>
118+
buildTerminalFitPipelineHarnessRequest({
119+
workbench,
120+
repositoryContext,
121+
depositedSourceRevision,
122+
readActivityId: harnessReadActivityId,
123+
}),
124+
[depositedSourceRevision, harnessReadActivityId, repositoryContext, workbench],
125+
);
126+
const canRunLiveFit =
127+
!showDemonstrationWorkbench &&
128+
recordingKey === null &&
129+
harnessState !== 'running' &&
130+
harnessRequestState.ready;
131+
132+
const recordActivityId = (value: unknown) => {
133+
if (!value || typeof value !== 'object') return null;
134+
const id = (value as { id?: unknown }).id;
135+
return typeof id === 'string' && id.trim() ? id : null;
136+
};
86137

87138
const handleRecord = async (kind: 'deposit' | 'read' | 'fit') => {
88139
if (!workbench || !onRecordActivity) return;
@@ -141,7 +192,8 @@ export default function TerminalDepositReadWorkbench({
141192
setRecordMessage(null);
142193

143194
try {
144-
await onRecordActivity(buildTerminalReadAdmissionDraft(workbench));
195+
const recorded = await onRecordActivity(buildTerminalReadAdmissionDraft(workbench));
196+
setRecordedAdmittedReadActivityId(recordActivityId(recorded));
145197
setReadFitProgress('admitted');
146198
setRecordMessage(
147199
'Measured Read admitted for fit search. Next run or record the fit result posture as worthy_fit, no_worthy_fit, or blocked_readiness evidence.',
@@ -153,6 +205,33 @@ export default function TerminalDepositReadWorkbench({
153205
}
154206
};
155207

208+
const handleRunLiveFit = useCallback(async () => {
209+
if (!harnessRequestState.ready) {
210+
setHarnessState('failed');
211+
setHarnessMessage(`Live fit cannot start yet: missing ${harnessRequestState.missing.join(', ')}.`);
212+
return;
213+
}
214+
215+
setHarnessState('running');
216+
setHarnessMessage('Starting live AssetPack fit harness...');
217+
setHarnessEvents([]);
218+
219+
try {
220+
await streamTerminalFitPipelineHarness(harnessRequestState.request, {
221+
onEvent: (event) => {
222+
setHarnessEvents((currentEvents) => [...currentEvents.slice(-7), event]);
223+
setHarnessMessage(summarizeTerminalFitPipelineHarnessEvent(event));
224+
},
225+
});
226+
setHarnessState('completed');
227+
setRecordMessage('Live AssetPack fit harness completed. Refreshing activity and telemetry readback.');
228+
await onHarnessCompleted?.();
229+
} catch (error) {
230+
setHarnessState('failed');
231+
setHarnessMessage(error instanceof Error ? error.message : 'Live AssetPack fit harness failed.');
232+
}
233+
}, [harnessRequestState, onHarnessCompleted]);
234+
156235
if (!workbench) {
157236
return (
158237
<TerminalWorkspaceCard
@@ -286,6 +365,18 @@ export default function TerminalDepositReadWorkbench({
286365
>
287366
Review fit result posture
288367
</button>
368+
{!showDemonstrationWorkbench ? (
369+
<button
370+
type="button"
371+
disabled={!canRunLiveFit}
372+
onClick={() => {
373+
void handleRunLiveFit();
374+
}}
375+
className="rounded-[1.25rem] border border-sky-300/30 bg-sky-300/10 px-4 py-3 text-sm font-medium text-sky-100 transition hover:border-sky-200/50 hover:bg-sky-300/15 disabled:cursor-not-allowed disabled:opacity-55"
376+
>
377+
{liveFitActionLabel}
378+
</button>
379+
) : null}
289380
<button
290381
type="button"
291382
disabled={recordingKey !== null || readFitProgress !== 'admitted'}
@@ -297,6 +388,21 @@ export default function TerminalDepositReadWorkbench({
297388
{fitResultActionLabel}
298389
</button>
299390
</div>
391+
{!showDemonstrationWorkbench && (harnessMessage || !harnessRequestState.ready || harnessEvents.length > 0) ? (
392+
<div className="mt-4 rounded-[1.1rem] border border-white/8 bg-black/20 px-4 py-4 text-sm leading-6 text-neutral-300">
393+
<p className="font-medium text-neutral-100">
394+
{harnessMessage ||
395+
`Live fit waiting for ${harnessRequestState.ready ? 'stream events' : harnessRequestState.missing.join(', ')}.`}
396+
</p>
397+
{harnessEvents.length ? (
398+
<ul className="mt-3 space-y-1 text-xs text-neutral-400">
399+
{harnessEvents.slice(-4).map((event, index) => (
400+
<li key={`${event.event}-${index}`}>{summarizeTerminalFitPipelineHarnessEvent(event)}</li>
401+
))}
402+
</ul>
403+
) : null}
404+
</div>
405+
) : null}
300406
</section>
301407

302408
<article

uapi/app/terminal/TerminalPageClient.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,8 +312,27 @@ export default function TerminalPageClient() {
312312
commit: matchingSubmission.sourceCommit,
313313
activityId: matchingSubmission.id,
314314
createdAt: matchingSubmission.created_at,
315+
depositAssetId: matchingSubmission.candidateAssetId || null,
316+
hasWalletOrAttestationProof: Boolean(matchingSubmission.candidateAssetId),
317+
hasAssetMeasurementEvidence: Boolean(matchingSubmission.candidateAssetId),
315318
};
316319
}, [repositoryContext, runs, showDemonstrationSurfaces]);
320+
const admittedReadActivityId = useMemo(() => {
321+
if (showDemonstrationSurfaces) return null;
322+
const selectedRepository = repositoryContext?.selectedRepository || null;
323+
if (!selectedRepository) return null;
324+
const sourceBranch = depositedSourceRevision?.branch || repositoryContext?.selectedBranch || selectedRepository.defaultBranch || 'main';
325+
const sourceCommit = depositedSourceRevision?.commit || repositoryContext?.selectedCommit || null;
326+
const matchingRead = runs.find(
327+
(run) =>
328+
run.contextSource === 'terminal-deposit-read-workbench' &&
329+
run.contextWorkbench === 'read-admission' &&
330+
run.repository === selectedRepository.fullName &&
331+
run.branch === sourceBranch &&
332+
(!sourceCommit || run.sourceCommit === sourceCommit),
333+
);
334+
return matchingRead?.id || null;
335+
}, [depositedSourceRevision, repositoryContext, runs, showDemonstrationSurfaces]);
317336

318337
const handleSelectTransaction = (transactionId: string) => {
319338
replaceTerminalRoute(transactionId);
@@ -589,7 +608,9 @@ export default function TerminalPageClient() {
589608
<TerminalDepositReadWorkbench
590609
repositoryContext={repositoryContext}
591610
depositedSourceRevision={depositedSourceRevision}
611+
admittedReadActivityId={admittedReadActivityId}
592612
onRecordActivity={handleRecordActivity}
613+
onHarnessCompleted={refreshLiveRuns}
593614
showDemonstrationWorkbench={showDemonstrationSurfaces}
594615
/>
595616
<TerminalCoreNativeSections

uapi/app/terminal/terminal-deposit-read-workbench.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ export type TerminalSourceRevision = {
1919
createdAt?: string | null;
2020
};
2121

22-
export type TerminalDepositedSourceRevision = TerminalSourceRevision;
22+
export type TerminalDepositedSourceRevision = TerminalSourceRevision & {
23+
depositAssetId?: string | null;
24+
hasWalletOrAttestationProof?: boolean | null;
25+
hasAssetMeasurementEvidence?: boolean | null;
26+
};
2327

2428
type ShellSnapshot = {
2529
canonLabel?: string | null;

0 commit comments

Comments
 (0)