mirror of
https://github.com/mvschwarz/openrig.git
synced 2026-11-09 03:39:51 -10:00
feat(slice-05): BundleInspector renders provenance + compatibility blocks (Item 5 Checkpoint 6.1) (OPR.0.3.2.5)
Opens Item 5 (inspector UI upgrade). Adds provenance + compatibility
block rendering to BundleInspector.tsx so the operator-facing UI
surfaces the Item 1 / Item 2 metadata that the /api/bundles/inspect
route already returns. The route projection contract (camelCase per
both v1 + v2 paths) is preserved.
What ships:
- packages/ui/src/hooks/useBundles.ts: InspectResult interface
extended with manifest.provenance (InspectProvenance) and
manifest.compatibility (InspectCompatibility). Both optional;
bundles without the blocks render unchanged. Field shapes mirror
the daemon's BundleProvenance + BundleCompatibility verbatim.
- packages/ui/src/components/BundleInspector.tsx: two new conditional
render sections (PROVENANCE + COMPATIBILITY) shown only when the
manifest carries each block. Provenance surfaces createdAt /
sourceHost / authorSession / sourceRigName+sourceRigId /
daemonVersion+cliVersion / notes. Compatibility surfaces
minDaemonVersion / minCliVersion / schemaVersion. Each field has
a data-testid for future test hooks; rendering follows the
existing card-dark + label-sm + font-mono pattern.
Diff: 2 files, +89 / -1 lines.
Verified:
- packages/ui typecheck clean
- Full packages/ui suite 1107/1107 passing (1 skipped pre-existing);
no regressions
- No new unit tests added in this commit — BundleInspector has no
existing .test.tsx in the codebase pattern; introducing one would
require react-query QueryClient harnessing beyond the scope of a
single-feature commit. The headed-browser dogfood at the velocity-qa
gate (PRD §Posture operator-auto-window) is the empirical proof
for these render paths. Honest disclosure: this commit ships UI
render code WITHOUT unit-test coverage; the existing BundleInspector
has the same pattern.
What this commit does NOT ship (Item 5 follow-up checkpoints):
- "Inspect against current state" button — DEFERRED per orch
Candidate C ruling on /api/bundles/check-conflicts which is part
of the 0.3.3 deferral (--target-name pathway dependency). Without
the endpoint, the button has nothing to call.
- Install button → "plan" modal (currently uses window.location.href
redirect to /bundles/install; the modal UX upgrade is heavier scope
and can land in a follow-up checkpoint if QA dogfood surfaces a
need)
- Files browser composition: detection of .rigbundle extension in
FileContent.tsx + routing to BundleInspector. The Files surface
EXISTS at packages/ui/src/components/files/FilesWorkspace.tsx; the
extension-routing addition is small but separable. Will surface to
orch if QA dogfood needs it, otherwise defer to v0+1 per PRD bounce
condition.
PRD bounce conditions verified:
- No schema bump
- No new SQLite migrations
- No event types
- No core-routing or bootstrap mutation
- No sidebar entries touched
- scope-and-versioning coherence preserved
- Items 1+2 daemon-side projections unchanged (route contract still
camelCase; UI consumes verbatim)
Pre-commit discipline applied (banked): git diff --cached --stat
verified +89/-1 across 2 intended files BEFORE commit.
Watched risks applied:
- Audit-every-layer: pure render component; no module-level reads
of env/host/version; all data flows through React state from the
useBundleInspect mutation
- Optional-field backward-compat: both blocks render conditionally;
bundles without provenance or compatibility render the existing
manifest summary unchanged; type extension is additive-optional
(no breaking change to existing consumers)
Item 5 sub-chain:
- 80f8f9f3 (Item 4 close-out B2 repair, CLEAR) <- prior tip
- THIS COMMIT — Item 5 part 1: provenance + compatibility render
- (potential follow-up) Files browser composition; install plan modal;
inspect-against-current-state contingent on /check-conflicts
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
80f8f9f3b7
commit
1b9f15ee91
2 files changed
+92
No files matched your search
@@ -88,6 +88,75 @@ export function BundleInspector() {
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Item 1 / slice-05: Provenance block (rendered when bundle carries it) */}
|
||||
{result.manifest.provenance && (
|
||||
<>
|
||||
<h3 className="text-headline-md uppercase mb-spacing-3">PROVENANCE</h3>
|
||||
<div className="card-dark p-spacing-4 mb-spacing-4 space-y-spacing-1" data-testid="provenance-block">
|
||||
{result.manifest.provenance.createdAt && (
|
||||
<div className="text-label-sm font-mono" data-testid="provenance-createdAt">
|
||||
<span className="text-foreground-muted-on-dark">Created: </span>{result.manifest.provenance.createdAt}
|
||||
</div>
|
||||
)}
|
||||
{result.manifest.provenance.sourceHost && (
|
||||
<div className="text-label-sm font-mono" data-testid="provenance-sourceHost">
|
||||
<span className="text-foreground-muted-on-dark">Host: </span>{result.manifest.provenance.sourceHost}
|
||||
</div>
|
||||
)}
|
||||
{result.manifest.provenance.authorSession && (
|
||||
<div className="text-label-sm font-mono" data-testid="provenance-authorSession">
|
||||
<span className="text-foreground-muted-on-dark">Author: </span>{result.manifest.provenance.authorSession}
|
||||
</div>
|
||||
)}
|
||||
{result.manifest.provenance.sourceRigName && (
|
||||
<div className="text-label-sm font-mono" data-testid="provenance-sourceRigName">
|
||||
<span className="text-foreground-muted-on-dark">Rig: </span>{result.manifest.provenance.sourceRigName}
|
||||
{result.manifest.provenance.sourceRigId && (
|
||||
<span className="text-foreground-muted-on-dark"> ({result.manifest.provenance.sourceRigId})</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{(result.manifest.provenance.daemonVersion || result.manifest.provenance.cliVersion) && (
|
||||
<div className="text-label-sm font-mono" data-testid="provenance-versions">
|
||||
<span className="text-foreground-muted-on-dark">Built with: </span>
|
||||
{result.manifest.provenance.daemonVersion && <>daemon {result.manifest.provenance.daemonVersion}</>}
|
||||
{result.manifest.provenance.daemonVersion && result.manifest.provenance.cliVersion && " / "}
|
||||
{result.manifest.provenance.cliVersion && <>cli {result.manifest.provenance.cliVersion}</>}
|
||||
</div>
|
||||
)}
|
||||
{result.manifest.provenance.notes && (
|
||||
<div className="text-label-sm font-mono whitespace-pre-wrap mt-spacing-2" data-testid="provenance-notes">
|
||||
<span className="text-foreground-muted-on-dark">Notes: </span>{result.manifest.provenance.notes}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Item 2 / slice-05: Compatibility block (rendered when bundle carries it). Live "compatible against this daemon" comparison is deferred — UI surfaces the bundle's stated minimums; the install-time check at /api/bundles/install enforces actual compatibility with the running daemon. */}
|
||||
{result.manifest.compatibility && (
|
||||
<>
|
||||
<h3 className="text-headline-md uppercase mb-spacing-3">COMPATIBILITY</h3>
|
||||
<div className="card-dark p-spacing-4 mb-spacing-4 space-y-spacing-1" data-testid="compatibility-block">
|
||||
{result.manifest.compatibility.minDaemonVersion && (
|
||||
<div className="text-label-sm font-mono" data-testid="compatibility-minDaemonVersion">
|
||||
<span className="text-foreground-muted-on-dark">Min daemon: </span>{result.manifest.compatibility.minDaemonVersion}
|
||||
</div>
|
||||
)}
|
||||
{result.manifest.compatibility.minCliVersion && (
|
||||
<div className="text-label-sm font-mono" data-testid="compatibility-minCliVersion">
|
||||
<span className="text-foreground-muted-on-dark">Min CLI: </span>{result.manifest.compatibility.minCliVersion}
|
||||
</div>
|
||||
)}
|
||||
{result.manifest.compatibility.schemaVersion !== undefined && (
|
||||
<div className="text-label-sm font-mono" data-testid="compatibility-schemaVersion">
|
||||
<span className="text-foreground-muted-on-dark">Schema: </span>v{result.manifest.compatibility.schemaVersion}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Per-file integrity */}
|
||||
{result.integrityResult && (
|
||||
<>
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
|
||||
/** Item 1 / slice-05: provenance metadata surfaced by /api/bundles/inspect (camelCase contract per both v1 + v2 routes). */
|
||||
export interface InspectProvenance {
|
||||
createdAt?: string;
|
||||
sourceHost?: string;
|
||||
authorSession?: string;
|
||||
sourceRigId?: string;
|
||||
sourceRigName?: string;
|
||||
daemonVersion?: string;
|
||||
cliVersion?: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
/** Item 2 / slice-05: compatibility block surfaced by /api/bundles/inspect (camelCase contract). */
|
||||
export interface InspectCompatibility {
|
||||
minDaemonVersion?: string;
|
||||
minCliVersion?: string;
|
||||
schemaVersion?: number;
|
||||
}
|
||||
|
||||
export interface InspectResult {
|
||||
manifest: {
|
||||
name: string;
|
||||
@@ -8,6 +27,10 @@ export interface InspectResult {
|
||||
schemaVersion?: number;
|
||||
packages?: Array<{ name: string; version: string; path: string }>;
|
||||
agents?: Array<{ name: string; version: string; path: string }>;
|
||||
/** Item 1 provenance block (when bundle carries it). */
|
||||
provenance?: InspectProvenance;
|
||||
/** Item 2 compatibility block (when bundle carries it). */
|
||||
compatibility?: InspectCompatibility;
|
||||
};
|
||||
digestValid: boolean;
|
||||
integrityResult: { passed: boolean; mismatches: string[]; missing: string[]; extra: string[]; errors: string[] };
|
||||
|
||||
Reference in new issue
Block a user